@usefragments/ui 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. package/README.md +4 -4
  2. package/dist/assets/fragments-wordmark.cjs +2 -2
  3. package/dist/assets/fragments-wordmark.d.ts.map +1 -1
  4. package/dist/assets/fragments-wordmark.js +2 -2
  5. package/dist/assets/ui.css +4720 -4159
  6. package/dist/chart.cjs +24 -6
  7. package/dist/chart.js +24 -6
  8. package/dist/codeblock.cjs +55 -29
  9. package/dist/codeblock.js +55 -29
  10. package/dist/colorpicker.cjs +3 -1
  11. package/dist/colorpicker.js +3 -1
  12. package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
  13. package/dist/components/Accordion/Accordion.module.scss.js +8 -8
  14. package/dist/components/Alert/Alert.module.scss.cjs +15 -12
  15. package/dist/components/Alert/Alert.module.scss.js +15 -12
  16. package/dist/components/Alert/index.cjs +7 -1
  17. package/dist/components/Alert/index.d.ts +12 -6
  18. package/dist/components/Alert/index.d.ts.map +1 -1
  19. package/dist/components/Alert/index.js +7 -1
  20. package/dist/components/AppShell/AppShell.module.scss.cjs +14 -14
  21. package/dist/components/AppShell/AppShell.module.scss.js +14 -14
  22. package/dist/components/Avatar/Avatar.module.scss.cjs +14 -14
  23. package/dist/components/Avatar/Avatar.module.scss.js +14 -14
  24. package/dist/components/Badge/Badge.module.scss.cjs +19 -19
  25. package/dist/components/Badge/Badge.module.scss.js +19 -19
  26. package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
  27. package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
  28. package/dist/components/Box/Box.module.scss.cjs +152 -152
  29. package/dist/components/Box/Box.module.scss.js +152 -152
  30. package/dist/components/Box/index.cjs +64 -75
  31. package/dist/components/Box/index.d.ts +16 -16
  32. package/dist/components/Box/index.d.ts.map +1 -1
  33. package/dist/components/Box/index.js +64 -75
  34. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
  35. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
  36. package/dist/components/Button/Button.module.scss.cjs +14 -14
  37. package/dist/components/Button/Button.module.scss.js +14 -14
  38. package/dist/components/Card/Card.module.scss.cjs +29 -17
  39. package/dist/components/Card/Card.module.scss.js +30 -18
  40. package/dist/components/Card/index.cjs +8 -0
  41. package/dist/components/Card/index.d.ts +12 -2
  42. package/dist/components/Card/index.d.ts.map +1 -1
  43. package/dist/components/Card/index.js +8 -0
  44. package/dist/components/Chart/Chart.module.scss.cjs +15 -15
  45. package/dist/components/Chart/Chart.module.scss.js +15 -15
  46. package/dist/components/Chart/index.d.ts.map +1 -1
  47. package/dist/components/Checkbox/Checkbox.module.scss.cjs +9 -9
  48. package/dist/components/Checkbox/Checkbox.module.scss.js +9 -9
  49. package/dist/components/Checkbox/index.cjs +2 -2
  50. package/dist/components/Checkbox/index.d.ts.map +1 -1
  51. package/dist/components/Checkbox/index.js +2 -2
  52. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  53. package/dist/components/Chip/Chip.module.scss.js +15 -15
  54. package/dist/components/Chip/index.cjs +2 -1
  55. package/dist/components/Chip/index.d.ts.map +1 -1
  56. package/dist/components/Chip/index.js +2 -1
  57. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +26 -23
  58. package/dist/components/CodeBlock/CodeBlock.module.scss.js +26 -23
  59. package/dist/components/CodeBlock/css-variables-theme.cjs +98 -0
  60. package/dist/components/CodeBlock/css-variables-theme.d.ts +27 -0
  61. package/dist/components/CodeBlock/css-variables-theme.d.ts.map +1 -0
  62. package/dist/components/CodeBlock/css-variables-theme.js +98 -0
  63. package/dist/components/CodeBlock/index.d.ts +17 -3
  64. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  65. package/dist/components/Collapsible/Collapsible.module.scss.cjs +9 -9
  66. package/dist/components/Collapsible/Collapsible.module.scss.js +9 -9
  67. package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
  68. package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
  69. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  70. package/dist/components/Combobox/Combobox.module.scss.cjs +21 -21
  71. package/dist/components/Combobox/Combobox.module.scss.js +21 -21
  72. package/dist/components/Combobox/index.cjs +17 -1
  73. package/dist/components/Combobox/index.d.ts.map +1 -1
  74. package/dist/components/Combobox/index.js +17 -1
  75. package/dist/components/Command/Command.module.scss.cjs +11 -11
  76. package/dist/components/Command/Command.module.scss.js +11 -11
  77. package/dist/components/Command/index.cjs +26 -15
  78. package/dist/components/Command/index.d.ts +2 -2
  79. package/dist/components/Command/index.d.ts.map +1 -1
  80. package/dist/components/Command/index.js +26 -15
  81. package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
  82. package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
  83. package/dist/components/DataTable/DataTable.icons.cjs +6 -33
  84. package/dist/components/DataTable/DataTable.icons.d.ts.map +1 -1
  85. package/dist/components/DataTable/DataTable.icons.js +6 -33
  86. package/dist/components/DataTable/DataTable.module.scss.cjs +27 -27
  87. package/dist/components/DataTable/DataTable.module.scss.js +27 -27
  88. package/dist/components/DataTable/index.d.ts.map +1 -1
  89. package/dist/components/DatePicker/DatePicker.module.scss.cjs +33 -33
  90. package/dist/components/DatePicker/DatePicker.module.scss.js +33 -33
  91. package/dist/components/DatePicker/index.d.ts.map +1 -1
  92. package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
  93. package/dist/components/Dialog/Dialog.module.scss.js +14 -14
  94. package/dist/components/Dialog/index.cjs +11 -14
  95. package/dist/components/Dialog/index.d.ts +7 -7
  96. package/dist/components/Dialog/index.d.ts.map +1 -1
  97. package/dist/components/Dialog/index.js +11 -14
  98. package/dist/components/Drawer/Drawer.module.scss.cjs +29 -29
  99. package/dist/components/Drawer/Drawer.module.scss.js +29 -29
  100. package/dist/components/Editor/Editor.module.scss.cjs +17 -17
  101. package/dist/components/Editor/Editor.module.scss.js +17 -17
  102. package/dist/components/Editor/index.d.ts +10 -10
  103. package/dist/components/Editor/index.d.ts.map +1 -1
  104. package/dist/components/EmptyState/EmptyState.module.scss.cjs +11 -8
  105. package/dist/components/EmptyState/EmptyState.module.scss.js +11 -8
  106. package/dist/components/EmptyState/index.cjs +8 -6
  107. package/dist/components/EmptyState/index.d.ts +9 -4
  108. package/dist/components/EmptyState/index.d.ts.map +1 -1
  109. package/dist/components/EmptyState/index.js +8 -6
  110. package/dist/components/Field/Field.module.scss.cjs +5 -5
  111. package/dist/components/Field/Field.module.scss.js +5 -5
  112. package/dist/components/Field/index.cjs +9 -1
  113. package/dist/components/Field/index.d.ts.map +1 -1
  114. package/dist/components/Field/index.js +9 -1
  115. package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
  116. package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
  117. package/dist/components/Grid/index.cjs +1 -1
  118. package/dist/components/Grid/index.js +1 -1
  119. package/dist/components/Header/Header.module.scss.cjs +33 -33
  120. package/dist/components/Header/Header.module.scss.js +33 -33
  121. package/dist/components/Header/index.cjs +17 -38
  122. package/dist/components/Header/index.d.ts +15 -11
  123. package/dist/components/Header/index.d.ts.map +1 -1
  124. package/dist/components/Header/index.js +17 -38
  125. package/dist/components/Icon/Icon.module.scss.cjs +15 -15
  126. package/dist/components/Icon/Icon.module.scss.js +15 -15
  127. package/dist/components/IconButton/IconButton.module.scss.cjs +8 -8
  128. package/dist/components/IconButton/IconButton.module.scss.js +8 -8
  129. package/dist/components/IconButton/index.cjs +2 -1
  130. package/dist/components/IconButton/index.d.ts.map +1 -1
  131. package/dist/components/IconButton/index.js +2 -1
  132. package/dist/components/Image/Image.module.scss.cjs +27 -27
  133. package/dist/components/Image/Image.module.scss.js +27 -27
  134. package/dist/components/Input/Input.module.scss.cjs +17 -17
  135. package/dist/components/Input/Input.module.scss.js +17 -17
  136. package/dist/components/Link/Link.module.scss.cjs +14 -10
  137. package/dist/components/Link/Link.module.scss.js +14 -10
  138. package/dist/components/Link/index.d.ts +1 -1
  139. package/dist/components/Link/index.d.ts.map +1 -1
  140. package/dist/components/List/List.module.scss.cjs +19 -19
  141. package/dist/components/List/List.module.scss.js +19 -19
  142. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  143. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  144. package/dist/components/Loading/Loading.module.scss.cjs +34 -34
  145. package/dist/components/Loading/Loading.module.scss.js +34 -34
  146. package/dist/components/Loading/index.cjs +1 -1
  147. package/dist/components/Loading/index.js +1 -1
  148. package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
  149. package/dist/components/Markdown/Markdown.module.scss.js +1 -1
  150. package/dist/components/Markdown/index.d.ts +2 -2
  151. package/dist/components/Markdown/index.d.ts.map +1 -1
  152. package/dist/components/Menu/Menu.module.scss.cjs +14 -14
  153. package/dist/components/Menu/Menu.module.scss.js +14 -14
  154. package/dist/components/Message/Message.module.scss.cjs +18 -18
  155. package/dist/components/Message/Message.module.scss.js +18 -18
  156. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +34 -31
  157. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +34 -31
  158. package/dist/components/NavigationMenu/index.cjs +32 -15
  159. package/dist/components/NavigationMenu/index.d.ts +12 -6
  160. package/dist/components/NavigationMenu/index.d.ts.map +1 -1
  161. package/dist/components/NavigationMenu/index.js +32 -15
  162. package/dist/components/Pagination/Pagination.module.scss.cjs +10 -10
  163. package/dist/components/Pagination/Pagination.module.scss.js +10 -10
  164. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  165. package/dist/components/Popover/Popover.module.scss.js +10 -10
  166. package/dist/components/Progress/Progress.module.scss.cjs +25 -25
  167. package/dist/components/Progress/Progress.module.scss.js +25 -25
  168. package/dist/components/Prompt/Prompt.module.scss.cjs +28 -28
  169. package/dist/components/Prompt/Prompt.module.scss.js +28 -28
  170. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +15 -15
  171. package/dist/components/RadioGroup/RadioGroup.module.scss.js +15 -15
  172. package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +5 -5
  173. package/dist/components/ScrollArea/ScrollArea.module.scss.js +5 -5
  174. package/dist/components/ScrollArea/index.d.ts +4 -4
  175. package/dist/components/ScrollArea/index.d.ts.map +1 -1
  176. package/dist/components/ScrollArea/scroll-state.d.ts +5 -5
  177. package/dist/components/Select/Select.module.scss.cjs +21 -21
  178. package/dist/components/Select/Select.module.scss.js +21 -21
  179. package/dist/components/Separator/Separator.module.scss.cjs +11 -11
  180. package/dist/components/Separator/Separator.module.scss.js +11 -11
  181. package/dist/components/Sidebar/Sidebar.module.scss.cjs +43 -43
  182. package/dist/components/Sidebar/Sidebar.module.scss.js +43 -43
  183. package/dist/components/Sidebar/index.cjs +12 -35
  184. package/dist/components/Sidebar/index.d.ts +19 -19
  185. package/dist/components/Sidebar/index.d.ts.map +1 -1
  186. package/dist/components/Sidebar/index.js +12 -35
  187. package/dist/components/Skeleton/Skeleton.module.scss.cjs +50 -46
  188. package/dist/components/Skeleton/Skeleton.module.scss.js +50 -46
  189. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  190. package/dist/components/Slider/Slider.module.scss.js +12 -12
  191. package/dist/components/Stack/Stack.module.scss.cjs +25 -25
  192. package/dist/components/Stack/Stack.module.scss.js +25 -25
  193. package/dist/components/Stack/index.cjs +1 -1
  194. package/dist/components/Stack/index.js +1 -1
  195. package/dist/components/Switch/Switch.module.scss.cjs +9 -9
  196. package/dist/components/Switch/Switch.module.scss.js +9 -9
  197. package/dist/components/Table/Table.module.scss.cjs +19 -19
  198. package/dist/components/Table/Table.module.scss.js +19 -19
  199. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
  200. package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
  201. package/dist/components/TableOfContents/index.cjs +13 -9
  202. package/dist/components/TableOfContents/index.d.ts +5 -3
  203. package/dist/components/TableOfContents/index.d.ts.map +1 -1
  204. package/dist/components/TableOfContents/index.js +13 -9
  205. package/dist/components/Tabs/Tabs.module.scss.cjs +12 -12
  206. package/dist/components/Tabs/Tabs.module.scss.js +12 -12
  207. package/dist/components/Tabs/index.cjs +26 -6
  208. package/dist/components/Tabs/index.d.ts.map +1 -1
  209. package/dist/components/Tabs/index.js +26 -6
  210. package/dist/components/Text/Text.module.scss.cjs +87 -75
  211. package/dist/components/Text/Text.module.scss.js +87 -75
  212. package/dist/components/Text/index.cjs +49 -41
  213. package/dist/components/Text/index.d.ts +12 -11
  214. package/dist/components/Text/index.d.ts.map +1 -1
  215. package/dist/components/Text/index.js +49 -41
  216. package/dist/components/Textarea/Textarea.module.scss.cjs +24 -24
  217. package/dist/components/Textarea/Textarea.module.scss.js +24 -24
  218. package/dist/components/Theme/index.cjs +2 -1
  219. package/dist/components/Theme/index.d.ts.map +1 -1
  220. package/dist/components/Theme/index.js +2 -1
  221. package/dist/components/ThemeToggle/ThemeToggle.module.scss.cjs +9 -6
  222. package/dist/components/ThemeToggle/ThemeToggle.module.scss.js +9 -6
  223. package/dist/components/ThemeToggle/index.cjs +31 -6
  224. package/dist/components/ThemeToggle/index.d.ts +7 -2
  225. package/dist/components/ThemeToggle/index.d.ts.map +1 -1
  226. package/dist/components/ThemeToggle/index.js +32 -7
  227. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +13 -13
  228. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +13 -13
  229. package/dist/components/Toast/Toast.module.scss.cjs +20 -20
  230. package/dist/components/Toast/Toast.module.scss.js +20 -20
  231. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  232. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  233. package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
  234. package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
  235. package/dist/components/Tooltip/index.cjs +24 -40
  236. package/dist/components/Tooltip/index.d.ts +4 -4
  237. package/dist/components/Tooltip/index.d.ts.map +1 -1
  238. package/dist/components/Tooltip/index.js +24 -40
  239. package/dist/components/VisuallyHidden/index.d.ts +2 -2
  240. package/dist/data-table.cjs +2 -1
  241. package/dist/data-table.js +2 -1
  242. package/dist/datepicker.cjs +3 -2
  243. package/dist/datepicker.js +3 -2
  244. package/dist/editor.cjs +68 -28
  245. package/dist/editor.js +68 -28
  246. package/dist/index.cjs +1 -1
  247. package/dist/index.d.ts +1 -1
  248. package/dist/index.d.ts.map +1 -1
  249. package/dist/index.js +2 -2
  250. package/dist/markdown.cjs +21 -29
  251. package/dist/markdown.js +21 -29
  252. package/dist/measurements/generated.cjs +9 -1
  253. package/dist/measurements/generated.d.ts +7 -0
  254. package/dist/measurements/generated.d.ts.map +1 -1
  255. package/dist/measurements/generated.js +9 -1
  256. package/dist/utils/a11y.cjs +5 -2
  257. package/dist/utils/a11y.d.ts +5 -5
  258. package/dist/utils/a11y.d.ts.map +1 -1
  259. package/dist/utils/a11y.js +5 -2
  260. package/dist/utils/canonical-stamp.cjs +2 -8
  261. package/dist/utils/canonical-stamp.d.ts.map +1 -1
  262. package/dist/utils/canonical-stamp.js +1 -7
  263. package/dist/utils/css-warning.cjs +1 -1
  264. package/dist/utils/css-warning.js +1 -1
  265. package/dist/utils/env.cjs +17 -0
  266. package/dist/utils/env.d.ts +3 -0
  267. package/dist/utils/env.d.ts.map +1 -0
  268. package/dist/utils/env.js +17 -0
  269. package/dist/utils/keyboard-shortcuts.cjs +3 -10
  270. package/dist/utils/keyboard-shortcuts.d.ts +4 -4
  271. package/dist/utils/keyboard-shortcuts.d.ts.map +1 -1
  272. package/dist/utils/keyboard-shortcuts.js +3 -10
  273. package/dist/utils/seed-derivation.cjs +10 -6
  274. package/dist/utils/seed-derivation.d.ts.map +1 -1
  275. package/dist/utils/seed-derivation.js +10 -6
  276. package/fragments.json +1 -1
  277. package/package.json +6 -4
  278. package/src/assets/fragments-logo.tsx +2 -2
  279. package/src/assets/fragments-wordmark.tsx +4 -2
  280. package/src/components/Accordion/Accordion.contract.json +24 -48
  281. package/src/components/Alert/Alert.contract.json +37 -53
  282. package/src/components/Alert/Alert.module.scss +24 -0
  283. package/src/components/Alert/index.tsx +55 -29
  284. package/src/components/AppShell/AppShell.contract.json +34 -51
  285. package/src/components/AppShell/AppShell.module.scss +53 -40
  286. package/src/components/Avatar/Avatar.contract.json +31 -48
  287. package/src/components/Avatar/Avatar.module.scss +4 -1
  288. package/src/components/Badge/Badge.contract.json +37 -42
  289. package/src/components/Badge/Badge.module.scss +9 -2
  290. package/src/components/BentoGrid/BentoGrid.contract.json +21 -45
  291. package/src/components/Box/Box.contract.json +40 -148
  292. package/src/components/Box/index.tsx +92 -99
  293. package/src/components/Breadcrumbs/Breadcrumbs.contract.json +21 -34
  294. package/src/components/Breadcrumbs/Breadcrumbs.module.scss +12 -7
  295. package/src/components/Button/Button.module.scss +8 -7
  296. package/src/components/ButtonGroup/ButtonGroup.contract.json +32 -47
  297. package/src/components/Card/Card.module.scss +82 -1
  298. package/src/components/Card/index.tsx +21 -2
  299. package/src/components/Chart/Chart.contract.json +21 -29
  300. package/src/components/Chart/index.tsx +36 -6
  301. package/src/components/Checkbox/Checkbox.contract.json +24 -24
  302. package/src/components/Checkbox/Checkbox.module.scss +32 -23
  303. package/src/components/Checkbox/index.tsx +4 -2
  304. package/src/components/Chip/Chip.contract.json +33 -40
  305. package/src/components/Chip/Chip.module.scss +2 -2
  306. package/src/components/Chip/index.tsx +2 -1
  307. package/src/components/CodeBlock/CodeBlock.contract.json +46 -76
  308. package/src/components/CodeBlock/CodeBlock.module.scss +40 -15
  309. package/src/components/CodeBlock/css-variables-theme.ts +102 -0
  310. package/src/components/CodeBlock/index.tsx +91 -35
  311. package/src/components/Collapsible/Collapsible.contract.json +21 -36
  312. package/src/components/ColorPicker/ColorPicker.contract.json +29 -48
  313. package/src/components/ColorPicker/ColorPicker.module.scss +15 -12
  314. package/src/components/ColorPicker/index.tsx +5 -1
  315. package/src/components/Combobox/Combobox.contract.json +36 -37
  316. package/src/components/Combobox/Combobox.module.scss +1 -1
  317. package/src/components/Combobox/index.tsx +31 -5
  318. package/src/components/Command/Command.contract.json +21 -43
  319. package/src/components/Command/index.tsx +58 -47
  320. package/src/components/ConversationList/ConversationList.contract.json +27 -32
  321. package/src/components/DataTable/DataTable.icons.tsx +4 -21
  322. package/src/components/DataTable/DataTable.module.scss +12 -8
  323. package/src/components/DataTable/index.tsx +8 -7
  324. package/src/components/DatePicker/DatePicker.contract.json +27 -28
  325. package/src/components/DatePicker/DatePicker.module.scss +12 -5
  326. package/src/components/DatePicker/index.tsx +5 -2
  327. package/src/components/Dialog/Dialog.module.scss +3 -3
  328. package/src/components/Dialog/index.tsx +47 -37
  329. package/src/components/Drawer/Drawer.contract.json +22 -36
  330. package/src/components/Editor/Editor.contract.json +31 -48
  331. package/src/components/Editor/Editor.module.scss +36 -14
  332. package/src/components/Editor/index.tsx +240 -179
  333. package/src/components/EmptyState/EmptyState.contract.json +31 -43
  334. package/src/components/EmptyState/EmptyState.module.scss +8 -0
  335. package/src/components/EmptyState/index.tsx +48 -23
  336. package/src/components/Field/Field.contract.json +28 -46
  337. package/src/components/Field/index.tsx +5 -1
  338. package/src/components/Fieldset/Fieldset.contract.json +21 -38
  339. package/src/components/Fieldset/Fieldset.module.scss +10 -3
  340. package/src/components/Form/Form.contract.json +20 -20
  341. package/src/components/Grid/Grid.contract.json +28 -64
  342. package/src/components/Grid/index.tsx +10 -10
  343. package/src/components/Header/Header.contract.json +31 -67
  344. package/src/components/Header/Header.module.scss +36 -21
  345. package/src/components/Header/index.tsx +134 -122
  346. package/src/components/Icon/Icon.contract.json +22 -62
  347. package/src/components/IconButton/IconButton.contract.json +34 -18
  348. package/src/components/IconButton/IconButton.module.scss +6 -7
  349. package/src/components/IconButton/index.tsx +2 -1
  350. package/src/components/Image/Image.contract.json +23 -56
  351. package/src/components/Input/Input.contract.json +26 -32
  352. package/src/components/Input/Input.module.scss +3 -2
  353. package/src/components/Link/Link.contract.json +32 -52
  354. package/src/components/Link/Link.module.scss +23 -6
  355. package/src/components/Link/index.tsx +1 -1
  356. package/src/components/List/List.contract.json +23 -52
  357. package/src/components/List/List.module.scss +1 -1
  358. package/src/components/Listbox/Listbox.contract.json +21 -37
  359. package/src/components/Loading/Loading.contract.json +37 -61
  360. package/src/components/Loading/Loading.module.scss +10 -7
  361. package/src/components/Loading/index.tsx +2 -2
  362. package/src/components/Main/Main.contract.json +17 -9
  363. package/src/components/Markdown/Markdown.contract.json +22 -43
  364. package/src/components/Markdown/Markdown.module.scss +43 -5
  365. package/src/components/Markdown/index.tsx +48 -49
  366. package/src/components/Menu/Menu.contract.json +25 -41
  367. package/src/components/Menu/Menu.module.scss +23 -8
  368. package/src/components/Message/Message.contract.json +29 -52
  369. package/src/components/Message/Message.module.scss +12 -5
  370. package/src/components/NavigationMenu/NavigationMenu.contract.json +36 -45
  371. package/src/components/NavigationMenu/NavigationMenu.module.scss +64 -19
  372. package/src/components/NavigationMenu/index.tsx +105 -81
  373. package/src/components/Pagination/Pagination.contract.json +22 -40
  374. package/src/components/Pagination/Pagination.module.scss +2 -2
  375. package/src/components/Popover/Popover.contract.json +24 -46
  376. package/src/components/Popover/Popover.module.scss +6 -5
  377. package/src/components/Progress/Progress.contract.json +32 -28
  378. package/src/components/Progress/Progress.module.scss +3 -2
  379. package/src/components/Prompt/Prompt.contract.json +31 -47
  380. package/src/components/Prompt/Prompt.module.scss +13 -5
  381. package/src/components/RadioGroup/RadioGroup.contract.json +23 -24
  382. package/src/components/RadioGroup/RadioGroup.module.scss +13 -14
  383. package/src/components/ScrollArea/ScrollArea.contract.json +18 -19
  384. package/src/components/ScrollArea/ScrollArea.module.scss +15 -15
  385. package/src/components/ScrollArea/index.tsx +16 -16
  386. package/src/components/ScrollArea/scroll-state.ts +24 -24
  387. package/src/components/Select/Select.module.scss +2 -2
  388. package/src/components/Separator/Separator.contract.json +24 -48
  389. package/src/components/Sidebar/Sidebar.contract.json +35 -67
  390. package/src/components/Sidebar/Sidebar.module.scss +22 -13
  391. package/src/components/Sidebar/index.tsx +164 -164
  392. package/src/components/Skeleton/Skeleton.contract.json +28 -54
  393. package/src/components/Skeleton/Skeleton.module.scss +27 -10
  394. package/src/components/Slider/Slider.contract.json +27 -39
  395. package/src/components/Slider/Slider.module.scss +3 -3
  396. package/src/components/Stack/Stack.contract.json +29 -56
  397. package/src/components/Stack/Stack.module.scss +13 -12
  398. package/src/components/Stack/index.tsx +3 -3
  399. package/src/components/Switch/Switch.contract.json +33 -46
  400. package/src/components/Switch/Switch.module.scss +64 -26
  401. package/src/components/Table/Table.contract.json +28 -46
  402. package/src/components/Table/Table.module.scss +15 -3
  403. package/src/components/TableOfContents/TableOfContents.contract.json +34 -21
  404. package/src/components/TableOfContents/TableOfContents.module.scss +15 -5
  405. package/src/components/TableOfContents/index.tsx +26 -9
  406. package/src/components/Tabs/Tabs.contract.json +24 -45
  407. package/src/components/Tabs/Tabs.module.scss +1 -1
  408. package/src/components/Tabs/index.tsx +15 -3
  409. package/src/components/Text/Text.contract.json +30 -72
  410. package/src/components/Text/Text.module.scss +21 -4
  411. package/src/components/Text/index.tsx +113 -75
  412. package/src/components/Textarea/Textarea.contract.json +25 -43
  413. package/src/components/Textarea/Textarea.module.scss +2 -4
  414. package/src/components/Theme/Theme.contract.json +32 -51
  415. package/src/components/Theme/index.tsx +2 -1
  416. package/src/components/ThemeToggle/ThemeToggle.module.scss +23 -7
  417. package/src/components/ThemeToggle/index.tsx +43 -7
  418. package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +23 -40
  419. package/src/components/Toast/Toast.contract.json +30 -40
  420. package/src/components/Toast/Toast.module.scss +1 -1
  421. package/src/components/ToggleGroup/ToggleGroup.contract.json +29 -30
  422. package/src/components/ToggleGroup/ToggleGroup.module.scss +38 -5
  423. package/src/components/Tooltip/Tooltip.contract.json +31 -52
  424. package/src/components/Tooltip/index.tsx +19 -24
  425. package/src/components/VisuallyHidden/VisuallyHidden.contract.json +22 -44
  426. package/src/components/VisuallyHidden/index.tsx +5 -5
  427. package/src/index.ts +2 -2
  428. package/src/measurements/generated.ts +9 -2
  429. package/src/measurements/measurements.json +7 -0
  430. package/src/recipes/_boolean-range.scss +3 -11
  431. package/src/recipes/_field.scss +5 -1
  432. package/src/recipes/_layout.scss +14 -7
  433. package/src/recipes/_popup.scss +12 -2
  434. package/src/recipes/_prose.scss +13 -5
  435. package/src/recipes/_table-chrome.scss +16 -2
  436. package/src/scss.d.ts +1 -1
  437. package/src/styles/globals.scss +20 -19
  438. package/src/tokens/_computed.scss +5 -16
  439. package/src/tokens/_derive.scss +112 -210
  440. package/src/tokens/_measurements.catalog.generated.css +6 -1
  441. package/src/tokens/_measurements.generated.scss +14 -1
  442. package/src/tokens/_mixins.scss +7 -8
  443. package/src/tokens/_palettes.scss +39 -167
  444. package/src/tokens/_seeds.scss +20 -20
  445. package/src/tokens/_variables.scss +183 -38
  446. package/src/utils/a11y.tsx +69 -69
  447. package/src/utils/aria.ts +3 -3
  448. package/src/utils/canonical-stamp.ts +2 -12
  449. package/src/utils/css-warning.ts +7 -7
  450. package/src/utils/env.ts +25 -0
  451. package/src/utils/keyboard-shortcuts.ts +131 -126
  452. package/src/utils/seed-derivation.ts +10 -6
  453. package/src/components/Button/Button.contract.json +0 -218
  454. package/src/components/Card/Card.contract.json +0 -175
  455. package/src/components/DataTable/DataTable.contract.json +0 -302
  456. package/src/components/Dialog/Dialog.contract.json +0 -159
  457. package/src/components/Select/Select.contract.json +0 -259
