pixelize-native-library 1.2.0 → 1.2.1

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 (353) hide show
  1. package/lib/module/core/MODULE.md +2 -1
  2. package/lib/module/core/gradient/AccentGradientFill.js +80 -0
  3. package/lib/module/core/gradient/darkenHex.js +13 -0
  4. package/lib/module/core/gradient/gradientStops.js +27 -0
  5. package/lib/module/core/gradient/index.js +7 -0
  6. package/lib/module/core/gradient/withAlpha.js +19 -0
  7. package/lib/module/core/haptics/MODULE.md +4 -0
  8. package/lib/module/core/haptics/context.js +7 -0
  9. package/lib/module/core/haptics/haptics.js +17 -0
  10. package/lib/module/core/haptics/index.js +6 -0
  11. package/lib/module/core/haptics/useHaptics.js +73 -0
  12. package/lib/module/core/icon/MODULE.md +16 -9
  13. package/lib/module/core/icon/icons/trending-up.js +10 -0
  14. package/lib/module/core/icon/resolve.js +2 -0
  15. package/lib/module/core/media/expoImage.js +6 -0
  16. package/lib/module/core/motion/MODULE.md +12 -12
  17. package/lib/module/core/motion/config.js +4 -1
  18. package/lib/module/core/motion/index.js +2 -1
  19. package/lib/module/core/motion/usePressState.js +145 -0
  20. package/lib/module/core/style/index.js +1 -0
  21. package/lib/module/core/style/radius.js +4 -0
  22. package/lib/module/index.js +1 -0
  23. package/lib/module/modules/accordion/Accordion.js +69 -49
  24. package/lib/module/modules/accordion/Accordion.variants.js +4 -3
  25. package/lib/module/modules/accordion/MODULE.md +2 -1
  26. package/lib/module/modules/alert-dialog/AlertDialog.js +6 -5
  27. package/lib/module/modules/alert-dialog/AlertDialog.variants.js +4 -0
  28. package/lib/module/modules/app-bar/AppBar.js +6 -4
  29. package/lib/module/modules/app-bar/AppBar.variants.js +1 -2
  30. package/lib/module/modules/avatar/Avatar.js +7 -1
  31. package/lib/module/modules/avatar/Avatar.variants.js +1 -1
  32. package/lib/module/modules/avatar/MODULE.md +2 -2
  33. package/lib/module/modules/avatar-group/AvatarGroup.js +10 -6
  34. package/lib/module/modules/avatar-group/AvatarGroup.variants.js +23 -0
  35. package/lib/module/modules/avatar-group/MODULE.md +16 -0
  36. package/lib/module/modules/badge/Badge.js +11 -5
  37. package/lib/module/modules/badge/Badge.variants.js +2 -1
  38. package/lib/module/modules/badge/MODULE.md +5 -5
  39. package/lib/module/modules/banner/Banner.js +106 -60
  40. package/lib/module/modules/banner/Banner.variants.js +2 -2
  41. package/lib/module/modules/banner/MODULE.md +7 -2
  42. package/lib/module/modules/bottom-nav/BottomNav.js +6 -3
  43. package/lib/module/modules/bottom-nav/BottomNav.variants.js +9 -10
  44. package/lib/module/modules/bottom-nav/BottomNavOverflowSheet.js +28 -4
  45. package/lib/module/modules/bottom-nav/BottomNavTab.js +28 -4
  46. package/lib/module/modules/bottom-nav/MODULE.md +10 -1
  47. package/lib/module/modules/bottom-sheet/BottomSheet.js +20 -7
  48. package/lib/module/modules/bottom-sheet/BottomSheet.variants.js +15 -5
  49. package/lib/module/modules/bottom-sheet/MODULE.md +13 -2
  50. package/lib/module/modules/button/Button.js +87 -101
  51. package/lib/module/modules/button/Button.variants.js +8 -7
  52. package/lib/module/modules/button/MODULE.md +6 -0
  53. package/lib/module/modules/button-group/ButtonGroup.js +36 -37
  54. package/lib/module/modules/button-group/ButtonGroup.variants.js +21 -46
  55. package/lib/module/modules/button-group/MODULE.md +25 -30
  56. package/lib/module/modules/card/Card.js +117 -19
  57. package/lib/module/modules/card/Card.variants.js +1 -0
  58. package/lib/module/modules/card/MODULE.md +13 -10
  59. package/lib/module/modules/charts/BarChart.js +29 -14
  60. package/lib/module/modules/charts/BarList.js +31 -18
  61. package/lib/module/modules/charts/Charts.variants.js +66 -2
  62. package/lib/module/modules/charts/DonutChart.js +9 -4
  63. package/lib/module/modules/charts/LineChart.js +5 -3
  64. package/lib/module/modules/charts/MODULE.md +24 -11
  65. package/lib/module/modules/charts/PieChart.js +13 -4
  66. package/lib/module/modules/charts/Sparkline.js +4 -2
  67. package/lib/module/modules/checkbox/Checkbox.js +10 -2
  68. package/lib/module/modules/checkbox/MODULE.md +5 -0
  69. package/lib/module/modules/chip/Chip.js +83 -38
  70. package/lib/module/modules/chip/Chip.variants.js +15 -3
  71. package/lib/module/modules/chip/MODULE.md +6 -4
  72. package/lib/module/modules/combobox/Combobox.js +93 -57
  73. package/lib/module/modules/combobox/Combobox.variants.js +22 -7
  74. package/lib/module/modules/combobox/MODULE.md +14 -4
  75. package/lib/module/modules/composer/Composer.js +9 -2
  76. package/lib/module/modules/composer/Composer.variants.js +2 -0
  77. package/lib/module/modules/composer/MODULE.md +5 -0
  78. package/lib/module/modules/copy-button/CopyButton.js +22 -4
  79. package/lib/module/modules/copy-button/CopyButton.variants.js +4 -2
  80. package/lib/module/modules/copy-button/MODULE.md +5 -0
  81. package/lib/module/modules/data-table/DataTable.js +28 -9
  82. package/lib/module/modules/data-table/DataTable.variants.js +3 -2
  83. package/lib/module/modules/data-table/MODULE.md +1 -0
  84. package/lib/module/modules/date-picker/Calendar.js +75 -29
  85. package/lib/module/modules/date-picker/DatePicker.variants.js +24 -9
  86. package/lib/module/modules/date-picker/MODULE.md +25 -4
  87. package/lib/module/modules/date-picker/PickerField.js +13 -4
  88. package/lib/module/modules/date-picker/PickerShell.js +2 -0
  89. package/lib/module/modules/date-picker/TimePicker.js +13 -18
  90. package/lib/module/modules/divider/Divider.variants.js +6 -5
  91. package/lib/module/modules/divider/MODULE.md +2 -0
  92. package/lib/module/modules/drawer/Drawer.js +20 -8
  93. package/lib/module/modules/drawer/Drawer.variants.js +4 -4
  94. package/lib/module/modules/drawer/MODULE.md +3 -0
  95. package/lib/module/modules/empty-state/EmptyState.js +18 -29
  96. package/lib/module/modules/empty-state/EmptyState.variants.js +7 -0
  97. package/lib/module/modules/empty-state/MODULE.md +1 -0
  98. package/lib/module/modules/fab/Fab.js +41 -61
  99. package/lib/module/modules/fab/Fab.variants.js +15 -1
  100. package/lib/module/modules/fab/FabGroup.js +84 -57
  101. package/lib/module/modules/fab/MODULE.md +19 -6
  102. package/lib/module/modules/file-grid/FileGrid.js +30 -16
  103. package/lib/module/modules/file-grid/FileGrid.variants.js +2 -2
  104. package/lib/module/modules/file-grid/MODULE.md +3 -1
  105. package/lib/module/modules/file-upload/FileUpload.variants.js +3 -1
  106. package/lib/module/modules/file-upload/MODULE.md +2 -0
  107. package/lib/module/modules/filter-sheet/FilterChip.js +11 -3
  108. package/lib/module/modules/filter-sheet/FilterSheetBody.js +15 -3
  109. package/lib/module/modules/filter-sheet/MODULE.md +9 -0
  110. package/lib/module/modules/folder-row/FolderRow.js +29 -17
  111. package/lib/module/modules/folder-row/FolderRow.variants.js +4 -2
  112. package/lib/module/modules/folder-row/MODULE.md +2 -1
  113. package/lib/module/modules/gantt/Gantt.js +30 -9
  114. package/lib/module/modules/gantt/Gantt.variants.js +36 -0
  115. package/lib/module/modules/gantt/MODULE.md +11 -1
  116. package/lib/module/modules/image-viewer/ImageViewer.js +35 -5
  117. package/lib/module/modules/image-viewer/MODULE.md +6 -0
  118. package/lib/module/modules/input/Input.js +20 -7
  119. package/lib/module/modules/input/Input.variants.js +8 -7
  120. package/lib/module/modules/input/MODULE.md +2 -0
  121. package/lib/module/modules/list-item/ListItem.js +48 -26
  122. package/lib/module/modules/list-item/ListItem.variants.js +11 -2
  123. package/lib/module/modules/list-item/MODULE.md +2 -3
  124. package/lib/module/modules/markdown/MODULE.md +8 -1
  125. package/lib/module/modules/markdown/Markdown.js +57 -22
  126. package/lib/module/modules/markdown/Markdown.variants.js +2 -1
  127. package/lib/module/modules/menu/MODULE.md +11 -0
  128. package/lib/module/modules/menu/Menu.js +99 -40
  129. package/lib/module/modules/menu/Menu.variants.js +3 -3
  130. package/lib/module/modules/message-bubble/MODULE.md +4 -1
  131. package/lib/module/modules/message-bubble/MessageBubble.js +4 -5
  132. package/lib/module/modules/message-bubble/MessageBubble.variants.js +5 -5
  133. package/lib/module/modules/modal/MODULE.md +11 -0
  134. package/lib/module/modules/modal/Modal.js +87 -35
  135. package/lib/module/modules/modal/Modal.variants.js +2 -2
  136. package/lib/module/modules/more-items/MODULE.md +5 -0
  137. package/lib/module/modules/more-items/MoreItems.js +7 -1
  138. package/lib/module/modules/more-items/MoreItems.variants.js +4 -1
  139. package/lib/module/modules/multi-select/MODULE.md +5 -0
  140. package/lib/module/modules/multi-select/MultiSelect.js +23 -1
  141. package/lib/module/modules/multi-select/MultiSelect.variants.js +4 -2
  142. package/lib/module/modules/number-input/MODULE.md +2 -1
  143. package/lib/module/modules/number-input/NumberInput.js +97 -84
  144. package/lib/module/modules/number-input/NumberInput.variants.js +9 -6
  145. package/lib/module/modules/org-switcher/MODULE.md +13 -1
  146. package/lib/module/modules/org-switcher/OrgSwitcher.js +13 -2
  147. package/lib/module/modules/org-switcher/OrgSwitcher.variants.js +4 -2
  148. package/lib/module/modules/pagination/MODULE.md +2 -2
  149. package/lib/module/modules/pagination/Pagination.js +76 -37
  150. package/lib/module/modules/pagination/Pagination.variants.js +4 -2
  151. package/lib/module/modules/pagination/PaginationControls.js +55 -35
  152. package/lib/module/modules/pin-input/MODULE.md +5 -1
  153. package/lib/module/modules/pin-input/PinInput.js +9 -2
  154. package/lib/module/modules/pin-input/PinInput.variants.js +2 -1
  155. package/lib/module/modules/radio-group/MODULE.md +2 -2
  156. package/lib/module/modules/radio-group/RadioGroup.js +122 -63
  157. package/lib/module/modules/radio-group/RadioGroup.variants.js +2 -1
  158. package/lib/module/modules/reorder/MODULE.md +2 -0
  159. package/lib/module/modules/reorder/Reorder.js +4 -3
  160. package/lib/module/modules/reorder/Reorder.variants.js +4 -2
  161. package/lib/module/modules/rich-text/MODULE.md +3 -1
  162. package/lib/module/modules/rich-text/RichText.js +42 -22
  163. package/lib/module/modules/rich-text-editor/MODULE.md +4 -1
  164. package/lib/module/modules/rich-text-editor/RichTextEditor.js +8 -1
  165. package/lib/module/modules/rich-text-editor/RichTextEditor.variants.js +9 -6
  166. package/lib/module/modules/screen/MODULE.md +7 -0
  167. package/lib/module/modules/screen/Screen.js +50 -17
  168. package/lib/module/modules/screen/Screen.variants.js +18 -0
  169. package/lib/module/modules/search-bar/MODULE.md +1 -0
  170. package/lib/module/modules/search-bar/SearchBar.js +46 -26
  171. package/lib/module/modules/search-bar/SearchBar.variants.js +11 -8
  172. package/lib/module/modules/section/MODULE.md +2 -0
  173. package/lib/module/modules/section/Section.js +8 -15
  174. package/lib/module/modules/section/Section.variants.js +1 -6
  175. package/lib/module/modules/segmented-control/MODULE.md +3 -1
  176. package/lib/module/modules/segmented-control/SegmentedControl.js +110 -46
  177. package/lib/module/modules/segmented-control/SegmentedControl.variants.js +3 -2
  178. package/lib/module/modules/select/MODULE.md +26 -5
  179. package/lib/module/modules/select/Select.js +39 -12
  180. package/lib/module/modules/select/Select.variants.js +36 -12
  181. package/lib/module/modules/skeleton/MODULE.md +23 -27
  182. package/lib/module/modules/skeleton/Skeleton.js +46 -51
  183. package/lib/module/modules/skeleton/Skeleton.variants.js +17 -75
  184. package/lib/module/modules/slider/MODULE.md +2 -0
  185. package/lib/module/modules/slider/Slider.js +2 -1
  186. package/lib/module/modules/stage-progress/MODULE.md +12 -8
  187. package/lib/module/modules/stage-progress/StageProgress.js +94 -47
  188. package/lib/module/modules/stage-progress/StageProgress.variants.js +17 -12
  189. package/lib/module/modules/stat-tile/MODULE.md +2 -0
  190. package/lib/module/modules/stat-tile/StatTile.js +15 -10
  191. package/lib/module/modules/stat-tile/StatTile.variants.js +2 -0
  192. package/lib/module/modules/state-block/MODULE.md +3 -0
  193. package/lib/module/modules/state-block/StateBlock.js +11 -6
  194. package/lib/module/modules/state-block/StateBlock.variants.js +7 -0
  195. package/lib/module/modules/surface/MODULE.md +59 -0
  196. package/lib/module/modules/surface/Surface.js +42 -0
  197. package/lib/module/modules/surface/Surface.variants.js +33 -0
  198. package/lib/module/modules/surface/index.js +4 -0
  199. package/lib/module/modules/swipeable-row/MODULE.md +9 -0
  200. package/lib/module/modules/swipeable-row/SwipeableRow.js +28 -7
  201. package/lib/module/modules/switch/MODULE.md +2 -0
  202. package/lib/module/modules/switch/Switch.js +8 -2
  203. package/lib/module/modules/tabs/MODULE.md +2 -1
  204. package/lib/module/modules/tabs/Tabs.js +37 -18
  205. package/lib/module/modules/tabs/Tabs.variants.js +4 -2
  206. package/lib/module/modules/text/MODULE.md +5 -2
  207. package/lib/module/modules/text/Text.js +18 -6
  208. package/lib/module/modules/text/Text.variants.js +108 -44
  209. package/lib/module/modules/textarea/MODULE.md +2 -0
  210. package/lib/module/modules/textarea/Textarea.js +3 -2
  211. package/lib/module/modules/textarea/Textarea.variants.js +2 -1
  212. package/lib/module/modules/toast/MODULE.md +8 -4
  213. package/lib/module/modules/toast/Toast.js +31 -13
  214. package/lib/module/modules/toast/Toast.variants.js +5 -0
  215. package/lib/module/modules/tooltip/MODULE.md +15 -11
  216. package/lib/module/modules/tooltip/Tooltip.js +41 -9
  217. package/lib/module/modules/tooltip/Tooltip.variants.js +8 -1
  218. package/lib/module/theme/MODULE.md +3 -1
  219. package/lib/module/theme/platform/MODULE.md +14 -2
  220. package/lib/module/theme/platform/elevation.native.js +0 -44
  221. package/lib/module/theme/platform/floatingSurface.native.js +75 -0
  222. package/lib/module/theme/platform/highlight.native.js +59 -0
  223. package/lib/module/theme/platform/index.js +5 -0
  224. package/lib/module/theme/platform/motion.native.js +31 -11
  225. package/lib/module/theme/platform/stateLayer.native.js +14 -0
  226. package/lib/module/theme/platform/surfaces.native.js +11 -0
  227. package/lib/module/theme/provider/PixelizeProvider.js +12 -5
  228. package/lib/module/theme/tokens/MODULE.md +32 -28
  229. package/lib/module/theme/tokens/THEME-CONTRACT.md +137 -0
  230. package/lib/module/theme/tokens/assertPalette.js +29 -0
  231. package/lib/module/theme/tokens/brands/emerald/palette.light.js +7 -6
  232. package/lib/module/theme/tokens/brands/lavender/palette.light.js +3 -2
  233. package/lib/module/theme/tokens/brands/meadow/palette.light.js +7 -6
  234. package/lib/module/theme/tokens/brands/radiant/palette.light.js +7 -6
  235. package/lib/module/theme/tokens/brands/rosewood/palette.light.js +7 -6
  236. package/lib/module/theme/tokens/brands/skyline/palette.light.js +7 -6
  237. package/lib/module/theme/tokens/brands/slate/palette.light.js +8 -10
  238. package/lib/module/theme/tokens/brands/storefront/palette.light.js +7 -6
  239. package/lib/module/theme/tokens/brands/zinc/palette.dark.js +3 -2
  240. package/lib/module/theme/tokens/brands/zinc/palette.light.js +3 -2
  241. package/lib/module/theme/tokens/builders/buildDarkPalette.js +3 -2
  242. package/lib/module/theme/tokens/builders/finalizePalette.js +34 -0
  243. package/lib/module/theme/tokens/builders/liftToContrast.js +44 -0
  244. package/lib/module/theme/tokens/builders/placeholderInk.js +22 -0
  245. package/lib/module/theme/tokens/builders/semanticText.js +14 -0
  246. package/lib/module/theme/tokens/builders/surfaceRungs.js +44 -0
  247. package/lib/module/theme/tokens/index.js +5 -0
  248. package/lib/module/theme/tokens/roles/index.js +5 -0
  249. package/lib/typescript/core/gradient/AccentGradientFill.d.ts +7 -0
  250. package/lib/typescript/core/gradient/darkenHex.d.ts +2 -0
  251. package/lib/typescript/core/gradient/gradientStops.d.ts +10 -0
  252. package/lib/typescript/core/gradient/index.d.ts +5 -0
  253. package/lib/typescript/core/gradient/withAlpha.d.ts +2 -0
  254. package/lib/typescript/core/haptics/context.d.ts +3 -0
  255. package/lib/typescript/core/haptics/haptics.d.ts +33 -0
  256. package/lib/typescript/core/haptics/index.d.ts +6 -0
  257. package/lib/typescript/core/haptics/useHaptics.d.ts +12 -0
  258. package/lib/typescript/core/icon/icons/trending-up.d.ts +3 -0
  259. package/lib/typescript/core/icon/names.d.ts +1 -1
  260. package/lib/typescript/core/media/expoImage.d.ts +15 -6
  261. package/lib/typescript/core/media/pickers.d.ts +5 -5
  262. package/lib/typescript/core/motion/config.d.ts +2 -1
  263. package/lib/typescript/core/motion/index.d.ts +3 -1
  264. package/lib/typescript/core/motion/usePressState.d.ts +21 -0
  265. package/lib/typescript/core/style/index.d.ts +1 -0
  266. package/lib/typescript/core/style/radius.d.ts +2 -0
  267. package/lib/typescript/index.d.ts +4 -2
  268. package/lib/typescript/modules/accordion/Accordion.variants.d.ts +2 -2
  269. package/lib/typescript/modules/alert-dialog/AlertDialog.variants.d.ts +1 -0
  270. package/lib/typescript/modules/avatar/Avatar.variants.d.ts +1 -1
  271. package/lib/typescript/modules/avatar-group/AvatarGroup.d.ts +4 -2
  272. package/lib/typescript/modules/avatar-group/AvatarGroup.variants.d.ts +19 -0
  273. package/lib/typescript/modules/banner/Banner.d.ts +2 -0
  274. package/lib/typescript/modules/bottom-nav/BottomNav.variants.d.ts +1 -3
  275. package/lib/typescript/modules/bottom-sheet/BottomSheet.variants.d.ts +3 -1
  276. package/lib/typescript/modules/button/Button.d.ts +0 -25
  277. package/lib/typescript/modules/button/Button.variants.d.ts +6 -6
  278. package/lib/typescript/modules/button-group/ButtonGroup.d.ts +0 -19
  279. package/lib/typescript/modules/button-group/ButtonGroup.variants.d.ts +22 -56
  280. package/lib/typescript/modules/card/Card.d.ts +7 -5
  281. package/lib/typescript/modules/charts/Charts.variants.d.ts +29 -1
  282. package/lib/typescript/modules/chip/Chip.d.ts +3 -1
  283. package/lib/typescript/modules/chip/Chip.variants.d.ts +6 -2
  284. package/lib/typescript/modules/chip/index.d.ts +1 -1
  285. package/lib/typescript/modules/combobox/Combobox.variants.d.ts +17 -4
  286. package/lib/typescript/modules/data-table/DataTable.variants.d.ts +1 -1
  287. package/lib/typescript/modules/date-picker/DatePicker.variants.d.ts +15 -3
  288. package/lib/typescript/modules/date-picker/TimePicker.d.ts +1 -7
  289. package/lib/typescript/modules/divider/Divider.variants.d.ts +4 -4
  290. package/lib/typescript/modules/empty-state/EmptyState.d.ts +2 -0
  291. package/lib/typescript/modules/empty-state/EmptyState.variants.d.ts +1 -0
  292. package/lib/typescript/modules/fab/Fab.variants.d.ts +2 -0
  293. package/lib/typescript/modules/folder-row/FolderRow.d.ts +0 -8
  294. package/lib/typescript/modules/gantt/Gantt.variants.d.ts +21 -0
  295. package/lib/typescript/modules/input/Input.variants.d.ts +6 -6
  296. package/lib/typescript/modules/list-item/ListItem.d.ts +1 -5
  297. package/lib/typescript/modules/list-item/ListItem.variants.d.ts +137 -1
  298. package/lib/typescript/modules/markdown/Markdown.d.ts +7 -0
  299. package/lib/typescript/modules/message-bubble/MessageBubble.d.ts +2 -2
  300. package/lib/typescript/modules/message-bubble/MessageBubble.variants.d.ts +1 -2
  301. package/lib/typescript/modules/number-input/NumberInput.variants.d.ts +7 -5
  302. package/lib/typescript/modules/pagination/PaginationControls.d.ts +1 -4
  303. package/lib/typescript/modules/reorder/Reorder.d.ts +1 -1
  304. package/lib/typescript/modules/screen/Screen.d.ts +3 -9
  305. package/lib/typescript/modules/screen/Screen.variants.d.ts +4 -0
  306. package/lib/typescript/modules/search-bar/SearchBar.variants.d.ts +6 -6
  307. package/lib/typescript/modules/section/Section.variants.d.ts +0 -3
  308. package/lib/typescript/modules/segmented-control/SegmentedControl.variants.d.ts +1 -1
  309. package/lib/typescript/modules/select/Select.d.ts +4 -1
  310. package/lib/typescript/modules/select/Select.variants.d.ts +22 -8
  311. package/lib/typescript/modules/select/index.d.ts +1 -1
  312. package/lib/typescript/modules/skeleton/Skeleton.d.ts +3 -18
  313. package/lib/typescript/modules/skeleton/Skeleton.variants.d.ts +12 -68
  314. package/lib/typescript/modules/stage-progress/StageProgress.variants.d.ts +15 -6
  315. package/lib/typescript/modules/state-block/StateBlock.d.ts +4 -0
  316. package/lib/typescript/modules/state-block/StateBlock.variants.d.ts +1 -0
  317. package/lib/typescript/modules/surface/Surface.d.ts +19 -0
  318. package/lib/typescript/modules/surface/Surface.variants.d.ts +15 -0
  319. package/lib/typescript/modules/surface/index.d.ts +4 -0
  320. package/lib/typescript/modules/text/Text.d.ts +8 -4
  321. package/lib/typescript/modules/text/Text.variants.d.ts +14 -11
  322. package/lib/typescript/modules/toast/Toast.variants.d.ts +2 -0
  323. package/lib/typescript/modules/tooltip/Tooltip.variants.d.ts +7 -0
  324. package/lib/typescript/theme/index.d.ts +1 -1
  325. package/lib/typescript/theme/platform/elevation.native.d.ts +0 -30
  326. package/lib/typescript/theme/platform/floatingSurface.native.d.ts +10 -0
  327. package/lib/typescript/theme/platform/highlight.native.d.ts +17 -0
  328. package/lib/typescript/theme/platform/index.d.ts +9 -0
  329. package/lib/typescript/theme/platform/motion.native.d.ts +33 -13
  330. package/lib/typescript/theme/platform/stateLayer.native.d.ts +11 -0
  331. package/lib/typescript/theme/platform/surfaces.native.d.ts +8 -0
  332. package/lib/typescript/theme/provider/PixelizeProvider.d.ts +1 -1
  333. package/lib/typescript/theme/provider/types.d.ts +8 -0
  334. package/lib/typescript/theme/tokens/assertPalette.d.ts +10 -0
  335. package/lib/typescript/theme/tokens/brands/emerald/palette.light.d.ts +4 -3
  336. package/lib/typescript/theme/tokens/brands/lavender/palette.light.d.ts +4 -3
  337. package/lib/typescript/theme/tokens/brands/meadow/palette.light.d.ts +4 -3
  338. package/lib/typescript/theme/tokens/brands/radiant/palette.light.d.ts +4 -3
  339. package/lib/typescript/theme/tokens/brands/rosewood/palette.light.d.ts +4 -3
  340. package/lib/typescript/theme/tokens/brands/skyline/palette.light.d.ts +4 -3
  341. package/lib/typescript/theme/tokens/brands/slate/palette.light.d.ts +4 -3
  342. package/lib/typescript/theme/tokens/brands/storefront/palette.light.d.ts +4 -3
  343. package/lib/typescript/theme/tokens/brands/zinc/palette.light.d.ts +4 -3
  344. package/lib/typescript/theme/tokens/builders/finalizePalette.d.ts +4 -0
  345. package/lib/typescript/theme/tokens/builders/liftToContrast.d.ts +9 -0
  346. package/lib/typescript/theme/tokens/builders/placeholderInk.d.ts +13 -0
  347. package/lib/typescript/theme/tokens/builders/semanticText.d.ts +4 -0
  348. package/lib/typescript/theme/tokens/builders/surfaceRungs.d.ts +12 -0
  349. package/lib/typescript/theme/tokens/index.d.ts +5 -0
  350. package/lib/typescript/theme/tokens/roles/index.d.ts +1 -0
  351. package/lib/typescript/theme/tokens/types.d.ts +8 -7
  352. package/package.json +10 -2
  353. package/registry.json +5 -0
