one 1.2.69 → 1.2.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/__mocks__/@react-navigation/native-stack.cjs +29 -0
- package/dist/cjs/__mocks__/@react-navigation/native-stack.js +24 -0
- package/dist/cjs/__mocks__/@react-navigation/native-stack.js.map +6 -0
- package/dist/cjs/__mocks__/@react-navigation/native-stack.native.js +38 -0
- package/dist/cjs/__mocks__/@react-navigation/native-stack.native.js.map +1 -0
- package/dist/cjs/__mocks__/@react-navigation/native.js +45 -0
- package/dist/cjs/__mocks__/@react-navigation/native.js.map +1 -0
- package/dist/cjs/__mocks__/expo-linking.cjs +36 -0
- package/dist/cjs/__mocks__/expo-linking.js +25 -0
- package/dist/cjs/__mocks__/expo-linking.js.map +6 -0
- package/dist/cjs/__mocks__/expo-linking.native.js +47 -0
- package/dist/cjs/__mocks__/expo-linking.native.js.map +1 -0
- package/dist/cjs/__mocks__/expo-modules-core.cjs +36 -0
- package/dist/cjs/__mocks__/expo-modules-core.js +31 -0
- package/dist/cjs/__mocks__/expo-modules-core.js.map +6 -0
- package/dist/cjs/__mocks__/expo-modules-core.native.js +67 -0
- package/dist/cjs/__mocks__/expo-modules-core.native.js.map +1 -0
- package/dist/cjs/__mocks__/react-native-screens.cjs +28 -0
- package/dist/cjs/__mocks__/react-native-screens.js +22 -0
- package/dist/cjs/__mocks__/react-native-screens.js.map +6 -0
- package/dist/cjs/__mocks__/react-native-screens.native.js +31 -0
- package/dist/cjs/__mocks__/react-native-screens.native.js.map +1 -0
- package/dist/cjs/__mocks__/react-native.js +49 -0
- package/dist/cjs/__mocks__/react-native.js.map +1 -0
- package/dist/cjs/cli/build.cjs +9 -1
- package/dist/cjs/cli/build.js +8 -1
- package/dist/cjs/cli/build.js.map +1 -1
- package/dist/cjs/cli/build.native.js +13 -1
- package/dist/cjs/cli/build.native.js.map +1 -1
- package/dist/cjs/fork/NavigationContainer.js.map +1 -1
- package/dist/cjs/fork/NavigationContainer.native.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/layouts/Stack.cjs +75 -6
- package/dist/cjs/layouts/Stack.js +44 -4
- package/dist/cjs/layouts/Stack.js.map +2 -2
- package/dist/cjs/layouts/Stack.native.js +81 -6
- package/dist/cjs/layouts/Stack.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.cjs +40 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.js +35 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js +43 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.cjs +90 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.js +68 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js +99 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.cjs +35 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.js +30 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js +40 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.cjs +35 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.js +30 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js +40 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.cjs +35 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.js +30 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js +38 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.cjs +65 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.js +52 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js +68 -0
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/StackScreen.cjs +57 -0
- package/dist/cjs/layouts/stack-utils/StackScreen.js +43 -0
- package/dist/cjs/layouts/stack-utils/StackScreen.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/StackScreen.native.js +64 -0
- package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.cjs +455 -0
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.js +406 -0
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js +480 -0
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -0
- package/dist/cjs/layouts/stack-utils/index.cjs +47 -0
- package/dist/cjs/layouts/stack-utils/index.js +36 -0
- package/dist/cjs/layouts/stack-utils/index.js.map +6 -0
- package/dist/cjs/layouts/stack-utils/index.native.js +50 -0
- package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -0
- package/dist/cjs/layouts/withLayoutContext.cjs +2 -1
- package/dist/cjs/layouts/withLayoutContext.js +2 -2
- package/dist/cjs/layouts/withLayoutContext.js.map +1 -1
- package/dist/cjs/layouts/withLayoutContext.native.js +3 -2
- package/dist/cjs/layouts/withLayoutContext.native.js.map +1 -1
- package/dist/cjs/useLoader.cjs +4 -2
- package/dist/cjs/useLoader.js +4 -2
- package/dist/cjs/useLoader.js.map +1 -1
- package/dist/cjs/useLoader.native.js +4 -2
- package/dist/cjs/useLoader.native.js.map +1 -1
- package/dist/cjs/utils/children.cjs +46 -0
- package/dist/cjs/utils/children.js +47 -0
- package/dist/cjs/utils/children.js.map +6 -0
- package/dist/cjs/utils/children.native.js +76 -0
- package/dist/cjs/utils/children.native.js.map +1 -0
- package/dist/cjs/utils/style.cjs +28 -0
- package/dist/cjs/utils/style.js +24 -0
- package/dist/cjs/utils/style.js.map +6 -0
- package/dist/cjs/utils/style.native.js +31 -0
- package/dist/cjs/utils/style.native.js.map +1 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.js +8 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.js.map +6 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.mjs +6 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.mjs.map +1 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.native.js +12 -0
- package/dist/esm/__mocks__/@react-navigation/native-stack.native.js.map +1 -0
- package/dist/esm/__mocks__/@react-navigation/native.js +18 -0
- package/dist/esm/__mocks__/@react-navigation/native.js.map +1 -0
- package/dist/esm/__mocks__/expo-linking.js +9 -0
- package/dist/esm/__mocks__/expo-linking.js.map +6 -0
- package/dist/esm/__mocks__/expo-linking.mjs +10 -0
- package/dist/esm/__mocks__/expo-linking.mjs.map +1 -0
- package/dist/esm/__mocks__/expo-linking.native.js +18 -0
- package/dist/esm/__mocks__/expo-linking.native.js.map +1 -0
- package/dist/esm/__mocks__/expo-modules-core.js +15 -0
- package/dist/esm/__mocks__/expo-modules-core.js.map +6 -0
- package/dist/esm/__mocks__/expo-modules-core.mjs +10 -0
- package/dist/esm/__mocks__/expo-modules-core.mjs.map +1 -0
- package/dist/esm/__mocks__/expo-modules-core.native.js +38 -0
- package/dist/esm/__mocks__/expo-modules-core.native.js.map +1 -0
- package/dist/esm/__mocks__/react-native-screens.js +6 -0
- package/dist/esm/__mocks__/react-native-screens.js.map +6 -0
- package/dist/esm/__mocks__/react-native-screens.mjs +4 -0
- package/dist/esm/__mocks__/react-native-screens.mjs.map +1 -0
- package/dist/esm/__mocks__/react-native-screens.native.js +4 -0
- package/dist/esm/__mocks__/react-native-screens.native.js.map +1 -0
- package/dist/esm/__mocks__/react-native.js +19 -0
- package/dist/esm/__mocks__/react-native.js.map +1 -0
- package/dist/esm/cli/build.js +8 -1
- package/dist/esm/cli/build.js.map +1 -1
- package/dist/esm/cli/build.mjs +9 -1
- package/dist/esm/cli/build.mjs.map +1 -1
- package/dist/esm/cli/build.native.js +13 -1
- package/dist/esm/cli/build.native.js.map +1 -1
- package/dist/esm/fork/NavigationContainer.js.map +1 -1
- package/dist/esm/fork/NavigationContainer.mjs.map +1 -1
- package/dist/esm/fork/NavigationContainer.native.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/layouts/Stack.js +45 -1
- package/dist/esm/layouts/Stack.js.map +1 -1
- package/dist/esm/layouts/Stack.mjs +59 -1
- package/dist/esm/layouts/Stack.mjs.map +1 -1
- package/dist/esm/layouts/Stack.native.js +65 -1
- package/dist/esm/layouts/Stack.native.js.map +1 -1
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.js +19 -0
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.mjs +16 -0
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.native.js +16 -0
- package/dist/esm/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.js +71 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.mjs +66 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.native.js +72 -0
- package/dist/esm/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.js +14 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.mjs +11 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.native.js +13 -0
- package/dist/esm/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.js +14 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.mjs +11 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.native.js +13 -0
- package/dist/esm/layouts/stack-utils/StackHeaderRight.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.js +14 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.mjs +11 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.native.js +11 -0
- package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.js +37 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.mjs +41 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.native.js +41 -0
- package/dist/esm/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/StackScreen.js +33 -0
- package/dist/esm/layouts/stack-utils/StackScreen.js.map +6 -0
- package/dist/esm/layouts/stack-utils/StackScreen.mjs +33 -0
- package/dist/esm/layouts/stack-utils/StackScreen.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/StackScreen.native.js +38 -0
- package/dist/esm/layouts/stack-utils/StackScreen.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.js +431 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.js.map +6 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs +456 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js +478 -0
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -0
- package/dist/esm/layouts/stack-utils/index.js +33 -0
- package/dist/esm/layouts/stack-utils/index.js.map +6 -0
- package/dist/esm/layouts/stack-utils/index.mjs +16 -0
- package/dist/esm/layouts/stack-utils/index.mjs.map +1 -0
- package/dist/esm/layouts/stack-utils/index.native.js +16 -0
- package/dist/esm/layouts/stack-utils/index.native.js.map +1 -0
- package/dist/esm/layouts/withLayoutContext.js +2 -1
- package/dist/esm/layouts/withLayoutContext.js.map +1 -1
- package/dist/esm/layouts/withLayoutContext.mjs +2 -1
- package/dist/esm/layouts/withLayoutContext.mjs.map +1 -1
- package/dist/esm/layouts/withLayoutContext.native.js +2 -1
- package/dist/esm/layouts/withLayoutContext.native.js.map +1 -1
- package/dist/esm/useLoader.js +4 -2
- package/dist/esm/useLoader.js.map +1 -1
- package/dist/esm/useLoader.mjs +4 -2
- package/dist/esm/useLoader.mjs.map +1 -1
- package/dist/esm/useLoader.native.js +4 -2
- package/dist/esm/useLoader.native.js.map +1 -1
- package/dist/esm/utils/children.js +33 -0
- package/dist/esm/utils/children.js.map +6 -0
- package/dist/esm/utils/children.mjs +19 -0
- package/dist/esm/utils/children.mjs.map +1 -0
- package/dist/esm/utils/children.native.js +46 -0
- package/dist/esm/utils/children.native.js.map +1 -0
- package/dist/esm/utils/style.js +8 -0
- package/dist/esm/utils/style.js.map +6 -0
- package/dist/esm/utils/style.mjs +5 -0
- package/dist/esm/utils/style.mjs.map +1 -0
- package/dist/esm/utils/style.native.js +5 -0
- package/dist/esm/utils/style.native.js.map +1 -0
- package/package.json +9 -9
- package/src/__mocks__/@react-navigation/native-stack.ts +32 -0
- package/src/__mocks__/@react-navigation/native.ts +21 -0
- package/src/__mocks__/expo-linking.ts +6 -0
- package/src/__mocks__/expo-modules-core.ts +11 -0
- package/src/__mocks__/react-native-screens.ts +17 -0
- package/src/__mocks__/react-native.ts +20 -0
- package/src/cli/build.ts +27 -2
- package/src/fork/NavigationContainer.tsx +2 -0
- package/src/index.ts +10 -0
- package/src/layouts/Stack.tsx +96 -1
- package/src/layouts/stack-utils/README.md +211 -0
- package/src/layouts/stack-utils/StackHeaderBackButton.tsx +34 -0
- package/src/layouts/stack-utils/StackHeaderComponent.tsx +136 -0
- package/src/layouts/stack-utils/StackHeaderLeft.tsx +29 -0
- package/src/layouts/stack-utils/StackHeaderRight.tsx +29 -0
- package/src/layouts/stack-utils/StackHeaderSearchBar.tsx +21 -0
- package/src/layouts/stack-utils/StackHeaderTitle.tsx +79 -0
- package/src/layouts/stack-utils/StackScreen.tsx +69 -0
- package/src/layouts/stack-utils/__tests__/composition.test.tsx +643 -0
- package/src/layouts/stack-utils/index.tsx +45 -0
- package/src/layouts/withLayoutContext.tsx +6 -2
- package/src/router/router.ts +1 -1
- package/src/useLoader.ts +14 -6
- package/src/utils/children.ts +74 -0
- package/src/utils/style.ts +17 -0
- package/types/__mocks__/@react-navigation/native-stack.d.ts +30 -0
- package/types/__mocks__/@react-navigation/native-stack.d.ts.map +1 -0
- package/types/__mocks__/@react-navigation/native.d.ts +17 -0
- package/types/__mocks__/@react-navigation/native.d.ts.map +1 -0
- package/types/__mocks__/expo-linking.d.ts +9 -0
- package/types/__mocks__/expo-linking.d.ts.map +1 -0
- package/types/__mocks__/expo-modules-core.d.ts +11 -0
- package/types/__mocks__/expo-modules-core.d.ts.map +1 -0
- package/types/__mocks__/react-native-screens.d.ts +14 -0
- package/types/__mocks__/react-native-screens.d.ts.map +1 -0
- package/types/__mocks__/react-native.d.ts +12 -0
- package/types/__mocks__/react-native.d.ts.map +1 -0
- package/types/cli/build.d.ts.map +1 -1
- package/types/fork/NavigationContainer.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/layouts/Stack.d.ts +14 -3
- package/types/layouts/Stack.d.ts.map +1 -1
- package/types/layouts/stack-utils/StackHeaderBackButton.d.ts +17 -0
- package/types/layouts/stack-utils/StackHeaderBackButton.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackHeaderComponent.d.ts +36 -0
- package/types/layouts/stack-utils/StackHeaderComponent.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackHeaderLeft.d.ts +13 -0
- package/types/layouts/stack-utils/StackHeaderLeft.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackHeaderRight.d.ts +13 -0
- package/types/layouts/stack-utils/StackHeaderRight.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackHeaderSearchBar.d.ts +10 -0
- package/types/layouts/stack-utils/StackHeaderSearchBar.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackHeaderTitle.d.ts +26 -0
- package/types/layouts/stack-utils/StackHeaderTitle.d.ts.map +1 -0
- package/types/layouts/stack-utils/StackScreen.d.ts +22 -0
- package/types/layouts/stack-utils/StackScreen.d.ts.map +1 -0
- package/types/layouts/stack-utils/index.d.ts +20 -0
- package/types/layouts/stack-utils/index.d.ts.map +1 -0
- package/types/layouts/withLayoutContext.d.ts.map +1 -1
- package/types/useLoader.d.ts.map +1 -1
- package/types/utils/children.d.ts +23 -0
- package/types/utils/children.d.ts.map +1 -0
- package/types/utils/style.d.ts +7 -0
- package/types/utils/style.d.ts.map +1 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
|
|
4
|
+
import { Children, isValidElement, useMemo, type PropsWithChildren } from 'react'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
StackHeaderComponent,
|
|
8
|
+
appendStackHeaderPropsToOptions,
|
|
9
|
+
type StackHeaderProps,
|
|
10
|
+
} from './StackHeaderComponent'
|
|
11
|
+
import { Screen } from '../../views/Screen'
|
|
12
|
+
|
|
13
|
+
export interface StackScreenProps extends PropsWithChildren {
|
|
14
|
+
name?: string
|
|
15
|
+
options?: NativeStackNavigationOptions
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Stack screen component with support for compositional header configuration.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <Stack.Screen name="home" options={{ title: 'Home' }}>
|
|
24
|
+
* <Stack.Header>
|
|
25
|
+
* <Stack.Header.Title large>Welcome</Stack.Header.Title>
|
|
26
|
+
* <Stack.Header.SearchBar placeholder="Search..." />
|
|
27
|
+
* </Stack.Header>
|
|
28
|
+
* </Stack.Screen>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function StackScreen({ children, options, ...rest }: StackScreenProps) {
|
|
32
|
+
const updatedOptions = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
appendScreenStackPropsToOptions(options ?? {}, {
|
|
35
|
+
children,
|
|
36
|
+
}),
|
|
37
|
+
[options, children]
|
|
38
|
+
)
|
|
39
|
+
return <Screen {...rest} options={updatedOptions} />
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function appendScreenStackPropsToOptions(
|
|
43
|
+
options: NativeStackNavigationOptions,
|
|
44
|
+
props: StackScreenProps
|
|
45
|
+
): NativeStackNavigationOptions {
|
|
46
|
+
let updatedOptions = { ...options, ...props.options }
|
|
47
|
+
|
|
48
|
+
function appendChildOptions(
|
|
49
|
+
child: React.ReactElement,
|
|
50
|
+
options: NativeStackNavigationOptions
|
|
51
|
+
) {
|
|
52
|
+
if (child.type === StackHeaderComponent) {
|
|
53
|
+
return appendStackHeaderPropsToOptions(options, child.props as StackHeaderProps)
|
|
54
|
+
} else {
|
|
55
|
+
console.warn(
|
|
56
|
+
`Warning: Unknown child element passed to Stack.Screen: ${(child.type as { name: string }).name ?? child.type}`
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
return options
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Children.forEach(props.children, (child) => {
|
|
63
|
+
if (isValidElement(child)) {
|
|
64
|
+
updatedOptions = appendChildOptions(child, updatedOptions)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return updatedOptions
|
|
69
|
+
}
|
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Platform } from 'react-native'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
StackHeaderTitle,
|
|
7
|
+
appendStackHeaderTitlePropsToOptions,
|
|
8
|
+
} from '../StackHeaderTitle'
|
|
9
|
+
import { StackHeaderLeft, appendStackHeaderLeftPropsToOptions } from '../StackHeaderLeft'
|
|
10
|
+
import {
|
|
11
|
+
StackHeaderRight,
|
|
12
|
+
appendStackHeaderRightPropsToOptions,
|
|
13
|
+
} from '../StackHeaderRight'
|
|
14
|
+
import {
|
|
15
|
+
StackHeaderBackButton,
|
|
16
|
+
appendStackHeaderBackButtonPropsToOptions,
|
|
17
|
+
} from '../StackHeaderBackButton'
|
|
18
|
+
import {
|
|
19
|
+
StackHeaderSearchBar,
|
|
20
|
+
appendStackHeaderSearchBarPropsToOptions,
|
|
21
|
+
} from '../StackHeaderSearchBar'
|
|
22
|
+
import {
|
|
23
|
+
StackHeaderComponent,
|
|
24
|
+
appendStackHeaderPropsToOptions,
|
|
25
|
+
} from '../StackHeaderComponent'
|
|
26
|
+
import { appendScreenStackPropsToOptions } from '../StackScreen'
|
|
27
|
+
import { StackHeader } from '../index'
|
|
28
|
+
|
|
29
|
+
describe('Stack Header Composition', () => {
|
|
30
|
+
describe('StackHeaderTitle', () => {
|
|
31
|
+
it('sets title from children', () => {
|
|
32
|
+
const result = appendStackHeaderTitlePropsToOptions({}, { children: 'My Title' })
|
|
33
|
+
expect(result.title).toBe('My Title')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('sets headerLargeTitle when large is true', () => {
|
|
37
|
+
const result = appendStackHeaderTitlePropsToOptions({}, { large: true })
|
|
38
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('sets headerTitleAlign from style.textAlign', () => {
|
|
42
|
+
const result = appendStackHeaderTitlePropsToOptions(
|
|
43
|
+
{},
|
|
44
|
+
{
|
|
45
|
+
style: { textAlign: 'center' },
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
expect(result.headerTitleAlign).toBe('center')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('converts numeric fontWeight to string', () => {
|
|
52
|
+
const result = appendStackHeaderTitlePropsToOptions(
|
|
53
|
+
{},
|
|
54
|
+
{
|
|
55
|
+
style: { fontWeight: '700' },
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
expect(result.headerTitleStyle).toMatchObject({ fontWeight: '700' })
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('preserves existing options', () => {
|
|
62
|
+
const result = appendStackHeaderTitlePropsToOptions(
|
|
63
|
+
{ animation: 'slide_from_right' },
|
|
64
|
+
{ children: 'Title' }
|
|
65
|
+
)
|
|
66
|
+
expect(result.animation).toBe('slide_from_right')
|
|
67
|
+
expect(result.title).toBe('Title')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('sets headerTransparent only on iOS when large is true', () => {
|
|
71
|
+
// Store original Platform.OS
|
|
72
|
+
const originalOS = Platform.OS
|
|
73
|
+
|
|
74
|
+
// Test on iOS - should set headerTransparent
|
|
75
|
+
;(Platform as any).OS = 'ios'
|
|
76
|
+
const iosResult = appendStackHeaderTitlePropsToOptions({}, { large: true })
|
|
77
|
+
expect(iosResult.headerTransparent).toBe(true)
|
|
78
|
+
|
|
79
|
+
// Test on Android - should NOT set headerTransparent
|
|
80
|
+
;(Platform as any).OS = 'android'
|
|
81
|
+
const androidResult = appendStackHeaderTitlePropsToOptions({}, { large: true })
|
|
82
|
+
expect(androidResult.headerTransparent).toBeUndefined()
|
|
83
|
+
|
|
84
|
+
// Test on web - should NOT set headerTransparent
|
|
85
|
+
;(Platform as any).OS = 'web'
|
|
86
|
+
const webResult = appendStackHeaderTitlePropsToOptions({}, { large: true })
|
|
87
|
+
expect(webResult.headerTransparent).toBeUndefined()
|
|
88
|
+
|
|
89
|
+
// Restore original
|
|
90
|
+
;(Platform as any).OS = originalOS
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('StackHeaderLeft', () => {
|
|
95
|
+
it('does not set headerLeft without asChild', () => {
|
|
96
|
+
const result = appendStackHeaderLeftPropsToOptions(
|
|
97
|
+
{},
|
|
98
|
+
{
|
|
99
|
+
children: <button>Back</button>,
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
expect(result.headerLeft).toBeUndefined()
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('sets headerLeft with asChild', () => {
|
|
106
|
+
const CustomButton = () => <button>Back</button>
|
|
107
|
+
const result = appendStackHeaderLeftPropsToOptions(
|
|
108
|
+
{},
|
|
109
|
+
{
|
|
110
|
+
asChild: true,
|
|
111
|
+
children: <CustomButton />,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
expect(result.headerLeft).toBeDefined()
|
|
115
|
+
expect(typeof result.headerLeft).toBe('function')
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('sets headerLeft with asChild even without children', () => {
|
|
119
|
+
const result = appendStackHeaderLeftPropsToOptions({}, { asChild: true })
|
|
120
|
+
// headerLeft is set as a function that returns undefined children
|
|
121
|
+
expect(result.headerLeft).toBeDefined()
|
|
122
|
+
expect(typeof result.headerLeft).toBe('function')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('preserves existing options when setting headerLeft', () => {
|
|
126
|
+
const result = appendStackHeaderLeftPropsToOptions(
|
|
127
|
+
{ title: 'Existing Title', animation: 'slide_from_right' },
|
|
128
|
+
{
|
|
129
|
+
asChild: true,
|
|
130
|
+
children: <button>Back</button>,
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
expect(result.title).toBe('Existing Title')
|
|
134
|
+
expect(result.animation).toBe('slide_from_right')
|
|
135
|
+
expect(result.headerLeft).toBeDefined()
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('headerLeft function returns children when called', () => {
|
|
139
|
+
const BackButton = () => <button>Back</button>
|
|
140
|
+
const result = appendStackHeaderLeftPropsToOptions(
|
|
141
|
+
{},
|
|
142
|
+
{
|
|
143
|
+
asChild: true,
|
|
144
|
+
children: <BackButton />,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
const headerLeftResult = result.headerLeft?.({} as any)
|
|
148
|
+
expect(headerLeftResult).toBeDefined()
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('StackHeaderRight', () => {
|
|
153
|
+
it('does not set headerRight without asChild', () => {
|
|
154
|
+
const result = appendStackHeaderRightPropsToOptions(
|
|
155
|
+
{},
|
|
156
|
+
{
|
|
157
|
+
children: <button>Action</button>,
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
expect(result.headerRight).toBeUndefined()
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('sets headerRight with asChild', () => {
|
|
164
|
+
const CustomButton = () => <button>Action</button>
|
|
165
|
+
const result = appendStackHeaderRightPropsToOptions(
|
|
166
|
+
{},
|
|
167
|
+
{
|
|
168
|
+
asChild: true,
|
|
169
|
+
children: <CustomButton />,
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
expect(result.headerRight).toBeDefined()
|
|
173
|
+
expect(typeof result.headerRight).toBe('function')
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('sets headerRight with asChild even without children', () => {
|
|
177
|
+
const result = appendStackHeaderRightPropsToOptions({}, { asChild: true })
|
|
178
|
+
// headerRight is set as a function that returns undefined children
|
|
179
|
+
expect(result.headerRight).toBeDefined()
|
|
180
|
+
expect(typeof result.headerRight).toBe('function')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('preserves existing options when setting headerRight', () => {
|
|
184
|
+
const result = appendStackHeaderRightPropsToOptions(
|
|
185
|
+
{ title: 'Existing Title', headerLargeTitle: true },
|
|
186
|
+
{
|
|
187
|
+
asChild: true,
|
|
188
|
+
children: <button>Action</button>,
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
expect(result.title).toBe('Existing Title')
|
|
192
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
193
|
+
expect(result.headerRight).toBeDefined()
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('headerRight function returns children when called', () => {
|
|
197
|
+
const ActionButton = () => <button>Action</button>
|
|
198
|
+
const result = appendStackHeaderRightPropsToOptions(
|
|
199
|
+
{},
|
|
200
|
+
{
|
|
201
|
+
asChild: true,
|
|
202
|
+
children: <ActionButton />,
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
const headerRightResult = result.headerRight?.({} as any)
|
|
206
|
+
expect(headerRightResult).toBeDefined()
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
describe('StackHeaderBackButton', () => {
|
|
211
|
+
it('sets headerBackTitle from children', () => {
|
|
212
|
+
const result = appendStackHeaderBackButtonPropsToOptions(
|
|
213
|
+
{},
|
|
214
|
+
{
|
|
215
|
+
children: 'Go Back',
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
expect(result.headerBackTitle).toBe('Go Back')
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('sets headerBackVisible to false when hidden', () => {
|
|
222
|
+
const result = appendStackHeaderBackButtonPropsToOptions(
|
|
223
|
+
{},
|
|
224
|
+
{
|
|
225
|
+
hidden: true,
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
expect(result.headerBackVisible).toBe(false)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('sets headerBackButtonMenuEnabled', () => {
|
|
232
|
+
const result = appendStackHeaderBackButtonPropsToOptions(
|
|
233
|
+
{},
|
|
234
|
+
{
|
|
235
|
+
withMenu: true,
|
|
236
|
+
}
|
|
237
|
+
)
|
|
238
|
+
expect(result.headerBackButtonMenuEnabled).toBe(true)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('sets headerBackButtonDisplayMode', () => {
|
|
242
|
+
const result = appendStackHeaderBackButtonPropsToOptions(
|
|
243
|
+
{},
|
|
244
|
+
{
|
|
245
|
+
displayMode: 'minimal',
|
|
246
|
+
}
|
|
247
|
+
)
|
|
248
|
+
expect(result.headerBackButtonDisplayMode).toBe('minimal')
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
describe('StackHeaderSearchBar', () => {
|
|
253
|
+
it('sets headerSearchBarOptions with placeholder', () => {
|
|
254
|
+
const result = appendStackHeaderSearchBarPropsToOptions(
|
|
255
|
+
{},
|
|
256
|
+
{
|
|
257
|
+
placeholder: 'Search...',
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
261
|
+
placeholder: 'Search...',
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('sets headerSearchBarOptions with autoCapitalize', () => {
|
|
266
|
+
const result = appendStackHeaderSearchBarPropsToOptions(
|
|
267
|
+
{},
|
|
268
|
+
{
|
|
269
|
+
autoCapitalize: 'none',
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
273
|
+
autoCapitalize: 'none',
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('sets headerSearchBarOptions with multiple props', () => {
|
|
278
|
+
const result = appendStackHeaderSearchBarPropsToOptions(
|
|
279
|
+
{},
|
|
280
|
+
{
|
|
281
|
+
placeholder: 'Search articles...',
|
|
282
|
+
autoCapitalize: 'words',
|
|
283
|
+
hideWhenScrolling: true,
|
|
284
|
+
obscureBackground: false,
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
288
|
+
placeholder: 'Search articles...',
|
|
289
|
+
autoCapitalize: 'words',
|
|
290
|
+
hideWhenScrolling: true,
|
|
291
|
+
obscureBackground: false,
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it('preserves existing options when setting search bar', () => {
|
|
296
|
+
const result = appendStackHeaderSearchBarPropsToOptions(
|
|
297
|
+
{ title: 'Articles', headerLargeTitle: true },
|
|
298
|
+
{
|
|
299
|
+
placeholder: 'Search...',
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
expect(result.title).toBe('Articles')
|
|
303
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
304
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
305
|
+
placeholder: 'Search...',
|
|
306
|
+
})
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
it('sets headerSearchBarOptions with placement prop', () => {
|
|
310
|
+
const result = appendStackHeaderSearchBarPropsToOptions(
|
|
311
|
+
{},
|
|
312
|
+
{
|
|
313
|
+
placeholder: 'Search...',
|
|
314
|
+
placement: 'stacked',
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
318
|
+
placeholder: 'Search...',
|
|
319
|
+
placement: 'stacked',
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('sets empty headerSearchBarOptions when no props', () => {
|
|
324
|
+
const result = appendStackHeaderSearchBarPropsToOptions({}, {})
|
|
325
|
+
expect(result.headerSearchBarOptions).toBeDefined()
|
|
326
|
+
expect(result.headerSearchBarOptions).toEqual({})
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
describe('StackHeaderComponent', () => {
|
|
331
|
+
it('sets headerShown false when hidden', () => {
|
|
332
|
+
const result = appendStackHeaderPropsToOptions({}, { hidden: true })
|
|
333
|
+
expect(result.headerShown).toBe(false)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('sets headerBlurEffect', () => {
|
|
337
|
+
const result = appendStackHeaderPropsToOptions({}, { blurEffect: 'regular' })
|
|
338
|
+
expect(result.headerBlurEffect).toBe('regular')
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
it('sets headerShadowVisible false when shadowColor is transparent', () => {
|
|
342
|
+
const result = appendStackHeaderPropsToOptions(
|
|
343
|
+
{},
|
|
344
|
+
{
|
|
345
|
+
style: { shadowColor: 'transparent' },
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
expect(result.headerShadowVisible).toBe(false)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('sets headerTransparent when backgroundColor is transparent', () => {
|
|
352
|
+
const result = appendStackHeaderPropsToOptions(
|
|
353
|
+
{},
|
|
354
|
+
{
|
|
355
|
+
style: { backgroundColor: 'transparent' },
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
expect(result.headerTransparent).toBe(true)
|
|
360
|
+
expect(result.headerStyle).toMatchObject({ backgroundColor: 'transparent' })
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('sets headerTransparent with SearchBar (user controls via options if needed)', () => {
|
|
364
|
+
const result = appendStackHeaderPropsToOptions(
|
|
365
|
+
{},
|
|
366
|
+
{
|
|
367
|
+
style: { backgroundColor: 'transparent' },
|
|
368
|
+
children: <StackHeaderSearchBar placeholder="Search..." />,
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
// headerTransparent is set when backgroundColor is transparent
|
|
373
|
+
// Users can override with options={{ headerTransparent: false }} if no ScrollView
|
|
374
|
+
expect(result.headerTransparent).toBe(true)
|
|
375
|
+
expect(result.headerSearchBarOptions).toMatchObject({ placeholder: 'Search...' })
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('processes child Title component', () => {
|
|
379
|
+
const result = appendStackHeaderPropsToOptions(
|
|
380
|
+
{},
|
|
381
|
+
{
|
|
382
|
+
children: <StackHeaderTitle large>Test Title</StackHeaderTitle>,
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
expect(result.title).toBe('Test Title')
|
|
386
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it('processes child BackButton component', () => {
|
|
390
|
+
const result = appendStackHeaderPropsToOptions(
|
|
391
|
+
{},
|
|
392
|
+
{
|
|
393
|
+
children: <StackHeaderBackButton hidden>Back</StackHeaderBackButton>,
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
expect(result.headerBackTitle).toBe('Back')
|
|
397
|
+
expect(result.headerBackVisible).toBe(false)
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('processes multiple children', () => {
|
|
401
|
+
const result = appendStackHeaderPropsToOptions(
|
|
402
|
+
{},
|
|
403
|
+
{
|
|
404
|
+
children: [
|
|
405
|
+
<StackHeaderTitle key="title" large>
|
|
406
|
+
My Screen
|
|
407
|
+
</StackHeaderTitle>,
|
|
408
|
+
<StackHeaderBackButton key="back" hidden />,
|
|
409
|
+
],
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
expect(result.title).toBe('My Screen')
|
|
413
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
414
|
+
expect(result.headerBackVisible).toBe(false)
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
it('processes child Left component', () => {
|
|
418
|
+
const result = appendStackHeaderPropsToOptions(
|
|
419
|
+
{},
|
|
420
|
+
{
|
|
421
|
+
children: (
|
|
422
|
+
<StackHeaderLeft asChild>
|
|
423
|
+
<button>Back</button>
|
|
424
|
+
</StackHeaderLeft>
|
|
425
|
+
),
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
expect(result.headerLeft).toBeDefined()
|
|
429
|
+
expect(typeof result.headerLeft).toBe('function')
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('processes child Right component', () => {
|
|
433
|
+
const result = appendStackHeaderPropsToOptions(
|
|
434
|
+
{},
|
|
435
|
+
{
|
|
436
|
+
children: (
|
|
437
|
+
<StackHeaderRight asChild>
|
|
438
|
+
<button>Action</button>
|
|
439
|
+
</StackHeaderRight>
|
|
440
|
+
),
|
|
441
|
+
}
|
|
442
|
+
)
|
|
443
|
+
expect(result.headerRight).toBeDefined()
|
|
444
|
+
expect(typeof result.headerRight).toBe('function')
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('processes child SearchBar component', () => {
|
|
448
|
+
const result = appendStackHeaderPropsToOptions(
|
|
449
|
+
{},
|
|
450
|
+
{
|
|
451
|
+
children: <StackHeaderSearchBar placeholder="Search..." />,
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
455
|
+
placeholder: 'Search...',
|
|
456
|
+
})
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('processes all child components together', () => {
|
|
460
|
+
const result = appendStackHeaderPropsToOptions(
|
|
461
|
+
{},
|
|
462
|
+
{
|
|
463
|
+
children: [
|
|
464
|
+
<StackHeaderTitle key="title" large>
|
|
465
|
+
Articles
|
|
466
|
+
</StackHeaderTitle>,
|
|
467
|
+
<StackHeaderLeft key="left" asChild>
|
|
468
|
+
<button>Back</button>
|
|
469
|
+
</StackHeaderLeft>,
|
|
470
|
+
<StackHeaderRight key="right" asChild>
|
|
471
|
+
<button>More</button>
|
|
472
|
+
</StackHeaderRight>,
|
|
473
|
+
<StackHeaderSearchBar key="search" placeholder="Search articles..." />,
|
|
474
|
+
<StackHeaderBackButton key="back" displayMode="minimal" />,
|
|
475
|
+
],
|
|
476
|
+
}
|
|
477
|
+
)
|
|
478
|
+
expect(result.title).toBe('Articles')
|
|
479
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
480
|
+
expect(result.headerLeft).toBeDefined()
|
|
481
|
+
expect(result.headerRight).toBeDefined()
|
|
482
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
483
|
+
placeholder: 'Search articles...',
|
|
484
|
+
})
|
|
485
|
+
expect(result.headerBackButtonDisplayMode).toBe('minimal')
|
|
486
|
+
})
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
describe('StackScreen composition', () => {
|
|
490
|
+
it('StackHeader is same reference as StackHeaderComponent', () => {
|
|
491
|
+
// This is critical - if they are different, the child type check will fail
|
|
492
|
+
expect(StackHeader).toBe(StackHeaderComponent)
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
it('merges options with Header composition', () => {
|
|
496
|
+
const result = appendScreenStackPropsToOptions(
|
|
497
|
+
{ animation: 'slide_from_right' },
|
|
498
|
+
{
|
|
499
|
+
options: { gestureEnabled: true },
|
|
500
|
+
children: (
|
|
501
|
+
<StackHeaderComponent blurEffect="regular">
|
|
502
|
+
<StackHeaderTitle large>Composed Title</StackHeaderTitle>
|
|
503
|
+
</StackHeaderComponent>
|
|
504
|
+
),
|
|
505
|
+
}
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
expect(result.animation).toBe('slide_from_right')
|
|
509
|
+
expect(result.gestureEnabled).toBe(true)
|
|
510
|
+
expect(result.headerBlurEffect).toBe('regular')
|
|
511
|
+
expect(result.title).toBe('Composed Title')
|
|
512
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
it('works with StackHeader compound component (as used via Stack.Header)', () => {
|
|
516
|
+
const result = appendScreenStackPropsToOptions(
|
|
517
|
+
{},
|
|
518
|
+
{
|
|
519
|
+
children: (
|
|
520
|
+
<StackHeader>
|
|
521
|
+
<StackHeader.Title large>Large Title Test</StackHeader.Title>
|
|
522
|
+
</StackHeader>
|
|
523
|
+
),
|
|
524
|
+
}
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
expect(result.title).toBe('Large Title Test')
|
|
528
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
it('works with StackHeader compound component with Left child', () => {
|
|
532
|
+
const result = appendScreenStackPropsToOptions(
|
|
533
|
+
{},
|
|
534
|
+
{
|
|
535
|
+
children: (
|
|
536
|
+
<StackHeader>
|
|
537
|
+
<StackHeader.Title large>Articles</StackHeader.Title>
|
|
538
|
+
<StackHeader.Left asChild>
|
|
539
|
+
<button>Back</button>
|
|
540
|
+
</StackHeader.Left>
|
|
541
|
+
</StackHeader>
|
|
542
|
+
),
|
|
543
|
+
}
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
expect(result.title).toBe('Articles')
|
|
547
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
548
|
+
expect(result.headerLeft).toBeDefined()
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
it('composition overrides options prop', () => {
|
|
552
|
+
const result = appendScreenStackPropsToOptions(
|
|
553
|
+
{},
|
|
554
|
+
{
|
|
555
|
+
options: { title: 'Options Title' },
|
|
556
|
+
children: (
|
|
557
|
+
<StackHeaderComponent>
|
|
558
|
+
<StackHeaderTitle>Composed Title</StackHeaderTitle>
|
|
559
|
+
</StackHeaderComponent>
|
|
560
|
+
),
|
|
561
|
+
}
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
// Composition should override the options prop title
|
|
565
|
+
expect(result.title).toBe('Composed Title')
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
it('works with StackHeader compound component with Right child', () => {
|
|
569
|
+
const result = appendScreenStackPropsToOptions(
|
|
570
|
+
{},
|
|
571
|
+
{
|
|
572
|
+
children: (
|
|
573
|
+
<StackHeader>
|
|
574
|
+
<StackHeader.Title>Settings</StackHeader.Title>
|
|
575
|
+
<StackHeader.Right asChild>
|
|
576
|
+
<button>Save</button>
|
|
577
|
+
</StackHeader.Right>
|
|
578
|
+
</StackHeader>
|
|
579
|
+
),
|
|
580
|
+
}
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
expect(result.title).toBe('Settings')
|
|
584
|
+
expect(result.headerRight).toBeDefined()
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
it('works with StackHeader compound component with SearchBar child', () => {
|
|
588
|
+
const result = appendScreenStackPropsToOptions(
|
|
589
|
+
{},
|
|
590
|
+
{
|
|
591
|
+
children: (
|
|
592
|
+
<StackHeader>
|
|
593
|
+
<StackHeader.Title large>Articles</StackHeader.Title>
|
|
594
|
+
<StackHeader.SearchBar placeholder="Search articles..." />
|
|
595
|
+
</StackHeader>
|
|
596
|
+
),
|
|
597
|
+
}
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
expect(result.title).toBe('Articles')
|
|
601
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
602
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
603
|
+
placeholder: 'Search articles...',
|
|
604
|
+
})
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
it('works with full compositional setup', () => {
|
|
608
|
+
const result = appendScreenStackPropsToOptions(
|
|
609
|
+
{},
|
|
610
|
+
{
|
|
611
|
+
options: { animation: 'slide_from_right' },
|
|
612
|
+
children: (
|
|
613
|
+
<StackHeader blurEffect="regular">
|
|
614
|
+
<StackHeader.Title large>My App</StackHeader.Title>
|
|
615
|
+
<StackHeader.Left asChild>
|
|
616
|
+
<button>Menu</button>
|
|
617
|
+
</StackHeader.Left>
|
|
618
|
+
<StackHeader.Right asChild>
|
|
619
|
+
<button>Settings</button>
|
|
620
|
+
</StackHeader.Right>
|
|
621
|
+
<StackHeader.BackButton displayMode="minimal" />
|
|
622
|
+
<StackHeader.SearchBar placeholder="Search..." placement="stacked" />
|
|
623
|
+
</StackHeader>
|
|
624
|
+
),
|
|
625
|
+
}
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
expect(result.animation).toBe('slide_from_right')
|
|
629
|
+
expect(result.headerBlurEffect).toBe('regular')
|
|
630
|
+
expect(result.title).toBe('My App')
|
|
631
|
+
expect(result.headerLargeTitle).toBe(true)
|
|
632
|
+
// headerTransparent is only auto-set on iOS, not on web/android (test runs in web mock)
|
|
633
|
+
expect(result.headerTransparent).toBeUndefined()
|
|
634
|
+
expect(result.headerLeft).toBeDefined()
|
|
635
|
+
expect(result.headerRight).toBeDefined()
|
|
636
|
+
expect(result.headerBackButtonDisplayMode).toBe('minimal')
|
|
637
|
+
expect(result.headerSearchBarOptions).toMatchObject({
|
|
638
|
+
placeholder: 'Search...',
|
|
639
|
+
placement: 'stacked',
|
|
640
|
+
})
|
|
641
|
+
})
|
|
642
|
+
})
|
|
643
|
+
})
|