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
@@ -1,12 +1,13 @@
1
1
  # button-group/ — a segmented single-choice control
2
2
 
3
- Visually connected segments sharing one outer border and a divider line between adjacent
4
- segments — NOT a row of standalone `Button`s. One component owns the whole group, same shape as
5
- `radio-group/`: each segment carries its own `accessibilityRole="radio"`; the container carries
6
- `accessibilityRole="radiogroup"` so assistive tech announces the grouping without collapsing the
7
- individually-focusable segments into one. The border/divider is drawn PER SEGMENT (never once on
8
- the container) so it can be selectively omitted where it touches the selected segment — see
9
- **1.4.11** below.
3
+ Segments sit on one shared tonal container fill (`bg.raised`) with a hairline divider between
4
+ adjacent unselected segments — NOT a row of standalone `Button`s. One component owns the whole
5
+ group, same shape as `radio-group/`: each segment carries its own `accessibilityRole="radio"`; the
6
+ container carries `accessibilityRole="radiogroup"` so assistive tech announces the grouping without
7
+ collapsing the individually-focusable segments into one. The divider is drawn PER SEGMENT (never
8
+ once on the container) so it can be selectively omitted where it touches the selected segment — see
9
+ **1.4.11** below. There is no outer frame border any more (Wave 5 tonal restyle) — the container's
10
+ own fill carries the group's shape.
10
11
 
11
12
  ## Files
12
13
 
@@ -65,18 +66,12 @@ appearances. The selected fill is always `accent.solid`; the shared outline/divi
65
66
  canvas (resting) and `bg.sunken` (pressed) — NOT `bg.hover`, whose saturated mid-tone was measured
66
67
  to drop the brand-tinted label below 4.5:1 on several brands, the same class of bug Button's
67
68
  "neutral" tone and RadioGroup's pressed row document fixing the same way.
68
- - **1.4.11** — the shared `outline` token (`border.interactive`) clears 3:1 against `bg.canvas` on
69
- every brand × mode, but measured against a SELECTED segment's `accent.solid` fill it FAILS 3:1 on
70
- 15 of 16 brand × mode combinations (some catastrophically: slate light 1.00, emerald light 1.02).
71
- Because `value` is required, some segment is always selected that adjacency is every render, not
72
- an edge case, and it previously went unmeasured (the shipped test only checked outline-vs-canvas).
73
- Fixed: `resolveButtonGroupSegmentEdgeColors` computes, per edge of per segment, whether that edge
74
- touches the selected segment; any edge that does gets `transparent` instead of `outline`, and the
75
- boundary there is served instead by the selected fill's own contrast against the canvas —
76
- `accent.solid` clears 3:1 against `bg.canvas` on all 16 brand × mode combinations (worst case
77
- 3.24:1, emerald light) — the same mechanism every other solid-fill component in this library
78
- already relies on. `ButtonGroup.test.ts` measures every actually-rendered boundary pairing (not
79
- just the easy outline-vs-canvas one) for first/middle/last selected × all 8 brands × both modes.
69
+ - **1.4.11** — the shared `outline` token (`border.interactive`) is now only ever drawn as the
70
+ divider between two adjacent unselected segments; any edge touching the selected segment gets
71
+ `transparent` instead, and the boundary there is served by `accent.solid` (`selectedFill`) against
72
+ the group's own `containerFill` (`bg.raised`) measured 3:1 on all 16 brand × mode combinations
73
+ (worst case 3.31:1, rosewood light). `ButtonGroup.test.ts` measures every actually-rendered
74
+ boundary for first/middle/last selected × all 8 brands × both modes.
80
75
  - **2.1.1 (keyboard) — roving tabindex.** `accessibilityRole="radio"` per segment means ARIA requires
81
76
  the group to be ONE tab stop whose arrows both move and select. `tabIndex` is `0` on exactly one
82
77
  segment and `-1` on the rest; arrows move and select (wrapping), Home/End jump to the ends
@@ -92,8 +87,8 @@ appearances. The selected fill is always `accent.solid`; the shared outline/divi
92
87
  offsets inside the segment instead; `ButtonGroup.render.test.tsx` asserts both halves — that the
93
88
  container really clips, and that every ring edge is a positive inset that therefore survives it.
94
89
  Segments also carry `focusable={!disabled}`, since RN's `Pressable` stays focusable when disabled.
95
- - **2.3.3** — n/a: nothing here animates. Selection is a conditional fill (not a slide or a fade), so
96
- there is no transition for `useReducedMotion` to gate — same as `RadioGroup`.
90
+ - **2.3.3** — n/a for selection (conditional fill, not a slide). Segment presses use `usePressState`
91
+ (scale + state-layer overlay), which snaps under reduce motion — same gating as `Button`.
97
92
  - Disabled segments are exempt from the contrast minimum (WCAG 1.4.3), so the uniform `opacity: 0.5`