@@ -15,28 +15,36 @@
15
15
 
16
16
  import { cloneElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
17
17
  import { Animated, Modal, Platform, Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
18
+ import Reanimated from "react-native-reanimated";
18
19
  import { focusItemProps, useDismissOnEscape, useFocusTrap, useRovingKeys, useSpaceActivation } from "../../core/a11y/keyboard";
19
- import { useMotion } from "../../core/motion/index.js";
20
+ import { MOTION_TRANSFORM, useAnimatedValue, useMotion } from "../../core/motion/index.js";
21
+ import { usePressState } from "../../core/motion/usePressState.js";
22
+ import { withAlpha } from "../../core/gradient/index.js";
20
23
  import { Icon } from "../../core/icon/index.js";
21
24
  import { VirtualList } from "../../core/list/index.js";
25
+ import { concentric } from "../../core/style/index.js";
26
+ import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
27
+ import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
22
28
  import { useTheme } from "../../theme/hooks.js";
23
29
  import { ModalPortalContext } from "../modal/ModalPortalContext.js";
24
30
  import { renderWebPortal } from "../modal/renderWebPortal";
25
- import { MENU_ROW_ICON_SIZE, MENU_ROW_MIN_HEIGHT, menuOverlayStructure, menuRowStructure, menuSheetStructure, resolveMenuItemColor, resolveMenuRowPressedBackground } from "./Menu.variants.js";
31
+ import { MENU_ROW_ICON_SIZE, MENU_ROW_MIN_HEIGHT, menuOverlayStructure, menuRowStructure, menuSheetStructure, resolveMenuItemColor } from "./Menu.variants.js";
26
32
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
27
33
  const VIRTUALIZE_THRESHOLD = 15;
28
34
  const ICON_STROKE = 2;
29
- const BACKDROP_SCRIM = "#00000099";
35
+ // Opacity is the shared `scrimOpacity` knob, not a locally-guessed hex — matches Modal/Drawer/BottomSheet.
36
+ const BACKDROP_SCRIM = withAlpha("#000000", MOTION_TRANSFORM.scrimOpacity);
37
+ const AnimatedPressable = Reanimated.createAnimatedComponent(Pressable);
30
38
  const MenuRow = /*#__PURE__*/memo(function MenuRow({
31
39
  item,
32
40
  index,
33
41
  tabIndex,
34
42
  theme,
35
- pressedRowBg,
36
43
  onSelect,
37
44
  testID
38
45
  }) {
39
46
  const color = resolveMenuItemColor(theme.colors, item.tone ?? "default");
47
+ const press = usePressState(false);
40
48
  const handlePress = useCallback(() => onSelect(item), [onSelect, item]);
41
49
  const rowRef = useRef(null);
42
50
  const active = tabIndex === 0;
@@ -50,24 +58,33 @@ const MenuRow = /*#__PURE__*/memo(function MenuRow({
50
58
 
51
59
  // `menuitem` is not `button`, so RNW never presses on Space — see `core/a11y/keyboard.web.ts`.
52
60
  useSpaceActivation(rowRef, handlePress);
53
- const rowStyle = useCallback(({
54
- pressed
55
- }) => [menuRowStructure(theme), pressed && {
56
- backgroundColor: pressedRowBg
57
- }], [theme, pressedRowBg]);
61
+ const rowStyle = useMemo(() => [menuRowStructure(theme), {
62
+ overflow: "hidden"
63
+ }, press.animatedStyle], [theme, press.animatedStyle]);
64
+ const overlayStaticStyle = useMemo(() => ({
65
+ backgroundColor: theme.mode === "dark" ? "#ffffff" : "#000000",
66
+ borderRadius: concentric(theme.radii.lg, theme.space[4]),
67
+ borderCurve: "continuous"
68
+ }), [theme.mode, theme.radii.lg, theme.space]);
58
69
  const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
59
70
  flex: 1,
60
71
  fontSize: theme.fontSizes.md,
61
72
  color
62
73
  }], [theme, color]);
63
- return /*#__PURE__*/_jsxs(Pressable, {
74
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
64
75
  ref: rowRef,
65
76
  testID: testID ? `${testID}-item-${index}` : undefined,
66
77
  accessibilityRole: "menuitem",
67
78
  tabIndex: tabIndex,
68
79
  onPress: handlePress,
80
+ onPressIn: press.handlers.onPressIn,
81
+ onPressOut: press.handlers.onPressOut,
82
+ onLayout: press.onLayout,
69
83
  style: rowStyle,
70
- children: [item.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
84
+ children: [/*#__PURE__*/_jsx(Reanimated.View, {
85
+ pointerEvents: "none",
86
+ style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
87
+ }), item.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
71
88
  name: item.icon,
72
89
  size: MENU_ROW_ICON_SIZE,
73
90
  color: color,
@@ -89,28 +106,59 @@ export const Menu = /*#__PURE__*/memo(function Menu({
89
106
  const motion = useMotion();
90
107
  const portalContainer = useContext(ModalPortalContext);
91
108
  const [open, setOpen] = useState(false);
109
+ const [mounted, setMounted] = useState(false);
110
+ const mountedRef = useRef(mounted);
111
+ mountedRef.current = mounted;
92
112
  const [activeIndex, setActiveIndex] = useState(0);
93
113
  const sheetRef = useRef(null);
94
- const enter = useRef(new Animated.Value(0)).current;
95
- const entering = useRef(null);
114
+ const enter = useAnimatedValue(0);
115
+ const running = useRef(null);
116
+ const unmountTimer = useRef(null);
96
117
  useEffect(() => {
97
- entering.current?.stop();
98
- if (!open) {
118
+ const clearUnmount = () => {
119
+ if (unmountTimer.current !== null) {
120
+ clearTimeout(unmountTimer.current);
121
+ unmountTimer.current = null;
122
+ }
123
+ };
124
+ running.current?.stop();
125
+ clearUnmount();
126
+ if (open) {
127
+ setMounted(true);
128
+ if (!motion.enabled) {
129
+ enter.setValue(1);
130
+ return;
131
+ }
99
132
  enter.setValue(0);
133
+ running.current = motion.timing(enter, 1, {
134
+ duration: "fast",
135
+ easing: "decelerate"
136
+ });
137
+ running.current.start();
100
138
  return;
101
139
  }
102
- if (!motion.enabled) {
103
- enter.setValue(1);
140
+ if (!mountedRef.current) return;
141
+ const exitMs = motion.duration("fast");
142
+ if (!motion.enabled || exitMs === 0) {
143
+ enter.setValue(0);
144
+ setMounted(false);
104
145
  return;
105
146
  }
106
- enter.setValue(0);
107
- entering.current = motion.timing(enter, 1, {
147
+ running.current = motion.timing(enter, 0, {
108
148
  duration: "fast",
109
- easing: "decelerate"
149
+ easing: "accelerate"
110
150
  });
111
- entering.current.start();
151
+ running.current.start();
152
+ unmountTimer.current = setTimeout(() => {
153
+ unmountTimer.current = null;
154
+ setMounted(false);
155
+ }, exitMs);
156
+ return clearUnmount;
112
157
  }, [open, motion, enter]);
113
- useEffect(() => () => entering.current?.stop(), []);
158
+ useEffect(() => () => {
159
+ running.current?.stop();
160
+ if (unmountTimer.current !== null) clearTimeout(unmountTimer.current);
161
+ }, []);
114
162
  const openMenu = useCallback(() => {
115
163
  if (disabled) return;
116
164
  setActiveIndex(0);
@@ -141,7 +189,6 @@ export const Menu = /*#__PURE__*/memo(function Menu({
141
189
  const clonedTrigger = /*#__PURE__*/cloneElement(trigger, {
142
190
  onPress: handleTriggerPress
143
191
  });
144
- const pressedRowBg = useMemo(() => resolveMenuRowPressedBackground(theme.colors), [theme.colors]);
145
192
  const keyExtractor = useCallback((item, index) => `${item.label}-${index}`, []);
146
193
  const renderItem = useCallback(({
147
194
  item,
@@ -151,12 +198,20 @@ export const Menu = /*#__PURE__*/memo(function Menu({
151
198
  index: index,
152
199
  tabIndex: focusItemProps(index, activeIndex).tabIndex,
153
200
  theme: theme,
154
- pressedRowBg: pressedRowBg,
155
201
  onSelect: selectItem,
156
202
  testID: testID
157
- }), [activeIndex, theme, pressedRowBg, selectItem, testID]);
158
- const sheetStyle = useMemo(() => [menuSheetStructure(theme), {
159
- backgroundColor: theme.colors.bg.surface,
203
+ }), [activeIndex, theme, selectItem, testID]);
204
+ const floatingStyle = useMemo(() => {
205
+ highlight("subtle", theme.mode);
206
+ elevation(elevationTokens.md);
207
+ void theme.elevatedSurfaces;
208
+ return {
209
+ backgroundColor: floatingBackground(theme, "md"),
210
+ ...floatingSurfaceStyle(theme, "md")
211
+ };
212
+ }, [theme]);
213
+ const sheetStyle = useMemo(() => [menuSheetStructure(theme), floatingStyle, {
214
+ opacity: enter,
160
215
  transform: [{
161
216
  scale: enter.interpolate({
162
217
  inputRange: [0, 1],
@@ -168,27 +223,30 @@ export const Menu = /*#__PURE__*/memo(function Menu({
168
223
  outputRange: [motion.transform.offsetY, 0]
169
224
  })
170
225
  }]
171
- }], [theme, enter, motion.transform.pressScale, motion.transform.offsetY]);
226
+ }], [theme, floatingStyle, enter, motion.transform.pressScale, motion.transform.offsetY]);
227
+ const backdropStyle = useMemo(() => [styles.backdrop, {
228
+ opacity: enter
229
+ }], [enter]);
172
230
 
173
- // Built only while open: a closed Menu must not materialize one element per item on every render
174
- // of the screen that hosts it.
175
- const sheet = open ? /*#__PURE__*/_jsxs(_Fragment, {
231
+ // Built only while mounted: a closed, settled Menu must not materialize one element per item on
232
+ // every render of the screen that hosts it.
233
+ const sheet = mounted ? /*#__PURE__*/_jsxs(_Fragment, {
176
234
  children: [/*#__PURE__*/_jsx(Pressable, {
177
235
  testID: testID ? `${testID}-backdrop` : undefined,
178
236
  accessible: false,
179
237
  tabIndex: -1,
180
- style: styles.backdrop,
181
- onPress: closeMenu
238
+ style: StyleSheet.absoluteFill,
239
+ onPress: closeMenu,
240
+ children: /*#__PURE__*/_jsx(Animated.View, {
241
+ pointerEvents: "none",
242
+ style: backdropStyle
243
+ })
182
244
  }), /*#__PURE__*/_jsx(View, {
183
245
  style: menuOverlayStructure(theme),
184
246
  pointerEvents: "box-none",
185
247
  children: /*#__PURE__*/_jsx(Animated.View, {
186
248
  ref: sheetRef,
187
- testID: testID ? `${testID}-sheet` : undefined
188
- // The container role the `menuitem` rows below need, plus the modal semantics every other
189
- // overlay in this library gives its panel. Declared HERE, before the portal branch, so the
190
- // web-portal path — which renders no RN `<Modal>` at all — inherits them too.
191
- ,
249
+ testID: testID ? `${testID}-sheet` : undefined,
192
250
  accessibilityRole: "menu",
193
251
  accessibilityViewIsModal: true,
194
252
  onAccessibilityEscape: closeMenu,
@@ -205,7 +263,6 @@ export const Menu = /*#__PURE__*/memo(function Menu({
205
263
  index: index,
206
264
  tabIndex: focusItemProps(index, activeIndex).tabIndex,
207
265
  theme: theme,
208
- pressedRowBg: pressedRowBg,
209
266
  onSelect: selectItem,
210
267
  testID: testID
211
268
  }, `${item.label}-${index}`))
@@ -213,13 +270,15 @@ export const Menu = /*#__PURE__*/memo(function Menu({
213
270
  })
214
271
  })]
215
272
  }) : null;
216
- const menu = Platform.OS === "web" && portalContainer != null ? open ? renderWebPortal(/*#__PURE__*/_jsx(View, {
273
+ const menu = Platform.OS === "web" && portalContainer != null ? mounted ? renderWebPortal(/*#__PURE__*/_jsx(View, {
217
274
  style: StyleSheet.absoluteFill,
218
275
  pointerEvents: "box-none",
219
276
  children: sheet
220
277
  }), portalContainer) : null : /*#__PURE__*/_jsx(Modal, {
221
278
  visible: open,
222
279
  transparent: true,
280
+ statusBarTranslucent: true,
281
+ navigationBarTranslucent: true,
223
282
  animationType: motion.enabled ? "fade" : "none",
224
283
  onRequestClose: closeMenu,
225
284
  children: sheet
@@ -67,10 +67,10 @@ export const menuOverlayStructure = createThemedVariants(theme => ({
67
67
  }));
68
68
  export const menuSheetStructure = createThemedVariants(theme => ({
69
69
  base: {
70
- borderRadius: theme.radii.base,
70
+ borderRadius: theme.radii.lg,
71
+ borderCurve: "continuous",
71
72
  paddingVertical: theme.space[2],
72
- maxHeight: 320,
73
- ...theme.elevation.lg
73
+ maxHeight: 320
74
74
  }
75
75
  }));
76
76
  export const menuRowStructure = createThemedVariants(theme => ({
@@ -1,6 +1,6 @@
1
1
  # message-bubble/
2
2
 
3
- Single chat bubble — `user` (accent) or `assistant` (surface + border). Plain `content` string.
3
+ Single chat bubble — `user` (accent) or `assistant` (tonal surface). Plain `content` string.
4
4
 
5
5
  ## Motion contract
6
6
 
@@ -36,3 +36,6 @@ mean a new prop — not added speculatively.
36
36
  | `content` | `string` | — |
37
37
  | `style` | `LayoutStyle` | — |
38
38
  | `testID` | `string` | — |
39
+
40
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
41
+ - **Round 5 tonal** — assistant's `borderWidth.thin` hairline dropped; `bg.surface` alone now separates the bubble from its parent by tone, matching `Card`'s borderless-flat precedent.
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * MessageBubble — a single chat turn bubble. User variant uses accent fill; assistant uses surface
5
- * card with border. Plain-text `content` only (rich assistant replies compose Markdown/RichText
4
+ * MessageBubble — a single chat turn bubble. User variant uses accent fill; assistant uses a tonal
5
+ * surface fill, no border. Plain-text `content` only (rich assistant replies compose Markdown/RichText
6
6
  * upstream).
7
7
  *
8
8
  * The accessible label names the sender ("You" / "Assistant") ahead of the content: alignment and
@@ -32,9 +32,8 @@ export const MessageBubble = /*#__PURE__*/memo(function MessageBubble({
32
32
  const bubbleStyle = useMemo(() => [messageBubbleStructure(theme, {
33
33
  variant
34
34
  }), {
35
- backgroundColor: colors.background,
36
- borderColor: colors.border
37
- }, style], [theme, variant, colors.background, colors.border, style]);
35
+ backgroundColor: colors.background
36
+ }, style], [theme, variant, colors.background, style]);
38
37
  const textStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
39
38
  fontSize: theme.fontSizes.md,
40
39
  lineHeight: theme.fontSizes.md * 1.45,
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import { createThemedVariants } from "../../core/style/index.js";
4
+ /** Assistant separates from the canvas by tone (`bg.surface`) alone now — no hairline border. */
4
5
  export function resolveMessageBubbleColors(colors, variant) {
5
6
  if (variant === "user") {
6
7
  return {
@@ -10,8 +11,7 @@ export function resolveMessageBubbleColors(colors, variant) {
10
11
  }
11
12
  return {
12
13
  background: colors.bg.surface,
13
- text: colors.fg.default,
14
- border: colors.border.default
14
+ text: colors.fg.default
15
15
  };
16
16
  }
17
17
  export const messageBubbleStructure = createThemedVariants(theme => ({
@@ -19,7 +19,8 @@ export const messageBubbleStructure = createThemedVariants(theme => ({
19
19
  maxWidth: "85%",
20
20
  paddingHorizontal: theme.space[3],
21
21
  paddingVertical: theme.space[2],
22
- borderRadius: theme.radii.lg
22
+ borderRadius: theme.radii.lg,
23
+ borderCurve: "continuous"
23
24
  },
24
25
  variants: {
25
26
  variant: {
@@ -29,8 +30,7 @@ export const messageBubbleStructure = createThemedVariants(theme => ({
29
30
  },
30
31
  assistant: {
31
32
  alignSelf: "flex-start",
32
- borderBottomLeftRadius: theme.radii.sm,
33
- borderWidth: theme.borderWidths.thin
33
+ borderBottomLeftRadius: theme.radii.sm
34
34
  }
35
35
  }
36
36
  },
@@ -135,6 +135,14 @@ none of them contains keyboard code, and each has a test asserting the inheritan
135
135
  4. **Closed `size` union** reusing the shared `sizes` primitive (384/448/512dp) instead of
136
136
  Modal-local numbers — `theme/tokens/primitives/sizes.ts` is documented for exactly this case.
137
137
 
138
+ ## Android edge-to-edge
139
+
140
+ Every RN `<Modal transparent>` in this library (`Modal`, `Select`, `MultiSelect`, `Combobox`,
141
+ `Menu`, `OrgSwitcher`, `PickerShell`, `Drawer`) also sets `statusBarTranslucent` and
142
+ `navigationBarTranslucent`, both `true`. Without them, Android edge-to-edge (Expo default since
143
+ SDK 53) paints the modal's backing window opaque instead of transparent — the whole screen goes
144
+ solid white on open. Add both any time a new module renders its own RN `<Modal transparent>`.
145
+
138
146
  ## Known gaps
139
147
 
140
148
  - **No full SCREEN-READER trap.** iOS gets `accessibilityViewIsModal` (constrains VoiceOver to the
@@ -162,3 +170,6 @@ Both `Modal` and `ModalPortalProvider` are wrapped in `React.memo` (repo-wide re
162
170
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
163
171
  - List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
164
172
  - `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
173
+
174
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
175
+ - **Round 5 motion** — dropped the ad hoc reanimated `FadeInDown`/`FadeOut` layer; the panel's own `enter` value now drives backdrop opacity too, so scrim fade and panel slide+fade are one gesture on both the RNModal and web-portal paths. The portal branch now tracks `mounted` through a real timed exit instead of unmounting instantly. `MODAL_BACKDROP`'s opacity comes from `MOTION_TRANSFORM.scrimOpacity`.
@@ -33,19 +33,22 @@
33
33
  * which is where all three silently went missing.
34
34
  */
35
35
 
36
- import { memo, useContext, useEffect, useMemo, useRef } from "react";
37
- import { Animated, Modal as RNModal, Platform, Pressable, StyleSheet, Text, View } from "react-native";
36
+ import { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
37
+ import { Animated, Modal as RNModal, Platform, Pressable, StyleSheet, View } from "react-native";
38
38
  import { useDismissOnEscape, useFocusTrap } from "../../core/a11y/keyboard";
39
- import { useAnimatedValue, useMotion } from "../../core/motion/index.js";
39
+ import { MOTION_TRANSFORM, useAnimatedValue, useMotion } from "../../core/motion/index.js";
40
+ import { withAlpha } from "../../core/gradient/index.js";
41
+ import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
42
+ import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
40
43
  import { useTheme } from "../../theme/hooks.js";
44
+ import { Heading } from "../text/index.js";
41
45
  import { ModalPortalContext } from "./ModalPortalContext.js";
42
46
  import { renderWebPortal } from "./renderWebPortal";
43
- import { modalOverlayStructure, modalPanelStructure, resolveModalAnimationType, resolveModalPanelColors } from "./Modal.variants.js";
47
+ import { modalOverlayStructure, modalPanelStructure, resolveModalAnimationType } from "./Modal.variants.js";
44
48
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
45
- // Decorative dismiss scrim behind the panel — a design constant, not a role token: it is neither
46
- // text nor an interactive boundary, so WCAG's contrast minimums don't apply to it. Same
47
- // justification as Button's PRESS_SCRIM_DARK/LIGHT and Select's BACKDROP_SCRIM.
48
- const MODAL_BACKDROP = "#00000080";
49
+ // Decorative dismiss scrim, not a role token same reasoning Button's PRESS_SCRIM and Select's
50
+ // BACKDROP_SCRIM record. Opacity is the shared `scrimOpacity` knob, not a locally-guessed hex.
51
+ const MODAL_BACKDROP = withAlpha("#000000", MOTION_TRANSFORM.scrimOpacity);
49
52
  export const Modal = /*#__PURE__*/memo(function Modal({
50
53
  visible,
51
54
  onRequestClose,
@@ -56,54 +59,105 @@ export const Modal = /*#__PURE__*/memo(function Modal({
56
59
  }) {
57
60
  const theme = useTheme();
58
61
  const motion = useMotion();
59
- const panelColors = useMemo(() => resolveModalPanelColors(theme.colors), [theme.colors]);
60
62
  const portalContainer = useContext(ModalPortalContext);
61
63
  const panelRef = useRef(null);
62
64
  const portalled = Platform.OS === "web" && portalContainer != null;
63
65
  useDismissOnEscape(portalled && visible, onRequestClose);
64
66
  useFocusTrap(panelRef, portalled && visible);
67
+
68
+ // `mounted` only gates the web-portal render below — the RNModal branch keeps handing `visible`
69
+ // straight to RN's own <Modal>, which still owns that surface's native fade in and out.
70
+ const [mounted, setMounted] = useState(visible);
71
+ const mountedRef = useRef(mounted);
72
+ mountedRef.current = mounted;
65
73
  const enter = useAnimatedValue(visible ? 1 : 0);
66
- const entering = useRef(null);
74
+ const running = useRef(null);
75
+ const unmountTimer = useRef(null);
67
76
  useEffect(() => {
68
- entering.current?.stop();
69
- if (!visible) {
77
+ const clearUnmount = () => {
78
+ if (unmountTimer.current !== null) {
79
+ clearTimeout(unmountTimer.current);
80
+ unmountTimer.current = null;
81
+ }
82
+ };
83
+ running.current?.stop();
84
+ clearUnmount();
85
+ if (visible) {
86
+ setMounted(true);
87
+ if (!motion.enabled) {
88
+ enter.setValue(1);
89
+ return;
90
+ }
70
91
  enter.setValue(0);
92
+ running.current = motion.timing(enter, 1, {
93
+ easing: "decelerate"
94
+ });
95
+ running.current.start();
71
96
  return;
72
97
  }
73
- if (!motion.enabled) {
74
- enter.setValue(1);
98
+ if (!mountedRef.current) return;
99
+ const exitMs = motion.duration("fast");
100
+ if (!motion.enabled || exitMs === 0) {
101
+ enter.setValue(0);
102
+ setMounted(false);
75
103
  return;
76
104
  }
77
- enter.setValue(0);
78
- entering.current = motion.timing(enter, 1, {
79
- easing: "decelerate"
105
+ running.current = motion.timing(enter, 0, {
106
+ duration: "fast",
107
+ easing: "accelerate"
80
108
  });
81
- entering.current.start();
109
+ running.current.start();
110
+ unmountTimer.current = setTimeout(() => {
111
+ unmountTimer.current = null;
112
+ setMounted(false);
113
+ }, exitMs);
114
+ return clearUnmount;
82
115
  }, [visible, motion, enter]);
83
- useEffect(() => () => entering.current?.stop(), []);
116
+ useEffect(() => () => {
117
+ running.current?.stop();
118
+ if (unmountTimer.current !== null) clearTimeout(unmountTimer.current);
119
+ }, []);
120
+ const floatingStyle = useMemo(() => {
121
+ highlight("subtle", theme.mode);
122
+ elevation(elevationTokens.lg);
123
+ void theme.elevatedSurfaces;
124
+ return {
125
+ backgroundColor: floatingBackground(theme, "lg"),
126
+ ...floatingSurfaceStyle(theme, "lg")
127
+ };
128
+ }, [theme]);
84
129
  const panelStyle = useMemo(() => [modalPanelStructure(theme, {
85
130
  size
86
- }), {
87
- backgroundColor: panelColors.background,
131
+ }), floatingStyle, {
132
+ opacity: enter,
88
133
  transform: [{
89
134
  translateY: enter.interpolate({
90
135
  inputRange: [0, 1],
91
136
  outputRange: [motion.transform.offsetY, 0]
92
137
  })
93
138
  }]
94
- }], [theme, size, panelColors.background, enter, motion.transform.offsetY]);
95
- const titleStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.semibold), {
96
- fontSize: theme.fontSizes.lg,
97
- color: panelColors.title,
98
- marginBottom: theme.space[3]
99
- }], [theme, panelColors.title]);
139
+ }], [theme, size, floatingStyle, enter, motion.transform.offsetY]);
140
+ const backdropStyle = useMemo(() => [styles.backdrop, {
141
+ opacity: enter
142
+ }], [enter]);
143
+ const titleBlock = title !== undefined ? /*#__PURE__*/_jsx(Heading, {
144
+ variant: "h3",
145
+ style: {
146
+ marginBottom: theme.space[3]
147
+ },
148
+ children: title
149
+ }) : null;
100
150
  const overlay = /*#__PURE__*/_jsxs(_Fragment, {
101
151
  children: [/*#__PURE__*/_jsx(Pressable, {
102
152
  testID: testID ? `${testID}-backdrop` : undefined,
103
153
  accessible: false,
104
154
  tabIndex: -1,
105
- style: styles.backdrop,
106
- onPress: onRequestClose
155
+ style: StyleSheet.absoluteFill,
156
+ onPress: onRequestClose,
157
+ children: /*#__PURE__*/_jsx(Animated.View, {
158
+ pointerEvents: "none",
159
+ style: backdropStyle
160
+ })
107
161
  }), /*#__PURE__*/_jsx(View, {
108
162
  style: modalOverlayStructure(theme),
109
163
  pointerEvents: "box-none",
@@ -113,16 +167,12 @@ export const Modal = /*#__PURE__*/memo(function Modal({
113
167
  accessibilityViewIsModal: true,
114
168
  onAccessibilityEscape: onRequestClose,
115
169
  style: panelStyle,
116
- children: [title !== undefined && /*#__PURE__*/_jsx(Text, {
117
- accessibilityRole: "header",
118
- style: titleStyle,
119
- children: title
120
- }), children]
170
+ children: [titleBlock, children]
121
171
  })
122
172
  })]
123
173
  });
124
174
  if (portalled) {
125
- if (!visible) return null;
175
+ if (!mounted) return null;
126
176
  // RN's own <Modal> supplies a `position: fixed`/full-screen ancestor for `overlay`'s children
127
177
  // to size against (see ModalPortalContext.ts) — reproduce just that sizing here (never touching
128
178
  // the shared `modalOverlayStructure`/`modalPanelStructure` resolvers the RNModal path below
@@ -137,6 +187,8 @@ export const Modal = /*#__PURE__*/memo(function Modal({
137
187
  return /*#__PURE__*/_jsx(RNModal, {
138
188
  visible: visible,
139
189
  transparent: true,
190
+ statusBarTranslucent: true,
191
+ navigationBarTranslucent: true,
140
192
  animationType: resolveModalAnimationType(!motion.enabled),
141
193
  onRequestClose: onRequestClose,
142
194
  children: overlay
@@ -69,8 +69,8 @@ export const modalPanelStructure = createThemedVariants(theme => ({
69
69
  width: "100%",
70
70
  maxHeight: "92%",
71
71
  borderRadius: theme.radii.lg,
72
- padding: theme.space[5],
73
- ...theme.elevation.lg
72
+ borderCurve: "continuous",
73
+ padding: theme.space[5]
74
74
  },
75
75
  variants: {
76
76
  size: {
@@ -34,6 +34,9 @@ Renders `null` when the count is ≤0 and there is no `triggerText` — nothing
34
34
  - **Touch target (WCAG 2.5.5 / 2.5.8)** — the trigger carries `minHeight: 44` (this library's
35
35
  floor). It is a standalone node with no neighbouring target to overlap, so the floor is real
36
36
  height via `minHeight`, not `hitSlop` expansion the way `Button`'s shorter sizes reach it.
37
+ - **Android touch feedback** — the trigger carries `android_ripple` (`rippleColor(theme.mode)`,
38
+ `borderless: false`), gated on `Platform.OS === "android"`. The scrim `Pressable` gets none — it is
39
+ the same `accessible={false}` decoy described under Modal semantics below, not a real press target.
37
40
  - **Label in Name (WCAG 2.5.3)** — the accessible name is built to CONTAIN the visible text
38
41
  (`"${triggerText} +${count} more"`, or just `"+${count} more"` with no leading text), not a
39
42
  separately-worded `"${count} more items"`. Voice control says what it reads; the old name shared no
@@ -70,3 +73,5 @@ Renders `null` when the count is ≤0 and there is no `triggerText` — nothing
70
73
 
71
74
  - Rows are display-only — no press/selection. A selectable overflow list would be a different
72
75
  component (`Select`/`Menu`), not a prop added here.
76
+
77
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
@@ -5,10 +5,11 @@
5
5
  */
6
6
 
7
7
  import { memo, useCallback, useMemo, useState } from "react";
8
- import { Animated, Modal, Pressable, StyleSheet, Text, View } from "react-native";
8
+ import { Animated, Modal, Platform, Pressable, StyleSheet, Text, View } from "react-native";
9
9
  import { VirtualList } from "../../core/list/index.js";
10
10
  import { useEnterExit, usePressMotion } from "../../core/motion/index.js";
11
11
  import { useTheme } from "../../theme/hooks.js";
12
+ import { rippleColor } from "../../theme/platform/stateLayer.native.js";
12
13
  import { moreItemsBadgeStructure, moreItemsDotStructure, moreItemsOverlayStructure, moreItemsRowStructure, moreItemsSheetStructure, moreItemsTriggerContentStructure, moreItemsTriggerStructure, resolveMoreItemsCount, resolveMoreItemsDotColor } from "./MoreItems.variants.js";
13
14
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
15
  const BACKDROP = "#00000080";
@@ -72,6 +73,10 @@ export const MoreItems = /*#__PURE__*/memo(function MoreItems({
72
73
  backgroundColor: theme.colors.accent.subtle
73
74
  }], [theme]);
74
75
  const overlayStructure = useMemo(() => moreItemsOverlayStructure(theme), [theme]);
76
+ const androidRipple = useMemo(() => Platform.OS === "android" ? {
77
+ color: rippleColor(theme.mode),
78
+ borderless: false
79
+ } : undefined, [theme.mode]);
75
80
  const sheetStyle = useMemo(() => [moreItemsSheetStructure(theme), {
76
81
  backgroundColor: theme.colors.bg.surface
77
82
  }], [theme]);
@@ -102,6 +107,7 @@ export const MoreItems = /*#__PURE__*/memo(function MoreItems({
102
107
  onPress: openSheet,
103
108
  onPressIn: press.onPressIn,
104
109
  onPressOut: press.onPressOut,
110
+ android_ripple: androidRipple,
105
111
  style: triggerStyle,
106
112
  children: /*#__PURE__*/_jsxs(Animated.View, {
107
113
  style: [triggerContentStructure, press.style],
@@ -48,7 +48,8 @@ export const moreItemsDotStructure = createThemedVariants(theme => ({
48
48
  base: {
49
49
  width: MORE_ITEMS_DOT_SIZE,
50
50
  height: MORE_ITEMS_DOT_SIZE,
51
- borderRadius: theme.radii.full
51
+ borderRadius: theme.radii.full,
52
+ borderCurve: "continuous"
52
53
  }
53
54
  }));
54
55
  export const moreItemsOverlayStructure = createThemedVariants(theme => ({
@@ -61,6 +62,7 @@ export const moreItemsOverlayStructure = createThemedVariants(theme => ({
61
62
  export const moreItemsSheetStructure = createThemedVariants(theme => ({
62
63
  base: {
63
64
  borderRadius: theme.radii.lg,
65
+ borderCurve: "continuous",
64
66
  padding: theme.space[3],
65
67
  maxHeight: MORE_ITEMS_SHEET_MAX_HEIGHT
66
68
  }
@@ -71,6 +73,7 @@ export const moreItemsBadgeStructure = createThemedVariants(theme => ({
71
73
  paddingHorizontal: theme.space[2],
72
74
  paddingVertical: 2,
73
75
  borderRadius: theme.radii.full,
76
+ borderCurve: "continuous",
74
77
  fontSize: theme.fontSizes.xs
75
78
  }
76
79
  }));
@@ -164,3 +164,8 @@ Via `core/motion` only — `opacity`/`transform`, native driver, all reduce-moti
164
164
 
165
165
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
166
166
  - List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
167
+
168
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
169
+ - **Round 5 (Android parity)** — `android_ripple` (`borderless: false`) added to the trigger (gated
170
+ `!disabled`), the header close button, and each option row. The trigger and close button also
171
+ gained `overflow: "hidden"` so their ripple clips to their shape.