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.
Files changed (292) 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/cli/build.cjs +9 -1
  26. package/dist/cjs/cli/build.js +8 -1
  27. package/dist/cjs/cli/build.js.map +1 -1
  28. package/dist/cjs/cli/build.native.js +13 -1
  29. package/dist/cjs/cli/build.native.js.map +1 -1
  30. package/dist/cjs/fork/NavigationContainer.js.map +1 -1
  31. package/dist/cjs/fork/NavigationContainer.native.js.map +1 -1
  32. package/dist/cjs/index.js.map +1 -1
  33. package/dist/cjs/layouts/Stack.cjs +75 -6
  34. package/dist/cjs/layouts/Stack.js +44 -4
  35. package/dist/cjs/layouts/Stack.js.map +2 -2
  36. package/dist/cjs/layouts/Stack.native.js +81 -6
  37. package/dist/cjs/layouts/Stack.native.js.map +1 -1
  38. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.cjs +40 -0
  39. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.js +35 -0
  40. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.js.map +6 -0
  41. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js +43 -0
  42. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -0
  43. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.cjs +90 -0
  44. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.js +68 -0
  45. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.js.map +6 -0
  46. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js +99 -0
  47. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -0
  48. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.cjs +35 -0
  49. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.js +30 -0
  50. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.js.map +6 -0
  51. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js +40 -0
  52. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -0
  53. package/dist/cjs/layouts/stack-utils/StackHeaderRight.cjs +35 -0
  54. package/dist/cjs/layouts/stack-utils/StackHeaderRight.js +30 -0
  55. package/dist/cjs/layouts/stack-utils/StackHeaderRight.js.map +6 -0
  56. package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js +40 -0
  57. package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js.map +1 -0
  58. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.cjs +35 -0
  59. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.js +30 -0
  60. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.js.map +6 -0
  61. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js +38 -0
  62. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -0
  63. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.cjs +65 -0
  64. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.js +52 -0
  65. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.js.map +6 -0
  66. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js +68 -0
  67. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -0
  68. package/dist/cjs/layouts/stack-utils/StackScreen.cjs +57 -0
  69. package/dist/cjs/layouts/stack-utils/StackScreen.js +43 -0
  70. package/dist/cjs/layouts/stack-utils/StackScreen.js.map +6 -0
  71. package/dist/cjs/layouts/stack-utils/StackScreen.native.js +64 -0
  72. package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -0
  73. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.cjs +455 -0
  74. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.js +406 -0
  75. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.js.map +6 -0
  76. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js +480 -0
  77. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -0
  78. package/dist/cjs/layouts/stack-utils/index.cjs +47 -0
  79. package/dist/cjs/layouts/stack-utils/index.js +36 -0
  80. package/dist/cjs/layouts/stack-utils/index.js.map +6 -0
  81. package/dist/cjs/layouts/stack-utils/index.native.js +50 -0
  82. package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -0
  83. package/dist/cjs/layouts/withLayoutContext.cjs +2 -1
  84. package/dist/cjs/layouts/withLayoutContext.js +2 -2
  85. package/dist/cjs/layouts/withLayoutContext.js.map +1 -1
  86. package/dist/cjs/layouts/withLayoutContext.native.js +3 -2
  87. package/dist/cjs/layouts/withLayoutContext.native.js.map +1 -1
  88. package/dist/cjs/useLoader.cjs +4 -2
  89. package/dist/cjs/useLoader.js +4 -2
  90. package/dist/cjs/useLoader.js.map +1 -1
  91. package/dist/cjs/useLoader.native.js +4 -2
  92. package/dist/cjs/useLoader.native.js.map +1 -1
  93. package/dist/cjs/utils/children.cjs +46 -0
  94. package/dist/cjs/utils/children.js +47 -0
  95. package/dist/cjs/utils/children.js.map +6 -0
  96. package/dist/cjs/utils/children.native.js +76 -0
  97. package/dist/cjs/utils/children.native.js.map +1 -0
  98. package/dist/cjs/utils/style.cjs +28 -0
  99. package/dist/cjs/utils/style.js +24 -0
  100. package/dist/cjs/utils/style.js.map +6 -0
  101. package/dist/cjs/utils/style.native.js +31 -0
  102. package/dist/cjs/utils/style.native.js.map +1 -0
  103. package/dist/esm/__mocks__/@react-navigation/native-stack.js +8 -0
  104. package/dist/esm/__mocks__/@react-navigation/native-stack.js.map +6 -0
  105. package/dist/esm/__mocks__/@react-navigation/native-stack.mjs +6 -0
  106. package/dist/esm/__mocks__/@react-navigation/native-stack.mjs.map +1 -0
  107. package/dist/esm/__mocks__/@react-navigation/native-stack.native.js +12 -0
  108. package/dist/esm/__mocks__/@react-navigation/native-stack.native.js.map +1 -0
  109. package/dist/esm/__mocks__/@react-navigation/native.js +18 -0
  110. package/dist/esm/__mocks__/@react-navigation/native.js.map +1 -0
  111. package/dist/esm/__mocks__/expo-linking.js +9 -0
  112. package/dist/esm/__mocks__/expo-linking.js.map +6 -0
  113. package/dist/esm/__mocks__/expo-linking.mjs +10 -0
  114. package/dist/esm/__mocks__/expo-linking.mjs.map +1 -0
  115. package/dist/esm/__mocks__/expo-linking.native.js +18 -0
  116. package/dist/esm/__mocks__/expo-linking.native.js.map +1 -0
  117. package/dist/esm/__mocks__/expo-modules-core.js +15 -0
  118. package/dist/esm/__mocks__/expo-modules-core.js.map +6 -0
  119. package/dist/esm/__mocks__/expo-modules-core.mjs +10 -0
  120. package/dist/esm/__mocks__/expo-modules-core.mjs.map +1 -0
  121. package/dist/esm/__mocks__/expo-modules-core.native.js +38 -0
  122. package/dist/esm/__mocks__/expo-modules-core.native.js.map +1 -0
  123. package/dist/esm/__mocks__/react-native-screens.js +6 -0
  124. package/dist/esm/__mocks__/react-native-screens.js.map +6 -0
  125. package/dist/esm/__mocks__/react-native-screens.mjs +4 -0
  126. package/dist/esm/__mocks__/react-native-screens.mjs.map +1 -0
  127. package/dist/esm/__mocks__/react-native-screens.native.js +4 -0
  128. package/dist/esm/__mocks__/react-native-screens.native.js.map +1 -0
  129. package/dist/esm/__mocks__/react-native.js +19 -0
  130. package/dist/esm/__mocks__/react-native.js.map +1 -0
  131. package/dist/esm/cli/build.js +8 -1
  132. package/dist/esm/cli/build.js.map +1 -1
  133. package/dist/esm/cli/build.mjs +9 -1
  134. package/dist/esm/cli/build.mjs.map +1 -1
  135. package/dist/esm/cli/build.native.js +13 -1
  136. package/dist/esm/cli/build.native.js.map +1 -1
  137. package/dist/esm/fork/NavigationContainer.js.map +1 -1
  138. package/dist/esm/fork/NavigationContainer.mjs.map +1 -1
  139. package/dist/esm/fork/NavigationContainer.native.js.map +1 -1
  140. package/dist/esm/index.js.map +1 -1
  141. package/dist/esm/index.mjs.map +1 -1
  142. package/dist/esm/index.native.js.map +1 -1
  143. package/dist/esm/layouts/Stack.js +45 -1
  144. package/dist/esm/layouts/Stack.js.map +1 -1
  145. package/dist/esm/layouts/Stack.mjs +59 -1
  146. package/dist/esm/layouts/Stack.mjs.map +1 -1
  147. package/dist/esm/layouts/Stack.native.js +65 -1
  148. package/dist/esm/layouts/Stack.native.js.map +1 -1
  149. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.js +19 -0
  150. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.js.map +6 -0
  151. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.mjs +16 -0
  152. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.mjs.map +1 -0
  153. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.native.js +16 -0
  154. package/dist/esm/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -0
  155. package/dist/esm/layouts/stack-utils/StackHeaderComponent.js +71 -0
  156. package/dist/esm/layouts/stack-utils/StackHeaderComponent.js.map +6 -0
  157. package/dist/esm/layouts/stack-utils/StackHeaderComponent.mjs +66 -0
  158. package/dist/esm/layouts/stack-utils/StackHeaderComponent.mjs.map +1 -0
  159. package/dist/esm/layouts/stack-utils/StackHeaderComponent.native.js +72 -0
  160. package/dist/esm/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -0
  161. package/dist/esm/layouts/stack-utils/StackHeaderLeft.js +14 -0
  162. package/dist/esm/layouts/stack-utils/StackHeaderLeft.js.map +6 -0
  163. package/dist/esm/layouts/stack-utils/StackHeaderLeft.mjs +11 -0
  164. package/dist/esm/layouts/stack-utils/StackHeaderLeft.mjs.map +1 -0
  165. package/dist/esm/layouts/stack-utils/StackHeaderLeft.native.js +13 -0
  166. package/dist/esm/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -0
  167. package/dist/esm/layouts/stack-utils/StackHeaderRight.js +14 -0
  168. package/dist/esm/layouts/stack-utils/StackHeaderRight.js.map +6 -0
  169. package/dist/esm/layouts/stack-utils/StackHeaderRight.mjs +11 -0
  170. package/dist/esm/layouts/stack-utils/StackHeaderRight.mjs.map +1 -0
  171. package/dist/esm/layouts/stack-utils/StackHeaderRight.native.js +13 -0
  172. package/dist/esm/layouts/stack-utils/StackHeaderRight.native.js.map +1 -0
  173. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.js +14 -0
  174. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.js.map +6 -0
  175. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.mjs +11 -0
  176. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.mjs.map +1 -0
  177. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.native.js +11 -0
  178. package/dist/esm/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -0
  179. package/dist/esm/layouts/stack-utils/StackHeaderTitle.js +37 -0
  180. package/dist/esm/layouts/stack-utils/StackHeaderTitle.js.map +6 -0
  181. package/dist/esm/layouts/stack-utils/StackHeaderTitle.mjs +41 -0
  182. package/dist/esm/layouts/stack-utils/StackHeaderTitle.mjs.map +1 -0
  183. package/dist/esm/layouts/stack-utils/StackHeaderTitle.native.js +41 -0
  184. package/dist/esm/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -0
  185. package/dist/esm/layouts/stack-utils/StackScreen.js +33 -0
  186. package/dist/esm/layouts/stack-utils/StackScreen.js.map +6 -0
  187. package/dist/esm/layouts/stack-utils/StackScreen.mjs +33 -0
  188. package/dist/esm/layouts/stack-utils/StackScreen.mjs.map +1 -0
  189. package/dist/esm/layouts/stack-utils/StackScreen.native.js +38 -0
  190. package/dist/esm/layouts/stack-utils/StackScreen.native.js.map +1 -0
  191. package/dist/esm/layouts/stack-utils/__tests__/composition.test.js +431 -0
  192. package/dist/esm/layouts/stack-utils/__tests__/composition.test.js.map +6 -0
  193. package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs +456 -0
  194. package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs.map +1 -0
  195. package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js +478 -0
  196. package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -0
  197. package/dist/esm/layouts/stack-utils/index.js +33 -0
  198. package/dist/esm/layouts/stack-utils/index.js.map +6 -0
  199. package/dist/esm/layouts/stack-utils/index.mjs +16 -0
  200. package/dist/esm/layouts/stack-utils/index.mjs.map +1 -0
  201. package/dist/esm/layouts/stack-utils/index.native.js +16 -0
  202. package/dist/esm/layouts/stack-utils/index.native.js.map +1 -0
  203. package/dist/esm/layouts/withLayoutContext.js +2 -1
  204. package/dist/esm/layouts/withLayoutContext.js.map +1 -1
  205. package/dist/esm/layouts/withLayoutContext.mjs +2 -1
  206. package/dist/esm/layouts/withLayoutContext.mjs.map +1 -1
  207. package/dist/esm/layouts/withLayoutContext.native.js +2 -1
  208. package/dist/esm/layouts/withLayoutContext.native.js.map +1 -1
  209. package/dist/esm/useLoader.js +4 -2
  210. package/dist/esm/useLoader.js.map +1 -1
  211. package/dist/esm/useLoader.mjs +4 -2
  212. package/dist/esm/useLoader.mjs.map +1 -1
  213. package/dist/esm/useLoader.native.js +4 -2
  214. package/dist/esm/useLoader.native.js.map +1 -1
  215. package/dist/esm/utils/children.js +33 -0
  216. package/dist/esm/utils/children.js.map +6 -0
  217. package/dist/esm/utils/children.mjs +19 -0
  218. package/dist/esm/utils/children.mjs.map +1 -0
  219. package/dist/esm/utils/children.native.js +46 -0
  220. package/dist/esm/utils/children.native.js.map +1 -0
  221. package/dist/esm/utils/style.js +8 -0
  222. package/dist/esm/utils/style.js.map +6 -0
  223. package/dist/esm/utils/style.mjs +5 -0
  224. package/dist/esm/utils/style.mjs.map +1 -0
  225. package/dist/esm/utils/style.native.js +5 -0
  226. package/dist/esm/utils/style.native.js.map +1 -0
  227. package/package.json +9 -9
  228. package/src/__mocks__/@react-navigation/native-stack.ts +32 -0
  229. package/src/__mocks__/@react-navigation/native.ts +21 -0
  230. package/src/__mocks__/expo-linking.ts +6 -0
  231. package/src/__mocks__/expo-modules-core.ts +11 -0
  232. package/src/__mocks__/react-native-screens.ts +17 -0
  233. package/src/__mocks__/react-native.ts +20 -0
  234. package/src/cli/build.ts +27 -2
  235. package/src/fork/NavigationContainer.tsx +2 -0
  236. package/src/index.ts +10 -0
  237. package/src/layouts/Stack.tsx +96 -1
  238. package/src/layouts/stack-utils/README.md +211 -0
  239. package/src/layouts/stack-utils/StackHeaderBackButton.tsx +34 -0
  240. package/src/layouts/stack-utils/StackHeaderComponent.tsx +136 -0
  241. package/src/layouts/stack-utils/StackHeaderLeft.tsx +29 -0
  242. package/src/layouts/stack-utils/StackHeaderRight.tsx +29 -0
  243. package/src/layouts/stack-utils/StackHeaderSearchBar.tsx +21 -0
  244. package/src/layouts/stack-utils/StackHeaderTitle.tsx +79 -0
  245. package/src/layouts/stack-utils/StackScreen.tsx +69 -0
  246. package/src/layouts/stack-utils/__tests__/composition.test.tsx +643 -0
  247. package/src/layouts/stack-utils/index.tsx +45 -0
  248. package/src/layouts/withLayoutContext.tsx +6 -2
  249. package/src/router/router.ts +1 -1
  250. package/src/useLoader.ts +14 -6
  251. package/src/utils/children.ts +74 -0
  252. package/src/utils/style.ts +17 -0
  253. package/types/__mocks__/@react-navigation/native-stack.d.ts +30 -0
  254. package/types/__mocks__/@react-navigation/native-stack.d.ts.map +1 -0
  255. package/types/__mocks__/@react-navigation/native.d.ts +17 -0
  256. package/types/__mocks__/@react-navigation/native.d.ts.map +1 -0
  257. package/types/__mocks__/expo-linking.d.ts +9 -0
  258. package/types/__mocks__/expo-linking.d.ts.map +1 -0
  259. package/types/__mocks__/expo-modules-core.d.ts +11 -0
  260. package/types/__mocks__/expo-modules-core.d.ts.map +1 -0
  261. package/types/__mocks__/react-native-screens.d.ts +14 -0
  262. package/types/__mocks__/react-native-screens.d.ts.map +1 -0
  263. package/types/__mocks__/react-native.d.ts +12 -0
  264. package/types/__mocks__/react-native.d.ts.map +1 -0
  265. package/types/cli/build.d.ts.map +1 -1
  266. package/types/fork/NavigationContainer.d.ts.map +1 -1
  267. package/types/index.d.ts +1 -0
  268. package/types/index.d.ts.map +1 -1
  269. package/types/layouts/Stack.d.ts +14 -3
  270. package/types/layouts/Stack.d.ts.map +1 -1
  271. package/types/layouts/stack-utils/StackHeaderBackButton.d.ts +17 -0
  272. package/types/layouts/stack-utils/StackHeaderBackButton.d.ts.map +1 -0
  273. package/types/layouts/stack-utils/StackHeaderComponent.d.ts +36 -0
  274. package/types/layouts/stack-utils/StackHeaderComponent.d.ts.map +1 -0
  275. package/types/layouts/stack-utils/StackHeaderLeft.d.ts +13 -0
  276. package/types/layouts/stack-utils/StackHeaderLeft.d.ts.map +1 -0
  277. package/types/layouts/stack-utils/StackHeaderRight.d.ts +13 -0
  278. package/types/layouts/stack-utils/StackHeaderRight.d.ts.map +1 -0
  279. package/types/layouts/stack-utils/StackHeaderSearchBar.d.ts +10 -0
  280. package/types/layouts/stack-utils/StackHeaderSearchBar.d.ts.map +1 -0
  281. package/types/layouts/stack-utils/StackHeaderTitle.d.ts +26 -0
  282. package/types/layouts/stack-utils/StackHeaderTitle.d.ts.map +1 -0
  283. package/types/layouts/stack-utils/StackScreen.d.ts +22 -0
  284. package/types/layouts/stack-utils/StackScreen.d.ts.map +1 -0
  285. package/types/layouts/stack-utils/index.d.ts +20 -0
  286. package/types/layouts/stack-utils/index.d.ts.map +1 -0
  287. package/types/layouts/withLayoutContext.d.ts.map +1 -1
  288. package/types/useLoader.d.ts.map +1 -1
  289. package/types/utils/children.d.ts +23 -0
  290. package/types/utils/children.d.ts.map +1 -0
  291. package/types/utils/style.d.ts +7 -0
  292. package/types/utils/style.d.ts.map +1 -0
