Skip to content

Commit 299ce6a

Browse files
committed
Add types for native search bar
1 parent 6dacf11 commit 299ce6a

File tree

5 files changed

+82
-81
lines changed

5 files changed

+82
-81
lines changed

src/components/SearchBar.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,30 @@ import {
33
isSearchBarAvailableForCurrentPlatform,
44
SearchBarCommands,
55
SearchBarProps,
6-
RenamedSearchBarProps,
6+
SearchBarEvents,
77
} from 'react-native-screens';
8-
import { View } from 'react-native';
8+
import { View, NativeSyntheticEvent, TargetedEvent } from 'react-native';
99

1010
// Native components
1111
import SearchBarNativeComponent, {
1212
Commands as SearchBarNativeCommands,
13+
SearchBarNativeProps,
1314
} from '../fabric/SearchBarNativeComponent';
1415

15-
export const NativeSearchBar: React.ComponentType<RenamedSearchBarProps> &
16+
// Remove all events from SearchBar native component, since they differ from types in SearchBarEvents
17+
// and add ref object for commands.
18+
type SearchBarNativeType = Omit<
19+
SearchBarNativeProps,
20+
keyof SearchBarEvents | 'onSearchFocus' | 'onSearchBlur'
21+
> & {
22+
ref?: React.RefObject<SearchBarCommands>;
23+
onSearchFocus?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
24+
onSearchBlur?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
25+
};
26+
27+
export const NativeSearchBar: React.ComponentType<SearchBarNativeType> &
1628
typeof NativeSearchBarCommands =
17-
SearchBarNativeComponent as unknown as React.ComponentType<RenamedSearchBarProps> &
29+
SearchBarNativeComponent as unknown as React.ComponentType<SearchBarNativeType> &
1830
SearchBarCommandsType;
1931
export const NativeSearchBarCommands: SearchBarCommandsType =
2032
SearchBarNativeCommands as SearchBarCommandsType;
@@ -30,7 +42,10 @@ type SearchBarCommandsType = {
3042
cancelSearch: (viewRef: NativeSearchBarRef) => void;
3143
};
3244

