one 1.2.68 → 1.2.70

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