@@ -44,6 +44,7 @@ import { useThenable } from './useThenable'
44
44
 
45
45
  declare global {
46
46
  // eslint-disable-next-line no-var
47
+ // @ts-ignore - Type differs between react-navigation versions
47
48
  var REACT_NAVIGATION_DEVTOOLS: WeakMap<
48
49
  NavigationContainerRef<any>,
49
50
  { readonly linking: LinkingOptions<any> }
@@ -147,6 +148,7 @@ function NavigationContainerInner(
147
148
  // This will be used by the devtools
148
149
  React.useEffect(() => {
149
150
  if (refContainer.current) {
151
+ // @ts-ignore - Type differs between react-navigation versions in monorepo
150
152
  REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, {
151
153
  get linking() {
152
154
  return {
package/src/index.ts CHANGED
@@ -72,6 +72,16 @@ export { href } from './href'
72
72
  export { Stack } from './layouts/Stack'
73
73
  export { Tabs } from './layouts/Tabs'
74
74
  export { Protected, type ProtectedProps } from './views/Protected'
75
+ // Stack header compositional API types
76
+ export type {
77
+ StackHeaderProps,
78
+ StackHeaderBackButtonProps,
79
+ StackHeaderTitleProps,
80
+ StackHeaderLeftProps,
81
+ StackHeaderRightProps,
82
+ StackHeaderSearchBarProps,
83
+ StackScreenProps,
84
+ } from './layouts/stack-utils'
75
85
  // utilities
76
86
  export { withLayoutContext } from './layouts/withLayoutContext'
77
87
  export { Link } from './link/Link'
@@ -4,16 +4,111 @@ import {
4
4
  type NativeStackNavigationEventMap,
5
5
  type NativeStackNavigationOptions,
6
6
  } from '@react-navigation/native-stack'
7
+ import React, { Children, useMemo, type ComponentProps } from 'react'
7
8
 
9
+ import {
10
+ StackScreen,
11
+ StackHeader,
12
+ StackHeaderComponent,
13
+ StackHeaderSearchBar,
14
+ appendScreenStackPropsToOptions,
15
+ type StackScreenProps,
16
+ } from './stack-utils'
8
17
  import { withLayoutContext } from './withLayoutContext'
18
+ import { isChildOfType } from '../utils/children'
19
+ import { Protected } from '../views/Protected'
20
+ import { Screen } from '../views/Screen'
9
21
 
10
22
  const NativeStackNavigator = createNativeStackNavigator().Navigator
11
23
 
12
- export const Stack = withLayoutContext<
24
+ const RNStack = withLayoutContext<
13
25
  NativeStackNavigationOptions,
14
26
  typeof NativeStackNavigator,
15
27
  StackNavigationState<ParamListBase>,
16
28
  NativeStackNavigationEventMap
17
29
  >(NativeStackNavigator)
18
30
 
31
+ /**
32
+ * Pre-process children to convert StackScreen (with Header children) to Screen (with options).
33
+ * This allows the Header Composition API to work in layout files.
34
+ */
35
+ function mapChildren(children: React.ReactNode): React.ReactNode {
36
+ return Children.toArray(children)
37
+ .map((child, index) => {
38
+ if (isChildOfType(child, StackScreen)) {
39
+ // convert StackScreen to Screen with options extracted from Header children
40
+ const options = appendScreenStackPropsToOptions({}, child.props)
41
+ const { children: _, ...rest } = child.props
42
+ return <Screen key={child.props.name ?? index} {...rest} options={options} />
43
+ }
44
+
45
+ if (isChildOfType(child, Protected)) {
46
+ // recursively process Protected children
47
+ return (
48
+ <Protected key={`protected-${index}`} guard={child.props.guard}>
49
+ {mapChildren(child.props.children)}
50
+ </Protected>
51
+ )
52
+ }
53
+
54
+ if (isChildOfType(child, StackHeaderComponent)) {
55
+ // Stack.Header at the Stack level is used for screenOptions, handled separately
56
+ return null
57
+ }
58
+
59
+ // pass through other children (like Screen)
60
+ return child
61
+ })
62
+ .filter(Boolean)
63
+ }
64
+
65
+ /**
66
+ * Stack navigator with support for Header Composition API.
67
+ * Wraps the base Stack to pre-process StackScreen children.
68
+ */
69
+ const StackWithComposition = React.forwardRef<unknown, ComponentProps<typeof RNStack>>(
70
+ (props, ref) => {
71
+ const { children, screenOptions, ...rest } = props
72
+
73
+ // extract Stack.Header from children for screenOptions
74
+ const screenOptionsWithHeader = useMemo(() => {
75
+ const stackHeader = Children.toArray(children).find((child) =>
76
+ isChildOfType(child, StackHeaderComponent)
77
+ )
78
+
79
+ if (stackHeader && isChildOfType(stackHeader, StackHeaderComponent)) {
80
+ const headerProps: StackScreenProps = { children: stackHeader }
81
+ if (screenOptions) {
82
+ if (typeof screenOptions === 'function') {
83
+ return (...args: Parameters<typeof screenOptions>) => {
84
+ const opts = screenOptions(...args)
85
+ return appendScreenStackPropsToOptions(opts, headerProps)
86
+ }
87
+ }
88
+ return appendScreenStackPropsToOptions(screenOptions, headerProps)
89
+ }
90
+ return appendScreenStackPropsToOptions({}, headerProps)
91
+ }
92
+
93
+ return screenOptions
94
+ }, [children, screenOptions])
95
+
96
+ // pre-process children to convert StackScreen to Screen
97
+ const processedChildren = useMemo(() => mapChildren(children), [children])
98
+
99
+ return (
100
+ <RNStack {...rest} ref={ref} screenOptions={screenOptionsWithHeader}>
101
+ {processedChildren}
102
+ </RNStack>
103
+ )
104
+ }
105
+ )
106
+
107
+ export const Stack = Object.assign(StackWithComposition, {
108
+ Screen: StackScreen,
109
+ Header: StackHeader,
110
+ Protected,
111
+ SearchBar: StackHeaderSearchBar,
112
+ })
113
+
19
114
  export default Stack
@@ -0,0 +1,211 @@
1
+ # Stack Header Composition API
2
+
3
+ A declarative JSX API for configuring native stack headers in One.
4
+
5
+ ## Overview
6
+
7
+ The Stack Header Composition API provides a more intuitive way to configure stack navigation headers using JSX components instead of the traditional options object. This is particularly useful for complex header configurations like large titles, custom buttons, and search bars.
8
+
9
+ ## Installation
10
+
11
+ The components are available through the main `one` package:
12
+
13
+ ```tsx
14
+ import { Stack } from 'one'
15
+ ```
16
+
17
+ ## Core Components
18
+
19
+ | Component | Description |
20
+ |-----------|-------------|
21
+ | `Stack.Screen` | Screen wrapper with header composition support |
22
+ | `Stack.Header` | Main header configuration container |
23
+ | `Stack.Header.Title` | Configure title text and large title mode |
24
+ | `Stack.Header.Left` | Custom left header content |
25
+ | `Stack.Header.Right` | Custom right header content |
26
+ | `Stack.Header.BackButton` | Back button configuration |
27
+ | `Stack.Header.SearchBar` | Search bar configuration |
28
+
29
+ ## Basic Usage
30
+
31
+ ```tsx
32
+ import { Stack } from 'one'
33
+
34
+ export default function Layout() {
35
+ return (
36
+ <Stack>
37
+ <Stack.Screen name="index">
38
+ <Stack.Header>
39
+ <Stack.Header.Title large>Welcome</Stack.Header.Title>
40
+ </Stack.Header>
41
+ </Stack.Screen>
42
+ </Stack>
43
+ )
44
+ }
45
+ ```
46
+
47
+ ## Large Title with Blur Effect (iOS)
48
+
49
+ The classic iOS large title pattern with blur effect:
50
+
51
+ ```tsx
52
+ <Stack.Screen name="feed">
53
+ <Stack.Header blurEffect="regular" style={{ backgroundColor: 'transparent' }}>
54
+ <Stack.Header.Title large>Feed</Stack.Header.Title>
55
+ </Stack.Header>
56
+ </Stack.Screen>
57
+ ```
58
+
59
+ ## Custom Header Buttons
60
+
61
+ Add custom buttons to the left or right side of the header:
62
+
63
+ ```tsx
64
+ <Stack.Screen name="profile">
65
+ <Stack.Header>
66
+ <Stack.Header.Title>Profile</Stack.Header.Title>
67
+ <Stack.Header.Left asChild>
68
+ <Button onPress={goBack}>Back</Button>
69
+ </Stack.Header.Left>
70
+ <Stack.Header.Right asChild>
71
+ <Button onPress={openSettings}>Settings</Button>
72
+ </Stack.Header.Right>
73
+ </Stack.Header>
74
+ </Stack.Screen>
75
+ ```
76
+
77
+ ## Search Bar
78
+
79
+ Add an integrated search bar to the header:
80
+
81
+ ```tsx
82
+ <Stack.Screen name="search">
83
+ <Stack.Header>
84
+ <Stack.Header.Title>Search</Stack.Header.Title>
85
+ <Stack.Header.SearchBar
86
+ placeholder="Search..."
87
+ onChangeText={handleSearch}
88
+ />
89
+ </Stack.Header>
90
+ </Stack.Screen>
91
+ ```
92
+
93
+ ## Back Button Configuration
94
+
95
+ Customize the back button appearance and behavior:
96
+
97
+ ```tsx
98
+ <Stack.Screen name="detail">
99
+ <Stack.Header>
100
+ <Stack.Header.Title>Detail</Stack.Header.Title>
101
+ <Stack.Header.BackButton
102
+ displayMode="minimal"
103
+ hidden={false}
104
+ >
105
+ Back
106
+ </Stack.Header.BackButton>
107
+ </Stack.Header>
108
+ </Stack.Screen>
109
+ ```
110
+
111
+ ## Custom Header Component
112
+
113
+ Replace the entire header with a custom component:
114
+
115
+ ```tsx
116
+ <Stack.Screen name="custom">
117
+ <Stack.Header asChild>
118
+ <CustomHeader />
119
+ </Stack.Header>
120
+ </Stack.Screen>
121
+ ```
122
+
123
+ ## Combining with Options
124
+
125
+ You can combine the composition API with the traditional options prop:
126
+
127
+ ```tsx
128
+ <Stack.Screen
129
+ name="mixed"
130
+ options={{
131
+ animation: 'slide_from_right',
132
+ gestureEnabled: true,
133
+ }}
134
+ >
135
+ <Stack.Header>
136
+ <Stack.Header.Title large>Mixed Config</Stack.Header.Title>
137
+ </Stack.Header>
138
+ </Stack.Screen>
139
+ ```
140
+
141
+ ## API Reference
142
+
143
+ ### Stack.Header Props
144
+
145
+ | Prop | Type | Description |
146
+ |------|------|-------------|
147
+ | `hidden` | `boolean` | Hide the header entirely |
148
+ | `asChild` | `boolean` | Render children as the entire header |
149
+ | `blurEffect` | `'regular' \| 'prominent' \| ...` | iOS blur effect |
150
+ | `style` | `StyleProp` | Header style (backgroundColor, shadowColor) |
151
+ | `largeStyle` | `StyleProp` | Large title header style |
152
+
153
+ ### Stack.Header.Title Props
154
+
155
+ | Prop | Type | Description |
156
+ |------|------|-------------|
157
+ | `children` | `string` | Title text |
158
+ | `large` | `boolean` | Enable large title mode |
159
+ | `style` | `StyleProp` | Title text style |
160
+ | `largeStyle` | `StyleProp` | Large title text style |
161
+
162
+ ### Stack.Header.Left / Right Props
163
+
164
+ | Prop | Type | Description |
165
+ |------|------|-------------|
166
+ | `children` | `ReactNode` | Content to render |
167
+ | `asChild` | `boolean` | Required to render custom content |
168
+
169
+ ### Stack.Header.BackButton Props
170
+
171
+ | Prop | Type | Description |
172
+ |------|------|-------------|
173
+ | `children` | `string` | Back button title |
174
+ | `hidden` | `boolean` | Hide the back button |
175
+ | `displayMode` | `'default' \| 'minimal' \| 'generic'` | Display mode |
176
+ | `withMenu` | `boolean` | Enable back button menu |
177
+ | `src` | `ImageSourcePropType` | Custom back button image |
178
+ | `style` | `TextStyle` | Back button title style |
179
+
180
+ ### Stack.Header.SearchBar Props
181
+
182
+ Accepts all props from `react-native-screens` SearchBarProps.
183
+
184
+ ## Comparison with Options API
185
+
186
+ **Traditional options API:**
187
+ ```tsx
188
+ <Stack.Screen
189
+ name="index"
190
+ options={{
191
+ title: 'Welcome',
192
+ headerLargeTitle: true,
193
+ headerBlurEffect: 'regular',
194
+ headerRight: () => <Button>Action</Button>,
195
+ }}
196
+ />
197
+ ```
198
+
199
+ **Composition API:**
200
+ ```tsx
201
+ <Stack.Screen name="index">
202
+ <Stack.Header blurEffect="regular">
203
+ <Stack.Header.Title large>Welcome</Stack.Header.Title>
204
+ <Stack.Header.Right asChild>
205
+ <Button>Action</Button>
206
+ </Stack.Header.Right>
207
+ </Stack.Header>
208
+ </Stack.Screen>
209
+ ```
210
+
211
+ Both approaches work, choose based on your preference. The composition API can be more readable for complex configurations.
@@ -0,0 +1,34 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import type { ImageSourcePropType } from 'react-native'
3
+ import type { ScreenStackHeaderConfigProps } from 'react-native-screens'
4
+
5
+ export interface StackHeaderBackButtonProps {
6
+ children?: string
7
+ style?: NativeStackNavigationOptions['headerBackTitleStyle']
8
+ withMenu?: boolean
9
+ displayMode?: ScreenStackHeaderConfigProps['backButtonDisplayMode']
10
+ hidden?: boolean
11
+ src?: ImageSourcePropType
12
+ }
13
+
14
+ /**
15
+ * Configuration component for the back button in stack headers.
16
+ */
17
+ export function StackHeaderBackButton(_props: StackHeaderBackButtonProps) {
18
+ return null
19
+ }
20
+
21
+ export function appendStackHeaderBackButtonPropsToOptions(
22
+ options: NativeStackNavigationOptions,
23
+ props: StackHeaderBackButtonProps
24
+ ): NativeStackNavigationOptions {
25
+ return {
26
+ ...options,
27
+ headerBackTitle: props.children,
28
+ headerBackTitleStyle: props.style,
29
+ headerBackImageSource: props.src,
30
+ headerBackButtonDisplayMode: props.displayMode,
31
+ headerBackButtonMenuEnabled: props.withMenu,
32
+ headerBackVisible: props.hidden !== undefined ? !props.hidden : undefined,
33
+ }
34
+ }
@@ -0,0 +1,136 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import { Children, isValidElement, type ReactNode } from 'react'
3
+ import { StyleSheet, type ColorValue, type StyleProp } from 'react-native'
4
+ import type { ScreenStackHeaderConfigProps } from 'react-native-screens'
5
+
6
+ import {
7
+ appendStackHeaderBackButtonPropsToOptions,
8
+ StackHeaderBackButton,
9
+ } from './StackHeaderBackButton'
10
+ import { StackHeaderLeft, appendStackHeaderLeftPropsToOptions } from './StackHeaderLeft'
11
+ import {
12
+ StackHeaderRight,
13
+ appendStackHeaderRightPropsToOptions,
14
+ } from './StackHeaderRight'
15
+ import {
16
+ appendStackHeaderSearchBarPropsToOptions,
17
+ StackHeaderSearchBar,
18
+ } from './StackHeaderSearchBar'
19
+ import {
20
+ appendStackHeaderTitlePropsToOptions,
21
+ StackHeaderTitle,
22
+ } from './StackHeaderTitle'
23
+ import { isChildOfType } from '../../utils/children'
24
+
25
+ export interface StackHeaderProps {
26
+ children?: ReactNode
27
+ hidden?: boolean
28
+ asChild?: boolean
29
+ blurEffect?: ScreenStackHeaderConfigProps['blurEffect']
30
+ style?: StyleProp<{
31
+ color?: ColorValue
32
+ backgroundColor?: ScreenStackHeaderConfigProps['backgroundColor']
33
+ shadowColor?: undefined | 'transparent'
34
+ }>
35
+ largeStyle?: StyleProp<{
36
+ backgroundColor?: ScreenStackHeaderConfigProps['largeTitleBackgroundColor']
37
+ shadowColor?: undefined | 'transparent'
38
+ }>
39
+ }
40
+
41
+ /**
42
+ * Configuration component for stack headers.
43
+ * Use child components to configure different parts of the header.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * <Stack.Header blurEffect="regular">
48
+ * <Stack.Header.Title large>My Title</Stack.Header.Title>
49
+ * <Stack.Header.Right asChild>
50
+ * <Button>Action</Button>
51
+ * </Stack.Header.Right>
52
+ * </Stack.Header>
53
+ * ```
54
+ */
55
+ export function StackHeaderComponent(_props: StackHeaderProps) {
56
+ return null
57
+ }
58
+
59
+ export function appendStackHeaderPropsToOptions(
60
+ options: NativeStackNavigationOptions,
61
+ props: StackHeaderProps
62
+ ): NativeStackNavigationOptions {
63
+ const flattenedStyle = StyleSheet.flatten(props.style)
64
+ const flattenedLargeStyle = StyleSheet.flatten(props.largeStyle)
65
+
66
+ if (props.hidden) {
67
+ return { ...options, headerShown: false }
68
+ }
69
+
70
+ if (props.asChild) {
71
+ return { ...options, header: () => props.children }
72
+ }
73
+
74
+ const isTransparent = flattenedStyle?.backgroundColor === 'transparent'
75
+ const hasCustomShadow = flattenedStyle?.shadowColor !== undefined
76
+ const hasBackgroundColor = flattenedStyle?.backgroundColor !== undefined
77
+ const hasLargeBackgroundColor = flattenedLargeStyle?.backgroundColor !== undefined
78
+
79
+ let updatedOptions: NativeStackNavigationOptions = {
80
+ ...options,
81
+ headerShown: !props.hidden,
82
+ headerBlurEffect: props.blurEffect,
83
+ // Set headerTransparent when backgroundColor is 'transparent'
84
+ // This works on both iOS and Android for normal headers
85
+ // Note: When using SearchBar on iOS, if you don't have a ScrollView with
86
+ // contentInsetAdjustmentBehavior="automatic", set headerTransparent: false in options
87
+ ...(isTransparent && { headerTransparent: true }),
88
+ // Only set header styles when explicitly configured to avoid interfering with native defaults
89
+ ...(hasBackgroundColor && {
90
+ headerStyle: { backgroundColor: flattenedStyle.backgroundColor as string },
91
+ }),
92
+ ...(hasLargeBackgroundColor && {
93
+ headerLargeStyle: {
94
+ backgroundColor: flattenedLargeStyle.backgroundColor as string,
95
+ },
96
+ }),
97
+ // Only set shadow visibility when explicitly configured
98
+ ...(hasCustomShadow && {
99
+ headerShadowVisible: flattenedStyle?.shadowColor !== 'transparent',
100
+ }),
101
+ ...(flattenedLargeStyle?.shadowColor !== undefined && {
102
+ headerLargeTitleShadowVisible: flattenedLargeStyle?.shadowColor !== 'transparent',
103
+ }),
104
+ }
105
+
106
+ function appendChildOptions(
107
+ child: React.ReactElement,
108
+ options: NativeStackNavigationOptions
109
+ ) {
110
+ let result = options
111
+ if (isChildOfType(child, StackHeaderTitle)) {
112
+ result = appendStackHeaderTitlePropsToOptions(result, child.props)
113
+ } else if (isChildOfType(child, StackHeaderLeft)) {
114
+ result = appendStackHeaderLeftPropsToOptions(result, child.props)
115
+ } else if (isChildOfType(child, StackHeaderRight)) {
116
+ result = appendStackHeaderRightPropsToOptions(result, child.props)
117
+ } else if (isChildOfType(child, StackHeaderBackButton)) {
118
+ result = appendStackHeaderBackButtonPropsToOptions(result, child.props)
119
+ } else if (isChildOfType(child, StackHeaderSearchBar)) {
120
+ result = appendStackHeaderSearchBarPropsToOptions(result, child.props)
121
+ } else {
122
+ console.warn(
123
+ `Warning: Unknown child element passed to Stack.Header: ${(child.type as { name: string }).name ?? child.type}`
124
+ )
125
+ }
126
+ return result
127
+ }
128
+
129
+ Children.forEach(props.children, (child) => {
130
+ if (isValidElement(child)) {
131
+ updatedOptions = appendChildOptions(child, updatedOptions)
132
+ }
133
+ })
134
+
135
+ return updatedOptions
136
+ }
@@ -0,0 +1,29 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import type { ReactNode } from 'react'
3
+
4
+ export interface StackHeaderLeftProps {
5
+ children?: ReactNode
6
+ asChild?: boolean
7
+ }
8
+
9
+ /**
10
+ * Configuration component for custom left header content.
11
+ * Use `asChild` to render custom components in the left header area.
12
+ */
13
+ export function StackHeaderLeft(_props: StackHeaderLeftProps) {
14
+ return null
15
+ }
16
+
17
+ export function appendStackHeaderLeftPropsToOptions(
18
+ options: NativeStackNavigationOptions,
19
+ props: StackHeaderLeftProps
20
+ ): NativeStackNavigationOptions {
21
+ if (!props.asChild) {
22
+ return options
23
+ }
24
+
25
+ return {
26
+ ...options,
27
+ headerLeft: () => props.children,
28
+ }
29
+ }
@@ -0,0 +1,29 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import type { ReactNode } from 'react'
3
+
4
+ export interface StackHeaderRightProps {
5
+ children?: ReactNode
6
+ asChild?: boolean
7
+ }
8
+
9
+ /**
10
+ * Configuration component for custom right header content.
11
+ * Use `asChild` to render custom components in the right header area.
12
+ */
13
+ export function StackHeaderRight(_props: StackHeaderRightProps) {
14
+ return null
15
+ }
16
+
17
+ export function appendStackHeaderRightPropsToOptions(
18
+ options: NativeStackNavigationOptions,
19
+ props: StackHeaderRightProps
20
+ ): NativeStackNavigationOptions {
21
+ if (!props.asChild) {
22
+ return options
23
+ }
24
+
25
+ return {
26
+ ...options,
27
+ headerRight: () => props.children,
28
+ }
29
+ }
@@ -0,0 +1,21 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import type { SearchBarProps } from 'react-native-screens'
3
+
4
+ export interface StackHeaderSearchBarProps extends SearchBarProps {}
5
+
6
+ /**
7
+ * Configuration component for adding a search bar to stack headers.
8
+ */
9
+ export function StackHeaderSearchBar(_props: StackHeaderSearchBarProps) {
10
+ return null
11
+ }
12
+
13
+ export function appendStackHeaderSearchBarPropsToOptions(
14
+ options: NativeStackNavigationOptions,
15
+ props: StackHeaderSearchBarProps
16
+ ): NativeStackNavigationOptions {
17
+ return {
18
+ ...options,
19
+ headerSearchBarOptions: props,
20
+ }
21
+ }
@@ -0,0 +1,79 @@
1
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
2
+ import { Platform, StyleSheet, type StyleProp, type TextStyle } from 'react-native'
3
+
4
+ import { convertFontWeightToStringFontWeight } from '../../utils/style'
5
+
6
+ export type StackHeaderTitleProps = {
7
+ children?: string
8
+ style?: StyleProp<{
9
+ fontFamily?: TextStyle['fontFamily']
10
+ fontSize?: TextStyle['fontSize']
11
+ fontWeight?: Exclude<TextStyle['fontWeight'], number>
12
+ color?: string
13
+ textAlign?: 'left' | 'center'
14
+ }>
15
+ largeStyle?: StyleProp<{
16
+ fontFamily?: TextStyle['fontFamily']
17
+ fontSize?: TextStyle['fontSize']
18
+ fontWeight?: Exclude<TextStyle['fontWeight'], number>
19
+ color?: string
20
+ }>
21
+ large?: boolean
22
+ }
23
+
24
+ /**
25
+ * Configuration component for stack header title.
26
+ * This component doesn't render anything - it's used to configure the header.
27
+ */
28
+ export function StackHeaderTitle(_props: StackHeaderTitleProps) {
29
+ return null
30
+ }
31
+
32
+ export function appendStackHeaderTitlePropsToOptions(
33
+ options: NativeStackNavigationOptions,
34
+ props: StackHeaderTitleProps
35
+ ): NativeStackNavigationOptions {
36
+ const flattenedStyle = StyleSheet.flatten(props.style)
37
+ const flattenedLargeStyle = StyleSheet.flatten(props.largeStyle)
38
+
39
+ // Build title style only if there are actual style properties
40
+ const titleStyle = flattenedStyle
41
+ ? {
42
+ ...flattenedStyle,
43
+ ...(flattenedStyle?.fontWeight
44
+ ? { fontWeight: convertFontWeightToStringFontWeight(flattenedStyle.fontWeight) }
45
+ : {}),
46
+ }
47
+ : undefined
48
+
49
+ // Build large title style only if there are actual style properties
50
+ const largeTitleStyle = flattenedLargeStyle
51
+ ? {
52
+ ...flattenedLargeStyle,
53
+ ...(flattenedLargeStyle?.fontWeight
54
+ ? {
55
+ fontWeight: convertFontWeightToStringFontWeight(
56
+ flattenedLargeStyle.fontWeight
57
+ ),
58
+ }
59
+ : {}),
60
+ }
61
+ : undefined
62
+
63
+ return {
64
+ ...options,
65
+ title: props.children,
66
+ headerLargeTitle: props.large,
67
+ // Large titles on iOS require headerTransparent for proper scroll behavior
68
+ // Only set on iOS since headerLargeTitle is iOS-only
69
+ ...(props.large && Platform.OS === 'ios' && { headerTransparent: true }),
70
+ headerTitleAlign: flattenedStyle?.textAlign,
71
+ // Only set styles when explicitly configured to avoid interfering with native defaults
72
+ ...(titleStyle &&
73
+ Object.keys(titleStyle).length > 0 && { headerTitleStyle: titleStyle }),
74
+ ...(largeTitleStyle &&
75
+ Object.keys(largeTitleStyle).length > 0 && {
76
+ headerLargeTitleStyle: largeTitleStyle,
77
+ }),
78
+ }
79
+ }