@hzblj/kara-components 0.20.1 → 0.22.0

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 (488) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/lib/module/atoms/activity-indicator/activity-indicator.android.js +1 -1
  3. package/lib/module/atoms/activity-indicator/activity-indicator.android.js.map +1 -1
  4. package/lib/module/atoms/activity-indicator/activity-indicator.ios.js +1 -1
  5. package/lib/module/atoms/activity-indicator/activity-indicator.ios.js.map +1 -1
  6. package/lib/module/atoms/badge/badge.android.js +1 -1
  7. package/lib/module/atoms/badge/badge.android.js.map +1 -1
  8. package/lib/module/atoms/badge/badge.ios.js +1 -1
  9. package/lib/module/atoms/badge/badge.ios.js.map +1 -1
  10. package/lib/module/atoms/blur-view/blur-view.android.js +22 -1
  11. package/lib/module/atoms/blur-view/blur-view.android.js.map +1 -1
  12. package/lib/module/atoms/blur-view/blur-view.ios.js +20 -0
  13. package/lib/module/atoms/blur-view/blur-view.ios.js.map +1 -1
  14. package/lib/module/atoms/button/button.android.js +1 -1
  15. package/lib/module/atoms/button/button.android.js.map +1 -1
  16. package/lib/module/atoms/button/button.ios.js +1 -1
  17. package/lib/module/atoms/button/button.ios.js.map +1 -1
  18. package/lib/module/atoms/card/card.android.js +1 -1
  19. package/lib/module/atoms/card/card.android.js.map +1 -1
  20. package/lib/module/atoms/card/card.ios.js +1 -1
  21. package/lib/module/atoms/card/card.ios.js.map +1 -1
  22. package/lib/module/atoms/checkbox/checkbox.android.js +1 -1
  23. package/lib/module/atoms/checkbox/checkbox.android.js.map +1 -1
  24. package/lib/module/atoms/checkbox/checkbox.ios.js +1 -1
  25. package/lib/module/atoms/checkbox/checkbox.ios.js.map +1 -1
  26. package/lib/module/atoms/color-picker/color-picker.android.js +1 -1
  27. package/lib/module/atoms/color-picker/color-picker.android.js.map +1 -1
  28. package/lib/module/atoms/color-picker/color-picker.ios.js +1 -1
  29. package/lib/module/atoms/color-picker/color-picker.ios.js.map +1 -1
  30. package/lib/module/atoms/date-picker/date-picker.android.js +1 -1
  31. package/lib/module/atoms/date-picker/date-picker.android.js.map +1 -1
  32. package/lib/module/atoms/date-picker/date-picker.ios.js +1 -1
  33. package/lib/module/atoms/date-picker/date-picker.ios.js.map +1 -1
  34. package/lib/module/atoms/divider/divider.android.js +1 -1
  35. package/lib/module/atoms/divider/divider.android.js.map +1 -1
  36. package/lib/module/atoms/divider/divider.ios.js +1 -1
  37. package/lib/module/atoms/divider/divider.ios.js.map +1 -1
  38. package/lib/module/atoms/fab/fab.android.js +1 -1
  39. package/lib/module/atoms/fab/fab.android.js.map +1 -1
  40. package/lib/module/atoms/fab/fab.ios.js +1 -1
  41. package/lib/module/atoms/fab/fab.ios.js.map +1 -1
  42. package/lib/module/atoms/glyph/glyph-button.android.js.map +1 -0
  43. package/lib/module/atoms/glyph/glyph-button.ios.js.map +1 -0
  44. package/lib/module/atoms/glyph/glyph-button.types.js.map +1 -0
  45. package/lib/module/atoms/glyph/glyph.android.js.map +1 -0
  46. package/lib/module/atoms/glyph/glyph.ios.js.map +1 -0
  47. package/lib/module/atoms/glyph/glyph.types.js.map +1 -0
  48. package/lib/module/atoms/glyph/index.js.map +1 -0
  49. package/lib/module/atoms/glyph/rn-glyph.android.js.map +1 -0
  50. package/lib/module/atoms/glyph/rn-glyph.ios.js.map +1 -0
  51. package/lib/module/atoms/h-stack/h-stack.android.js +2 -2
  52. package/lib/module/atoms/h-stack/h-stack.android.js.map +1 -1
  53. package/lib/module/atoms/h-stack/h-stack.ios.js +2 -2
  54. package/lib/module/atoms/h-stack/h-stack.ios.js.map +1 -1
  55. package/lib/module/atoms/icon/icon.android.js +1 -1
  56. package/lib/module/atoms/icon/icon.android.js.map +1 -1
  57. package/lib/module/atoms/icon/icon.ios.js +1 -1
  58. package/lib/module/atoms/icon/icon.ios.js.map +1 -1
  59. package/lib/module/atoms/icon-button/icon-button.android.js +1 -1
  60. package/lib/module/atoms/icon-button/icon-button.android.js.map +1 -1
  61. package/lib/module/atoms/icon-button/icon-button.ios.js +1 -1
  62. package/lib/module/atoms/icon-button/icon-button.ios.js.map +1 -1
  63. package/lib/module/atoms/island/island.android.js +3 -1
  64. package/lib/module/atoms/island/island.android.js.map +1 -1
  65. package/lib/module/atoms/island/island.ios.js +3 -1
  66. package/lib/module/atoms/island/island.ios.js.map +1 -1
  67. package/lib/module/atoms/list/list.android.js +2 -2
  68. package/lib/module/atoms/list/list.android.js.map +1 -1
  69. package/lib/module/atoms/list/list.ios.js +1 -1
  70. package/lib/module/atoms/list/list.ios.js.map +1 -1
  71. package/lib/module/atoms/picker/picker.android.js +2 -2
  72. package/lib/module/atoms/picker/picker.android.js.map +1 -1
  73. package/lib/module/atoms/picker/picker.ios.js +1 -1
  74. package/lib/module/atoms/picker/picker.ios.js.map +1 -1
  75. package/lib/module/atoms/pressable/pressable.js +1 -1
  76. package/lib/module/atoms/pressable/pressable.js.map +1 -1
  77. package/lib/module/atoms/progress/progress.android.js +1 -1
  78. package/lib/module/atoms/progress/progress.android.js.map +1 -1
  79. package/lib/module/atoms/progress/progress.ios.js +1 -1
  80. package/lib/module/atoms/progress/progress.ios.js.map +1 -1
  81. package/lib/module/atoms/scroll-view/scroll-view.android.js +2 -2
  82. package/lib/module/atoms/scroll-view/scroll-view.android.js.map +1 -1
  83. package/lib/module/atoms/scroll-view/scroll-view.ios.js +1 -1
  84. package/lib/module/atoms/scroll-view/scroll-view.ios.js.map +1 -1
  85. package/lib/module/atoms/segmented-control/segmented-control.android.js +1 -1
  86. package/lib/module/atoms/segmented-control/segmented-control.android.js.map +1 -1
  87. package/lib/module/atoms/segmented-control/segmented-control.ios.js +1 -1
  88. package/lib/module/atoms/segmented-control/segmented-control.ios.js.map +1 -1
  89. package/lib/module/atoms/slider/slider.android.js +1 -1
  90. package/lib/module/atoms/slider/slider.android.js.map +1 -1
  91. package/lib/module/atoms/slider/slider.ios.js +1 -1
  92. package/lib/module/atoms/slider/slider.ios.js.map +1 -1
  93. package/lib/module/atoms/spacer/spacer.android.js +1 -1
  94. package/lib/module/atoms/spacer/spacer.android.js.map +1 -1
  95. package/lib/module/atoms/spacer/spacer.ios.js +1 -1
  96. package/lib/module/atoms/spacer/spacer.ios.js.map +1 -1
  97. package/lib/module/atoms/surface/surface.android.js +1 -1
  98. package/lib/module/atoms/surface/surface.android.js.map +1 -1
  99. package/lib/module/atoms/surface/surface.ios.js +1 -1
  100. package/lib/module/atoms/surface/surface.ios.js.map +1 -1
  101. package/lib/module/atoms/switch/switch.android.js +1 -1
  102. package/lib/module/atoms/switch/switch.android.js.map +1 -1
  103. package/lib/module/atoms/switch/switch.ios.js +1 -1
  104. package/lib/module/atoms/switch/switch.ios.js.map +1 -1
  105. package/lib/module/atoms/text/text.android.js +1 -1
  106. package/lib/module/atoms/text/text.android.js.map +1 -1
  107. package/lib/module/atoms/text/text.ios.js +1 -1
  108. package/lib/module/atoms/text/text.ios.js.map +1 -1
  109. package/lib/module/atoms/text-field/text-field.android.js +2 -2
  110. package/lib/module/atoms/text-field/text-field.android.js.map +1 -1
  111. package/lib/module/atoms/text-field/text-field.ios.js +1 -1
  112. package/lib/module/atoms/text-field/text-field.ios.js.map +1 -1
  113. package/lib/module/atoms/v-stack/v-stack.android.js +2 -2
  114. package/lib/module/atoms/v-stack/v-stack.android.js.map +1 -1
  115. package/lib/module/atoms/v-stack/v-stack.ios.js +2 -2
  116. package/lib/module/atoms/v-stack/v-stack.ios.js.map +1 -1
  117. package/lib/module/atoms/z-stack/z-stack.android.js +2 -2
  118. package/lib/module/atoms/z-stack/z-stack.android.js.map +1 -1
  119. package/lib/module/atoms/z-stack/z-stack.ios.js +2 -2
  120. package/lib/module/atoms/z-stack/z-stack.ios.js.map +1 -1
  121. package/lib/module/hooks/host-context.js.map +1 -0
  122. package/lib/module/hooks/use-refresh-state.js.map +1 -0
  123. package/lib/module/hooks/use-stack-modifiers.js.map +1 -0
  124. package/lib/module/molecules/collapsible/collapsible.android.js +2 -2
  125. package/lib/module/molecules/collapsible/collapsible.android.js.map +1 -1
  126. package/lib/module/molecules/collapsible/collapsible.ios.js +1 -1
  127. package/lib/module/molecules/collapsible/collapsible.ios.js.map +1 -1
  128. package/lib/module/molecules/labeled-content/labeled-content.js +1 -1
  129. package/lib/module/molecules/labeled-content/labeled-content.js.map +1 -1
  130. package/lib/module/molecules/list-item/list-item.js +1 -1
  131. package/lib/module/molecules/list-item/list-item.js.map +1 -1
  132. package/lib/module/molecules/navigation-bar/navigation-bar.constants.js +5 -0
  133. package/lib/module/molecules/navigation-bar/navigation-bar.constants.js.map +1 -0
  134. package/lib/module/molecules/navigation-bar/navigation-bar.ios.js +31 -4
  135. package/lib/module/molecules/navigation-bar/navigation-bar.ios.js.map +1 -1
  136. package/lib/module/molecules/pager/pager.android.js +1 -1
  137. package/lib/module/molecules/pager/pager.android.js.map +1 -1
  138. package/lib/module/molecules/pager/pager.ios.js +1 -1
  139. package/lib/module/molecules/pager/pager.ios.js.map +1 -1
  140. package/lib/module/molecules/radio-group/radio-group.android.js +1 -1
  141. package/lib/module/molecules/radio-group/radio-group.android.js.map +1 -1
  142. package/lib/module/molecules/radio-group/radio-group.ios.js +2 -2
  143. package/lib/module/molecules/radio-group/radio-group.ios.js.map +1 -1
  144. package/lib/module/molecules/rn-list-item/rn-list-item.js +1 -1
  145. package/lib/module/molecules/rn-list-item/rn-list-item.js.map +1 -1
  146. package/lib/module/molecules/rn-tooltip/rn-tooltip.android.js +1 -1
  147. package/lib/module/molecules/rn-tooltip/rn-tooltip.android.js.map +1 -1
  148. package/lib/module/molecules/search-bar/search-bar.js +1 -1
  149. package/lib/module/molecules/search-bar/search-bar.js.map +1 -1
  150. package/lib/module/molecules/stepper/stepper.android.js +2 -2
  151. package/lib/module/molecules/stepper/stepper.android.js.map +1 -1
  152. package/lib/module/molecules/stepper/stepper.ios.js +1 -1
  153. package/lib/module/molecules/stepper/stepper.ios.js.map +1 -1
  154. package/lib/module/molecules/tooltip/tooltip.android.js +1 -1
  155. package/lib/module/molecules/tooltip/tooltip.android.js.map +1 -1
  156. package/lib/module/molecules/tooltip/tooltip.ios.js +1 -1
  157. package/lib/module/molecules/tooltip/tooltip.ios.js.map +1 -1
  158. package/lib/module/organisms/action-sheet/action-sheet.android.js +1 -1
  159. package/lib/module/organisms/action-sheet/action-sheet.android.js.map +1 -1
  160. package/lib/module/organisms/action-sheet/action-sheet.ios.js +1 -1
  161. package/lib/module/organisms/action-sheet/action-sheet.ios.js.map +1 -1
  162. package/lib/module/organisms/alert/alert.android.js +1 -1
  163. package/lib/module/organisms/alert/alert.android.js.map +1 -1
  164. package/lib/module/organisms/alert/alert.ios.js +1 -1
  165. package/lib/module/organisms/alert/alert.ios.js.map +1 -1
  166. package/lib/module/organisms/context-menu/context-menu.android.js +2 -2
  167. package/lib/module/organisms/context-menu/context-menu.android.js.map +1 -1
  168. package/lib/module/organisms/fab-menu/fab-menu.android.js +2 -2
  169. package/lib/module/organisms/fab-menu/fab-menu.android.js.map +1 -1
  170. package/lib/module/organisms/fab-menu/fab-menu.ios.js +2 -2
  171. package/lib/module/organisms/fab-menu/fab-menu.ios.js.map +1 -1
  172. package/lib/module/organisms/form/form.android.js +1 -1
  173. package/lib/module/organisms/form/form.android.js.map +1 -1
  174. package/lib/module/organisms/form/form.ios.js +1 -1
  175. package/lib/module/organisms/form/form.ios.js.map +1 -1
  176. package/lib/module/organisms/header/header-color.js +8 -0
  177. package/lib/module/organisms/header/header-color.js.map +1 -0
  178. package/lib/module/organisms/header/header-inset.android.js +6 -0
  179. package/lib/module/organisms/header/header-inset.android.js.map +1 -0
  180. package/lib/module/organisms/header/header-inset.ios.js +19 -0
  181. package/lib/module/organisms/header/header-inset.ios.js.map +1 -0
  182. package/lib/module/organisms/header/header-large-title-fade.android.js +6 -0
  183. package/lib/module/organisms/header/header-large-title-fade.android.js.map +1 -0
  184. package/lib/module/organisms/header/header-large-title-fade.ios.js +15 -0
  185. package/lib/module/organisms/header/header-large-title-fade.ios.js.map +1 -0
  186. package/lib/module/organisms/header/header-options.android.js +180 -0
  187. package/lib/module/organisms/header/header-options.android.js.map +1 -0
  188. package/lib/module/organisms/header/header-options.ios.js +145 -0
  189. package/lib/module/organisms/header/header-options.ios.js.map +1 -0
  190. package/lib/module/organisms/header/header-options.types.js +4 -0
  191. package/lib/module/organisms/header/header-options.types.js.map +1 -0
  192. package/lib/module/organisms/header/header-search-accessory.android.js +5 -0
  193. package/lib/module/organisms/header/header-search-accessory.android.js.map +1 -0
  194. package/lib/module/organisms/header/header-search-accessory.ios.js +35 -0
  195. package/lib/module/organisms/header/header-search-accessory.ios.js.map +1 -0
  196. package/lib/module/organisms/header/header-search-accessory.types.js +4 -0
  197. package/lib/module/organisms/header/header-search-accessory.types.js.map +1 -0
  198. package/lib/module/organisms/header/header-search-input.android.js +80 -0
  199. package/lib/module/organisms/header/header-search-input.android.js.map +1 -0
  200. package/lib/module/organisms/header/header-search-input.ios.js +8 -0
  201. package/lib/module/organisms/header/header-search-input.ios.js.map +1 -0
  202. package/lib/module/organisms/header/header-search-input.types.js +4 -0
  203. package/lib/module/organisms/header/header-search-input.types.js.map +1 -0
  204. package/lib/module/organisms/header/header-search-scrim.js +62 -0
  205. package/lib/module/organisms/header/header-search-scrim.js.map +1 -0
  206. package/lib/module/organisms/header/header-title.js +230 -0
  207. package/lib/module/organisms/header/header-title.js.map +1 -0
  208. package/lib/module/organisms/header/header.types.js +4 -0
  209. package/lib/module/organisms/header/header.types.js.map +1 -0
  210. package/lib/module/organisms/header/hero-header-background.android.js +33 -0
  211. package/lib/module/organisms/header/hero-header-background.android.js.map +1 -0
  212. package/lib/module/organisms/header/hero-header-background.ios.js +40 -0
  213. package/lib/module/organisms/header/hero-header-background.ios.js.map +1 -0
  214. package/lib/module/organisms/header/hero-header-background.types.js +4 -0
  215. package/lib/module/organisms/header/hero-header-background.types.js.map +1 -0
  216. package/lib/module/organisms/header/index.js +14 -0
  217. package/lib/module/organisms/header/index.js.map +1 -0
  218. package/lib/module/organisms/header/native-subtitle.android.js +5 -0
  219. package/lib/module/organisms/header/native-subtitle.android.js.map +1 -0
  220. package/lib/module/organisms/header/native-subtitle.ios.js +22 -0
  221. package/lib/module/organisms/header/native-subtitle.ios.js.map +1 -0
  222. package/lib/module/organisms/header/native-subtitle.types.js +4 -0
  223. package/lib/module/organisms/header/native-subtitle.types.js.map +1 -0
  224. package/lib/module/organisms/header/sheet-grabber.android.js +5 -0
  225. package/lib/module/organisms/header/sheet-grabber.android.js.map +1 -0
  226. package/lib/module/organisms/header/sheet-grabber.ios.js +15 -0
  227. package/lib/module/organisms/header/sheet-grabber.ios.js.map +1 -0
  228. package/lib/module/organisms/header/sheet-grabber.types.js +4 -0
  229. package/lib/module/organisms/header/sheet-grabber.types.js.map +1 -0
  230. package/lib/module/organisms/header/use-header-bar-inset.android.js +4 -0
  231. package/lib/module/organisms/header/use-header-bar-inset.android.js.map +1 -0
  232. package/lib/module/organisms/header/use-header-bar-inset.ios.js +9 -0
  233. package/lib/module/organisms/header/use-header-bar-inset.ios.js.map +1 -0
  234. package/lib/module/organisms/header/use-header-bar-inset.types.js +2 -0
  235. package/lib/module/organisms/header/use-header-bar-inset.types.js.map +1 -0
  236. package/lib/module/organisms/header/use-header-scroll-to-top.js +51 -0
  237. package/lib/module/organisms/header/use-header-scroll-to-top.js.map +1 -0
  238. package/lib/module/organisms/header/use-header-search.js +135 -0
  239. package/lib/module/organisms/header/use-header-search.js.map +1 -0
  240. package/lib/module/organisms/header/use-header.js +74 -0
  241. package/lib/module/organisms/header/use-header.js.map +1 -0
  242. package/lib/module/organisms/header/use-hero-header.js +189 -0
  243. package/lib/module/organisms/header/use-hero-header.js.map +1 -0
  244. package/lib/module/organisms/header/use-stack-screen-options.js +77 -0
  245. package/lib/module/organisms/header/use-stack-screen-options.js.map +1 -0
  246. package/lib/module/organisms/menu/menu.android.js +2 -2
  247. package/lib/module/organisms/menu/menu.android.js.map +1 -1
  248. package/lib/module/organisms/menu/menu.ios.js +1 -1
  249. package/lib/module/organisms/menu/menu.ios.js.map +1 -1
  250. package/lib/module/organisms/sheet/use-sheet-header.js +3 -1
  251. package/lib/module/organisms/sheet/use-sheet-header.js.map +1 -1
  252. package/lib/module/organisms/snackbar/snackbar.js +1 -1
  253. package/lib/module/organisms/snackbar/snackbar.js.map +1 -1
  254. package/lib/module/organisms/swipe-actions/swipe-actions.android.js +1 -1
  255. package/lib/module/organisms/swipe-actions/swipe-actions.android.js.map +1 -1
  256. package/lib/module/organisms/swipe-actions/swipe-actions.ios.js +1 -1
  257. package/lib/module/organisms/swipe-actions/swipe-actions.ios.js.map +1 -1
  258. package/lib/module/templates/screen/screen.android.js +3 -3
  259. package/lib/module/templates/screen/screen.android.js.map +1 -1
  260. package/lib/module/templates/screen/screen.ios.js +3 -3
  261. package/lib/module/templates/screen/screen.ios.js.map +1 -1
  262. package/lib/module/utils/ripple-clip.js.map +1 -0
  263. package/lib/module/utils/tap-modifiers.js.map +1 -0
  264. package/lib/typescript/atoms/blur-view/blur-view.types.d.ts +8 -0
  265. package/lib/typescript/atoms/island/island.types.d.ts +17 -0
  266. package/lib/typescript/molecules/navigation-bar/navigation-bar.constants.d.ts +2 -0
  267. package/lib/typescript/molecules/navigation-bar/navigation-bar.types.d.ts +67 -4
  268. package/lib/typescript/organisms/header/header-color.d.ts +6 -0
  269. package/lib/typescript/organisms/header/header-inset.d.ts +1 -0
  270. package/lib/typescript/organisms/header/header-inset.ios.d.ts +2 -0
  271. package/lib/typescript/organisms/header/header-large-title-fade.d.ts +1 -0
  272. package/lib/typescript/organisms/header/header-large-title-fade.ios.d.ts +7 -0
  273. package/lib/typescript/organisms/header/header-options.d.ts +1 -0
  274. package/lib/typescript/organisms/header/header-options.ios.d.ts +2 -0
  275. package/lib/typescript/organisms/header/header-options.types.d.ts +4 -0
  276. package/lib/typescript/organisms/header/header-search-accessory.d.ts +1 -0
  277. package/lib/typescript/organisms/header/header-search-accessory.ios.d.ts +6 -0
  278. package/lib/typescript/organisms/header/header-search-accessory.types.d.ts +9 -0
  279. package/lib/typescript/organisms/header/header-search-input.d.ts +1 -0
  280. package/lib/typescript/organisms/header/header-search-input.ios.d.ts +5 -0
  281. package/lib/typescript/organisms/header/header-search-input.types.d.ts +17 -0
  282. package/lib/typescript/organisms/header/header-search-scrim.d.ts +11 -0
  283. package/lib/typescript/organisms/header/header-title.d.ts +22 -0
  284. package/lib/typescript/organisms/header/header.types.d.ts +445 -0
  285. package/lib/typescript/organisms/header/hero-header-background.d.ts +1 -0
  286. package/lib/typescript/organisms/header/hero-header-background.ios.d.ts +7 -0
  287. package/lib/typescript/organisms/header/hero-header-background.types.d.ts +9 -0
  288. package/lib/typescript/organisms/header/index.d.ts +12 -0
  289. package/lib/typescript/organisms/header/native-subtitle.d.ts +1 -0
  290. package/lib/typescript/organisms/header/native-subtitle.ios.d.ts +4 -0
  291. package/lib/typescript/organisms/header/native-subtitle.types.d.ts +6 -0
  292. package/lib/typescript/organisms/header/sheet-grabber.d.ts +1 -0
  293. package/lib/typescript/organisms/header/sheet-grabber.ios.d.ts +7 -0
  294. package/lib/typescript/organisms/header/sheet-grabber.types.d.ts +6 -0
  295. package/lib/typescript/organisms/header/use-header-bar-inset.d.ts +1 -0
  296. package/lib/typescript/organisms/header/use-header-bar-inset.ios.d.ts +1 -0
  297. package/lib/typescript/organisms/header/use-header-bar-inset.types.d.ts +6 -0
  298. package/lib/typescript/organisms/header/use-header-scroll-to-top.d.ts +8 -0
  299. package/lib/typescript/organisms/header/use-header-search.d.ts +12 -0
  300. package/lib/typescript/organisms/header/use-header.d.ts +14 -0
  301. package/lib/typescript/organisms/header/use-hero-header.d.ts +10 -0
  302. package/lib/typescript/organisms/header/use-stack-screen-options.d.ts +17 -0
  303. package/lib/typescript/templates/screen/screen.types.d.ts +6 -2
  304. package/package.json +24 -5
  305. package/src/atoms/activity-indicator/activity-indicator.android.tsx +1 -1
  306. package/src/atoms/activity-indicator/activity-indicator.ios.tsx +1 -1
  307. package/src/atoms/badge/badge.android.tsx +1 -1
  308. package/src/atoms/badge/badge.ios.tsx +1 -1
  309. package/src/atoms/blur-view/blur-view.android.tsx +28 -1
  310. package/src/atoms/blur-view/blur-view.ios.tsx +25 -0
  311. package/src/atoms/blur-view/blur-view.types.ts +8 -0
  312. package/src/atoms/button/button.android.tsx +1 -1
  313. package/src/atoms/button/button.ios.tsx +1 -1
  314. package/src/atoms/card/card.android.tsx +1 -1
  315. package/src/atoms/card/card.ios.tsx +1 -1
  316. package/src/atoms/checkbox/checkbox.android.tsx +1 -1
  317. package/src/atoms/checkbox/checkbox.ios.tsx +1 -1
  318. package/src/atoms/color-picker/color-picker.android.tsx +1 -1
  319. package/src/atoms/color-picker/color-picker.ios.tsx +1 -1
  320. package/src/atoms/date-picker/date-picker.android.tsx +1 -1
  321. package/src/atoms/date-picker/date-picker.ios.tsx +1 -1
  322. package/src/atoms/divider/divider.android.tsx +1 -1
  323. package/src/atoms/divider/divider.ios.tsx +1 -1
  324. package/src/atoms/fab/fab.android.tsx +1 -1
  325. package/src/atoms/fab/fab.ios.tsx +1 -1
  326. package/src/atoms/h-stack/h-stack.android.tsx +2 -2
  327. package/src/atoms/h-stack/h-stack.ios.tsx +2 -2
  328. package/src/atoms/icon/icon.android.tsx +1 -1
  329. package/src/atoms/icon/icon.ios.tsx +1 -1
  330. package/src/atoms/icon-button/icon-button.android.tsx +1 -1
  331. package/src/atoms/icon-button/icon-button.ios.tsx +1 -1
  332. package/src/atoms/island/island.android.tsx +3 -1
  333. package/src/atoms/island/island.ios.tsx +10 -2
  334. package/src/atoms/island/island.types.ts +18 -0
  335. package/src/atoms/list/list.android.tsx +2 -2
  336. package/src/atoms/list/list.ios.tsx +1 -1
  337. package/src/atoms/picker/picker.android.tsx +2 -3
  338. package/src/atoms/picker/picker.ios.tsx +1 -1
  339. package/src/atoms/pressable/pressable.tsx +1 -1
  340. package/src/atoms/progress/progress.android.tsx +1 -1
  341. package/src/atoms/progress/progress.ios.tsx +1 -1
  342. package/src/atoms/scroll-view/scroll-view.android.tsx +2 -2
  343. package/src/atoms/scroll-view/scroll-view.ios.tsx +1 -1
  344. package/src/atoms/segmented-control/segmented-control.android.tsx +1 -1
  345. package/src/atoms/segmented-control/segmented-control.ios.tsx +1 -1
  346. package/src/atoms/slider/slider.android.tsx +1 -1
  347. package/src/atoms/slider/slider.ios.tsx +1 -1
  348. package/src/atoms/spacer/spacer.android.tsx +1 -1
  349. package/src/atoms/spacer/spacer.ios.tsx +1 -1
  350. package/src/atoms/surface/surface.android.tsx +1 -1
  351. package/src/atoms/surface/surface.ios.tsx +1 -1
  352. package/src/atoms/switch/switch.android.tsx +1 -1
  353. package/src/atoms/switch/switch.ios.tsx +1 -1
  354. package/src/atoms/text/text.android.tsx +1 -1
  355. package/src/atoms/text/text.ios.tsx +1 -1
  356. package/src/atoms/text-field/text-field.android.tsx +2 -2
  357. package/src/atoms/text-field/text-field.ios.tsx +1 -1
  358. package/src/atoms/v-stack/v-stack.android.tsx +2 -2
  359. package/src/atoms/v-stack/v-stack.ios.tsx +2 -2
  360. package/src/atoms/z-stack/z-stack.android.tsx +2 -2
  361. package/src/atoms/z-stack/z-stack.ios.tsx +2 -2
  362. package/src/molecules/collapsible/collapsible.android.tsx +2 -2
  363. package/src/molecules/collapsible/collapsible.ios.tsx +1 -1
  364. package/src/molecules/labeled-content/labeled-content.tsx +1 -1
  365. package/src/molecules/list-item/list-item.tsx +1 -2
  366. package/src/molecules/navigation-bar/navigation-bar.constants.ts +2 -0
  367. package/src/molecules/navigation-bar/navigation-bar.ios.tsx +35 -5
  368. package/src/molecules/navigation-bar/navigation-bar.types.ts +69 -5
  369. package/src/molecules/pager/pager.android.tsx +1 -1
  370. package/src/molecules/pager/pager.ios.tsx +1 -1
  371. package/src/molecules/radio-group/radio-group.android.tsx +1 -1
  372. package/src/molecules/radio-group/radio-group.ios.tsx +2 -2
  373. package/src/molecules/rn-list-item/rn-list-item.tsx +1 -1
  374. package/src/molecules/rn-tooltip/rn-tooltip.android.tsx +1 -1
  375. package/src/molecules/search-bar/search-bar.tsx +1 -1
  376. package/src/molecules/stepper/stepper.android.tsx +2 -2
  377. package/src/molecules/stepper/stepper.ios.tsx +1 -1
  378. package/src/molecules/tooltip/tooltip.android.tsx +1 -1
  379. package/src/molecules/tooltip/tooltip.ios.tsx +1 -1
  380. package/src/organisms/action-sheet/action-sheet.android.tsx +1 -1
  381. package/src/organisms/action-sheet/action-sheet.ios.tsx +1 -1
  382. package/src/organisms/alert/alert.android.tsx +1 -1
  383. package/src/organisms/alert/alert.ios.tsx +1 -1
  384. package/src/organisms/context-menu/context-menu.android.tsx +2 -2
  385. package/src/organisms/fab-menu/fab-menu.android.tsx +2 -2
  386. package/src/organisms/fab-menu/fab-menu.ios.tsx +2 -3
  387. package/src/organisms/form/form.android.tsx +1 -1
  388. package/src/organisms/form/form.ios.tsx +1 -1
  389. package/src/organisms/header/header-color.ts +7 -0
  390. package/src/organisms/header/header-inset.android.tsx +3 -0
  391. package/src/organisms/header/header-inset.ios.tsx +12 -0
  392. package/src/organisms/header/header-large-title-fade.android.tsx +3 -0
  393. package/src/organisms/header/header-large-title-fade.ios.tsx +12 -0
  394. package/src/organisms/header/header-options.android.tsx +168 -0
  395. package/src/organisms/header/header-options.ios.tsx +138 -0
  396. package/src/organisms/header/header-options.types.ts +6 -0
  397. package/src/organisms/header/header-search-accessory.android.tsx +4 -0
  398. package/src/organisms/header/header-search-accessory.ios.tsx +42 -0
  399. package/src/organisms/header/header-search-accessory.types.ts +12 -0
  400. package/src/organisms/header/header-search-input.android.tsx +89 -0
  401. package/src/organisms/header/header-search-input.ios.tsx +7 -0
  402. package/src/organisms/header/header-search-input.types.ts +21 -0
  403. package/src/organisms/header/header-search-scrim.tsx +49 -0
  404. package/src/organisms/header/header-title.tsx +220 -0
  405. package/src/organisms/header/header.types.ts +423 -0
  406. package/src/organisms/header/hero-header-background.android.tsx +22 -0
  407. package/src/organisms/header/hero-header-background.ios.tsx +26 -0
  408. package/src/organisms/header/hero-header-background.types.ts +11 -0
  409. package/src/organisms/header/index.ts +12 -0
  410. package/src/organisms/header/native-subtitle.android.tsx +5 -0
  411. package/src/organisms/header/native-subtitle.ios.tsx +22 -0
  412. package/src/organisms/header/native-subtitle.types.ts +8 -0
  413. package/src/organisms/header/sheet-grabber.android.tsx +4 -0
  414. package/src/organisms/header/sheet-grabber.ios.tsx +12 -0
  415. package/src/organisms/header/sheet-grabber.types.ts +8 -0
  416. package/src/organisms/header/use-header-bar-inset.android.ts +1 -0
  417. package/src/organisms/header/use-header-bar-inset.ios.ts +7 -0
  418. package/src/organisms/header/use-header-bar-inset.types.ts +6 -0
  419. package/src/organisms/header/use-header-scroll-to-top.ts +48 -0
  420. package/src/organisms/header/use-header-search.tsx +138 -0
  421. package/src/organisms/header/use-header.ts +67 -0
  422. package/src/organisms/header/use-hero-header.tsx +222 -0
  423. package/src/organisms/header/use-stack-screen-options.ts +66 -0
  424. package/src/organisms/menu/menu.android.tsx +2 -2
  425. package/src/organisms/menu/menu.ios.tsx +1 -1
  426. package/src/organisms/sheet/use-sheet-header.tsx +4 -1
  427. package/src/organisms/snackbar/snackbar.tsx +1 -1
  428. package/src/organisms/swipe-actions/swipe-actions.android.tsx +1 -1
  429. package/src/organisms/swipe-actions/swipe-actions.ios.tsx +1 -1
  430. package/src/templates/screen/screen.android.tsx +8 -3
  431. package/src/templates/screen/screen.ios.tsx +8 -3
  432. package/src/templates/screen/screen.types.ts +7 -2
  433. package/lib/module/glyph/glyph-button.android.js.map +0 -1
  434. package/lib/module/glyph/glyph-button.ios.js.map +0 -1
  435. package/lib/module/glyph/glyph-button.types.js.map +0 -1
  436. package/lib/module/glyph/glyph.android.js.map +0 -1
  437. package/lib/module/glyph/glyph.ios.js.map +0 -1
  438. package/lib/module/glyph/glyph.types.js.map +0 -1
  439. package/lib/module/glyph/index.js.map +0 -1
  440. package/lib/module/glyph/rn-glyph.android.js.map +0 -1
  441. package/lib/module/glyph/rn-glyph.ios.js.map +0 -1
  442. package/lib/module/host-context.js.map +0 -1
  443. package/lib/module/ripple-clip.js.map +0 -1
  444. package/lib/module/tap-modifiers.js.map +0 -1
  445. package/lib/module/use-refresh-state.js.map +0 -1
  446. package/lib/module/use-stack-modifiers.js.map +0 -1
  447. /package/lib/module/{glyph → atoms/glyph}/glyph-button.android.js +0 -0
  448. /package/lib/module/{glyph → atoms/glyph}/glyph-button.ios.js +0 -0
  449. /package/lib/module/{glyph → atoms/glyph}/glyph-button.types.js +0 -0
  450. /package/lib/module/{glyph → atoms/glyph}/glyph.android.js +0 -0
  451. /package/lib/module/{glyph → atoms/glyph}/glyph.ios.js +0 -0
  452. /package/lib/module/{glyph → atoms/glyph}/glyph.types.js +0 -0
  453. /package/lib/module/{glyph → atoms/glyph}/index.js +0 -0
  454. /package/lib/module/{glyph → atoms/glyph}/rn-glyph.android.js +0 -0
  455. /package/lib/module/{glyph → atoms/glyph}/rn-glyph.ios.js +0 -0
  456. /package/lib/module/{host-context.js → hooks/host-context.js} +0 -0
  457. /package/lib/module/{use-refresh-state.js → hooks/use-refresh-state.js} +0 -0
  458. /package/lib/module/{use-stack-modifiers.js → hooks/use-stack-modifiers.js} +0 -0
  459. /package/lib/module/{ripple-clip.js → utils/ripple-clip.js} +0 -0
  460. /package/lib/module/{tap-modifiers.js → utils/tap-modifiers.js} +0 -0
  461. /package/lib/typescript/{glyph → atoms/glyph}/glyph-button.d.ts +0 -0
  462. /package/lib/typescript/{glyph → atoms/glyph}/glyph-button.ios.d.ts +0 -0
  463. /package/lib/typescript/{glyph → atoms/glyph}/glyph-button.types.d.ts +0 -0
  464. /package/lib/typescript/{glyph → atoms/glyph}/glyph.d.ts +0 -0
  465. /package/lib/typescript/{glyph → atoms/glyph}/glyph.ios.d.ts +0 -0
  466. /package/lib/typescript/{glyph → atoms/glyph}/glyph.types.d.ts +0 -0
  467. /package/lib/typescript/{glyph → atoms/glyph}/index.d.ts +0 -0
  468. /package/lib/typescript/{glyph → atoms/glyph}/rn-glyph.d.ts +0 -0
  469. /package/lib/typescript/{glyph → atoms/glyph}/rn-glyph.ios.d.ts +0 -0
  470. /package/lib/typescript/{host-context.d.ts → hooks/host-context.d.ts} +0 -0
  471. /package/lib/typescript/{use-refresh-state.d.ts → hooks/use-refresh-state.d.ts} +0 -0
  472. /package/lib/typescript/{use-stack-modifiers.d.ts → hooks/use-stack-modifiers.d.ts} +0 -0
  473. /package/lib/typescript/{ripple-clip.d.ts → utils/ripple-clip.d.ts} +0 -0
  474. /package/lib/typescript/{tap-modifiers.d.ts → utils/tap-modifiers.d.ts} +0 -0
  475. /package/src/{glyph → atoms/glyph}/glyph-button.android.tsx +0 -0
  476. /package/src/{glyph → atoms/glyph}/glyph-button.ios.tsx +0 -0
  477. /package/src/{glyph → atoms/glyph}/glyph-button.types.ts +0 -0
  478. /package/src/{glyph → atoms/glyph}/glyph.android.tsx +0 -0
  479. /package/src/{glyph → atoms/glyph}/glyph.ios.tsx +0 -0
  480. /package/src/{glyph → atoms/glyph}/glyph.types.ts +0 -0
  481. /package/src/{glyph → atoms/glyph}/index.ts +0 -0
  482. /package/src/{glyph → atoms/glyph}/rn-glyph.android.tsx +0 -0
  483. /package/src/{glyph → atoms/glyph}/rn-glyph.ios.tsx +0 -0
  484. /package/src/{host-context.tsx → hooks/host-context.tsx} +0 -0
  485. /package/src/{use-refresh-state.ts → hooks/use-refresh-state.ts} +0 -0
  486. /package/src/{use-stack-modifiers.ts → hooks/use-stack-modifiers.ts} +0 -0
  487. /package/src/{ripple-clip.ts → utils/ripple-clip.ts} +0 -0
  488. /package/src/{tap-modifiers.ts → utils/tap-modifiers.ts} +0 -0