@@ -1,16 +1,9 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "Loading",
4
- "description": "Versatile loading indicator with multiple variants for showing progress or waiting states",
4
+ "description": "Signals that something is happening when you cannot say how long it will take.",
5
5
  "category": "feedback",
6
- "tags": [
7
- "loading",
8
- "spinner",
9
- "progress",
10
- "feedback",
11
- "indicator",
12
- "async"
13
- ],
6
+ "tags": ["loading", "spinner", "progress", "feedback", "indicator", "async"],
14
7
  "status": "stable",
15
8
  "sourcePath": "src/components/Loading/index.tsx",
16
9
  "exportName": "Loading",
@@ -29,23 +22,14 @@
29
22
  "description": "Size of the loading indicator",
30
23
  "default": "md",
31
24
  "required": false,
32
- "values": [
33
- "sm",
34
- "md",
35
- "lg",
36
- "xl"
37
- ]
25
+ "values": ["sm", "md", "lg", "xl"]
38
26
  },
39
27
  "variant": {
40
28
  "type": "enum",
41
29
  "description": "Visual style of the loading animation",
42
30
  "default": "spinner",
43
31
  "required": false,
44
- "values": [
45
- "spinner",
46
- "dots",
47
- "pulse"
48
- ]
32
+ "values": ["spinner", "dots", "pulse"]
49
33
  },