98
93
  dim is correct, same as Button/RadioGroup.
99
94
 
@@ -105,15 +100,12 @@ appearances. The selected fill is always `accent.solid`; the shared outline/divi
105
100
  and — per edge, per segment — `outline` vs `transparent`) is resolved by `resolveButtonGroupColors`
106
101
  / `resolveButtonGroupSegmentEdgeColors` from role tokens and applied inline over the structural
107
102
  style.
108
- 2. **One connected control, not N buttons — and the border lives on the segments, not the container.**
109
- The container is only a clipping rect (`overflow: 'hidden'` + `borderRadius`, no border of its
110
- own): it clips a filled end segment's square corner into the shared rounded shape. Every segment
111
- structurally carries its own top/bottom/right border; the right one is the divider on every
112
- segment except the last, where it is instead that segment's own outer right edge; only the FIRST
113
- segment gets a left border + left-corner radii, only the LAST gets right-corner radii. A single
114
- container-wide border could never be selectively omitted per segment (one colour for its whole
115
- perimeter), which is exactly why 1.4.11 shipped broken the first time — moving the border onto the
116
- segments is what makes the WCAG fix possible at all.
103
+ 2. **One connected control, not N buttons — the divider lives on the segments, the shape on the
104
+ container.** The container clips (`overflow: 'hidden'` + `borderRadius`) AND carries the tonal
105
+ `containerFill`; it clips a filled end segment's square corner into the shared rounded shape.
106
+ Every segment but the last structurally carries its own right border, the divider between it and
107
+ its neighbour; a single container-wide border could never be selectively omitted per segment (one
108
+ colour for its whole perimeter), which is why the divider still lives on the segments.
117
109
  3. **Pure, testable resolvers** in `ButtonGroup.variants.ts` (no React) so the WCAG + behaviour
118
110
  contract is unit-tested against the real palettes — never eyeballed.
119
111
  4. **No `{...rest}`, `style` once on the outermost node**, no icon (per spec), no import from
@@ -148,6 +140,9 @@ an `if (dark)` branch. Worst case now 3.08:1 (rosewood light); the unselected la
148
140
 
149
141
  Wrapped in `React.memo` (repo-wide re-render audit, 2026-07-17 — see root `CLAUDE.md`) — renamed to `ButtonGroupImpl` internally, exported as `ButtonGroup = memo(ButtonGroupImpl)`. The `options.map()` hands every per-row prop to host elements (`Pressable`/`Text`/`View`), never a library child component, so no `useCallback`/`useMemo` was needed.
150
142
 
143
+ Android segments carry `android_ripple` (mirrors Button/RadioGroup), gated off while
144
+ `disabled || selected` since a selected segment already reads via its fill.
145
+
151
146
  ## Modernization (v1.0.7)
152
147
 
153
148
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
@@ -1,42 +1,140 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * Card — a plain container for grouping content. No interaction, no text of its own: `children` is
5
- * ordinary composition (a consumer places `Text`, `Button`, whatever it needs inside), so there is
6
- * nothing here for `accessibilityRole` to announce — the container is intentionally invisible to
7
- * assistive tech and its children carry their own semantics, exactly like a plain `View` would.
4
+ * Card — a plain container for grouping content, optionally pressable. When `onPress` is absent the
5
+ * root is a plain `View` with no press hook or animated values. Children carry their own semantics.
8
6
  */
9
7
 