@@ -6,9 +6,9 @@ import {
6
6
  } from '@hzblj/kara-native/jetpack-compose'
7
7
  import {useAppTheme} from '@hzblj/kara-theme'
8
8
  import {useCallback, useState} from 'react'
9
+ import {Glyph} from '../../atoms/glyph'
9
10
  import {Icon} from '../../atoms/icon'
10
- import {Glyph} from '../../glyph'
11
- import {useHostGuard} from '../../host-context'
11
+ import {useHostGuard} from '../../hooks/host-context'
12
12
  import type {MenuAction} from '../menu'
13
13
  import type {FabMenuComponent, FabMenuProps} from './fab-menu.types'
14
14
 
@@ -1,11 +1,10 @@
1
1
  import {Button, Image, Label, Menu} from '@expo/ui/swift-ui'
2
2
  import {disabled} from '@expo/ui/swift-ui/modifiers'
3
3
  import {iconResourceName} from '@hzblj/expo-native-icons'
4
-
4
+ import {Glyph} from '../../atoms/glyph'
5
5
  import {Icon} from '../../atoms/icon'
6
6
  import {VStack} from '../../atoms/v-stack'
7
- import {Glyph} from '../../glyph'
8
- import {useHostGuard} from '../../host-context'
7
+ import {useHostGuard} from '../../hooks/host-context'
9
8
  import type {FabMenuComponent, FabMenuProps} from './fab-menu.types'