50
34
  "label": {
51
35
  "type": "string",
@@ -76,87 +60,79 @@
76
60
  "description": "Color variant - accent uses theme color, current inherits text color",
77
61
  "default": "accent",
78
62
  "required": false,
79
- "values": [
80
- "accent",
81
- "current",
82
- "muted"
83
- ]
63
+ "values": ["accent", "current", "muted"]
84
64
  }
85
65
  },
86
66
  "usage": {
87
67
  "when": [
88
- "Indicating content is being fetched or processed",
89
- "Showing a pending state while waiting for an async operation",
90
- "Displaying loading state for buttons, forms, or page sections",
91
- "Full-screen loading during initial app/page load"
68
+ "Fetching or processing content",
69
+ "Waiting on an async action to come back",
70
+ "Buttons, forms, and page sections mid-request",
71
+ "The first paint of an app or page"
92
72
  ],
93
73
  "whenNot": [
94
- "For showing determinate progress - use Progress component instead",
95
- "For showing skeleton placeholders - use Skeleton component instead",
96
- "For AI-specific thinking states - use ThinkingIndicator instead"
74
+ "You know the percentage use Progress",
75
+ "You know the page shape use Skeleton",
76
+ "AI reasoning states use ThinkingIndicator"
97
77
  ],
98
78
  "guidelines": [
99
- "Use spinner variant for general loading states",
100
- "Use dots variant for chat/messaging contexts",
101
- "Use pulse variant for subtle, ambient loading",
102
- "Always provide a meaningful label for screen readers",
103
- "Consider using Loading.Screen for initial page loads",
104
- "Use Loading.Inline when loading indicator should flow with text"
79
+ "spinner for general waits",
80
+ "dots for chat and messaging",
81
+ "pulse for quiet ambient waiting",
82
+ "Always pass a label describing what is loading",
83
+ "Loading.Screen for first page load, Loading.Inline to sit inside a sentence"
105
84
  ],
106
85
  "accessibility": [
107
- "Component uses role=\"status\" and aria-live=\"polite\"",
108
- "Always provide descriptive label prop for screen readers",
109
- "Animations respect prefers-reduced-motion preference"
86
+ "Announced through role=\"status\" with aria-live=\"polite\"",
87
+ "label is what a screen reader reads — make it specific",
88
+ "Animation stops for prefers-reduced-motion"
110
89
  ]
111
90
  },
