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
@@ -6,10 +6,11 @@
6
6
  */
7
7
 
8
8
  import { memo, useCallback, useMemo, useRef, useState } from "react";
9
- import { Animated, FlatList, Pressable, Share, StyleSheet, useWindowDimensions, View } from "react-native";
9
+ import { Animated, FlatList, Platform, Pressable, Share, StyleSheet, useWindowDimensions, View } from "react-native";
10
10
  import { MediaImage } from "../../core/media/index.js";
11
11
  import { useEnterExit, useMotion } from "../../core/motion/index.js";
12
12
  import { useTheme } from "../../theme/hooks.js";
13
+ import { rippleColor } from "../../theme/platform/stateLayer.native.js";
13
14
  import { Button } from "../button/Button.js";
14
15
  import { Modal } from "../modal/Modal.js";
15
16
  import { IMAGE_VIEWER_PAGE_PADDING } from "./ImageViewer.variants.js";
@@ -105,16 +106,22 @@ export const ImageViewer = /*#__PURE__*/memo(function ImageViewer({
105
106
  testID: testID ? `${testID}-page-${item.id}` : undefined
106
107
  }), [pageStyle, testID]);
107
108
  const activeBorder = theme.colors.accent.solid;
109
+ const thumbCount = imageItems.length;
108
110
  const renderThumb = useCallback(({
109
- item
111
+ item,
112
+ index
110
113
  }) => /*#__PURE__*/_jsx(ImageViewerThumb, {
111
114
  id: item.id,
112
115
  uri: item.thumbUri ?? item.uri,
116
+ label: item.label,
117
+ position: index + 1,
118
+ total: thumbCount,
113
119
  active: item.id === currentId,
114
120
  activeBorder: activeBorder,
121
+ mode: theme.mode,
115
122
  onPress: handleThumbPress,
116
123
  testID: testID ? `${testID}-thumb-${item.id}` : undefined
117
- }), [currentId, activeBorder, handleThumbPress, testID]);
124
+ }), [currentId, activeBorder, theme.mode, thumbCount, handleThumbPress, testID]);
118
125
  const bodyStyle = useMemo(() => ({
119
126
  gap: theme.space[3]
120
127
  }), [theme]);
