Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ class SearchBarManager :
view?.handleCancelSearchJsRequest()
}

override fun setActive(
view: SearchBarView?,
active: Boolean,
) = Unit

// iOS only

override fun setPlacement(
Expand Down Expand Up @@ -198,6 +203,11 @@ class SearchBarManager :
value: String?,
) = Unit

override fun setCancelButtonHidden(
view: SearchBarView?,
value: Boolean,
) = Unit

override fun setCancelButtonText(
view: SearchBarView?,
value: String?,
Expand Down
1 change: 1 addition & 0 deletions ios/legacy/RNSSearchBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@property (nonatomic, weak, nullable) id<RNSSearchBarNavigationItemDelegate> navigationItemDelegate;

@property (nonatomic) BOOL hideWhenScrolling;
@property (nonatomic) BOOL cancelButtonHidden;
@property (nonatomic) RNSSearchBarPlacement placement;
@property (nonatomic) BOOL allowToolbarIntegration;

Expand Down
54 changes: 51 additions & 3 deletions ios/legacy/RNSSearchBar.mm
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ static id RNSAddObserverRemovedWithSearchField(
@implementation RNSSearchBar {
UISearchController *_controller;
UIColor *_textColor;
BOOL _focusRequested;

// We use those booleans to log a warning if user attempts to restore
// default behavior after setting explicit value for the prop.
Expand Down Expand Up @@ -287,6 +288,17 @@ - (void)setCancelButtonText:(NSString *)text
[_controller.searchBar setValue:text forKey:@"cancelButtonText"];
}

- (void)setCancelButtonHidden:(BOOL)cancelButtonHidden
{
_cancelButtonHidden = cancelButtonHidden;
#if !TARGET_OS_TV
// Configure this before focus: changing the cancel control during activation
// rebuilds UIKit's integrated search field and can dismiss its keyboard.
[_controller.searchBar setShowsCancelButton:NO animated:NO];
_controller.automaticallyShowsCancelButton = !cancelButtonHidden;
#endif
}

- (void)hideCancelButton
{
#if !TARGET_OS_TV
Expand All @@ -302,7 +314,7 @@ - (void)hideCancelButton
- (void)showCancelButton
{
#if !TARGET_OS_TV
if (!_controller.automaticallyShowsCancelButton) {
if (!_cancelButtonHidden && !_controller.automaticallyShowsCancelButton) {
[_controller.searchBar setShowsCancelButton:YES animated:YES];
} else {
// On iOS 13+ UISearchController automatically shows/hides cancel button
Expand Down Expand Up @@ -390,6 +402,7 @@ - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
#if !TARGET_OS_TV
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
_focusRequested = NO;
_controller.searchBar.text = @"";
[self resignFirstResponder];
[self hideCancelButton];
Expand All @@ -401,12 +414,33 @@ - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar

- (void)blur
{
_focusRequested = NO;
[_controller.searchBar resignFirstResponder];
}

- (void)focus
{
[_controller.searchBar becomeFirstResponder];
_focusRequested = YES;
// Fabric can attach search and request focus in the same mounting transaction.
__weak RNSSearchBar *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
RNSSearchBar *strongSelf = weakSelf;
if (strongSelf == nil || !strongSelf->_focusRequested) {
return;
}
strongSelf->_focusRequested = NO;
#if !TARGET_OS_TV
// Integrated search replaces its field during layout. The configuration view
// is not mounted, so lay out its header's window before focusing that field.
id<RNSSearchBarNavigationItemDelegate> header = strongSelf.navigationItemDelegate;
if ([header isKindOfClass:UIView.class]) {
[((UIView *)header).window layoutIfNeeded];
}
[strongSelf->_controller.searchBar.searchTextField becomeFirstResponder];
#else
[strongSelf->_controller.searchBar becomeFirstResponder];
#endif
});
}

- (void)clearText
Expand All @@ -417,7 +451,7 @@ - (void)clearText
- (void)toggleCancelButton:(BOOL)flag
{
#if !TARGET_OS_TV
[_controller.searchBar setShowsCancelButton:flag animated:YES];
[_controller.searchBar setShowsCancelButton:flag && !_cancelButtonHidden animated:YES];
#endif
}

Expand All @@ -426,6 +460,16 @@ - (void)setText:(NSString *)text
[_controller.searchBar setText:text];
}

- (void)setActive:(BOOL)active
{
if (!active) {
_focusRequested = NO;
}
// Search can remain expanded after the keyboard is dismissed or its host reappears.
// Becoming first responder belongs to the separate focus command.
_controller.active = active;
}

- (void)cancelSearch
{
#if !TARGET_OS_TV
Expand All @@ -445,6 +489,10 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props::
[self setHideWhenScrolling:newScreenProps.hideWhenScrolling];
}

if (oldScreenProps.cancelButtonHidden != newScreenProps.cancelButtonHidden) {
self.cancelButtonHidden = newScreenProps.cancelButtonHidden;
}

if (oldScreenProps.cancelButtonText != newScreenProps.cancelButtonText) {
[self setCancelButtonText:RCTNSStringFromStringNilIfEmpty(newScreenProps.cancelButtonText)];
}
Expand Down
14 changes: 14 additions & 0 deletions ios/split/RNSSplitAppearanceApplicator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ - (void)updateSplitViewDisplayModeFor:(id<RNSSplitHostAppearanceProvider>)provid
return;
}

// UIKit's column transition also moves floating search toolbars. A UIView
// animation of preferredDisplayMode alone leaves those controls ahead of the sidebar.
if (splitHostController.style == UISplitViewControllerStyleDoubleColumn &&
(preferredDisplayMode == UISplitViewControllerDisplayModeOneBesideSecondary ||
preferredDisplayMode == UISplitViewControllerDisplayModeSecondaryOnly)) {
if (preferredDisplayMode == UISplitViewControllerDisplayModeSecondaryOnly) {
[splitHostController hideColumn:UISplitViewControllerColumnPrimary];
} else {
[splitHostController showColumn:UISplitViewControllerColumnPrimary];
}
splitHostController.preferredDisplayMode = preferredDisplayMode;
return;
}

[view layoutIfNeeded];
[UIView animateWithDuration:0.35
delay:0
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-screens",
"version": "5.0.0-t3.37",
"version": "5.0.0-t3.43",
"description": "Native navigation primitives for your React Native app.",
"scripts": {
"submodules": "git submodule update --init --recursive && (cd react-navigation && yarn && yarn build && cd ../)",
Expand Down
6 changes: 6 additions & 0 deletions src/fabric/legacy/SearchBarNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface NativeProps extends ViewProps {
obscureBackground?: CT.WithDefault<OptionalBoolean, 'undefined'>;
hideNavigationBar?: CT.WithDefault<OptionalBoolean, 'undefined'>;
cancelButtonText?: string | undefined;
cancelButtonHidden?: CT.WithDefault<boolean, false>;
// TODO: implement these on iOS
barTintColor?: ColorValue | undefined;
tintColor?: ColorValue | undefined;
Expand Down Expand Up @@ -84,6 +85,10 @@ interface NativeCommands {
flag: boolean,
) => void;
setText: (instance: React.ComponentRef<ComponentType>, text: string) => void;
setActive: (
instance: React.ComponentRef<ComponentType>,
active: boolean,
) => void;
cancelSearch: (instance: React.ComponentRef<ComponentType>) => void;
}

Expand All @@ -94,6 +99,7 @@ export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
'clearText',
'toggleCancelButton',
'setText',
'setActive',
'cancelSearch',
],
});
Expand Down
5 changes: 5 additions & 0 deletions src/legacy/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ function SearchBar(props: SearchBarProps) {
NativeSearchBarCommands.setText(instance, text),
);
},
setActive: (active: boolean) => {
_callWithNativeInstance(instance =>
NativeSearchBarCommands.setActive(instance, active),
);
},
cancelSearch: () => {
_callWithNativeInstance(instance =>
NativeSearchBarCommands.cancelSearch(instance),
Expand Down
10 changes: 10 additions & 0 deletions src/legacy/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type SearchBarCommands = {
clearText: () => void;
toggleCancelButton: (show: boolean) => void;
setText: (text: string) => void;
setActive: (active: boolean) => void;
cancelSearch: () => void;
};

Expand Down Expand Up @@ -969,6 +970,7 @@ export interface SearchBarProps {
* * `blur` - removes focus from the search bar
* * `clearText` - removes any text present in the search bar input field
* * `setText` - sets the search bar's content to given value
* * `setActive` - presents or dismisses iOS search without requesting keyboard focus
* * `cancelSearch` - cancel search in search bar.
* * `toggleCancelButton` - depending on passed boolean value, hides or shows cancel button (iOS only)
*/
Expand Down Expand Up @@ -1013,6 +1015,14 @@ export interface SearchBarProps {
* @platform ios
*/
cancelButtonText?: string | undefined;
/**
* Hides the cancel button, including while the search field is focused.
* Use when another control provides the search dismissal action.
* Defaults to `false`.
*
* @platform ios
*/
cancelButtonHidden?: boolean | undefined;
/**
* Specifies whether the back button should close search bar's text input or not.
*
Expand Down