112
91
  "examples": [
113
92
  {
114
93
  "name": "Default",
115
- "description": "Default spinner loading indicator",
116
- "code": "<Loading />"
94
+ "description": "Spinner at medium size, accent coloured.",
95
+ "code": "<Loading label=\"Loading content\" />"
117
96
  },
118
97
  {
119
98
  "name": "Sizes",
120
- "description": "Loading indicators in different sizes",
121
- "code": "<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>\n <Loading size=\"sm\" />\n <Loading size=\"md\" />\n <Loading size=\"lg\" />\n <Loading size=\"xl\" />\n</div>"
99
+ "description": "sm inside controls, xl for a whole page.",
100
+ "code": "import { Stack } from '@/components/Stack';\n\n<Stack direction=\"row\" gap=\"lg\" align=\"center\">\n <Loading size=\"sm\" label=\"Loading\" />\n <Loading size=\"md\" label=\"Loading\" />\n <Loading size=\"lg\" label=\"Loading\" />\n <Loading size=\"xl\" label=\"Loading\" />\n</Stack>"
122
101
  },
123
102
  {
124
103
  "name": "Dots",
125
- "description": "Bouncing dots animation",
126
- "code": "<Loading variant=\"dots\" />"
104
+ "description": "Three bouncing dots, at home in a message thread.",
105
+ "code": "<Loading variant=\"dots\" label=\"Sending message\" />"
127
106
  },
128
107
  {
129
108
  "name": "Pulse",
130
- "description": "Pulsing circle animation",
131
- "code": "<Loading variant=\"pulse\" />"
109
+ "description": "One breathing dot for ambient background work.",
110
+ "code": "<Loading variant=\"pulse\" label=\"Syncing\" />"
132
111
  },
133
112
  {
134
113
  "name": "Colors",
135
- "description": "Different color variants",
136
- "code": "<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>\n <Loading color=\"accent\" />\n <Loading color=\"muted\" />\n <span style={{ color: '#3b82f6' }}>\n <Loading color=\"current\" />\n </span>\n</div>"
114
+ "description": "Accent, muted, or whatever the surrounding text is.",
115
+ "code": "import { Stack } from '@/components/Stack';\n\n<Stack direction=\"row\" gap=\"lg\" align=\"center\">\n <Loading color=\"accent\" label=\"Loading\" />\n <Loading color=\"muted\" label=\"Loading\" />\n <span style={{ color: 'var(--fui-color-info)' }}>\n <Loading color=\"current\" label=\"Loading\" />\n </span>\n</Stack>"
137
116
  },
138
117
  {
139
118
  "name": "Inline",
140
- "description": "Inline loading indicator that flows with text",
141
- "code": "<p style={{ margin: 0 }}>\n Processing your request <Loading.Inline /> please wait...\n</p>"
119
+ "description": "Sits on the text baseline mid-sentence.",
120
+ "code": "<p style={{ margin: 0 }}>\n Processing your request <Loading.Inline label=\"Processing\" /> please wait…\n</p>"
142
121
  },
143
122
  {
144
123
  "name": "Centered",
145
- "description": "Centered in container",
146
- "code": "<div style={{ width: '200px', height: '100px', border: '1px dashed #ccc', borderRadius: '8px' }}>\n <Loading centered fill />\n</div>"
124
+ "description": "Fills its container and centres in it.",
125
+ "code": "<div\n style={{\n width: '200px',\n height: '100px',\n border: '1px dashed var(--fui-border)',\n borderRadius: 'var(--fui-radius-md)',\n }}\n>\n <Loading centered fill label=\"Loading section\" />\n</div>"
147
126
  },
148
127
  {
149
128
  "name": "Screen",
150
- "description": "Full-screen loading state with optional label",
151
- "code": "<div style={{ position: 'relative', width: '300px', height: '200px', border: '1px solid #ccc', borderRadius: '8px', overflow: 'hidden', transform: 'scale(1)' }}>\n <Loading.Screen size=\"lg\" label=\"Loading application...\" showLabel />\n</div>"
129
+ "description": "Covers the surface it sits on and names the wait.",
130
+ "code": "<div\n style={{\n position: 'relative',\n contain: 'layout',\n width: '300px',\n height: '200px',\n border: '1px solid var(--fui-border)',\n borderRadius: 'var(--fui-radius-md)',\n overflow: 'hidden',\n }}\n>\n <Loading.Screen size=\"lg\" label=\"Loading application…\" showLabel />\n</div>"
152
131
  }
153
132
  ],