10
- import { memo, useMemo } from "react";
11
- import { View } from "react-native";
8
+ import { memo, useCallback, useMemo } from "react";
9
+ import { Platform, Pressable, StyleSheet, View } from "react-native";
10
+ import Animated from "react-native-reanimated";
11
+ import { usePressState } from "../../core/motion/usePressState.js";
12
+ import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
13
+ import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
14
+ import { rippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
12
15
  import { useTheme } from "../../theme/hooks.js";
13
16
  import { cardStructure, resolveCardVariant } from "./Card.variants.js";
14
- import { jsx as _jsx } from "react/jsx-runtime";
15
- function CardImpl({
16
- variant = "elevated",
17
- children,
18
- style,
19
- testID
20
- }) {
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ function useCardStyles(variant, style) {
21
19
  const theme = useTheme();
22
- const rootStyle = useMemo(() => {
20
+ return useMemo(() => {
23
21
  const variantColors = resolveCardVariant(theme.colors, variant);
22
+ const elevated = variant === "elevated";
23
+ highlight("subtle", theme.mode);
24
+ elevation(elevationTokens.sm);
25
+ const elevatedBg = elevated ? floatingBackground(theme, "sm") : variantColors.background;
24
26
  return [cardStructure(theme, {
25
27
  variant
26
28
  }), {
27
- backgroundColor: variantColors.background
29
+ backgroundColor: elevatedBg,
30
+ borderCurve: "continuous"
28
31
  }, variantColors.border !== undefined && {
29
32
  borderColor: variantColors.border
30
- }, variant === "elevated" && theme.elevation.md, style];
33
+ }, elevated && floatingSurfaceStyle(theme, "sm"), style];
31
34
  }, [theme, variant, style]);
35
+ }
36
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
37
+ function StaticCard({
38
+ variant,
39
+ children,
40
+ style,
41
+ testID
42
+ }) {
43
+ const rootStyle = useCardStyles(variant, style);
32
44
  return /*#__PURE__*/_jsx(View, {
33
45
  testID: testID,
34
46
  style: rootStyle,
35
47
  children: children
36
48
  });
37
49
  }
38
-
39
- // A consumer's screen re-renders far more often than Card's own props change — memo is near-free
40
- // insurance for a design-system primitive (see CLAUDE.md "Performance" section).
50
+ function PressableCard({
51
+ variant,
52
+ children,
53
+ style,
54
+ testID,
55
+ onPress,
56
+ onLongPress,
57
+ disabled = false
58
+ }) {
59
+ const theme = useTheme();
60
+ const blocked = disabled;
61
+ const press = usePressState(blocked);
62
+ const rootStyle = useCardStyles(variant, style);
63
+ const overlayStaticStyle = useMemo(() => ({
64
+ backgroundColor: stateLayerScrim(theme.mode),
65
+ borderRadius: theme.radii.lg,
66
+ borderCurve: "continuous"
67
+ }), [theme.mode, theme.radii.lg]);
68
+ const handlePressOut = useCallback(() => {
69
+ press.handlers.onPressOut();
70
+ }, [press.handlers]);
71
+ const androidRipple = useMemo(() => {
72
+ if (Platform.OS !== "android" || blocked) return undefined;
73
+ return {
74
+ color: rippleColor(theme.mode),
75
+ borderless: false
76
+ };
77
+ }, [blocked, theme.mode]);
78
+ return /*#__PURE__*/_jsx(AnimatedPressable, {
79
+ testID: testID,
80
+ accessibilityRole: "button",
81
+ disabled: blocked,
82
+ onPress: blocked ? undefined : onPress,
83
+ onLongPress: blocked ? undefined : onLongPress,
84
+ onPressIn: press.handlers.onPressIn,
85
+ onPressOut: handlePressOut,
86
+ onLayout: press.onLayout,
87
+ android_ripple: androidRipple,
88
+ style: [rootStyle, press.animatedStyle, blocked && styles.dimmed, {
89
+ overflow: "hidden"
90
+ }],
91
+ children: /*#__PURE__*/_jsxs(View, {
92
+ style: styles.rippleClip,
93
+ pointerEvents: "box-none",
94
+ children: [/*#__PURE__*/_jsx(Animated.View, {
95
+ pointerEvents: "none",
96
+ testID: testID === undefined ? undefined : `${testID}-press-overlay`,
97
+ style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
98
+ }), children]
99
+ })
100
+ });
101
+ }
102
+ function CardImpl({
103
+ variant = "elevated",
104
+ children,
105
+ onPress,
106
+ onLongPress,
107
+ disabled = false,
108
+ style,
109
+ testID
110
+ }) {
111
+ if (onPress === undefined) {
112
+ return /*#__PURE__*/_jsx(StaticCard, {
113
+ variant: variant,
114
+ style: style,
115
+ testID: testID,
116
+ children: children
117
+ });
118
+ }
119
+ return /*#__PURE__*/_jsx(PressableCard, {
120
+ variant: variant,
121
+ style: style,
122
+ testID: testID,
123
+ onPress: onPress,
124
+ onLongPress: onLongPress,
125
+ disabled: disabled,
126
+ children: children
127
+ });
128
+ }
129
+ const styles = StyleSheet.create({
130
+ dimmed: {
131
+ opacity: 0.5
132
+ },
133
+ rippleClip: {
134
+ flex: 1,
135
+ overflow: "hidden",
136
+ borderRadius: 0
137
+ }
138
+ });
41
139
  export const Card = /*#__PURE__*/memo(CardImpl);
42
140
  //# sourceMappingURL=Card.js.map
@@ -53,6 +53,7 @@ export function resolveCardVariant(colors, variant) {
53
53
  export const cardStructure = createThemedVariants(theme => ({
54
54
  base: {
55
55
  borderRadius: theme.radii.lg,
56
+ borderCurve: "continuous",
56
57
  padding: theme.space[4]
57
58
  },
58
59
  variants: {
@@ -1,13 +1,15 @@
1
1
  # card/ — a plain, variant-driven container
2
2
 
3
3
  `Card` groups content with a themed background, optional border, and optional elevation. It takes
4
- no icon, no press handler, and renders no text of its own — `children` is ordinary composition.
4
+ no icon and renders no text of its own — `children` is ordinary composition. When `onPress` is
5
+ provided the root becomes a pressable surface with scale + state-layer feedback; otherwise it stays
6
+ a plain `View` with no press hook.
5
7
 
6
8
  ## Files
7
9
 
8
10
  | File | Role |
9
11
  |------|------|
10
- | `Card.tsx` | The component. Resolves the variant's colours + elevation, applies them inline over the structural style, in that order, `style` last. |
12
+ | `Card.tsx` | The component. Resolves variant colours + `floatingSurfaceStyle` for `elevated`, applies inline over structure, `style` last. |
11
13
  | `Card.variants.ts` | Pure resolver (`resolveCardVariant`) + the themed structural variant resolver `cardStructure`. No React. |
12
14
  | `index.ts` | Public surface: `Card`, `CardProps`, `CardVariant`. |
13
15
  | `__tests__/Card.test.ts` | Pure: WCAG 1.4.11 (outline border, all brands × modes) + variant→colour resolution. |
@@ -18,6 +20,9 @@ no icon, no press handler, and renders no text of its own — `children` is ordi
18
20
  | Prop | Type | Default | Notes |
19
21
  |------|------|---------|-------|
20
22
  | `variant` | `elevated \| outline \| flat` | `elevated` | Closed union — see below. |
23
+ | `onPress` | `() => void` | — | When set, root is `Pressable` with `usePressState` feedback. |
24
+ | `onLongPress` | `(event) => void` | — | Only when `onPress` is set. |
25
+ | `disabled` | `boolean` | `false` | Only when `onPress` is set. |
21
26
  | `children` | `ReactNode` | — | Ordinary composition, not a prop spread. |
22
27
  | `style` | `LayoutStyle` | — | Layout-only, outermost, applied exactly once, last. |
23
28
  | `testID` | `string` | — | Forwarded to the outermost `View`. |
@@ -28,7 +33,7 @@ no icon, no press handler, and renders no text of its own — `children` is ordi
28
33
  |---------|-----------|--------|-----------|
29
34
  | `flat` | `bg.surface` | none | none |
30
35
  | `outline` | `bg.surface` | `border.interactive`, `borderWidths.thin` | none |
31
- | `elevated` (default) | `bg.raised` | none | `theme.elevation.md` (already-rendered `ElevationStyle`, spread as-is never re-derived) |
36
+ | `elevated` (default) | `floatingBackground(sm)` in dark | none | `floatingSurfaceStyle(sm)` `elevation` + `highlight` + `borderCurve` |
32
37
 
33
38
  Padding (`theme.space[4]`) and radius (`theme.radii.lg`) are shared across all three variants via
34
39
  `cardStructure`; only border WIDTH varies by variant there (colour is resolved separately and
@@ -49,17 +54,15 @@ edge. `elevated` additionally separates itself with a shadow, not a colour jump.
49
54
 
50
55
  ## Accessibility contract (WCAG)
51
56
 
52
- - **No `accessibilityRole`.** `Card` is a plain grouping container with no interaction and no text
53
- of its own — there is nothing here for assistive tech to announce beyond its children, so the
54
- *correct* role (rule 8) is none, exactly like an unstyled `View`. Children carry their own
55
- semantics.
57
+ - **No `accessibilityRole` when not pressable.** Plain grouping container children carry semantics.
58
+ When `onPress` is set, `accessibilityRole="button"`.
56
59
  - **1.4.11** — the only rendered non-text boundary (`outline`'s border) clears ≥ 3:1 against
57
60
  `bg.canvas`, measured for all 8 brands × both modes (`Card.test.ts`).
58
61
  - **1.4.3** — N/A. Card renders no text; contrast for whatever a consumer places in `children` is
59
62
  that content's own responsibility, same as `Button.test.ts` only measures what Button itself
60
63
  renders.
61
- - **2.3.3 (reduced motion)** — N/A. Card has no animation.
62
- - **Touch target (2.5.x)** — N/A. Card is not interactive; it has no press handler to reach 44dp.
64
+ - **2.3.3 (reduced motion)** — press feedback respects `usePressState` / `useMotion` when interactive.
65
+ - **Touch target (2.5.x)** — N/A unless `onPress` is set; the card's padded area is the target.
63
66
 
64
67
  ## Patterns copied from `button/` (the reference module)
65
68
 
@@ -74,7 +77,7 @@ edge. `elevated` additionally separates itself with a shadow, not a colour jump.
74
77
 
75
78
  ## Known gaps
76
79
 
77
- None — no icon, no new theme token, no new core helper needed for this component.
80
+ None.
78
81
 
79
82
  ## Performance
80
83
 
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  import { memo, useCallback, useMemo, useState } from "react";
4
- import { Pressable, StyleSheet, View } from "react-native";
4
+ import { Platform, Pressable, StyleSheet, View } from "react-native";
5
5
  import Svg, { Circle, Line, Path, Rect, Text as SvgText } from "react-native-svg";
6
+ import { useDeviceTier } from "../../core/device/index.js";
7
+ import { rippleColor } from "../../theme/platform/stateLayer.native.js";
6
8
  import { useTheme } from "../../theme/hooks.js";
7
9
  import { ChartLegend } from "./ChartLegend.js";
8
- import { BAR_MARKER_MIN_SPAN, BAR_MARKER_RADIUS, categoricalColorAt, defaultNumberFormatter, describeMarker, finiteOrZero, hitSlopFor, niceScale, resolveBarChartDomain, resolveBarLayout, resolveBarX, resolveChartAxisColors, scaleValue, seriesShapeAt, summarizeBarChart } from "./Charts.variants.js";
10
+ import { BAR_MARKER_MIN_SPAN, BAR_MARKER_RADIUS, categoricalColorAt, decimateCategories, defaultNumberFormatter, describeMarker, finiteOrZero, hitSlopFor, maxRenderedCategories, niceScale, resolveBarChartDomain, resolveBarLayout, resolveBarX, resolveChartAxisColors, scaleValue, seriesShapeAt, summarizeBarChart } from "./Charts.variants.js";
9
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
12
  const Y_AXIS_WIDTH = 40;
11
13
  const X_AXIS_HEIGHT = 24;
@@ -22,7 +24,8 @@ const BarPressTarget = /*#__PURE__*/memo(function BarPressTarget({
22
24
  height,
23
25
  label,
24
26
  testID,
25
- onPress
27
+ onPress,
28
+ androidRipple
26
29
  }) {
27
30
  const press = useCallback(() => onPress(categoryIndex, seriesIndex), [onPress, categoryIndex, seriesIndex]);
28
31
  const box = useMemo(() => ({
@@ -30,7 +33,8 @@ const BarPressTarget = /*#__PURE__*/memo(function BarPressTarget({
30
33
  left: x,
31
34
  top,
32
35
  width,
33
- height
36
+ height,
37
+ overflow: "hidden"
34
38
  }), [x, top, width, height]);
35
39
  return /*#__PURE__*/_jsx(Pressable, {
36
40
  testID: testID,
@@ -38,6 +42,7 @@ const BarPressTarget = /*#__PURE__*/memo(function BarPressTarget({
38
42
  accessibilityLabel: label,
39
43
  hitSlop: hitSlopFor(width, height),
40
44
  onPress: press,
45
+ android_ripple: androidRipple,
41
46
  style: box
42
47
  });
43
48
  });
@@ -57,23 +62,28 @@ export const BarChart = /*#__PURE__*/memo(function BarChart({
57
62
  const theme = useTheme();
58
63
  const axisColors = useMemo(() => resolveChartAxisColors(theme.colors), [theme.colors]);
59
64
  const [width, setWidth] = useState(0);
65
+ const tier = useDeviceTier();
60
66
  const onLayout = event => {
61
67
  setWidth(event.nativeEvent.layout.width);
62
68
  };
63
69
  const plotWidth = Math.max(0, width - Y_AXIS_WIDTH);
64
70
  const plotHeight = Math.max(0, height - X_AXIS_HEIGHT - PLOT_TOP);
65
- const summary = useMemo(() => summarizeBarChart(data, yAxisFormatter), [data, yAxisFormatter]);
66
- const seriesCount = useMemo(() => Math.max(1, data.reduce((max, datum) => Math.max(max, datum.values.length), 0)), [data]);
71
+
72
+ // An unbounded `data` array otherwise means unbounded svg nodes one bar, one label and one
73
+ // press target per category. Below the cap this is the same array reference as `data` itself.
74
+ const renderedData = useMemo(() => decimateCategories(data, maxRenderedCategories(tier)), [data, tier]);
75
+ const summary = useMemo(() => summarizeBarChart(renderedData, yAxisFormatter), [renderedData, yAxisFormatter]);
76
+ const seriesCount = useMemo(() => Math.max(1, renderedData.reduce((max, datum) => Math.max(max, datum.values.length), 0)), [renderedData]);
67
77
  const {
68
78
  bars,
69
79
  ticks,
70
80
  categories
71
81
  } = useMemo(() => {
72
- const domain = resolveBarChartDomain(data, stacked);
82
+ const domain = resolveBarChartDomain(renderedData, stacked);
73
83
  const scale = niceScale(domain.min, domain.max, TICK_COUNT);
74
- const layout = resolveBarLayout(data.length, seriesCount, plotWidth, stacked);
84
+ const layout = resolveBarLayout(renderedData.length, seriesCount, plotWidth, stacked);
75
85
  const zeroY = scaleValue(0, scale.min, scale.max, plotHeight, 0);
76
- const resolvedBars = data.flatMap((datum, categoryIndex) => {
86
+ const resolvedBars = renderedData.flatMap((datum, categoryIndex) => {
77
87
  let stackTop = 0;
78
88
  return datum.values.map((rawValue, seriesIndex) => {
79
89
  const value = finiteOrZero(rawValue);
@@ -120,16 +130,16 @@ export const BarChart = /*#__PURE__*/memo(function BarChart({
120
130
  y: PLOT_TOP + scaleValue(tick, scale.min, scale.max, plotHeight, 0),
121
131
  text: yAxisFormatter(tick)
122
132
  })),
123
- categories: data.map((datum, categoryIndex) => ({
133
+ categories: renderedData.map((datum, categoryIndex) => ({
124
134
  x: Y_AXIS_WIDTH + categoryIndex * layout.bandWidth + layout.bandWidth / 2,
125
135
  label: datum.label
126
136
  }))
127
137
  };
128
- }, [data, series, stacked, seriesCount, plotWidth, plotHeight, theme.colors, yAxisFormatter]);
138
+ }, [renderedData, series, stacked, seriesCount, plotWidth, plotHeight, theme.colors, yAxisFormatter]);
129
139
  const pressBar = useCallback((categoryIndex, seriesIndex) => {
130
- const datum = data[categoryIndex];
140
+ const datum = renderedData[categoryIndex];
131
141
  if (datum !== undefined) onPressBar?.(datum, seriesIndex);
132
- }, [data, onPressBar]);
142
+ }, [renderedData, onPressBar]);
133
143
  const legendEntries = useMemo(() => showLegend && seriesCount > 1 ? Array.from({
134
144
  length: seriesCount
135
145
  }, (_, index) => ({
@@ -140,6 +150,10 @@ export const BarChart = /*#__PURE__*/memo(function BarChart({
140
150
  const plotStyle = useMemo(() => ({
141
151
  height
142
152
  }), [height]);
153
+ const androidRipple = useMemo(() => Platform.OS === "android" ? {
154
+ color: rippleColor(theme.mode),
155
+ borderless: false
156
+ } : undefined, [theme.mode]);
143
157
  return /*#__PURE__*/_jsxs(View, {
144
158
  testID: testID,
145
159
  style: style,
@@ -229,7 +243,8 @@ export const BarChart = /*#__PURE__*/memo(function BarChart({
229
243
  width: bar.width,
230
244
  height: bar.height,
231
245
  label: bar.label,
232
- onPress: pressBar
246
+ onPress: pressBar,
247
+ androidRipple: androidRipple
233
248
  }, `press-${bar.categoryIndex}-${bar.seriesIndex}`))
234
249
  })]
235
250
  }), /*#__PURE__*/_jsx(ChartLegend, {
@@ -2,8 +2,9 @@
2
2
 
3
3
  import { memo, useCallback, useMemo } from "react";
4
4
  import { Pressable, StyleSheet, Text, View } from "react-native";
5
+ import { VirtualList } from "../../core/list/index.js";
5
6
  import { useTheme } from "../../theme/hooks.js";
6
- import { barListHeaderStructure, barListRowStructure, barListStructure, barListTrackStructure, resolveBarListColors } from "./Charts.variants.js";
7
+ import { BAR_LIST_ROW_HEIGHT, barListHeaderStructure, barListRowStructure, barListStructure, barListTrackStructure, resolveBarListColors } from "./Charts.variants.js";
7
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  function barFraction(value, max) {
9
10
  if (!Number.isFinite(value) || !Number.isFinite(max) || max <= 0) return 0;
@@ -97,25 +98,37 @@ export const BarList = /*#__PURE__*/memo(function BarList({
97
98
  const item = items[index];
98
99
  if (item !== undefined) onPressItem?.(item, index);
99
100
  }, [items, onPressItem]);
101
+ const contentContainerStyle = useMemo(() => barListStructure(theme), [theme]);
102
+ const keyExtractor = useCallback(row => row.key, []);
103
+ const renderItem = useCallback(({
104
+ item,
105
+ index
106
+ }) => /*#__PURE__*/_jsx(BarListRow, {
107
+ testID: testID === undefined ? undefined : `${testID}-item-${index}`,
108
+ index: index,
109
+ label: item.label,
110
+ value: item.value,
111
+ icon: item.icon,
112
+ fillWidth: item.fillWidth,
113
+ fillColor: item.fillColor,
114
+ trackColor: colors.track,
115
+ rowStyle: rowStyle,
116
+ headerStyle: headerStyle,
117
+ trackStyle: trackStyle,
118
+ labelTextStyle: labelTextStyle,
119
+ valueTextStyle: valueTextStyle,
120
+ onPress: onPressItem === undefined ? undefined : pressItem
121
+ }), [testID, colors.track, rowStyle, headerStyle, trackStyle, labelTextStyle, valueTextStyle, onPressItem, pressItem]);
100
122
  return /*#__PURE__*/_jsx(View, {
101
123
  testID: testID,
102
- style: [barListStructure(theme), style],
103
- children: rows.map((row, index) => /*#__PURE__*/_jsx(BarListRow, {
104
- testID: testID === undefined ? undefined : `${testID}-item-${index}`,
105
- index: index,
106
- label: row.label,
107
- value: row.value,
108
- icon: row.icon,
109
- fillWidth: row.fillWidth,
110
- fillColor: row.fillColor,
111
- trackColor: colors.track,
112
- rowStyle: rowStyle,
113
- headerStyle: headerStyle,
114
- trackStyle: trackStyle,
115
- labelTextStyle: labelTextStyle,
116
- valueTextStyle: valueTextStyle,
117
- onPress: onPressItem === undefined ? undefined : pressItem
118
- }, row.key))
124
+ style: style,
125
+ children: /*#__PURE__*/_jsx(VirtualList, {
126
+ data: rows,
127
+ renderItem: renderItem,
128
+ keyExtractor: keyExtractor,
129
+ itemHeight: BAR_LIST_ROW_HEIGHT,
130
+ contentContainerStyle: contentContainerStyle
131
+ })
119
132
  });
120
133
  });
121
134
  const styles = StyleSheet.create({
@@ -7,6 +7,10 @@
7
7
 
8
8
  import { createThemedVariants } from "../../core/style/index.js";
9
9
  export const BAR_LIST_TRACK_HEIGHT = 6;
10
+
11
+ /** Header text (`fontSizes.sm` line height) + row gap (`space[1]`) + track — a floor, not a hard
12
+ * clip, so `VirtualList`'s `itemHeight` gets a real offset hint without constraining content. */
13
+ export const BAR_LIST_ROW_HEIGHT = 30;
10
14
  export function resolveBarListColors(colors) {
11
15
  return {
12
16
  label: colors.fg.default,
@@ -39,7 +43,8 @@ export const barListStructure = createThemedVariants(theme => ({
39
43
  }));
40
44
  export const barListRowStructure = createThemedVariants(theme => ({
41
45
  base: {
42
- rowGap: theme.space[1]
46
+ rowGap: theme.space[1],
47
+ minHeight: BAR_LIST_ROW_HEIGHT
43
48
  }
44
49
  }));
45
50
  export const barListHeaderStructure = createThemedVariants(theme => ({
@@ -242,6 +247,46 @@ export function resolveBarChartDomain(data, stacked) {
242
247
  max
243
248
  };
244
249
  }
250
+
251
+ /** Per-`useDeviceTier()` cap on rendered categories — scaled down from `MAX_RENDERED_POINTS` (200)
252
+ * since each `BarChart` category costs THREE svg nodes (bar, label, press target) against a line
253
+ * series' one-per-sample, so the same node budget affords fewer categories on the low tiers. */
254
+ export const MAX_RENDERED_CATEGORIES_LOW = 60;
255
+ export const MAX_RENDERED_CATEGORIES_MID = 120;
256
+ export const MAX_RENDERED_CATEGORIES_HIGH = 200;
257
+ export function maxRenderedCategories(tier) {
258
+ switch (tier) {
259
+ case "low":
260
+ return MAX_RENDERED_CATEGORIES_LOW;
261
+ case "high":
262
+ return MAX_RENDERED_CATEGORIES_HIGH;
263
+ default:
264
+ return MAX_RENDERED_CATEGORIES_MID;
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Evenly-spaced stride sampling down to `maxCategories`, first and last category always kept.
270
+ * Unlike `decimateSeries`' min/max bucketing (built for a numeric y-value), a category has no
271
+ * "extreme" to preserve — only its label and position — so an even stride keeps the *shown*
272
+ * categories representative of the full range instead of clustering at one end. Below the cap the
273
+ * input array is returned as-is (same reference), so a typical chart is byte-identical to before.
274
+ */
275
+ export function decimateCategories(data, maxCategories) {
276
+ if (data.length <= maxCategories) return data;
277
+ if (maxCategories <= 1) return data.length === 0 ? [] : [data[0]];
278
+ const lastIndex = data.length - 1;
279
+ const result = [];
280
+ let lastPushedIndex = -1;
281
+ for (let i = 0; i < maxCategories; i++) {
282
+ const index = Math.round(i * lastIndex / (maxCategories - 1));
283
+ if (index !== lastPushedIndex) {
284
+ result.push(data[index]);
285
+ lastPushedIndex = index;
286
+ }
287
+ }
288
+ return result;
289
+ }
245
290
  /** "Bar chart, 4 categories, highest Revenue at 1,200" — the accessibility label IS the chart for
246
291
  * a screen reader, so it names the count and the single tallest bar drawn, across every series. */
247
292
  export function summarizeBarChart(data, formatter) {
@@ -285,9 +330,28 @@ export function resolveLineDomain(series) {
285
330
  }
286
331
 
287
332
  /** Above this sample count, line/sparkline series are decimated before any geometry is built —
288
- * one svg node per sample is what makes a 5,000-point series unusable on a mid-tier phone. */
333
+ * one svg node per sample is what makes a 5,000-point series unusable on a mid-tier phone. Equal
334
+ * to `maxRenderedPoints("high")` — kept as a named export since it's also `decimateSeries`'
335
+ * default `maxPoints`, for a caller that decimates without a device tier in hand. */
289
336
  export const MAX_RENDERED_POINTS = 200;
290
337
 
338
+ /** Per-`useDeviceTier()` cap on rendered line/sparkline points. A point costs ONE svg node versus a
339
+ * `BarChart` category's three (bar, label, press target), so the same low/mid-tier node budget
340
+ * affords more points than `MAX_RENDERED_CATEGORIES` at the same tier. */
341
+ export const MAX_RENDERED_POINTS_LOW = 80;
342
+ export const MAX_RENDERED_POINTS_MID = 140;
343
+ export const MAX_RENDERED_POINTS_HIGH = MAX_RENDERED_POINTS;
344
+ export function maxRenderedPoints(tier) {
345
+ switch (tier) {
346
+ case "low":
347
+ return MAX_RENDERED_POINTS_LOW;
348
+ case "high":
349
+ return MAX_RENDERED_POINTS_HIGH;
350
+ default:
351
+ return MAX_RENDERED_POINTS_MID;
352
+ }
353
+ }
354
+
291
355
  /**
292
356
  * Min/max bucket decimation down to ~`maxPoints`: both endpoints are kept, and the interior is
293
357
  * split into equal buckets that each contribute their lowest and highest sample, in original
@@ -5,7 +5,7 @@ import { StyleSheet, Text, View } from "react-native";
5
5
  import Svg, { Circle, G } from "react-native-svg";
6
6
  import { useTheme } from "../../theme/hooks.js";
7
7
  import { ChartLegend } from "./ChartLegend.js";
8
- import { DONUT_SEGMENT_GAP_RATIO, resolveDonutChartColors } from "./Charts.variants.js";
8
+ import { DONUT_SEGMENT_GAP_RATIO, resolveDonutChartColors, seriesShapeAt } from "./Charts.variants.js";
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  export const DonutChart = /*#__PURE__*/memo(function DonutChart({
11
11
  segments,
@@ -53,9 +53,14 @@ export const DonutChart = /*#__PURE__*/memo(function DonutChart({
53
53
  dashoffset: -arc.start * circumference - gap / 2
54
54
  };
55
55
  }), [arcs, circumference]);
56
- const legendEntries = useMemo(() => showLegend && arcs.length > 1 ? arcs.map(arc => ({
56
+
57
+ // Segment colour is consumer-supplied with no shared ramp to key off, but each segment's own
58
+ // position in `arcs` is stable index identity — the same thing `seriesShapeAt` already keys off
59
+ // for `PieChart`'s legend, reused here rather than reinvented.
60
+ const legendEntries = useMemo(() => showLegend && arcs.length > 1 ? arcs.map((arc, index) => ({
57
61
  color: arc.color,
58
- label: arc.label
62
+ label: arc.label,
63
+ shape: seriesShapeAt(index)
59
64
  })) : [], [arcs, showLegend]);
60
65
  const ringSize = useMemo(() => ({
61
66
  width: size,
@@ -116,7 +121,7 @@ export const DonutChart = /*#__PURE__*/memo(function DonutChart({
116
121
  })]
117
122
  }), /*#__PURE__*/_jsx(ChartLegend, {
118
123
  entries: legendEntries,
119
- glyph: "swatch",
124
+ glyph: "mark",
120
125
  testID: testID ? `${testID}-legend` : undefined
121
126
  })]
122
127
  });