@@ -180,8 +187,12 @@ const ImageViewerPage = /*#__PURE__*/memo(function ImageViewerPage({
180
187
  const ImageViewerThumb = /*#__PURE__*/memo(function ImageViewerThumb({
181
188
  id,
182
189
  uri,
190
+ label,
191
+ position,
192
+ total,
183
193
  active,
184
194
  activeBorder,
195
+ mode,
185
196
  onPress,
186
197
  testID
187
198
  }) {
@@ -189,9 +200,25 @@ const ImageViewerThumb = /*#__PURE__*/memo(function ImageViewerThumb({
189
200
  const thumbStyle = useMemo(() => [styles.thumb, active ? {
190
201
  borderColor: activeBorder,
191
202
  borderWidth: 2
192
- } : null], [active, activeBorder]);
203
+ } : styles.thumbInactive], [active, activeBorder]);
204
+ const androidRipple = useMemo(() => Platform.OS === "android" ? {
205
+ color: rippleColor(mode),
206
+ borderless: false
207
+ } : undefined, [mode]);
208
+ // Border colour alone isn't a reliable selection cue (colour-blind users, low-vision) — the
209
+ // dimmed opacity on unselected thumbs is the redundant, non-colour signal (WCAG 1.4.1).
210
+ const imageStyle = useMemo(() => [styles.thumbImage, {
211
+ opacity: active ? 1 : 0.6
212
+ }], [active]);
213
+ const accessibilityLabel = label ? `${label}, image ${position} of ${total}` : `Image ${position} of ${total}`;
193
214
  return /*#__PURE__*/_jsx(Pressable, {
215
+ accessibilityRole: "button",
216
+ accessibilityLabel: accessibilityLabel,
217
+ accessibilityState: {
218
+ selected: active
219
+ },
194
220
  onPress: handlePress,
221
+ android_ripple: androidRipple,
195
222
  style: thumbStyle,
196
223
  children: /*#__PURE__*/_jsx(MediaImage, {
197
224
  testID: testID,
@@ -200,7 +227,7 @@ const ImageViewerThumb = /*#__PURE__*/memo(function ImageViewerThumb({
200
227
  },
201
228
  contentFit: "cover",
202
229
  recyclingKey: uri,
203
- style: styles.thumbImage
230
+ style: imageStyle
204
231
  })
205
232
  });
206
233
  });
@@ -227,6 +254,9 @@ const styles = StyleSheet.create({
227
254
  borderRadius: 8,
228
255
  overflow: "hidden"
229
256
  },
257
+ thumbInactive: {
258
+ borderWidth: 0
259
+ },
230
260
  thumbImage: {
231
261
  width: "100%",
232
262
  height: "100%"
@@ -9,6 +9,12 @@ Modal image gallery with paging and thumbnails. Heavy module — subpath only.
9
9
  affordance is the backdrop, so on that branch a keyboard user previously had no way to close it at
10
10
  all. No keyboard code lives here — `__tests__/ImageViewer.keyboard.web.test.tsx` asserts the
11
11
  inheritance.
12
+ - **Thumbnail strip (1.3.1 / 1.4.1 / 4.1.2)** — each `ImageViewerThumb` carries
13
+ `accessibilityRole="button"`, `accessibilityState={{ selected: active }}`, and an
14
+ `accessibilityLabel` built from the item's own `label` plus its position ("Photo, image 2 of 5"),
15
+ never a bare unlabelled tap target. The active thumb is also marked by a dimmed opacity on every
16
+ OTHER thumb, not by `activeBorder` colour alone — a colour-blind or low-vision user can tell which
17
+ image is open without relying on hue.
12
18
 
13
19
  ## Motion contract
14
20
 
@@ -10,9 +10,10 @@
10
10
  * fades in and out. Both honour reduce-motion through `useMotion()`.
11
11
  */
12
12
 
13
- import { memo, useCallback, useEffect, useId, useMemo, useRef } from "react";
13
+ import { memo, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
14
14
  import { Animated, Platform, StyleSheet, Text, TextInput, View } from "react-native";
15
15
  import { useAnnounce } from "../../core/a11y/index.js";
16
+ import { withAlpha } from "../../core/gradient/index.js";
16
17
  import { Icon } from "../../core/icon/index.js";
17
18
  import { useAnimatedValue, useEnterExit, useMotion } from "../../core/motion/index.js";
18
19
  import { useTheme } from "../../theme/hooks.js";
@@ -41,6 +42,7 @@ export const Input = /*#__PURE__*/memo(function Input(props) {
41
42
  } = props;
42
43
  const theme = useTheme();
43
44
  const motion = useMotion();
45
+ const [focused, setFocused] = useState(false);
44
46
  const spec = INPUT_SIZES[size];
45
47
  const statusColors = resolveInputStatus(theme.colors, status);
46
48
  const a11y = resolveInputAccessibility({
@@ -78,9 +80,15 @@ export const Input = /*#__PURE__*/memo(function Input(props) {
78
80
  }, [motion, ringOpacity]);
79
81
  useEffect(() => () => ringAnimation.current?.stop(), []);
80
82
  const handleFocus = useCallback(() => {
81
- if (!disabled) setRingVisible(true);
83
+ if (!disabled) {
84
+ setFocused(true);
85
+ setRingVisible(true);
86
+ }
82
87
  }, [disabled, setRingVisible]);
83
- const handleBlur = useCallback(() => setRingVisible(false), [setRingVisible]);
88
+ const handleBlur = useCallback(() => {
89
+ setFocused(false);
90
+ setRingVisible(false);
91
+ }, [setRingVisible]);
84
92
  const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.medium), {
85
93
  fontSize: theme.fontSizes.sm,
86
94
  color: theme.colors.fg.default,
@@ -88,9 +96,13 @@ export const Input = /*#__PURE__*/memo(function Input(props) {
88
96
  }], [theme]);
89
97
  const fieldStyle = useMemo(() => [inputStructure(theme, {
90
98
  size
91
- }), {
99
+ }), focused ? {
100
+ borderWidth: 2,
101
+ borderColor: theme.colors.accent.solid,
102
+ backgroundColor: withAlpha(theme.colors.accent.solid, 0.04)
103
+ } : {
92
104
  borderColor: statusColors.border
93
- }, disabled && styles.dimmed], [theme, size, statusColors.border, disabled]);
105
+ }, disabled && styles.dimmed], [theme, size, statusColors.border, disabled, focused]);
94
106
  const focusRingStyle = useMemo(() => ({
95
107
  position: "absolute",
96
108
  top: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH),
@@ -99,7 +111,8 @@ export const Input = /*#__PURE__*/memo(function Input(props) {
99
111
  bottom: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH),
100
112
  borderWidth: FOCUS_RING_WIDTH,
101
113
  borderColor: theme.colors.border.focus,
102
- borderRadius: theme.radii.base + FOCUS_RING_GAP + FOCUS_RING_WIDTH
114
+ borderRadius: theme.radii.md + FOCUS_RING_GAP + FOCUS_RING_WIDTH,
115
+ borderCurve: "continuous"
103
116
  }), [theme]);
104
117
  const inputTextStyle = useMemo(() => [{
105
118
  flex: 1,
@@ -143,7 +156,7 @@ export const Input = /*#__PURE__*/memo(function Input(props) {
143
156
  value: value,
144
157
  onChangeText: onChangeText,
145
158
  placeholder: placeholder,
146
- placeholderTextColor: theme.colors.fg.muted,
159
+ placeholderTextColor: theme.colors.fg.placeholder,
147
160
  secureTextEntry: secureTextEntry,
148
161
  autoComplete: autoComplete,
149
162
  importantForAutofill: autoComplete === "off" ? "no" : undefined,
@@ -28,22 +28,22 @@ const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2)
28
28
  */
29
29
  export const INPUT_SIZES = {
30
30
  sm: {
31
- height: 32,
31
+ height: 44,
32
32
  fontSize: 14,
33
33
  iconSize: 16,
34
- hitSlop: slopFor(32)
34
+ hitSlop: slopFor(44)
35
35
  },
36
36
  md: {
37
- height: 40,
37
+ height: 52,
38
38
  fontSize: 16,
39
39
  iconSize: 18,
40
- hitSlop: slopFor(40)
40
+ hitSlop: slopFor(52)
41
41
  },
42
42
  lg: {
43
- height: 48,
43
+ height: 56,
44
44
  fontSize: 18,
45
45
  iconSize: 20,
46
- hitSlop: slopFor(48)
46
+ hitSlop: slopFor(56)
47
47
  }
48
48
  };
49
49
  /**
@@ -110,7 +110,8 @@ export const inputStructure = createThemedVariants(theme => ({
110
110
  flexDirection: "row",
111
111
  alignItems: "center",
112
112
  borderWidth: theme.borderWidths.thin,
113
- borderRadius: theme.radii.base,
113
+ borderRadius: theme.radii.md,
114
+ borderCurve: "continuous",
114
115
  columnGap: theme.space[2]
115
116
  },
116
117
  variants: {
@@ -125,3 +125,5 @@ Wrapped in `React.memo` (repo-wide re-render audit, 2026-07-17 — see root `CLA
125
125
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
126
126
  - List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
127
127
  - `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
128
+
129
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
 
3
3
  /**
4
- * ListItem — a row primitive. It is rendered AS a list cell at scale, so it carries no mount
5
- * animation and no loop: the only motion is `usePressMotion`, which starts on touch and runs on the
6
- * native driver. The pressable root is an animated `Pressable` rather than an `Animated.View`
7
- * wrapper so a 5000-row list pays for no extra node.
4
+ * ListItem — a row primitive. Press feedback uses `usePressState` (scale + state-layer overlay).
8
5
  */
9
6
 
10
7
  import { memo, useMemo } from "react";
11
- import { Animated, Pressable, Text, View } from "react-native";
12
- import { usePressMotion } from "../../core/motion/index.js";
8
+ import { Platform, Pressable, StyleSheet, View } from "react-native";
9
+ import Animated, { FadeInDown, ReduceMotion } from "react-native-reanimated";
10
+ import { usePressState } from "../../core/motion/usePressState.js";
11
+ import { concentric } from "../../core/style/index.js";
12
+ import { rippleColor as androidRippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
13
13
  import { useTheme } from "../../theme/hooks.js";
14
+ import { Text } from "../text/index.js";
14
15
  import { listItemBodyStructure, listItemDotStructure, listItemStructure, resolveListItemAccessibility, resolveListItemColors } from "./ListItem.variants.js";
15
16
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
17
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
@@ -26,7 +27,8 @@ export const ListItem = /*#__PURE__*/memo(function ListItem({
26
27
  }) {
27
28
  const theme = useTheme();
28
29
  const pressable = onPress !== undefined;
29
- const press = usePressMotion(!pressable);
30
+ const press = usePressState(!pressable);
31
+ const leadingRadius = useMemo(() => concentric(theme.radii.lg, theme.space[4]), [theme.radii.lg, theme.space]);
30
32
  const colors = useMemo(() => resolveListItemColors(theme.colors, unread), [theme.colors, unread]);
31
33
  const a11y = useMemo(() => resolveListItemAccessibility({
32
34
  title,
@@ -36,57 +38,77 @@ export const ListItem = /*#__PURE__*/memo(function ListItem({
36
38
  const baseStyle = useMemo(() => [listItemStructure(theme), {
37
39
  backgroundColor: colors.background
38
40
  }, style], [theme, colors, style]);
39
- // `style` stays last; the press style holds only opacity/transform, which `LayoutStyle` cannot name.
40
41
  const pressableStyle = useMemo(() => [listItemStructure(theme), {
41
- backgroundColor: colors.background
42
- }, press.style, style], [theme, colors, press.style, style]);
42
+ backgroundColor: colors.background,
43
+ overflow: "hidden"
44
+ }, press.animatedStyle, style], [theme, colors, press.animatedStyle, style]);
45
+ const overlayStaticStyle = useMemo(() => ({
46
+ backgroundColor: stateLayerScrim(theme.mode),
47
+ borderRadius: theme.radii.md,
48
+ borderCurve: "continuous"
49
+ }), [theme.mode, theme.radii.md]);
50
+ const androidRipple = useMemo(() => {
51
+ if (!pressable || Platform.OS !== "android") return undefined;
52
+ return {
53
+ color: androidRippleColor(theme.mode),
54
+ borderless: false
55
+ };
56
+ }, [pressable, theme.mode]);
43
57
  const dotStyle = useMemo(() => [listItemDotStructure(theme), {
44
58
  backgroundColor: colors.dot
45
59
  }], [theme, colors]);
46
60
  const bodyStyle = useMemo(() => listItemBodyStructure(theme), [theme]);
47
- const titleStyle = useMemo(() => [theme.fontStyleForWeight(unread ? theme.fontWeights.semibold : theme.fontWeights.medium), {
48
- fontSize: theme.fontSizes.md,
49
- color: colors.title
50
- }], [theme, unread, colors]);
51
- const subtitleStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
52
- fontSize: theme.fontSizes.sm,
53
- color: colors.subtitle
54
- }], [theme, colors]);
55
61
  const body = /*#__PURE__*/_jsxs(_Fragment, {
56
62
  children: [unread && /*#__PURE__*/_jsx(View, {
57
63
  testID: testID === undefined ? undefined : `${testID}-dot`,
58
64
  accessibilityElementsHidden: true,
59
65
  importantForAccessibility: "no-hide-descendants",
60
66
  style: dotStyle
61
- }), leading, /*#__PURE__*/_jsxs(View, {
67
+ }), leading !== undefined && /*#__PURE__*/_jsx(View, {
68
+ style: {
69
+ borderRadius: leadingRadius,
70
+ borderCurve: "continuous",
71
+ overflow: "hidden"
72
+ },
73
+ children: leading
74
+ }), /*#__PURE__*/_jsxs(View, {
62
75
  style: bodyStyle,
63
76
  children: [/*#__PURE__*/_jsx(Text, {
77
+ variant: "body",
78
+ weight: unread ? "semibold" : "medium",
64
79
  numberOfLines: 1,
65
- style: titleStyle,
66
80
  children: title
67
81
  }), subtitle !== undefined && /*#__PURE__*/_jsx(Text, {
82
+ variant: "caption",
83
+ color: "muted",
68
84
  numberOfLines: 2,
69
- style: subtitleStyle,
70
85
  children: subtitle
71
86
  })]
72
87
  }), trailing]
73
88
  });
74
89
  if (!pressable) {
75
- return /*#__PURE__*/_jsx(View, {
90
+ return /*#__PURE__*/_jsx(Animated.View, {
91
+ entering: FadeInDown.springify().reduceMotion(ReduceMotion.System),
76
92
  testID: testID,
77
93
  style: baseStyle,
78
94
  children: body
79
95
  });
80
96
  }
81
- return /*#__PURE__*/_jsx(AnimatedPressable, {
97
+ return /*#__PURE__*/_jsxs(AnimatedPressable, {
82
98
  testID: testID,
83
99
  accessibilityRole: "button",
84
100
  accessibilityLabel: a11y.accessibilityLabel,
85
101
  onPress: onPress,
86
- onPressIn: press.onPressIn,
87
- onPressOut: press.onPressOut,
102
+ onPressIn: press.handlers.onPressIn,
103
+ onPressOut: press.handlers.onPressOut,
104
+ onLayout: press.onLayout,
105
+ android_ripple: androidRipple,
88
106
  style: pressableStyle,
89
- children: body
107
+ children: [/*#__PURE__*/_jsx(Animated.View, {
108
+ pointerEvents: "none",
109
+ testID: testID === undefined ? undefined : `${testID}-press-overlay`,
110
+ style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
111
+ }), body]
90
112
  });
91
113
  });
92
114
  //# sourceMappingURL=ListItem.js.map
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
 
3
+ import { StyleSheet } from "react-native";
3
4
  /**
4
5
  * Pure resolvers for ListItem — no React, so the WCAG tests import this directly (mocking only
5
6
  * `react-native`'s `StyleSheet`, as every sibling module's tests do).
6
7
  */
7
8
 
8
9
  import { createThemedVariants } from "../../core/style/index.js";
10
+ import { floatingBackground, floatingSurfaceStyle } from "../../theme/platform/floatingSurface.native.js";
9
11
  export const LIST_ITEM_DOT_SIZE = 8;
10
- export const LIST_ITEM_MIN_HEIGHT = 44;
12
+ export const LIST_ITEM_MIN_HEIGHT = 56;
11
13
  export function resolveListItemColors(colors, unread) {
12
14
  return {
13
15
  background: unread ? colors.bg.surface : undefined,
@@ -34,7 +36,8 @@ export const listItemStructure = createThemedVariants(theme => ({
34
36
  columnGap: theme.space[3],
35
37
  minHeight: LIST_ITEM_MIN_HEIGHT,
36
38
  paddingVertical: theme.space[3],
37
- paddingHorizontal: theme.space[4]
39
+ paddingHorizontal: theme.space[4],
40
+ borderBottomWidth: StyleSheet.hairlineWidth
38
41
  }
39
42
  }));
40
43
  export const listItemBodyStructure = createThemedVariants(theme => ({
@@ -43,6 +46,12 @@ export const listItemBodyStructure = createThemedVariants(theme => ({
43
46
  rowGap: theme.space[1]
44
47
  }
45
48
  }));
49
+ export function listItemRaisedStyle(theme) {
50
+ return {
51
+ backgroundColor: floatingBackground(theme, "sm"),
52
+ ...floatingSurfaceStyle(theme, "sm")
53
+ };
54
+ }
46
55
  export const listItemDotStructure = createThemedVariants(theme => ({
47
56
  base: {
48
57
  width: LIST_ITEM_DOT_SIZE,
@@ -3,9 +3,8 @@
3
3
  `ListItem` renders one row for notification lists, inboxes, and settings screens: optional
4
4
  `leading`/`trailing` nodes around a title + subtitle column. `unread` adds an `accent.solid` dot
5
5
  and a `bg.surface` row emphasis (plus a semibold title) — `bg.surface`, not `bg.selected`, because
6
- `fg.muted` is only measured AA against surface/hover. A `Pressable` when `onPress` is set
7
- (`bg.sunken` pressed fill measured, `fg.default` fails AA on `bg.hover` on 4 light brands),
8
- a plain `View` otherwise.
6
+ `fg.muted` is only measured AA against surface/hover. A `Pressable` when `onPress` is set uses
7
+ `usePressState` (scale + state-layer overlay on the native driver); a plain `View` otherwise.
9
8
 
10
9
  ## Files
11
10
 
@@ -16,7 +16,7 @@ unclosed fence swallows the rest of the input as code.
16
16
  | `index.ts` | Public surface: `Markdown`, `MarkdownProps`, `parseMarkdown`, node types. |
17
17
  | `__tests__/parseMarkdown.test.ts` | Pure: every block/inline form + malformed-input robustness. |
18
18
  | `__tests__/Markdown.test.ts` | Pure: WCAG contrast for text/link/quote roles (all brands × modes). |
19
- | `__tests__/Markdown.render.test.tsx` | Render: headings, lists, code, link press wiring, and every heading of a 60-section document reaching the tree (the rotor guard — see Performance). |
19
+ | `__tests__/Markdown.render.test.tsx` | Render: headings, lists, code, link press wiring, every heading of a 60-section document reaching the tree (the rotor guard — see Performance), and the block/list-item safety caps (below-cap unchanged, above-cap capped + affordance reveals everything). |
20
20
  | `__tests__/Markdown.dom.test.tsx` | Real DOM (`jest.web.config.js`): a `#`/`##`/`###` document renders real `<h1>`/`<h2>`/`<h3>` tags, not three `<h1>`s. |
21
21
 
22
22
  ## Props
@@ -64,8 +64,15 @@ The parse is `useMemo`'d on `content`; the **render tree** is the other half of
64
64
  The cost is bounded by the content: blocks come from parsing one `content` string, which is a
65
65
  chat message or a notes body, not an unbounded dataset. If a caller ever does need a virtualized
66
66
  document, that is a different component with a different accessibility contract.
67
+ - **Safety caps exist for pathological/misuse input only — they do NOT contradict the above.**
68
+ `MAX_RENDERED_BLOCKS` (300) and `MAX_LIST_ITEMS` (50, per list block, independent of the block
69
+ cap) bound a degenerate `content` string; below either cap a document/list renders exactly as
70
+ before. Above it, a `Button` ("Show full document" / "+N more items") mounts the real, full tree
71
+ on press — never a re-introduction of windowing, so the rotor contract holds once expanded.
67
72
  - Links render through a memo'd `MarkdownLink` so no per-link closure is rebuilt each render.
68
73
 
69
74
  ## Modernization (v1.0.7)
70
75
 
71
76
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
77
+
78
+ - **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
@@ -7,8 +7,9 @@
7
7
  * VirtualizedList is an error in its own right.
8
8
  */
9
9
 
10
- import { Fragment, memo, useCallback, useMemo } from "react";
10
+ import { Fragment, memo, useCallback, useMemo, useState } from "react";
11
11
  import { Platform, StyleSheet, Text, View } from "react-native";
12
+ import { Button } from "../button/index.js";
12
13
  import { HeadingText } from "../../core/heading/index.js";
13
14
  import { useTheme } from "../../theme/hooks.js";
14
15
  import { markdownBlockquoteStructure, markdownCodeBlockStructure, markdownListRowStructure, markdownListStructure, markdownStructure, resolveMarkdownColors, resolveMarkdownHeading } from "./Markdown.variants.js";
@@ -18,6 +19,17 @@ const MONO_FONT = Platform.select({
18
19
  ios: "Menlo",
19
20
  default: "monospace"
20
21
  });
22
+
23
+ /**
24
+ * Safety caps for pathological/misuse input, not windowing (see MODULE.md "Performance") — below
25
+ * these numbers a document renders exactly as before; above, an affordance mounts the real, full
26
+ * tree on press, so the WCAG 2.4.1 rotor contract holds once expanded.
27
+ */
28
+ // Comfortably covers long-form docs/notes (the existing 60-heading test is a fifth of it) while
29
+ // bounding a document of thousands of blocks.
30
+ export const MAX_RENDERED_BLOCKS = 300;
31
+ // Covers realistic checklists/notes lists; bounds a single oversized list regardless of doc length.
32
+ export const MAX_LIST_ITEMS = 50;
21
33
  const MarkdownLink = /*#__PURE__*/memo(function MarkdownLink({
22
34
  content,
23
35
  url,
@@ -75,6 +87,9 @@ const MarkdownBlock = /*#__PURE__*/memo(function MarkdownBlock({
75
87
  colors,
76
88
  onLinkPress
77
89
  }) {
90
+ // Called unconditionally (rules of hooks) though only the "list" case below reads it.
91
+ const [itemsExpanded, setItemsExpanded] = useState(false);
92
+ const expandItems = useCallback(() => setItemsExpanded(true), []);
78
93
  switch (block.type) {
79
94
  case "heading":
80
95
  {
@@ -116,25 +131,35 @@ const MarkdownBlock = /*#__PURE__*/memo(function MarkdownBlock({
116
131
  })
117
132
  });
118
133
  case "list":
119
- return /*#__PURE__*/_jsx(View, {
120
- style: markdownListStructure(theme),
121
- children: block.items.map((item, itemIndex) => /*#__PURE__*/_jsxs(View, {
122
- style: markdownListRowStructure(theme),
123
- children: [/*#__PURE__*/_jsx(Text, {
124
- style: [theme.fontStyleForWeight(theme.fontWeights.regular), {
125
- fontSize: theme.fontSizes.md,
126
- color: colors.listMarker
127
- }],
128
- children: block.ordered ? `${itemIndex + 1}.` : "•"
129
- }), /*#__PURE__*/_jsx(Text, {
130
- style: [theme.fontStyleForWeight(theme.fontWeights.regular), styles.listContent, {
131
- fontSize: theme.fontSizes.md,
132
- color: colors.text
133
- }],
134
- children: renderInline(item, theme, colors, onLinkPress)
134
+ {
135
+ const visibleItems = itemsExpanded || block.items.length <= MAX_LIST_ITEMS ? block.items : block.items.slice(0, MAX_LIST_ITEMS);
136
+ const hiddenCount = block.items.length - visibleItems.length;
137
+ return /*#__PURE__*/_jsxs(View, {
138
+ style: markdownListStructure(theme),
139
+ children: [visibleItems.map((item, itemIndex) => /*#__PURE__*/_jsxs(View, {
140
+ style: markdownListRowStructure(theme),
141
+ children: [/*#__PURE__*/_jsx(Text, {
142
+ style: [theme.fontStyleForWeight(theme.fontWeights.regular), {
143
+ fontSize: theme.fontSizes.md,
144
+ color: colors.listMarker
145
+ }],
146
+ children: block.ordered ? `${itemIndex + 1}.` : "•"
147
+ }), /*#__PURE__*/_jsx(Text, {
148
+ style: [theme.fontStyleForWeight(theme.fontWeights.regular), styles.listContent, {
149
+ fontSize: theme.fontSizes.md,
150
+ color: colors.text
151
+ }],
152
+ children: renderInline(item, theme, colors, onLinkPress)
153
+ })]
154
+ }, itemIndex)), hiddenCount > 0 && /*#__PURE__*/_jsx(Button, {
155
+ variant: "link",
156
+ tone: "neutral",
157
+ size: "sm",
158
+ label: `+${hiddenCount} more items`,
159
+ onPress: expandItems
135
160
  })]
136
- }, itemIndex))
137
- });
161
+ });
162
+ }
138
163
  default:
139
164
  return /*#__PURE__*/_jsx(Text, {
140
165
  style: [theme.fontStyleForWeight(theme.fontWeights.regular), {
@@ -155,15 +180,25 @@ export const Markdown = /*#__PURE__*/memo(function Markdown({
155
180
  const colors = useMemo(() => resolveMarkdownColors(theme.colors), [theme.colors]);
156
181
  const blocks = useMemo(() => parseMarkdown(content), [content]);
157
182
  const rootStyle = useMemo(() => [markdownStructure(theme), style], [theme, style]);
158
- return /*#__PURE__*/_jsx(View, {
183
+ const [blocksExpanded, setBlocksExpanded] = useState(false);
184
+ const expandBlocks = useCallback(() => setBlocksExpanded(true), []);
185
+ const visibleBlocks = blocksExpanded || blocks.length <= MAX_RENDERED_BLOCKS ? blocks : blocks.slice(0, MAX_RENDERED_BLOCKS);
186
+ const hiddenBlockCount = blocks.length - visibleBlocks.length;
187
+ return /*#__PURE__*/_jsxs(View, {
159
188
  testID: testID,
160
189
  style: rootStyle,
161
- children: blocks.map((block, index) => /*#__PURE__*/_jsx(MarkdownBlock, {
190
+ children: [visibleBlocks.map((block, index) => /*#__PURE__*/_jsx(MarkdownBlock, {
162
191
  block: block,
163
192
  theme: theme,
164
193
  colors: colors,
165
194
  onLinkPress: onLinkPress
166
- }, `block-${index}-${block.type}`))
195
+ }, `block-${index}-${block.type}`)), hiddenBlockCount > 0 && /*#__PURE__*/_jsx(Button, {
196
+ variant: "outline",
197
+ tone: "neutral",
198
+ size: "sm",
199
+ label: `Show full document (${hiddenBlockCount} more)`,
200
+ onPress: expandBlocks
201
+ })]
167
202
  });
168
203
  });
169
204
  const styles = StyleSheet.create({
@@ -49,7 +49,8 @@ export const markdownStructure = createThemedVariants(theme => ({
49
49
  }));
50
50
  export const markdownCodeBlockStructure = createThemedVariants(theme => ({
51
51
  base: {
52
- borderRadius: theme.radii.base,
52
+ borderRadius: theme.radii.md,
53
+ borderCurve: "continuous",
53
54
  padding: theme.space[3]
54
55
  }
55
56
  }));
@@ -61,6 +61,7 @@ row size, since an action list's row height isn't a caller-facing choice.
61
61
  menu row is never icon-only.
62
62
  - **2.3.3** — the menu's `animationType` is `"none"` instead of `"fade"` when `useReducedMotion()`
63
63
  is true, and the sheet's own scale/lift `setValue`s straight to rest (`Menu.motion.test.tsx`).
64
+ Row presses use `usePressState` (scale + state-layer overlay).
64
65
  - Backdrop press closes the menu without calling any item's `onPress` — dismissal and selection are
65
66
  two distinct code paths (`closeMenu` vs. `selectItem`), so a stray tap can never accidentally fire
66
67
  an action.
@@ -127,6 +128,16 @@ supplied per row by `useSpaceActivation` (RNW's `isValidKeyPress` needs a `butto
127
128
 
128
129
  Wrapped in `React.memo` (repo-wide re-render audit, 2026-07-17 — see root `CLAUDE.md`). `openMenu`/`closeMenu` are `useCallback`'d, and the inline `onPress` previously injected into the caller-supplied `trigger` via `cloneElement` on every render is extracted to `handleTriggerPress` (`useCallback`, deps `[trigger, openMenu]`) — `trigger` is a consumer-supplied child (typically this library's own `Button`), so a fresh callback there would defeat its memo. `selectItem` and the per-row `onPress` stay inline: they go to `Pressable`/`Icon` (host elements / primitive props), not a memoized child. The sheet subtree (backdrop + rows) is built only while `open` — a closed menu mounts nothing beyond the trigger. Rows are rendered with a plain `.map()` inside a `ScrollView` (not `FlatList`): action menus are short, and mounting a fresh `VirtualizedList` on the same commit as the modal fade-in was measurable open-time cost (~2× p50 in a Jest open benchmark for a 2-item list) with no windowing benefit at current call sites — `ScrollView` has no such per-open setup and still lets a list taller than the sheet's `maxHeight: 320` scroll, which a bare `.map()` with no scroll container would silently lose. Rows get `bg.sunken` press feedback (`resolveMenuRowPressedBackground`, same non-`bg.hover` reasoning as `RadioGroup`/`Accordion`), measured in `Menu.test.ts`.
129
130
 
131
+ ## Round 5 motion
132
+
133
+ Dropped the ad hoc reanimated `FadeInDown` layer (per-row entrance, and the sheet's own former
134
+ entrance-only Reanimated bounce). `enter` (`core/motion`) now drives the sheet's scale/lift/opacity
135
+ AND the backdrop's fade together, and the web-portal path (no RN `<Modal>`) stays `mounted` through
136
+ a real timed exit instead of unmounting instantly — the RNModal path is unaffected, still gated on
137
+ `open` directly, since RN's own `animationType` already owns that surface's exit. `BACKDROP_SCRIM`'s
138
+ opacity now comes from the shared `MOTION_TRANSFORM.scrimOpacity` (previously a mismatched `0x99`
139
+ against Modal/Drawer/BottomSheet's `0x80`).
140
+
130
141
  ## Modernization (v1.0.7)
131
142
 
132
143
  - Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.