154
133
  "ai": {
155
134
  "compositionPattern": "compound",
156
- "subComponents": [
157
- "Inline",
158
- "Screen"
159
- ]
135
+ "subComponents": ["Inline", "Screen"]
160
136
  },
161
137
  "provenance": {
162
138
  "source": "migrated",
@@ -64,7 +64,7 @@
64
64
  .spinnerIcon {
65
65
  inline-size: 100%;
66
66
  block-size: 100%;
67
- animation: spin 0.8s linear infinite;
67
+ animation: spin var(--fui-duration-spin, $fui-duration-spin) linear infinite;
68
68
 
69
69
  @media (prefers-reduced-motion: reduce) {
70
70
  animation: none;
@@ -85,7 +85,10 @@
85
85
  // Dots Variant
86
86
  // ============================================
87
87
 
88
- .dots {
88
+ // `.dots`/`.pulse` on the root are variant hooks only — sizing lives on the
89
+ // inner track. Sharing one class between root and track let the track's
90
+ // 100% × 100% override the root's fixed activity footprint (rendered 0 × 0).
91
+ .dotsTrack {
89
92
  display: flex;
90
93
  align-items: center;
91
94
  justify-content: space-between;
@@ -98,7 +101,7 @@
98
101
  block-size: 25%;
99
102
  border-radius: var(--fui-radius-full, $fui-radius-full);
100
103
  background-color: currentColor;
101
- animation: bounce 1.4s ease-in-out infinite;
104
+ animation: bounce var(--fui-duration-pulse, $fui-duration-pulse) ease-in-out infinite;
102
105
 
103
106
  &:nth-child(1) {
104
107
  animation-delay: 0s;
@@ -135,7 +138,7 @@
135
138
  // Pulse Variant
136
139
  // ============================================
137
140
 
138
- .pulse {
141
+ .pulseTrack {
139
142
  position: relative;
140
143
  inline-size: 100%;
141
144
  block-size: 100%;
@@ -151,7 +154,7 @@
151
154
  border-radius: var(--fui-radius-full, $fui-radius-full);
152
155
  background-color: currentColor;
153
156
  opacity: 0.3;
154
- animation: pulseRing 1.5s ease-out infinite;
157
+ animation: pulseRing var(--fui-duration-pulse, $fui-duration-pulse) ease-out infinite;
155
158
 
156
159
  @media (prefers-reduced-motion: reduce) {
157
160
  animation: none;
@@ -189,7 +192,7 @@
189
192
  align-items: center;
190
193
  justify-content: center;
191
194
  background-color: var(--fui-backdrop, $fui-backdrop);
192
- z-index: 50;
195
+ z-index: var(--fui-overlay-layer-backdrop, 50);
193
196
  }
194
197
 
195
198
  .overlay {
@@ -217,7 +220,7 @@
217
220
  .inlineSpinner {
218
221
  width: var(--inline-size);
219
222
  height: var(--inline-size);
220
- animation: spin 0.8s linear infinite;
223
+ animation: spin var(--fui-duration-spin, $fui-duration-spin) linear infinite;
221
224
  color: currentColor;
222
225
 
223
226
  @media (prefers-reduced-motion: reduce) {
@@ -119,9 +119,9 @@ const LoadingRoot = React.forwardRef<HTMLDivElement, LoadingProps>(function Load
119
119
 
120
120
  const animation =
121
121
  variant === "dots" ? (
122
- <DotsAnimation className={styles.dots} />
122
+ <DotsAnimation className={styles.dotsTrack} />
123
123
  ) : variant === "pulse" ? (
124
- <PulseAnimation className={styles.pulse} />
124
+ <PulseAnimation className={styles.pulseTrack} />
125
125
  ) : (
126
126
  <SpinnerIcon className={styles.spinnerIcon} />
127
127
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "Main",
4
- "description": "Canonical page composition owning gutter, measure, and vertical rhythm.",
4
+ "description": "Owns a page's gutters, reading measure, and vertical rhythm.",
5
5
  "category": "layout",
6
6
  "tags": ["main", "page", "layout", "compound"],
7
7
  "status": "stable",
@@ -45,11 +45,19 @@
45
45
  }
46
46
  },
47
47
  "usage": {
48
- "when": ["Composing a page header, description, content, and footer"],
49
- "whenNot": ["Application shell navigation (use AppShell)"],
48
+ "when": [
49
+ "Laying out a page's header, description, content, and footer",
50
+ "Giving a page one consistent gutter and measure"
51
+ ],
52
+ "whenNot": [
53
+ "Shell-level navigation chrome (use AppShell)",
54
+ "Arbitrary spacing inside a component (use Stack or Box)"
55
+ ],
50
56
  "guidelines": [
51
- "Use one Main gutter owner per page",
52
- "Compose page regions with Main.Header, Main.Description, Main.Content, and Main.Footer"
57
+ "One Main per page owns the gutters — do not nest them",
58
+ "measure=\"narrow\" caps content for reading; \"full\" uses the whole canvas",
59
+ "Compose regions with Main.Header, Main.Description, Main.Content, Main.Footer",
60
+ "Main.Description caps itself at 68ch regardless of measure"
53
61
  ],
54
62
  "accessibility": [
55
63
  "Use the default main element unless an existing shell already owns the main landmark"
@@ -58,13 +66,13 @@
58
66
  "examples": [
59
67
  {
60
68
  "name": "Full Measure",
61
- "description": "Page composition that uses the full available canvas",
62
- "code": "<Main measure=\"full\">\n <Main.Header>Page statement</Main.Header>\n <Main.Description>Supporting page context.</Main.Description>\n <Main.Content>Page content</Main.Content>\n <Main.Footer>Page actions</Main.Footer>\n</Main>"
69
+ "description": "Content fills the canvas, inset only by the page gutter.",
70
+ "code": "import { Box } from '@/components/Box';\nimport { Main } from '@/components/Main';\n\n<Box width=\"100%\" border rounded=\"md\">\n <Main measure=\"full\">\n <Main.Header>Findings</Main.Header>\n <Main.Description>\n Every governance finding raised against this repository, newest first.\n </Main.Description>\n <Main.Content>\n Content stretches edge to edge, inset only by the page gutter.\n </Main.Content>\n <Main.Footer>Export report</Main.Footer>\n </Main>\n</Box>"
63
71
  },
64
72
  {
65
73
  "name": "Narrow Measure",
66
- "description": "Readable page composition constrained to the canonical 800px measure",
67
- "code": "<Main measure=\"narrow\">\n <Main.Header>Settings</Main.Header>\n <Main.Description>Manage the workspace contract.</Main.Description>\n <Main.Content>Settings content</Main.Content>\n <Main.Footer>Save changes</Main.Footer>\n</Main>"
74
+ "description": "Caps content at the reading measure and centres it on wide screens.",
75
+ "code": "import { Box } from '@/components/Box';\nimport { Main } from '@/components/Main';\n\n<Box width=\"100%\" border rounded=\"md\">\n <Main measure=\"narrow\">\n <Main.Header>Settings</Main.Header>\n <Main.Description>\n Manage the workspace contract, canonical components, and token files.\n </Main.Description>\n <Main.Content>\n Content is capped at the reading measure and centred, so long prose stays\n comfortable to read on wide displays.\n </Main.Content>\n <Main.Footer>Save changes</Main.Footer>\n </Main>\n</Box>"
68
76
  }
69
77
  ],
70
78
  "ai": {
@@ -1,16 +1,9 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "Markdown",
4
- "description": "Renders markdown strings as styled prose using react-markdown and remark-gfm. Supports headings, lists, tables, code blocks, blockquotes, and more.",
4
+ "description": "Turns a Markdown string into styled headings, lists, tables, code, and quotes.",
5
5
  "category": "display",
6
- "tags": [
7
- "markdown",
8
- "prose",
9
- "content",
10
- "text",
11
- "ai",
12
- "chat"
13
- ],
6
+ "tags": ["markdown", "prose", "content", "text", "ai", "chat"],
14
7
  "status": "stable",
15
8
  "dependencies": [
16
9
  {
@@ -26,11 +19,7 @@
26
19
  ],
27
20
  "sourcePath": "src/components/Markdown/index.tsx",
28
21
  "exportName": "Markdown",
29
- "propsSummary": [
30
- "content: string (required)",
31
- "components: object",
32
- "className: string"
33
- ],
22
+ "propsSummary": ["content: string (required)", "components: object", "className: string"],
34
23
  "props": {
35
24
  "content": {
36
25
  "type": "string",
@@ -50,50 +39,45 @@
50
39
  },
51
40
  "usage": {
52
41
  "when": [
53
- "Rendering AI/LLM response content",
54
- "Displaying user-authored markdown text",
55
- "Showing documentation or readme content",
56
- "Rich text display without a WYSIWYG editor"
42
+ "Rendering an LLM reply",
43
+ "Showing text a user wrote in Markdown",
44
+ "Docs or readme content inside the app"
57
45
  ],
58
46
  "whenNot": [
59
- "Plain text without formatting (use Text)",
60
- "Editing markdown (use a markdown editor component)",
61
- "Rendering trusted HTML directly (use dangerouslySetInnerHTML)"
47
+ "The string has no formatting (use Text)",
48
+ "The user needs to edit it (use an editor)"
62
49
  ],
63
50
  "guidelines": [
64
- "Install react-markdown and remark-gfm as peer dependencies",
65
- "Use the components prop to override default element rendering",
66
- "Content is sanitized by react-markdown by default",
67
- "The parser is loaded on demand, so the first render on a page is the plain-text fallback and parsed output arrives a tick later; call Markdown.preload() at startup to skip that frame",
68
- "Falls back to plain text paragraphs if react-markdown is not installed",
69
- "Standard div props (id, style, aria-*, data-*) are forwarded to the Markdown wrapper"
51
+ "react-markdown and remark-gfm are peer dependencies — install both",
52
+ "The parser loads on demand, so the first frame is plain text; call Markdown.preload() at startup to skip it",
53
+ "Without react-markdown installed it degrades to plain paragraphs",
54
+ "components overrides how any element renders",
55
+ "react-markdown sanitises the content for you"
70
56
  ],
71
57
  "accessibility": [
72
- "Rendered HTML follows semantic structure (headings, lists, tables)",
73
- "Links are rendered as proper anchor elements",
74
- "Images include alt text from markdown syntax",
75
- "Tables use proper th/td structure for screen readers"
58
+ "Output is real headings, lists, and tables",
59
+ "Links render as anchors, images keep their alt text"
76
60
  ]
77
61
  },
78
62
  "examples": [
79
63
  {
80
64
  "name": "Default",
81
- "description": "Basic markdown with headings, paragraphs, inline code, lists, and blockquote",
65
+ "description": "Headings, emphasis, lists, and quotes all pick up the type scale.",
82
66
  "code": "<Markdown content={`# Hello World\n\nThis is a paragraph with **bold text** and *italic text*.\n\nHere is some \\`inline code\\` within a sentence.\n\n- First item\n- Second item\n- Third item\n\n> A blockquote for emphasis.\n`} />"
83
67
  },
84
68
  {
85
69
  "name": "GFM Table",
86
- "description": "GitHub Flavored Markdown with tables and task lists",
70
+ "description": "remark-gfm adds tables and checkbox items on top of the basics.",
87
71
  "code": "<Markdown content={`## Data Overview\n\n| Feature | Status | Priority |\n|------------|-----------|----------|\n| Markdown | Done | High |\n| Tables | Done | Medium |\n| Task Lists | Planned | Low |\n\nNotes:\n- [x] Support GFM tables\n- [x] Support task lists\n- [ ] Syntax highlighting\n`} />"
88
72
  },
89
73
  {
90
74
  "name": "Code Block",
91
- "description": "Markdown with fenced code blocks and inline code",
92
- "code": "<Markdown content={`## Code Example\\n\\nHere is a JavaScript function:\\n\\n```js\\nfunction greet(name) {\\n return \\`Hello, ${name}!\\`;\\n}\\n```\\n\\nAnd some inline code: \\`const x = 42;\\``} />"
75
+ "description": "Fenced blocks get the same code surface as CodeBlock.",
76
+ "code": "<Markdown content={`## Code Example\n\nHere is a JavaScript function:\n\n```js\nfunction greet(name) {\n return 'Hello, ' + name;\n}\n```\n\nAnd some inline code: \\`const x = 42;\\``} />"
93
77
  },
94
78
  {
95
79
  "name": "Mixed Content",
96
- "description": "Complex markdown mixing headings, lists, tables, blockquotes, and task lists",
80
+ "description": "A realistic document the worst case worth checking.",
97
81
  "code": "<Markdown content={`# Project Update\n\n## Summary\n\nThe project is progressing well. Here are the **key highlights**:\n\n1. Completed the *design system* components\n2. Added markdown rendering support\n3. Integrated with the documentation site\n\n### Performance Metrics\n\n| Metric | Before | After |\n|-------------|--------|-------|\n| Bundle Size | 142kb | 98kb |\n| Load Time | 1.2s | 0.8s |\n| Lighthouse | 72 | 95 |\n\n> These improvements were achieved through tree-shaking and code splitting.\n\n### Next Steps\n\n- [ ] Add syntax highlighting\n- [ ] Support custom themes\n- [x] GFM table support\n`} />"
98
82
  }
99
83
  ],
@@ -121,16 +105,11 @@
121
105
  "className: string - Additional CSS class",
122
106
  "Forwards standard HTML div attributes to the wrapper element"
123
107
  ],
124
- "a11yRules": [
125
- "A11Y_SEMANTIC_HTML"
126
- ]
108
+ "a11yRules": ["A11Y_SEMANTIC_HTML"]
127
109
  },
128
110
  "ai": {
129
111
  "compositionPattern": "compound",
130
- "subComponents": [
131
- "Root",
132
- "preload"
133
- ]
112
+ "subComponents": ["Root", "preload"]
134
113
  },
135
114
  "provenance": {
136
115
  "source": "migrated",
@@ -22,10 +22,10 @@
22
22
  a {
23
23
  @include prose.link;
24
24
 
25
- color: var(--fui-color-accent, $fui-color-accent);
25
+ color: var(--fui-link-ink, #{$fui-link-ink});
26
26
 
27
27
  &:hover {
28
- opacity: 0.8;
28
+ text-decoration: underline;
29
29
  }
30
30
  }
31
31
 
@@ -37,8 +37,46 @@
37
37
  @include prose.list("decimal");
38
38
  }
39
39
 
40
+ // Markdown's tight list items carry one inline run of text + <strong> +
41
+ // <code>. The prose recipe's per-item subgrid fragments that run: every
42
+ // element child becomes its own grid row and the bare text auto-places into
43
+ // the marker column. Markdown lists therefore fall back to block items with
44
+ // a hanging absolute marker (the recipe still supplies the marker content
45
+ // and counter).
46
+ ul,
47
+ ol {
48
+ display: block;
49
+ padding-inline-start: calc(var(--fui-raw-space-20, 20px) + var(--fui-raw-space-8, 8px));
50
+
51
+ > li {
52
+ position: relative;
53
+ display: block;
54
+ min-inline-size: 0;
55
+
56
+ &::before {
57
+ position: absolute;
58
+ inset-inline-start: calc(
59
+ -1 * (var(--fui-raw-space-20, 20px) + var(--fui-raw-space-8, 8px))
60
+ );
61
+ inline-size: var(--fui-raw-space-20, 20px);
62
+ text-align: end;
63
+ }
64
+ }
65
+ }
66
+
40
67
  li + li {
41
- margin-block-start: var(--fui-raw-space-4);
68
+ margin-block-start: var(--fui-raw-space-4, 4px);
69
+ }
70
+
71
+ // GFM task items are `<li><input type="checkbox"> label text</li>`. The
72
+ // checkbox replaces the bullet; block items already keep it inline with the
73
+ // label. `task-list-item` is remark-gfm's runtime class, so the selector
74
+ // must stay global — a module-scoped `.task-list-item` gets hashed and
75
+ // never matches.
76
+ li:global(.task-list-item) {
77
+ &::before {
78
+ content: none;
79
+ }
42
80
  }
43
81
 
44
82
  code {
@@ -78,7 +116,7 @@
78
116
 
79
117
  th,
80
118
  td {
81
- border: var(--fui-stroke-hairline) solid var(--fui-border, $fui-border);
119
+ border: var(--fui-stroke-hairline, $fui-stroke-hairline) solid var(--fui-border, $fui-border);
82
120
  text-align: start;
83
121
  }
84
122
 
@@ -93,7 +131,7 @@
93
131
  }
94
132
 
95
133
  input[type="checkbox"] {
96
- margin-inline-end: var(--fui-raw-space-4);
134
+ margin-inline-end: var(--fui-raw-space-4, 4px);
97
135
  }
98
136
 
99
137
  strong {
@@ -1,7 +1,8 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as React from 'react';
4
- import styles from './Markdown.module.scss';
3
+ import * as React from "react";
4
+ import styles from "./Markdown.module.scss";
5
+ import { isDevelopmentBuild } from "../../utils/env";
5
6
 
6
7
  // ============================================
7
8
  // Types
@@ -10,7 +11,7 @@ import styles from './Markdown.module.scss';
10
11
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
12
  type MarkdownComponentMap = Record<string, React.ComponentType<any>>;
12
13
 
13
- export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
14
+ export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
14
15
  /** Markdown string to render */
15
16
  content: string;
16
17
  /** Override map for markdown element components */
@@ -47,22 +48,22 @@ function loadDeps(): Promise<void> {
47
48
  if (!loadPromise) {
48
49
  loadPromise = (async () => {
49
50
  try {
50
- const mod = await import('react-markdown');
51
+ const mod = await import("react-markdown");
51
52
  ReactMarkdown = ((mod as { default?: ReactMarkdownType }).default ??
52
53
  mod) as ReactMarkdownType;
53
54
  } catch {
54
55
  loadFailed = true;
55
- if (process.env.NODE_ENV === 'development') {
56
+ if (isDevelopmentBuild()) {
56
57
  console.warn(
57
- '[@usefragments/ui] Markdown: react-markdown is not installed. ' +
58
- 'Install it with: npm install react-markdown remark-gfm'
58
+ "[@usefragments/ui] Markdown: react-markdown is not installed. " +
59
+ "Install it with: npm install react-markdown remark-gfm"
59
60
  );
60
61
  }
61
62
  return;
62
63
  }
63
64
 
64
65
  try {
65
- const mod = await import('remark-gfm');
66
+ const mod = await import("remark-gfm");
66
67
  remarkGfm = (mod as { default?: unknown }).default ?? mod;
67
68
  } catch {
68
69
  // remark-gfm is optional; markdown still works without it
@@ -80,8 +81,8 @@ function FallbackRenderer({ content }: { content: string }) {
80
81
  const paragraphs = content.split(/\n{2,}/);
81
82
  return (
82
83
  <>
83
- {paragraphs.map((p) => (
84
- <p key={p}>{p}</p>
84
+ {paragraphs.map((p, index) => (
85
+ <p key={index}>{p}</p>
85
86
  ))}
86
87
  </>
87
88
  );
@@ -91,49 +92,47 @@ function FallbackRenderer({ content }: { content: string }) {
91
92
  // Component
92
93
  // ============================================
93
94
 
94
- const MarkdownRoot = React.forwardRef<HTMLDivElement, MarkdownProps>(
95
- function Markdown({ content, components: componentOverrides, className, ...htmlProps }, ref) {
96
- // The parser resolves asynchronously, so the first mount on a page renders
97
- // the fallback and then swaps. Both module-level results are cached, so
98
- // every later mount is synchronous; an app that knows prose is coming can
99
- // skip even the first swap by calling Markdown.preload() up front.
100
- const [, rerender] = React.useReducer((n: number) => n + 1, 0);
101
-
102
- React.useEffect(() => {
103
- if (ReactMarkdown || loadFailed) return;
104
- let active = true;
105
- void loadDeps().then(() => {
106
- if (active) rerender();
107
- });
108
- return () => {
109
- active = false;
110
- };
111
- }, []);
112
-
113
- const classes = [styles.markdown, className].filter(Boolean).join(' ');
114
-
115
- if (!ReactMarkdown) {
116
- return (
117
- <div ref={ref} {...htmlProps} className={classes}>
118
- <FallbackRenderer content={content} />
119
- </div>
120
- );
121
- }
122
-
123
- const plugins = remarkGfm ? [remarkGfm] : [];
124
-
95
+ const MarkdownRoot = React.forwardRef<HTMLDivElement, MarkdownProps>(function Markdown(
96
+ { content, components: componentOverrides, className, ...htmlProps },
97
+ ref
98
+ ) {
99
+ // The parser resolves asynchronously, so the first mount on a page renders
100
+ // the fallback and then swaps. Both module-level results are cached, so
101
+ // every later mount is synchronous; an app that knows prose is coming can
102
+ // skip even the first swap by calling Markdown.preload() up front.
103
+ const [, rerender] = React.useReducer((n: number) => n + 1, 0);
104
+
105
+ React.useEffect(() => {
106
+ if (ReactMarkdown || loadFailed) return;
107
+ let active = true;
108
+ void loadDeps().then(() => {
109
+ if (active) rerender();
110
+ });
111
+ return () => {
112
+ active = false;
113
+ };
114
+ }, []);
115
+
116
+ const classes = [styles.markdown, className].filter(Boolean).join(" ");
117
+
118
+ if (!ReactMarkdown) {
125
119
  return (
126
120
  <div ref={ref} {...htmlProps} className={classes}>
127
- <ReactMarkdown
128
- remarkPlugins={plugins}
129
- components={componentOverrides}
130
- >
131
- {content}
132
- </ReactMarkdown>
121
+ <FallbackRenderer content={content} />
133
122
  </div>
134
123
  );
135
124
  }
136
- );
125
+
126
+ const plugins = remarkGfm ? [remarkGfm] : [];
127
+
128
+ return (
129
+ <div ref={ref} {...htmlProps} className={classes}>
130
+ <ReactMarkdown remarkPlugins={plugins} components={componentOverrides}>
131
+ {content}
132
+ </ReactMarkdown>
133
+ </div>
134
+ );
135
+ });
137
136
 
138
137
  export const Markdown = Object.assign(MarkdownRoot, {
139
138
  Root: MarkdownRoot,