33-
function SearchBar(props: SearchBarProps, ref: React.Ref<SearchBarCommands>) {
45+
function SearchBar(
46+
props: SearchBarProps & SearchBarEvents,
47+
ref: React.Ref<SearchBarCommands>
48+
) {
3449
const searchBarRef = React.useRef<SearchBarCommands | null>(null);
3550

3651
React.useImperativeHandle(ref, () => ({
@@ -87,4 +102,7 @@ function SearchBar(props: SearchBarProps, ref: React.Ref<SearchBarCommands>) {
87102
);
88103
}
89104

90-
export default React.forwardRef<SearchBarCommands, SearchBarProps>(SearchBar);
105+
export default React.forwardRef<
106+
SearchBarCommands,
107+
SearchBarProps & SearchBarEvents
108+
>(SearchBar);

src/fabric/SearchBarNativeComponent.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type SearchBarPlacement = 'automatic' | 'inline' | 'stacked';
2121

2222
type AutoCapitalizeType = 'none' | 'words' | 'sentences' | 'characters';
2323

24-
interface NativeProps extends ViewProps {
24+
export interface SearchBarNativeProps extends ViewProps {
2525
onSearchFocus?: DirectEventHandler<SearchBarEvent> | null;
2626
onSearchBlur?: DirectEventHandler<SearchBarEvent> | null;
2727
onSearchButtonPress?: DirectEventHandler<SearchButtonPressedEvent> | null;
@@ -50,9 +50,9 @@ interface NativeProps extends ViewProps {
5050
shouldShowHintSearchIcon?: WithDefault<boolean, true>;
5151
}
5252

53-
type ComponentType = HostComponent<NativeProps>;
53+
type ComponentType = HostComponent<SearchBarNativeProps>;
5454

55-
interface NativeCommands {
55+
interface SearchBarNativeCommands {
5656
blur: (viewRef: React.ElementRef<ComponentType>) => void;
5757
focus: (viewRef: React.ElementRef<ComponentType>) => void;
5858
clearText: (viewRef: React.ElementRef<ComponentType>) => void;
@@ -64,15 +64,16 @@ interface NativeCommands {
6464
cancelSearch: (viewRef: React.ElementRef<ComponentType>) => void;
6565
}
6666

67-
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
68-
supportedCommands: [
69-
'blur',
70-
'focus',
71-
'clearText',
72-
'toggleCancelButton',
73-
'setText',
74-
'cancelSearch',
75-
],
76-
});
67+
export const Commands: SearchBarNativeCommands =
68+
codegenNativeCommands<SearchBarNativeCommands>({
69+
supportedCommands: [
70+
'blur',
71+
'focus',
72+
'clearText',
73+
'toggleCancelButton',
74+
'setText',
75+
'cancelSearch',
76+
],
77+
});
7778

78-
export default codegenNativeComponent<NativeProps>('RNSSearchBar', {});
79+
export default codegenNativeComponent<SearchBarNativeProps>('RNSSearchBar', {});

src/native-stack/types.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
ScreenProps,
2323
ScreenStackHeaderConfigProps,
2424
SearchBarProps,
25+
SearchBarEvents,
2526
SheetDetentTypes,
2627
} from 'react-native-screens';
2728

@@ -334,7 +335,7 @@ export type NativeStackNavigationOptions = {
334335
/**
335336
* Object in which you should pass props in order to render native iOS searchBar.
336337
*/
337-
searchBar?: SearchBarProps;
338+
searchBar?: SearchBarProps & SearchBarEvents;
338339
/**
339340
* Describes heights where a sheet can rest.
340341
* Works only when `stackPresentation` is set to `formSheet`.

src/native-stack/views/HeaderConfig.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
ScreenStackHeaderRightView,
1010
ScreenStackHeaderSearchBarView,
1111
SearchBar,
12-
SearchBarProps,
12+
SearchBarEvents,
1313
isSearchBarAvailableForCurrentPlatform,
1414
executeNativeBackPress,
1515
} from 'react-native-screens';
@@ -84,11 +84,11 @@ export default function HeaderConfig({
8484
searchBar &&
8585
!searchBar.disableBackButtonOverride
8686
) {
87-
const onFocus: SearchBarProps['onFocus'] = (...args) => {
87+
const onFocus: SearchBarEvents['onFocus'] = (...args) => {
8888
createSubscription();
8989
searchBar.onFocus?.(...args);
9090
};
91-
const onClose: SearchBarProps['onClose'] = (...args) => {
91+
const onClose: SearchBarEvents['onClose'] = (...args) => {
9292
clearSubscription();
9393
searchBar.onClose?.(...args);
9494
};

src/types.tsx

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -633,44 +633,6 @@ export interface SearchBarProps {
633633
* Indicates whether to obscure the underlying content
634634
*/
635635
obscureBackground?: boolean;
636-
/**
637-
* A callback that gets called when search bar has lost focus
638-
*/
639-
onBlur?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
640-
/**
641-
* A callback that gets called when the cancel button is pressed
642-
*
643-
* @platform ios
644-
*/
645-
onCancelButtonPress?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
646-
647-
/**
648-
* A callback that gets called when the text changes. It receives the current text value of the search bar.
649-
*/
650-
onChangeText?: (e: NativeSyntheticEvent<TextInputFocusEventData>) => void;
651-
652-
/**
653-
* A callback that gets called when search bar is closed
654-
*
655-
* @platform android
656-
*/
657-
onClose?: () => void;
658-
/**
659-
* A callback that gets called when search bar has received focus
660-
*/
661-
onFocus?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
662-
/**
663-
* A callback that gets called when search bar is opened
664-
*
665-
* @platform android
666-
*/
667-
onOpen?: () => void;
668-
/**
669-
* A callback that gets called when the search button is pressed. It receives the current text value of the search bar.
670-
*/
671-
onSearchButtonPress?: (
672-
e: NativeSyntheticEvent<TextInputFocusEventData>
673-
) => void;
674636
/**
675637
* Text displayed when search field is empty
676638
*/
@@ -714,23 +676,42 @@ export interface SearchBarProps {
714676
shouldShowHintSearchIcon?: boolean;
715677
}
716678

717-
/**
718-
* Since the search bar is a component that is extended from View on iOS,
719-
* we can't use onFocus and onBlur events directly there (as of the event naming conflicts).
720-
* To omit any breaking changes, we're handling this type to rename onFocus and onBlur events
721-
* to onSearchFocus and onSearchBlur inside the native component of the search bar.
722-
*/
723-
export type RenamedSearchBarProps = Rename<
724-
SearchBarProps,
725-
{ onFocus: 'onSearchFocus'; onBlur: 'onSearchBlur' }
726-
>;
679+
export interface SearchBarEvents {
680+
/**
681+
* A callback that gets called when search bar has received focus
682+
*/
683+
onFocus?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
684+
/**
685+
* A callback that gets called when search bar has lost focus
686+
*/
687+
onBlur?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
688+
/**
689+
* A callback that gets called when the search button is pressed. It receives the current text value of the search bar.
690+
*/
691+
onSearchButtonPress?: (
692+
e: NativeSyntheticEvent<TextInputFocusEventData>
693+
) => void;
694+
/**
695+
* A callback that gets called when the cancel button is pressed
696+
*
697+
* @platform ios
698+
*/
699+
onCancelButtonPress?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
727700

728-
/**
729-
* Helper type, used to rename certain keys in the interface, given from object.
730-
*/
731-
type Rename<
732-
T,
733-
R extends {
734-
[K in keyof R]: K extends keyof T ? PropertyKey : 'Error: key not in T';
735-
}
736-
> = { [P in keyof T as P extends keyof R ? R[P] : P]: T[P] };
701+
/**
702+
* A callback that gets called when the text changes. It receives the current text value of the search bar.
703+
*/
704+
onChangeText?: (e: NativeSyntheticEvent<TextInputFocusEventData>) => void;
705+
/**
706+
* A callback that gets called when search bar is opened
707+
*
708+
* @platform android
709+
*/
710+
onOpen?: () => void;
711+
/**
712+
* A callback that gets called when search bar is closed
713+
*
714+
* @platform android
715+
*/
716+
onClose?: () => void;
717+
}

0 commit comments

Comments
 (0)