10
9
 
11
10
  /** Matches `Fab`, so a screen can switch between the two without the button changing shape. */
@@ -1,7 +1,7 @@
1
1
  import {Card} from '../../atoms/card'
2
2
  import {Text} from '../../atoms/text'
3
3
  import {VStack} from '../../atoms/v-stack'
4
- import {useHostGuard} from '../../host-context'
4
+ import {useHostGuard} from '../../hooks/host-context'
5
5
  import type {FormComponent, FormProps, FormSectionProps} from './form.types'
6
6
 
7
7
  /**
@@ -1,6 +1,6 @@
1
1
  import {Section, Form as SwiftUIForm} from '@expo/ui/swift-ui'
2
2
  import {Text} from '../../atoms/text'
3
- import {useHostGuard} from '../../host-context'
3
+ import {useHostGuard} from '../../hooks/host-context'
4
4
  import type {FormComponent, FormProps, FormSectionProps} from './form.types'
5
5
 
6
6
  const FormRoot = ({children, testID}: FormProps) => {
@@ -0,0 +1,7 @@
1
+ import type {ColorToken, Theme} from '@hzblj/kara-theme'
2
+
3
+ /**
4
+ * The native stack types header colours as `string`, but they only end up in native styles, which take any
5
+ * `ColorValue`, including the opaque `PlatformColor` a system token resolves to on iOS.
6
+ */
7
+ export const headerColor = (theme: Theme, token: ColorToken): string => theme.color(token) as string
@@ -0,0 +1,3 @@
1
+ import type {HeaderInsetComponent, HeaderInsetProps} from './header.types'
2
+
3
+ export const HeaderInset: HeaderInsetComponent = ({children}: HeaderInsetProps) => children
@@ -0,0 +1,12 @@
1
+ import {SafeAreaView} from 'react-native-screens/experimental'
2
+
3
+ import type {HeaderInsetComponent, HeaderInsetProps} from './header.types'
4
+
5
+ const TOP_EDGE = {top: true}
6
+ const INSET_STYLE = {flex: 0}
7
+
8
+ export const HeaderInset: HeaderInsetComponent = ({children}: HeaderInsetProps) => (
9
+ <SafeAreaView edges={TOP_EDGE} pointerEvents="box-none" style={INSET_STYLE}>
10
+ {children}
11
+ </SafeAreaView>
12
+ )
@@ -0,0 +1,3 @@
1
+ import type {HeaderLargeTitleFadeComponent, HeaderLargeTitleFadeProps} from './header.types'
2
+
3
+ export const HeaderLargeTitleFade: HeaderLargeTitleFadeComponent = ({children}: HeaderLargeTitleFadeProps) => children
@@ -0,0 +1,12 @@
1
+ import {LargeTitleFade} from '@hzblj/kara-native/swift-ui'
2
+
3
+ import type {HeaderLargeTitleFadeComponent, HeaderLargeTitleFadeProps} from './header.types'
4
+
5
+ /**
6
+ * Fades its content out and back with the large title when the header search opens and closes, in step with UIKit's
7
+ * own animation. Keep the content mounted while searching: a `HeaderInset` moves with the bar's animation, and content
8
+ * mounted into it mid-animation draws off its place until the animation ends.
9
+ */
10
+ export const HeaderLargeTitleFade: HeaderLargeTitleFadeComponent = ({children}: HeaderLargeTitleFadeProps) => (
11
+ <LargeTitleFade>{children}</LargeTitleFade>
12
+ )
@@ -0,0 +1,168 @@
1
+ import {Host} from '@expo/ui/jetpack-compose'
2
+ import {useAppTheme} from '@hzblj/kara-theme'
3
+ import type {ReactNode} from 'react'
4
+ import {StyleSheet, View} from 'react-native'
5
+
6
+ import {ActivityIndicator} from '../../atoms/activity-indicator'
7
+ import {Button} from '../../atoms/button'
8
+ import {GlyphButton} from '../../atoms/glyph'
9
+ import {IconButton} from '../../atoms/icon-button'
10
+ import {HostBoundary} from '../../hooks/host-context'
11
+ import {Menu, type MenuAction} from '../menu'
12
+ import type {
13
+ HeaderAction,
14
+ HeaderItemProps,
15
+ HeaderMenuItem,
16
+ HeaderNavigationAction,
17
+ HeaderOptions,
18
+ HeaderParams,
19
+ } from './header.types'
20
+ import type {HeaderOptionsBuilder} from './header-options.types'
21
+
22
+ const DEFAULT_LABELS = {back: 'Back', close: 'Close'} as const
23
+
24
+ const styles = StyleSheet.create({
25
+ // Material's navigation icon sits 4dp from the edge in a 48dp target; the toolbar insets custom content by 16dp.
26
+ navigationRow: {alignItems: 'center', flexDirection: 'row', marginStart: -12},
27
+ row: {alignItems: 'center', flexDirection: 'row'},
28
+ spinner: {alignItems: 'center', height: 48, justifyContent: 'center', width: 48},
29
+ })
30
+
31
+ /** A host sized to its button both ways: the toolbar gives custom content no width to fill. */
32
+ const ActionHost = ({children}: {children: ReactNode}) => {
33
+ const theme = useAppTheme()
34
+
35
+ return (
36
+ <Host colorScheme={theme.dark ? 'dark' : 'light'} matchContents seedColor={theme.materialSeed}>
37
+ <HostBoundary>{children}</HostBoundary>
38
+ </Host>
39
+ )
40
+ }
41
+
42
+ const toMenuActions = (items: HeaderMenuItem[]): MenuAction[] => {
43
+ const actions: MenuAction[] = []
44
+
45
+ for (const item of items) {
46
+ if (item.type === 'submenu') {
47
+ for (const nested of toMenuActions(item.items)) {
48
+ actions.push(nested)
49
+ }
50
+ continue
51
+ }
52
+
53
+ actions.push({
54
+ destructive: item.destructive,
55
+ disabled: item.disabled,
56
+ icon: item.icon,
57
+ label: item.label,
58
+ onPress: item.onPress,
59
+ })
60
+ }
61
+
62
+ return actions
63
+ }
64
+
65
+ const HeaderActionView = ({action}: {action: HeaderAction}) => {
66
+ switch (action.type) {
67
+ case 'back':
68
+ case 'close': {
69
+ const label = action.label ?? DEFAULT_LABELS[action.type]
70
+
71
+ return (
72
+ <ActionHost>
73
+ {action.icon ? (
74
+ <IconButton accessibilityLabel={label} name={action.icon} onPress={action.onPress} testID={action.testID} />
75
+ ) : (
76
+ <GlyphButton accessibilityLabel={label} name={action.type} onPress={action.onPress} />
77
+ )}
78
+ </ActionHost>
79
+ )
80
+ }
81
+ case 'icon':
82
+ if (action.loading) {
83
+ return (
84
+ <View style={styles.spinner} testID={action.testID}>
85
+ <ActivityIndicator accessibilityLabel={action.label} color={action.color ?? 'content.primary'} />
86
+ </View>
87
+ )
88
+ }
89
+
90
+ return (
91
+ <ActionHost>
92
+ <IconButton
93
+ accessibilityLabel={action.label}
94
+ color={action.color}
95
+ disabled={action.disabled}
96
+ name={action.icon}
97
+ onPress={action.onPress}
98
+ testID={action.testID}
99
+ />
100
+ </ActionHost>
101
+ )
102
+ case 'text':
103
+ return (
104
+ <ActionHost>
105
+ <Button
106
+ disabled={action.disabled}
107
+ label={action.label}
108
+ onPress={action.onPress}
109
+ testID={action.testID}
110
+ variant="plain"
111
+ wide={false}
112
+ />
113
+ </ActionHost>
114
+ )
115
+ case 'menu':
116
+ return (
117
+ <ActionHost>
118
+ <Menu
119
+ accessibilityLabel={action.label}
120
+ actions={toMenuActions(action.items)}
121
+ icon={action.icon}
122
+ testID={action.testID}
123
+ />
124
+ </ActionHost>
125
+ )
126
+ case 'custom':
127
+ return action.element
128
+ }
129
+ }
130
+
131
+ const renderActions =
132
+ (actions: HeaderAction[], isLeading: boolean, backHidden: boolean) =>
133
+ ({canGoBack}: HeaderItemProps) => (
134
+ <View style={isLeading && (backHidden || !canGoBack) ? styles.navigationRow : styles.row}>
135
+ {actions.map((action, index) => (
136
+ <HeaderActionView action={action} key={action.type === 'custom' ? action.key : index} />
137
+ ))}
138
+ </View>
139
+ )
140
+
141
+ const isClose = (action: HeaderAction): action is HeaderNavigationAction => action.type === 'close'
142
+
143
+ /** Material's full-screen dialog: with no back to show, the close is the navigation icon at the start. */
144
+ const placeClose = ({backHidden = false, leadingActions, trailingActions}: HeaderParams) => {
145
+ const close = backHidden && !leadingActions?.length ? trailingActions?.find(isClose) : undefined
146
+
147
+ if (!close) {
148
+ return {leading: leadingActions, trailing: trailingActions}
149
+ }
150
+
151
+ return {leading: [close], trailing: trailingActions?.filter(action => action !== close)}
152
+ }
153
+
154
+ export const toHeaderOptions: HeaderOptionsBuilder = (params: HeaderParams) => {
155
+ const backHidden = params.backHidden ?? false
156
+ const {leading, trailing} = placeClose(params)
157
+ const options: HeaderOptions = {headerBackVisible: !backHidden}
158
+
159
+ if (leading) {
160
+ options.headerLeft = leading.length > 0 ? renderActions(leading, true, backHidden) : undefined
161
+ }
162
+
163
+ if (trailing) {
164
+ options.headerRight = trailing.length > 0 ? renderActions(trailing, false, backHidden) : undefined
165
+ }
166
+
167
+ return options
168
+ }
@@ -0,0 +1,138 @@
1
+ import {iconResourceName} from '@hzblj/expo-native-icons'
2
+ import {GLYPHS} from '@hzblj/kara-native'
3
+ import type {Theme} from '@hzblj/kara-theme'
4
+
5
+ import {ActivityIndicator} from '../../atoms/activity-indicator'
6
+ import type {IconName} from '../../atoms/icon'
7
+ import type {
8
+ HeaderAction,
9
+ HeaderMenuItem,
10
+ HeaderOptions,
11
+ HeaderParams,
12
+ NativeHeaderItem,
13
+ NativeHeaderMenuElement,
14
+ } from './header.types'
15
+ import type {HeaderOptionsBuilder} from './header-options.types'
16
+
17
+ const DEFAULT_LABELS = {back: 'Back', close: 'Close'} as const
18
+
19
+ /** A zero-width spacing item between two groups is what ends a glass capsule on iOS 26, as the system's headers do. */
20
+ const GROUP_BREAK: NativeHeaderItem = {spacing: 0, type: 'spacing'}
21
+
22
+ const imageIcon = (icon: IconName) => ({source: {uri: iconResourceName(icon)}, type: 'image'}) as const
23
+
24
+ const toMenuElement = (item: HeaderMenuItem): NativeHeaderMenuElement => {
25
+ if (item.type === 'submenu') {
26
+ return {
27
+ icon: item.icon ? imageIcon(item.icon) : undefined,
28
+ inline: item.inline,
29
+ items: item.items.map(toMenuElement),
30
+ label: item.label,
31
+ type: 'submenu',
32
+ }
33
+ }
34
+
35
+ return {
36
+ description: item.description,
37
+ destructive: item.destructive,
38
+ disabled: item.disabled,
39
+ icon: item.icon ? imageIcon(item.icon) : undefined,
40
+ label: item.label,
41
+ onPress: item.onPress,
42
+ state: item.checked ? 'on' : undefined,
43
+ type: 'action',
44
+ }
45
+ }
46
+
47
+ const toItem = (action: HeaderAction, theme: Theme): NativeHeaderItem => {
48
+ switch (action.type) {
49
+ case 'back':
50
+ case 'close': {
51
+ const label = action.label ?? DEFAULT_LABELS[action.type]
52
+
53
+ return {
54
+ accessibilityLabel: label,
55
+ icon: action.icon ? imageIcon(action.icon) : {name: GLYPHS[action.type].ios, type: 'sfSymbol'},
56
+ identifier: action.testID,
57
+ label,
58
+ onPress: action.onPress,
59
+ sharesBackground: action.separated ? false : undefined,
60
+ type: 'button',
61
+ }
62
+ }
63
+ case 'icon':
64
+ if (action.loading) {
65
+ return {
66
+ element: <ActivityIndicator accessibilityLabel={action.label} color="content.primary" />,
67
+ type: 'custom',
68
+ }
69
+ }
70
+
71
+ return {
72
+ accessibilityLabel: action.label,
73
+ badge: action.badge === undefined ? undefined : {value: action.badge},
74
+ disabled: action.disabled,
75
+ icon: imageIcon(action.icon),
76
+ identifier: action.testID,
77
+ label: action.label,
78
+ onPress: action.onPress,
79
+ selected: action.selected,
80
+ sharesBackground: action.separated ? false : undefined,
81
+ tintColor: action.color ? theme.color(action.color) : undefined,
82
+ type: 'button',
83
+ }
84
+ case 'text':
85
+ return {
86
+ disabled: action.disabled,
87
+ identifier: action.testID,
88
+ label: action.label,
89
+ onPress: action.onPress,
90
+ sharesBackground: action.separated ? false : undefined,
91
+ type: 'button',
92
+ variant: action.prominent ? 'prominent' : undefined,
93
+ }
94
+ case 'menu':
95
+ return {
96
+ accessibilityLabel: action.label,
97
+ icon: imageIcon(action.icon),
98
+ identifier: action.testID,
99
+ label: action.label,
100
+ menu: {items: action.items.map(toMenuElement), title: action.title},
101
+ sharesBackground: action.separated ? false : undefined,
102
+ type: 'menu',
103
+ }
104
+ case 'custom':
105
+ return {element: action.element, hidesSharedBackground: action.separated, type: 'custom'}
106
+ }
107
+ }
108
+
109
+ const toItems = (actions: HeaderAction[], theme: Theme) => () => {
110
+ const items: NativeHeaderItem[] = []
111
+
112
+ for (const action of actions) {
113
+ items.push(toItem(action, theme))
114
+
115
+ if (action.separated) {
116
+ items.push(GROUP_BREAK)
117
+ }
118
+ }
119
+
120
+ return items
121
+ }
122
+
123
+ export const toHeaderOptions: HeaderOptionsBuilder = (
124
+ {backHidden = false, leadingActions, trailingActions}: HeaderParams,
125
+ theme: Theme
126
+ ) => {
127
+ const options: HeaderOptions = {headerBackVisible: !backHidden}
128
+
129
+ if (leadingActions) {
130
+ options.unstable_headerLeftItems = leadingActions.length > 0 ? toItems(leadingActions, theme) : undefined
131
+ }
132
+
133
+ if (trailingActions) {
134
+ options.unstable_headerRightItems = trailingActions.length > 0 ? toItems(trailingActions, theme) : undefined
135
+ }
136
+
137
+ return options
138
+ }
@@ -0,0 +1,6 @@
1
+ import type {Theme} from '@hzblj/kara-theme'
2
+
3
+ import type {HeaderOptions, HeaderParams} from './header.types'
4
+
5
+ /** Turns a header's actions into the native-stack options each platform draws them from. */
6
+ export type HeaderOptionsBuilder = (params: HeaderParams, theme: Theme) => HeaderOptions
@@ -0,0 +1,4 @@
1
+ import type {HeaderSearchAccessoryComponent} from './header-search-accessory.types'
2
+
3
+ /** Android's field is a Compose view of kara's own, which takes its glyphs and voice directly (`searchInput`). */
4
+ export const HeaderSearchAccessory: HeaderSearchAccessoryComponent = () => null
@@ -0,0 +1,42 @@
1
+ import {iconResourceName} from '@hzblj/expo-native-icons'
2
+ import {NavigationItemSearch} from '@hzblj/kara-native/swift-ui'
3
+ import {useAppTheme} from '@hzblj/kara-theme'
4
+ import {useMemo} from 'react'
5
+
6
+ import type {IconName} from '../../atoms/icon'
7
+ import {headerColor} from './header-color'
8
+ import type {HeaderSearchAccessoryComponent, HeaderSearchAccessoryProps} from './header-search-accessory.types'
9
+
10
+ const toImageName = (icon?: IconName) => (icon ? iconResourceName(icon) : undefined)
11
+
12
+ /**
13
+ * The header search field's glyphs and voice on iOS: react-native-screens' search bar belongs to the navigation item,
14
+ * so a layout-less native view in the screen's tree dresses it.
15
+ */
16
+ export const HeaderSearchAccessory: HeaderSearchAccessoryComponent = ({
17
+ cancelIcon,
18
+ clearIcon,
19
+ voice,
20
+ }: HeaderSearchAccessoryProps) => {
21
+ const theme = useAppTheme()
22
+ const color = headerColor(theme, 'content.primary')
23
+ const nativeVoice = useMemo(
24
+ () =>
25
+ voice && {
26
+ ...voice,
27
+ clearImageName: toImageName(voice.clearIcon ?? clearIcon),
28
+ color: voice.color ?? color,
29
+ microphoneImageName: toImageName(voice.microphoneIcon),
30
+ stopImageName: toImageName(voice.stopIcon),
31
+ },
32
+ [clearIcon, color, voice]
33
+ )
34
+
35
+ return (
36
+ <NavigationItemSearch
37
+ cancelImageName={toImageName(cancelIcon)}
38
+ clearImageName={toImageName(clearIcon)}
39
+ voice={nativeVoice}
40
+ />
41
+ )
42
+ }
@@ -0,0 +1,12 @@
1
+ import type {ReactNode} from 'react'
2
+
3
+ import type {IconName} from '../../atoms/icon'
4
+ import type {SearchFieldVoice} from '../../molecules/navigation-bar/navigation-bar.types'
5
+
6
+ export type HeaderSearchAccessoryProps = {
7
+ cancelIcon?: IconName
8
+ clearIcon?: IconName
9
+ voice?: SearchFieldVoice
10
+ }
11
+
12
+ export type HeaderSearchAccessoryComponent = (props: HeaderSearchAccessoryProps) => ReactNode
@@ -0,0 +1,89 @@
1
+ import {Host} from '@expo/ui/jetpack-compose'
2
+ import {iconResourceName} from '@hzblj/expo-native-icons'
3
+ import {SearchField, type SearchFieldRef} from '@hzblj/kara-native/jetpack-compose'
4
+ import {useAppTheme} from '@hzblj/kara-theme'
5
+ import {useImperativeHandle, useMemo, useRef} from 'react'
6
+ import {StyleSheet, View} from 'react-native'
7
+
8
+ import type {HeaderSearchInputComponent, HeaderSearchInputProps} from './header-search-input.types'
9
+
10
+ /** Material's search field is 56dp; the row adds 8dp above it and 12dp below, under the top app bar. */
11
+ const FIELD_HEIGHT = 56
12
+
13
+ /** The row's height under the bar, for what is laid out below it (the scrim starts there). */
14
+ export const HEADER_SEARCH_ROW_HEIGHT = 8 + FIELD_HEIGHT + 12
15
+
16
+ const styles = StyleSheet.create({
17
+ field: {height: FIELD_HEIGHT},
18
+ row: {paddingBottom: 12, paddingHorizontal: 16, paddingTop: 8},
19
+ })
20
+
21
+ const ignoreDetachedView = () => undefined
22
+
23
+ export const HeaderSearchInput: HeaderSearchInputComponent = ({
24
+ clearIcon,
25
+ onChangeText,
26
+ onFocusChange,
27
+ placeholder,
28
+ ref,
29
+ voice,
30
+ }: HeaderSearchInputProps) => {
31
+ const theme = useAppTheme()
32
+ const fieldRef = useRef<SearchFieldRef>(null)
33
+ const face = theme.typography.body
34
+
35
+ useImperativeHandle(
36
+ ref,
37
+ () => ({
38
+ blur: () => {
39
+ fieldRef.current?.blurField().catch(ignoreDetachedView)
40
+ },
41
+ clear: () => {
42
+ fieldRef.current?.clearQuery().catch(ignoreDetachedView)
43
+ },
44
+ setText: (text: string) => {
45
+ fieldRef.current?.setQuery(text).catch(ignoreDetachedView)
46
+ },
47
+ }),
48
+ []
49
+ )
50
+
51
+ const nativeVoice = useMemo(
52
+ () =>
53
+ voice && {
54
+ ...voice,
55
+ microphoneIconName: voice.microphoneIcon ? iconResourceName(voice.microphoneIcon) : undefined,
56
+ stopIconName: voice.stopIcon ? iconResourceName(voice.stopIcon) : undefined,
57
+ },
58
+ [voice]
59
+ )
60
+ const fieldClearIcon = voice?.clearIcon ?? clearIcon
61
+
62
+ return (
63
+ <View style={styles.row}>
64
+ <Host
65
+ colorScheme={theme.dark ? 'dark' : 'light'}
66
+ ignoreSafeAreaKeyboardInsets
67
+ seedColor={theme.materialSeed}
68
+ style={styles.field}
69
+ >
70
+ <SearchField
71
+ cancelLabel="Cancel"
72
+ clearIconName={fieldClearIcon ? iconResourceName(fieldClearIcon) : undefined}
73
+ clearLabel={voice?.clearLabel ?? 'Clear'}
74
+ containerColor={theme.color('fill.quaternary')}
75
+ fontFamily={face.fontFamily}
76
+ fontSize={face.fontSize}
77
+ iconColor={theme.color('content.secondary')}
78
+ onFocusChange={onFocusChange}
79
+ onQueryChange={onChangeText}
80
+ placeholder={placeholder}
81
+ placeholderColor={theme.color('content.tertiary')}
82
+ ref={fieldRef}
83
+ textColor={theme.color('content.primary')}
84
+ voice={nativeVoice}
85
+ />
86
+ </Host>
87
+ </View>
88
+ )
89
+ }
@@ -0,0 +1,7 @@
1
+ import type {HeaderSearchInputComponent} from './header-search-input.types'
2
+
3
+ /** iOS searches in the navigation bar itself (`headerSearchBarOptions`). */
4
+ export const HeaderSearchInput: HeaderSearchInputComponent = () => null
5
+
6
+ /** The row's height under the bar. iOS has none. */
7
+ export const HEADER_SEARCH_ROW_HEIGHT = 0
@@ -0,0 +1,21 @@
1
+ import type {ReactNode, Ref} from 'react'
2
+
3
+ import type {IconName} from '../../atoms/icon'
4
+ import type {SearchFieldVoice} from '../../molecules/navigation-bar/navigation-bar.types'
5
+
6
+ export type HeaderSearchInputRef = {
7
+ blur: () => void
8
+ clear: () => void
9
+ setText: (text: string) => void
10
+ }
11
+
12
+ export type HeaderSearchInputProps = {
13
+ clearIcon?: IconName
14
+ onChangeText: (text: string) => void
15
+ onFocusChange: (focused: boolean) => void
16
+ placeholder: string
17
+ ref?: Ref<HeaderSearchInputRef>
18
+ voice?: SearchFieldVoice
19
+ }
20
+
21
+ export type HeaderSearchInputComponent = (props: HeaderSearchInputProps) => ReactNode
@@ -0,0 +1,49 @@
1
+ import {useAppTheme} from '@hzblj/kara-theme'
2
+ import {Platform, Pressable, StyleSheet, View} from 'react-native'
3
+ import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
4
+ import {SafeAreaView} from 'react-native-screens/experimental'
5
+
6
+ const SCRIM_OPACITY = 0.7
7
+ const ENTERING = FadeIn.duration(200)
8
+ const EXITING = FadeOut.duration(200)
9
+ const TOP_EDGE = {top: true}
10
+
11
+ const styles = StyleSheet.create({
12
+ fill: {flex: 1},
13
+ layer: {bottom: 0, left: 0, position: 'absolute', right: 0, zIndex: 10},
14
+ })
15
+
16
+ type HeaderSearchScrimProps = {
17
+ onPress: () => void
18
+ topOffset: number
19
+ }
20
+
21
+ /**
22
+ * Washes the content out while the search field is focused and empty, as the system's own search does without
23
+ * dimming the bar; a tap on it ends the search. iOS starts it under the bar, following the bar natively
24
+ * (react-native-screens' `SafeAreaView`), Android under the search row.
25
+ */
26
+ export const HeaderSearchScrim = ({onPress, topOffset}: HeaderSearchScrimProps) => {
27
+ const theme = useAppTheme()
28
+ const scrim = (
29
+ <Animated.View
30
+ entering={ENTERING}
31
+ exiting={EXITING}
32
+ style={[styles.fill, {backgroundColor: theme.color('surface.base'), opacity: SCRIM_OPACITY}]}
33
+ >
34
+ <Pressable accessible={false} onPress={onPress} style={styles.fill} />
35
+ </Animated.View>
36
+ )
37
+
38
+ return (
39
+ <View pointerEvents="box-none" style={[styles.layer, {top: topOffset}]}>
40
+ {Platform.OS === 'ios' ? (
41
+ <SafeAreaView edges={TOP_EDGE} pointerEvents="box-none" style={styles.fill}>
42
+ {scrim}
43
+ </SafeAreaView>
44
+ ) : (
45
+ scrim
46
+ )}
47
+ </View>
48
+ )
49
+ }