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
@@ -25,16 +25,16 @@ const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2)
25
25
  */
26
26
  export const SEARCH_BAR_SIZES = {
27
27
  sm: {
28
- height: 32,
28
+ height: 44,
29
29
  fontSize: 14,
30
30
  iconSize: 16,
31
- hitSlop: slopFor(32)
31
+ hitSlop: slopFor(44)
32
32
  },
33
33
  md: {
34
- height: 40,
34
+ height: 52,
35
35
  fontSize: 16,
36
36
  iconSize: 18,
37
- hitSlop: slopFor(40)
37
+ hitSlop: slopFor(52)
38
38
  }
39
39
  };
40
40
 
@@ -59,7 +59,7 @@ export const CLEAR_BUTTON_WIDTH = MIN_TOUCH_TARGET;
59
59
  export function resolveSearchBarColors(colors) {
60
60
  return {
61
61
  text: colors.fg.default,
62
- placeholder: colors.fg.muted,
62
+ placeholder: colors.fg.placeholder,
63
63
  icon: colors.fg.muted,
64
64
  border: colors.border.interactive,
65
65
  focusBorder: colors.border.focus,
@@ -141,7 +141,8 @@ export const searchBarFieldStructure = createThemedVariants(theme => ({
141
141
  alignItems: "center",
142
142
  columnGap: theme.space[2],
143
143
  borderWidth: theme.borderWidths.thin,
144
- borderRadius: theme.radii.base
144
+ borderRadius: theme.radii.md,
145
+ borderCurve: "continuous"
145
146
  },
146
147
  variants: {
147
148
  size: {
@@ -171,7 +172,8 @@ export const searchBarClearStructure = createThemedVariants(theme => ({
171
172
  alignSelf: "stretch",
172
173
  alignItems: "center",
173
174
  justifyContent: "center",
174
- borderRadius: theme.radii.base
175
+ borderRadius: theme.radii.md,
176
+ borderCurve: "continuous"
175
177
  }
176
178
  }));
177
179
 
@@ -186,7 +188,8 @@ export const searchBarCancelStructure = createThemedVariants(theme => ({
186
188
  alignItems: "center",
187
189
  justifyContent: "center",
188
190
  paddingHorizontal: theme.space[2],
189
- borderRadius: theme.radii.base
191
+ borderRadius: theme.radii.md,
192
+ borderCurve: "continuous"
190
193
  },
191
194
  variants: {
192
195
  size: {
@@ -37,3 +37,5 @@ the settings-section pattern re-declared across consumer apps.
37
37
  ## Performance
38
38
 
39
39
  Wrapped in `React.memo`.
40
+
41
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
@@ -9,10 +9,10 @@
9
9
  */
10
10
 
11
11
  import { memo, useMemo } from "react";
12
- import { View } from "react-native";
13
- import { HEADING_LEVEL, HeadingText } from "../../core/heading/index.js";
12
+ import Reanimated, { FadeInDown, ReduceMotion } from "react-native-reanimated";
14
13
  import { useTheme } from "../../theme/hooks.js";
15
- import { resolveSectionColors, sectionContainerStructure, sectionLabelStructure } from "./Section.variants.js";
14
+ import { Text } from "../text/index.js";
15
+ import { sectionContainerStructure } from "./Section.variants.js";
16
16
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
17
  export const Section = /*#__PURE__*/memo(function Section({
18
18
  label,
@@ -21,20 +21,13 @@ export const Section = /*#__PURE__*/memo(function Section({
21
21
  testID
22
22
  }) {
23
23
  const theme = useTheme();
24
- const colors = useMemo(() => resolveSectionColors(theme.colors), [theme.colors]);
25
- const rootStyle = useMemo(() => [sectionContainerStructure(theme), {
26
- borderTopColor: colors.border
27
- }, style], [theme, colors, style]);
28
- const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.bold), sectionLabelStructure(theme), {
29
- color: colors.label
30
- }], [theme, colors]);
31
- return /*#__PURE__*/_jsxs(View, {
24
+ const rootStyle = useMemo(() => [sectionContainerStructure(theme), style], [theme, style]);
25
+ return /*#__PURE__*/_jsxs(Reanimated.View, {
26
+ entering: FadeInDown.springify().reduceMotion(ReduceMotion.System),
32
27
  testID: testID,
33
28
  style: rootStyle,
34
- children: [/*#__PURE__*/_jsx(HeadingText, {
35
- accessibilityRole: "header",
36
- "aria-level": HEADING_LEVEL.section,
37
- style: labelStyle,
29
+ children: [/*#__PURE__*/_jsx(Text, {
30
+ variant: "overline",
38
31
  children: label
39
32
  }), children]
40
33
  });
@@ -1,9 +1,5 @@
1
1
  "use strict";
2
2
 
3
- /**
4
- * Section's style resolution — same split as `Divider.variants` / `Card.variants`.
5
- */
6
-
7
3
  import { createThemedTextVariants, createThemedVariants } from "../../core/style/index.js";
8
4
  export function resolveSectionColors(colors) {
9
5
  return {
@@ -13,8 +9,7 @@ export function resolveSectionColors(colors) {
13
9
  }
14
10
  export const sectionContainerStructure = createThemedVariants(theme => ({
15
11
  base: {
16
- borderTopWidth: theme.borderWidths.thin,
17
- paddingTop: theme.space[2],
12
+ paddingTop: theme.space[4],
18
13
  paddingBottom: theme.space[2],
19
14
  rowGap: theme.space[2]
20
15
  }
@@ -74,7 +74,7 @@ The slide goes through **`useMotion()`**, not a direct `MOTION_DURATION` import:
74
74
  configured constant straight to `Animated.timing` read the CONFIGURED duration, never the one
75
75
  resolved against the device tier, so `MOTION_TIER[tier].durationScale` never reached the pill.
76
76
  Reduce-motion is `motion.enabled` — no second `useReducedMotion()` call (`core/motion/MODULE.md`
77
- rule 6). The in-flight slide is stopped on effect cleanup and on unmount.
77
+ rule 6). Segment presses use `usePressState` (scale + state-layer overlay). The in-flight slide is stopped on effect cleanup and on unmount.
78
78
 
79
79
  ## Patterns copied from Tabs / ButtonGroup / Card
80
80
 
@@ -122,3 +122,5 @@ Wrapped in `React.memo`. `handleSegmentLayout` is `useCallback`'d (mirroring `Ta
122
122
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
123
123
  - List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
124
124
  - `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
125
+ - **Round 5 (Android parity)** — segments were missing `android_ripple` entirely; added, bounded
126
+ (`borderless: false`), gated off while a segment is disabled.
@@ -17,14 +17,102 @@
17
17
  * the focused segment (WCAG 2.4.7), the same treatment `BottomNavTab` uses.
18
18
  */
19
19
 
20
- import { memo, useCallback, useEffect, useRef, useState } from "react";
21
- import { Animated, Pressable, StyleSheet, Text, View } from "react-native";
20
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
21
+ import { Animated, Platform, Pressable, StyleSheet, Text, View } from "react-native";
22
+ import Reanimated from "react-native-reanimated";
22
23
  import { useAnimatedValue, useMotion } from "../../core/motion/index.js";
24
+ import { useHaptics } from "../../core/haptics/index.js";
25
+ import { usePressState } from "../../core/motion/usePressState.js";
23
26
  import { Icon } from "../../core/icon/index.js";
27
+ import { rippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
24
28
  import { useTheme } from "../../theme/hooks.js";
29
+ import { floatingBackground, floatingSurfaceStyle } from "../../theme/platform/index.js";
25
30
  import { resolveSegmentedControlColors, resolveSegmentedControlSegmentAccessibility, resolveSegmentedControlSegmentHitSlop, SEGMENTED_CONTROL_SIZES, segmentedControlFocusRingStructure, segmentedControlPillStructure, segmentedControlSegmentStructure, segmentedControlTrackStructure } from "./SegmentedControl.variants.js";
26
31
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
27
32
  const ICON_STROKE = 2;
33
+ const AnimatedPressable = Reanimated.createAnimatedComponent(Pressable);
34
+ const SegmentButton = /*#__PURE__*/memo(function SegmentButton({
35
+ option,
36
+ selected,
37
+ segmentDisabled,
38
+ size,
39
+ fullWidth,
40
+ labelColor,
41
+ hitSlop,
42
+ focused,
43
+ onChange,
44
+ onLayout,
45
+ onFocus,
46
+ onBlur,
47
+ testID
48
+ }) {
49
+ const theme = useTheme();
50
+ const press = usePressState(segmentDisabled);
51
+ const a11y = resolveSegmentedControlSegmentAccessibility({
52
+ selected,
53
+ disabled: segmentDisabled
54
+ });
55
+ const spec = SEGMENTED_CONTROL_SIZES[size];
56
+ const overlayStaticStyle = useMemo(() => ({
57
+ backgroundColor: stateLayerScrim(theme.mode),
58
+ borderRadius: theme.radii.md,
59
+ borderCurve: "continuous"
60
+ }), [theme.mode, theme.radii.md]);
61
+ const androidRipple = useMemo(() => {
62
+ if (Platform.OS !== "android" || segmentDisabled) return undefined;
63
+ return {
64
+ color: rippleColor(theme.mode),
65
+ borderless: false
66
+ };
67
+ }, [segmentDisabled, theme.mode]);
68
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
69
+ testID: testID,
70
+ accessibilityRole: a11y.accessibilityRole,
71
+ "aria-selected": a11y["aria-selected"],
72
+ "aria-disabled": a11y["aria-disabled"],
73
+ accessibilityLabel: option.label,
74
+ disabled: a11y.disabled,
75
+ onPress: segmentDisabled ? undefined : () => onChange(option.value),
76
+ onLayout: event => {
77
+ press.onLayout(event);
78
+ onLayout(option.value, event);
79
+ },
80
+ onFocus: () => onFocus(option.value),
81
+ onBlur: () => onBlur(option.value),
82
+ onPressIn: press.handlers.onPressIn,
83
+ onPressOut: press.handlers.onPressOut,
84
+ hitSlop: hitSlop,
85
+ android_ripple: androidRipple,
86
+ style: [segmentedControlSegmentStructure(theme, {
87
+ size,
88
+ fullWidth: fullWidth ? "on" : "off"
89
+ }), {
90
+ overflow: "hidden"
91
+ }, press.animatedStyle, option.disabled === true && !segmentDisabled && styles.dimmed],
92
+ children: [/*#__PURE__*/_jsx(Reanimated.View, {
93
+ pointerEvents: "none",
94
+ style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
95
+ }), focused && /*#__PURE__*/_jsx(View, {
96
+ pointerEvents: "none",
97
+ testID: testID ? `${testID}-focus-ring` : undefined,
98
+ style: [segmentedControlFocusRingStructure(theme), {
99
+ borderColor: theme.colors.border.focus
100
+ }]
101
+ }), option.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
102
+ name: option.icon,
103
+ size: spec.iconSize,
104
+ color: labelColor,
105
+ strokeWidth: ICON_STROKE
106
+ }), /*#__PURE__*/_jsx(Text, {
107
+ numberOfLines: 1,
108
+ style: [theme.fontStyleForWeight(theme.fontWeights.medium), {
109
+ fontSize: spec.fontSize,
110
+ color: labelColor
111
+ }],
112
+ children: option.label
113
+ })]
114
+ });
115
+ });
28
116
  function SegmentedControlImpl({
29
117
  options,
30
118
  value,
@@ -37,8 +125,8 @@ function SegmentedControlImpl({
37
125
  }) {
38
126
  const theme = useTheme();
39
127
  const motion = useMotion();
128
+ const haptics = useHaptics();
40
129
  const colors = resolveSegmentedControlColors(theme.colors);
41
- const spec = SEGMENTED_CONTROL_SIZES[size];
42
130
  const hitSlop = resolveSegmentedControlSegmentHitSlop(size);
43
131
  const [layouts, setLayouts] = useState({});
44
132
  // Which segment holds keyboard/AT focus. One value rather than per-segment state: only one segment
@@ -78,11 +166,16 @@ function SegmentedControlImpl({
78
166
  return () => running.current?.stop();
79
167
  }, [activeLayout, motion, pillX]);
80
168
  useEffect(() => () => running.current?.stop(), []);
169
+ const handleChange = useCallback(optionValue => {
170
+ haptics.selection();
171
+ onChange(optionValue);
172
+ }, [haptics, onChange]);
81
173
  return /*#__PURE__*/_jsxs(View, {
82
174
  testID: testID,
83
175
  accessibilityRole: "tablist",
84
176
  style: [segmentedControlTrackStructure(theme), {
85
- backgroundColor: colors.track
177
+ backgroundColor: floatingBackground(theme, "sm"),
178
+ ...floatingSurfaceStyle(theme, "sm")
86
179
  }, disabled && styles.dimmed, style],
87
180
  children: [/*#__PURE__*/_jsx(Animated.View, {
88
181
  pointerEvents: "none",
@@ -97,50 +190,21 @@ function SegmentedControlImpl({
97
190
  }), options.map(option => {
98
191
  const selected = option.value === value;
99
192
  const segmentDisabled = disabled || option.disabled === true;
100
- const a11y = resolveSegmentedControlSegmentAccessibility({
101
- selected,
102
- disabled: segmentDisabled
103
- });
104
193
  const labelColor = selected ? colors.activeLabel : colors.inactiveLabel;
105
- return /*#__PURE__*/_jsxs(Pressable, {
106
- testID: testID ? `${testID}-${option.value}` : undefined,
107
- accessibilityRole: a11y.accessibilityRole,
108
- "aria-selected": a11y["aria-selected"],
109
- "aria-disabled": a11y["aria-disabled"],
110
- accessibilityLabel: option.label,
111
- disabled: a11y.disabled,
112
- onPress: segmentDisabled ? undefined : () => onChange(option.value),
113
- onLayout: event => handleSegmentLayout(option.value, event),
114
- onFocus: () => setFocusedValue(option.value),
115
- onBlur: () => setFocusedValue(current => current === option.value ? null : current),
194
+ return /*#__PURE__*/_jsx(SegmentButton, {
195
+ option: option,
196
+ selected: selected,
197
+ segmentDisabled: segmentDisabled,
198
+ size: size,
199
+ fullWidth: fullWidth,
200
+ labelColor: labelColor,
116
201
  hitSlop: hitSlop,
117
- style: ({
118
- pressed
119
- }) => [segmentedControlSegmentStructure(theme, {
120
- size,
121
- fullWidth: fullWidth ? "on" : "off"
122
- }), pressed && !selected && !segmentDisabled && {
123
- backgroundColor: colors.pressedSegment
124
- }, option.disabled === true && !disabled && styles.dimmed],
125
- children: [focusedValue === option.value && /*#__PURE__*/_jsx(View, {
126
- pointerEvents: "none",
127
- testID: testID ? `${testID}-${option.value}-focus-ring` : undefined,
128
- style: [segmentedControlFocusRingStructure(theme), {
129
- borderColor: theme.colors.border.focus
130
- }]
131
- }), option.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
132
- name: option.icon,
133
- size: spec.iconSize,
134
- color: labelColor,
135
- strokeWidth: ICON_STROKE
136
- }), /*#__PURE__*/_jsx(Text, {
137
- numberOfLines: 1,
138
- style: [theme.fontStyleForWeight(theme.fontWeights.medium), {
139
- fontSize: spec.fontSize,
140
- color: labelColor
141
- }],
142
- children: option.label
143
- })]
202
+ focused: focusedValue === option.value,
203
+ onChange: handleChange,
204
+ onLayout: handleSegmentLayout,
205
+ onFocus: setFocusedValue,
206
+ onBlur: v => setFocusedValue(current => current === v ? null : current),
207
+ testID: testID ? `${testID}-${option.value}` : undefined
144
208
  }, option.value);
145
209
  })]
146
210
  });
@@ -86,13 +86,14 @@ export const segmentedControlTrackStructure = createThemedVariants(theme => ({
86
86
  base: {
87
87
  flexDirection: "row",
88
88
  position: "relative",
89
- borderRadius: theme.radii.base,
89
+ borderRadius: theme.radii.md,
90
+ borderCurve: "continuous",
90
91
  padding: theme.space[1]
91
92
  }
92
93
  }));
93
94
 
94
95
  /**
95
- * The pill. `theme.radii.sm` — one step down from the track's `theme.radii.base` — nests cleanly
96
+ * The pill. `theme.radii.sm` — one step down from the track's `theme.radii.md` — nests cleanly
96
97
  * inside the track's own `space[1]` inset, the same "inner radius ≈ outer radius − inset" geometry
97
98
  * a nested rounded rect needs to read as concentric rather than mismatched. `top`/`bottom` pin it to
98
99
  * the row's own height (set by the segments, its flow siblings); `left`/`width` are driven by
@@ -27,7 +27,7 @@ context + a stateless helper with no React-tree footprint of its own, not a depe
27
27
 
28
28
  | Prop | Type | Default | Notes |
29
29
  |------|------|---------|-------|
30
- | `options` | `{ label: string; value: string; leading?: ReactNode }[]` | — | Required. `leading` is an optional fixed-size adornment (status chip / priority glyph / avatar) rendered before the row label AND on the trigger while that option is selected — the ReactNode content-slot precedent set by `ListItem`'s `leading`. |
30
+ | `options` | `SelectOption[]` | — | Required. Each option may set `tone` / `customColors` (same `custom` escape hatch as `Badge`). |
31
31
  | `value` | `string` | — | The currently selected option's `value`. |
32
32
  | `onValueChange` | `(value: string) => void` | — | Required. Fired on row press; the menu closes right after. |
33
33
  | `placeholder` | `string` | — | Shown when `value` matches no option. |
@@ -40,6 +40,16 @@ context + a stateless helper with no React-tree footprint of its own, not a depe
40
40
  No `icon` prop — the chevron/check glyphs are fixed to the component's own semantics, not
41
41
  caller-configurable.
42
42
 
43
+ ### `SelectOption`
44
+
45
+ | Field | Type | Notes |
46
+ |-------|------|-------|
47
+ | `label` | `string` | Row label (required). |
48
+ | `value` | `string` | Stable id (required). |
49
+ | `leading` | `ReactNode` | Optional fixed-size adornment on the row and trigger. |
50
+ | `tone` | `SelectOptionTone` | Optional label colour from role tokens, or `"custom"`. |
51
+ | `customColors` | `{ bg, fg }` | Required when `tone="custom"`. Label reads `fg`. |
52
+
43
53
  ## Accessibility contract (WCAG)
44
54
 
45
55
  - **2.5.x target size** — every trigger size reaches ≥ 44dp via `hitSlop`; option rows have a
@@ -56,14 +66,25 @@ caller-configurable.
56
66
  `bg.selected` isn't proven ≥ 4.5:1 against `fg.default` on every brand (measured: fails on
57
67
  radiant/rosewood light), so `resolveSelectRowColors` keeps the row fill at `bg.surface` for every
58
68
  row, selected or not.
59
- - Each option row is `accessibilityRole="menuitem"` with flat `aria-selected`; the "check" icon is
60
- the sighted echo of the same state, never the only signal.
69
+ - Each option row is `accessibilityRole="option"` with flat `aria-selected`; the "check" icon is
70
+ the sighted echo of the same state, never the only signal. **2026-08 sweep:** rows were
71
+ `accessibilityRole="menuitem"`, which made `aria-selected` invalid ARIA (only valid on
72
+ `option`/`row`/`tab`/`gridcell`/`treeitem`). Unlike `OrgSwitcher`'s identical bug — fixed to
73
+ `role="radio"` + `aria-checked` because that sheet's row list carries no `listbox` role — Select's
74
+ rows sit inside a `SELECT_LISTBOX_ROLE` (`"listbox"`) container, so `option` + `aria-selected` is
75
+ the textbook-correct ARIA listbox pattern; only the row's `accessibilityRole` changed, `aria-selected`
76
+ was already the right prop.
61
77
  - **2.3.3** — RN's `Modal animationType` is always `"none"`; the reveal is `core/motion`'s
62
78
  `useReveal`, which snaps to the final state (no tween) under reduce-motion. Row press feedback
63
79
  and the check fade go through the same `motion.enabled` gate. Covered by
64
80
  `__tests__/Select.motion.test.tsx`.
65
81
  - Disabled is exempt from the contrast minimum (WCAG 1.4.3) — like Button, it's signalled by a
66
82
  uniform `opacity: 0.5` dim rather than a separate, still-must-pass colour pair.
83
+ - **Android touch feedback** — the trigger and every option row carry `android_ripple`
84
+ (`rippleColor(theme.mode)`, `borderless: false`), gated on `Platform.OS === "android"`. The trigger
85
+ and the sheet container both gained `overflow: "hidden"` so the ripple clips to their rounded
86
+ bounds — rows have no radius of their own, the sheet does. The backdrop carries no ripple; it is
87
+ `accessible={false}` and not a real press target.
67
88
 
68
89
  ## Patterns copied from Button (the reference module)
69
90
 
@@ -86,9 +107,9 @@ the tab stop, and `useFocusTrap` needs the focused node to still be tabbable or
86
107
  sheet. `useFocusTrap` also restores focus to the trigger on close; `useDismissOnEscape` closes on
87
108
  Escape.
88
109
 
89
- **`useRovingKeys` gets no `onActivate`.** RNW already presses a `menuitem` on Enter, and Space is
110
+ **`useRovingKeys` gets no `onActivate`.** RNW already presses on Enter regardless of role, and Space is
90
111
  supplied per row by `useSpaceActivation` (RNW's `isValidKeyPress` needs a `button` tag/role, which
91
- `menuitem` deliberately is not) — passing `onActivate` too would select twice.
112
+ `option` deliberately is not) — passing `onActivate` too would select twice.
92
113
 
93
114
  The list container is `SELECT_LISTBOX_ROLE`: RN 0.86's role unions have no `listbox`, so the
94
115
  widening is one audited cast in `Select.variants.ts` rather than a cast at the call site.
@@ -10,10 +10,14 @@ import { focusItemProps, useDismissOnEscape, useFocusTrap, useRovingKeys, useSpa
10
10
  import { Icon } from "../../core/icon/index.js";
11
11
  import { VirtualList } from "../../core/list/index.js";
12
12
  import { useMotion, usePressMotion, useReveal } from "../../core/motion/index.js";
13
+ import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
14
+ import { rippleColor } from "../../theme/platform/stateLayer.native.js";
15
+ import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
16
+ import { withAlpha } from "../../core/gradient/index.js";
13
17
  import { useTheme } from "../../theme/hooks.js";
14
18
  import { ModalPortalContext } from "../modal/ModalPortalContext.js";
15
19
  import { renderWebPortal } from "../modal/renderWebPortal";
16
- import { resolveSelectAccessibility, resolveSelectRowColors, resolveSelectTriggerColors, SELECT_LISTBOX_ROLE, SELECT_ROW_ICON_SIZE, SELECT_ROW_MIN_HEIGHT, SELECT_SIZES, selectOverlayStructure, selectRowLeadingStructure, selectRowStructure, selectSheetStructure, selectTriggerStructure, selectTriggerValueStructure } from "./Select.variants.js";
20
+ import { resolveSelectAccessibility, resolveSelectOptionLabelColor, resolveSelectRowColors, resolveSelectTriggerColors, SELECT_LISTBOX_ROLE, SELECT_OPTION_ROLE, SELECT_ROW_ICON_SIZE, SELECT_ROW_MIN_HEIGHT, SELECT_SIZES, selectOverlayStructure, selectRowLeadingStructure, selectRowStructure, selectSheetStructure, selectTriggerStructure, selectTriggerValueStructure } from "./Select.variants.js";
17
21
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
18
22
  const ICON_STROKE = 2;
19
23
  const BACKDROP_SCRIM = "#00000099";
@@ -29,6 +33,10 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
29
33
  const motion = useMotion();
30
34
  const press = usePressMotion();
31
35
  const handlePress = useCallback(() => onSelect(option), [onSelect, option]);
36
+ const androidRipple = useMemo(() => Platform.OS === "android" ? {
37
+ color: rippleColor(theme.mode),
38
+ borderless: false
39
+ } : undefined, [theme.mode]);
32
40
  const rowRef = useRef(null);
33
41
  const active = tabIndex === 0;
34
42
 
@@ -39,7 +47,7 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
39
47
  rowRef.current?.focus();
40
48
  }, [active]);
41
49
 
42
- // `menuitem` is not `button`, so RNW never presses on Space — see `core/a11y/keyboard.web.ts`.
50
+ // `option` is not `button`, so RNW never presses on Space — see `core/a11y/keyboard.web.ts`.
43
51
  useSpaceActivation(rowRef, handlePress);
44
52
  const checkOpacity = useRef(new Animated.Value(selected ? 1 : 0)).current;
45
53
  const skipFirst = useRef(true);
@@ -73,17 +81,18 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
73
81
  const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
74
82
  flex: 1,
75
83
  fontSize: theme.fontSizes.md,
76
- color: rowColors.text
77
- }], [theme, rowColors]);
84
+ color: resolveSelectOptionLabelColor(theme.colors, option.tone, option.customColors)
85
+ }], [theme, option.tone, option.customColors]);
78
86
  return /*#__PURE__*/_jsx(Pressable, {
79
87
  ref: rowRef,
80
88
  testID: testID ? `${testID}-option-${option.value}` : undefined,
81
- accessibilityRole: "menuitem",
89
+ accessibilityRole: SELECT_OPTION_ROLE,
82
90
  "aria-selected": selected,
83
91
  tabIndex: tabIndex,
84
92
  onPress: handlePress,
85
93
  onPressIn: press.onPressIn,
86
94
  onPressOut: press.onPressOut,
95
+ android_ripple: androidRipple,
87
96
  style: rowStyle,
88
97
  children: /*#__PURE__*/_jsxs(Animated.View, {
89
98
  testID: testID ? `${testID}-option-${option.value}-content` : undefined,
@@ -156,7 +165,7 @@ export const Select = /*#__PURE__*/memo(function Select({
156
165
  const typeaheadLabels = useMemo(() => options.map(option => option.label), [options]);
157
166
 
158
167
  // Keyboard (web only — every hook below is a no-op on native, see `core/a11y/keyboard.ts`).
159
- // No `onActivate`: RNW already presses a `menuitem` on Enter, and each row's own
168
+ // No `onActivate`: RNW already presses on Enter regardless of role, and each row's own
160
169
  // `useSpaceActivation` owns Space — passing it here would select twice.
161
170
  useDismissOnEscape(open, closeMenu);
162
171
  useFocusTrap(sheetRef, open);
@@ -183,14 +192,29 @@ export const Select = /*#__PURE__*/memo(function Select({
183
192
  const triggerStyle = useMemo(() => [selectTriggerStructure(theme, {
184
193
  size
185
194
  }), {
186
- backgroundColor: triggerColors.background,
187
- borderColor: triggerColors.border
188
- }, disabled && styles.dimmed], [theme, size, triggerColors, disabled]);
195
+ backgroundColor: focused || open ? withAlpha(theme.colors.accent.solid, 0.04) : triggerColors.background,
196
+ borderColor: triggerColors.border,
197
+ borderWidth: focused || open ? 2 : theme.borderWidths.thin,
198
+ overflow: "hidden"
199
+ }, disabled && styles.dimmed], [theme, size, triggerColors, disabled, focused, open]);
189
200
  const valueStructure = useMemo(() => selectTriggerValueStructure(theme), [theme]);
190
201
  const overlayStructure = useMemo(() => selectOverlayStructure(theme), [theme]);
191
- const sheetStyle = useMemo(() => [selectSheetStructure(theme), {
192
- backgroundColor: theme.colors.bg.surface
193
- }], [theme]);
202
+ const floatingStyle = useMemo(() => {
203
+ highlight("subtle", theme.mode);
204
+ elevation(elevationTokens.md);
205
+ void theme.elevatedSurfaces;
206
+ return {
207
+ backgroundColor: floatingBackground(theme, "md"),
208
+ ...floatingSurfaceStyle(theme, "md")
209
+ };
210
+ }, [theme]);
211
+ const sheetStyle = useMemo(() => [selectSheetStructure(theme), floatingStyle, {
212
+ overflow: "hidden"
213
+ }], [theme, floatingStyle]);
214
+ const androidRipple = useMemo(() => Platform.OS === "android" ? {
215
+ color: rippleColor(theme.mode),
216
+ borderless: false
217
+ } : undefined, [theme.mode]);
194
218
  const fieldLabelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.medium), {
195
219
  fontSize: theme.fontSizes.sm,
196
220
  color: theme.colors.fg.muted,
@@ -231,6 +255,8 @@ export const Select = /*#__PURE__*/memo(function Select({
231
255
  }), portalContainer) : null : /*#__PURE__*/_jsx(Modal, {
232
256
  visible: open,
233
257
  transparent: true,
258
+ statusBarTranslucent: true,
259
+ navigationBarTranslucent: true,
234
260
  animationType: "none",
235
261
  onRequestClose: closeMenu,
236
262
  children: sheet
@@ -251,6 +277,7 @@ export const Select = /*#__PURE__*/memo(function Select({
251
277
  onFocus: handleFocus,
252
278
  onBlur: handleBlur,
253
279
  hitSlop: spec.hitSlop,
280
+ android_ripple: androidRipple,
254
281
  style: triggerStyle,
255
282
  children: [/*#__PURE__*/_jsxs(View, {
256
283
  style: valueStructure,
@@ -22,32 +22,41 @@ import { createThemedVariants } from "../../core/style/index.js";
22
22
  */
23
23
  export const SELECT_LISTBOX_ROLE = "listbox";
24
24
 
25
+ /**
26
+ * Each option row's role. `aria-selected` is only valid ARIA on `option`/`row`/`tab`/`gridcell`/
27
+ * `treeitem` — the row sits inside a `SELECT_LISTBOX_ROLE` container, so `option` is the
28
+ * textbook-correct pairing (2026-08 sweep fixed the row from the invalid `menuitem`+`aria-selected`
29
+ * combination). Same type gap as `SELECT_LISTBOX_ROLE`: RN 0.86's `AccessibilityRole` union has no
30
+ * `option` either.
31
+ */
32
+ export const SELECT_OPTION_ROLE = "option";
33
+
25
34
  /** Same touch-target floor as Button (44dp — Apple HIG minimum, WCAG 2.5.5 AAA). */
26
35
  export const MIN_TOUCH_TARGET = 44;
27
36
  const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2));
28
37
  export const SELECT_SIZES = {
29
38
  sm: {
30
- height: 32,
39
+ height: 44,
31
40
  fontSize: 14,
32
41
  iconSize: 16,
33
- hitSlop: slopFor(32)
42
+ hitSlop: slopFor(44)
34
43
  },
35
44
  md: {
36
- height: 40,
45
+ height: 52,
37
46
  fontSize: 16,
38
47
  iconSize: 18,
39
- hitSlop: slopFor(40)
48
+ hitSlop: slopFor(52)
40
49
  },
41
50
  lg: {
42
- height: 48,
51
+ height: 56,
43
52
  fontSize: 18,
44
53
  iconSize: 20,
45
- hitSlop: slopFor(48)
54
+ hitSlop: slopFor(56)
46
55
  }
47
56
  };
48
57
 
49
58
  /** Minimum height for an option row — a list item is still an interactive target (WCAG 2.5.8). */
50
- export const SELECT_ROW_MIN_HEIGHT = 44;
59
+ export const SELECT_ROW_MIN_HEIGHT = 48;
51
60
 
52
61
  /** The "check" glyph beside the active row. Fixed — independent of the trigger's own `size`. */
53
62
  export const SELECT_ROW_ICON_SIZE = 18;
@@ -60,7 +69,7 @@ export const SELECT_ROW_ICON_SIZE = 18;
60
69
  export function resolveSelectTriggerColors(colors, focused) {
61
70
  return {
62
71
  background: colors.bg.surface,
63
- border: focused ? colors.border.focus : colors.border.interactive,
72
+ border: focused ? colors.accent.solid : colors.border.interactive,
64
73
  text: colors.fg.default,
65
74
  placeholder: colors.fg.muted,
66
75
  icon: colors.fg.muted
@@ -74,6 +83,20 @@ export function resolveSelectRowColors(colors) {
74
83
  pressedRow: colors.bg.sunken
75
84
  };
76
85
  }
86
+ export function resolveSelectOptionLabelColor(colors, tone, customColors) {
87
+ if (tone === undefined) {
88
+ return colors.fg.default;
89
+ }
90
+ if (tone === "custom") {
91
+ if (!customColors) {
92
+ throw new Error('SelectOption tone="custom" requires customColors={{ bg, fg }}.');
93
+ }
94
+ return customColors.fg;
95
+ }
96
+ if (tone === "accent") return colors.accent.text;
97
+ if (tone === "neutral") return colors.fg.default;
98
+ return colors.status[tone].text;
99
+ }
77
100
  /**
78
101
  * Derives the trigger's accessibility surface once, purely: `expanded` tracks whether the option
79
102
  * list is showing (WCAG 4.1.2 — a collapsible control must expose its expanded/collapsed state),
@@ -99,7 +122,8 @@ export const selectTriggerStructure = createThemedVariants(theme => ({
99
122
  alignItems: "center",
100
123
  justifyContent: "space-between",
101
124
  columnGap: theme.space[2],
102
- borderRadius: theme.radii.base,
125
+ borderRadius: theme.radii.md,
126
+ borderCurve: "continuous",
103
127
  borderWidth: theme.borderWidths.thin
104
128
  },
105
129
  variants: {
@@ -145,10 +169,10 @@ export const selectOverlayStructure = createThemedVariants(theme => ({
145
169
  }));
146
170
  export const selectSheetStructure = createThemedVariants(theme => ({
147
171
  base: {
148
- borderRadius: theme.radii.base,
172
+ borderRadius: theme.radii.lg,
173
+ borderCurve: "continuous",
149
174
  paddingVertical: theme.space[2],
150
- maxHeight: 320,
151
- ...theme.elevation.lg
175
+ maxHeight: 320
152
176
  }
153
177
  }));
154
178
  export const selectRowStructure = createThemedVariants(theme => ({