@fragments-sdk/ui 0.17.1 → 0.19.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 (286) hide show
  1. package/dist/assets/ui.css +2700 -3256
  2. package/dist/chart.cjs +0 -1
  3. package/dist/chart.js +0 -1
  4. package/dist/codeblock.cjs +0 -1
  5. package/dist/codeblock.js +0 -1
  6. package/dist/colorpicker.cjs +0 -1
  7. package/dist/colorpicker.js +0 -1
  8. package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
  9. package/dist/components/Accordion/Accordion.module.scss.js +8 -8
  10. package/dist/components/Alert/Alert.module.scss.cjs +12 -12
  11. package/dist/components/Alert/Alert.module.scss.js +12 -12
  12. package/dist/components/AppShell/AppShell.module.scss.cjs +12 -12
  13. package/dist/components/AppShell/AppShell.module.scss.js +12 -12
  14. package/dist/components/Avatar/Avatar.module.scss.cjs +13 -13
  15. package/dist/components/Avatar/Avatar.module.scss.js +13 -13
  16. package/dist/components/Badge/Badge.module.scss.cjs +13 -13
  17. package/dist/components/Badge/Badge.module.scss.js +13 -13
  18. package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
  19. package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
  20. package/dist/components/Box/Box.module.scss.cjs +152 -152
  21. package/dist/components/Box/Box.module.scss.js +152 -152
  22. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
  23. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
  24. package/dist/components/Button/Button.module.scss.cjs +12 -12
  25. package/dist/components/Button/Button.module.scss.js +12 -12
  26. package/dist/components/Card/Card.module.scss.cjs +14 -14
  27. package/dist/components/Card/Card.module.scss.js +14 -14
  28. package/dist/components/Chart/Chart.module.scss.cjs +15 -15
  29. package/dist/components/Chart/Chart.module.scss.js +15 -15
  30. package/dist/components/Chart/index.d.ts +0 -1
  31. package/dist/components/Chart/index.d.ts.map +1 -1
  32. package/dist/components/Checkbox/Checkbox.module.scss.cjs +10 -10
  33. package/dist/components/Checkbox/Checkbox.module.scss.js +10 -10
  34. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  35. package/dist/components/Chip/Chip.module.scss.js +15 -15
  36. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +21 -21
  37. package/dist/components/CodeBlock/CodeBlock.module.scss.js +21 -21
  38. package/dist/components/CodeBlock/index.d.ts +0 -1
  39. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  40. package/dist/components/Collapsible/Collapsible.module.scss.cjs +10 -10
  41. package/dist/components/Collapsible/Collapsible.module.scss.js +10 -10
  42. package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
  43. package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
  44. package/dist/components/ColorPicker/index.d.ts +0 -1
  45. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  46. package/dist/components/Combobox/Combobox.module.scss.cjs +23 -23
  47. package/dist/components/Combobox/Combobox.module.scss.js +23 -23
  48. package/dist/components/Combobox/index.cjs +13 -10
  49. package/dist/components/Combobox/index.d.ts.map +1 -1
  50. package/dist/components/Combobox/index.js +13 -10
  51. package/dist/components/Command/Command.module.scss.cjs +11 -11
  52. package/dist/components/Command/Command.module.scss.js +11 -11
  53. package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
  54. package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
  55. package/dist/components/DataTable/DataTable.module.scss.cjs +26 -26
  56. package/dist/components/DataTable/DataTable.module.scss.js +26 -26
  57. package/dist/components/DataTable/index.cjs +0 -1
  58. package/dist/components/DataTable/index.d.ts +0 -1
  59. package/dist/components/DataTable/index.d.ts.map +1 -1
  60. package/dist/components/DataTable/index.js +0 -1
  61. package/dist/components/DatePicker/DatePicker.module.scss.cjs +31 -31
  62. package/dist/components/DatePicker/DatePicker.module.scss.js +31 -31
  63. package/dist/components/DatePicker/index.d.ts +0 -1
  64. package/dist/components/DatePicker/index.d.ts.map +1 -1
  65. package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
  66. package/dist/components/Dialog/Dialog.module.scss.js +14 -14
  67. package/dist/components/Drawer/Drawer.module.scss.cjs +33 -27
  68. package/dist/components/Drawer/Drawer.module.scss.js +34 -28
  69. package/dist/components/Drawer/index.cjs +36 -14
  70. package/dist/components/Drawer/index.d.ts +21 -3
  71. package/dist/components/Drawer/index.d.ts.map +1 -1
  72. package/dist/components/Drawer/index.js +36 -14
  73. package/dist/components/Editor/Editor.module.scss.cjs +17 -17
  74. package/dist/components/Editor/Editor.module.scss.js +17 -17
  75. package/dist/components/EmptyState/EmptyState.module.scss.cjs +8 -8
  76. package/dist/components/EmptyState/EmptyState.module.scss.js +8 -8
  77. package/dist/components/Field/Field.module.scss.cjs +4 -4
  78. package/dist/components/Field/Field.module.scss.js +4 -4
  79. package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
  80. package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
  81. package/dist/components/Header/Header.module.scss.cjs +28 -28
  82. package/dist/components/Header/Header.module.scss.js +28 -28
  83. package/dist/components/Icon/Icon.module.scss.cjs +8 -8
  84. package/dist/components/Icon/Icon.module.scss.js +8 -8
  85. package/dist/components/Image/Image.module.scss.cjs +27 -27
  86. package/dist/components/Image/Image.module.scss.js +27 -27
  87. package/dist/components/Input/Input.module.scss.cjs +19 -19
  88. package/dist/components/Input/Input.module.scss.js +19 -19
  89. package/dist/components/Link/Link.module.scss.cjs +10 -10
  90. package/dist/components/Link/Link.module.scss.js +10 -10
  91. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  92. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  93. package/dist/components/Loading/Loading.module.scss.cjs +30 -30
  94. package/dist/components/Loading/Loading.module.scss.js +30 -30
  95. package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
  96. package/dist/components/Markdown/Markdown.module.scss.js +1 -1
  97. package/dist/components/Markdown/index.d.ts +0 -1
  98. package/dist/components/Markdown/index.d.ts.map +1 -1
  99. package/dist/components/Menu/Menu.module.scss.cjs +16 -13
  100. package/dist/components/Menu/Menu.module.scss.js +17 -14
  101. package/dist/components/Menu/index.cjs +1 -1
  102. package/dist/components/Menu/index.d.ts.map +1 -1
  103. package/dist/components/Menu/index.js +1 -1
  104. package/dist/components/Message/Message.module.scss.cjs +18 -18
  105. package/dist/components/Message/Message.module.scss.js +18 -18
  106. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
  107. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
  108. package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
  109. package/dist/components/Pagination/Pagination.module.scss.js +7 -7
  110. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  111. package/dist/components/Popover/Popover.module.scss.js +10 -10
  112. package/dist/components/Progress/Progress.module.scss.cjs +25 -25
  113. package/dist/components/Progress/Progress.module.scss.js +25 -25
  114. package/dist/components/Prompt/Prompt.module.scss.cjs +26 -14
  115. package/dist/components/Prompt/Prompt.module.scss.js +26 -14
  116. package/dist/components/Prompt/index.cjs +16 -0
  117. package/dist/components/Prompt/index.d.ts +17 -1
  118. package/dist/components/Prompt/index.d.ts.map +1 -1
  119. package/dist/components/Prompt/index.js +16 -0
  120. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +16 -16
  121. package/dist/components/RadioGroup/RadioGroup.module.scss.js +16 -16
  122. package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +10 -10
  123. package/dist/components/ScrollArea/ScrollArea.module.scss.js +10 -10
  124. package/dist/components/Select/Select.module.scss.cjs +17 -17
  125. package/dist/components/Select/Select.module.scss.js +17 -17
  126. package/dist/components/Select/index.cjs +20 -20
  127. package/dist/components/Select/index.d.ts.map +1 -1
  128. package/dist/components/Select/index.js +20 -20
  129. package/dist/components/Separator/Separator.module.scss.cjs +10 -10
  130. package/dist/components/Separator/Separator.module.scss.js +10 -10
  131. package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
  132. package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
  133. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  134. package/dist/components/Slider/Slider.module.scss.js +12 -12
  135. package/dist/components/Slider/index.cjs +23 -21
  136. package/dist/components/Slider/index.js +23 -21
  137. package/dist/components/Stack/Stack.module.scss.cjs +35 -35
  138. package/dist/components/Stack/Stack.module.scss.js +35 -35
  139. package/dist/components/Table/Table.module.scss.cjs +16 -16
  140. package/dist/components/Table/Table.module.scss.js +16 -16
  141. package/dist/components/Table/index.d.ts +0 -1
  142. package/dist/components/Table/index.d.ts.map +1 -1
  143. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +7 -7
  144. package/dist/components/TableOfContents/TableOfContents.module.scss.js +7 -7
  145. package/dist/components/Tabs/Tabs.module.scss.cjs +9 -9
  146. package/dist/components/Tabs/Tabs.module.scss.js +9 -9
  147. package/dist/components/Text/Text.module.scss.cjs +38 -38
  148. package/dist/components/Text/Text.module.scss.js +38 -38
  149. package/dist/components/Textarea/Textarea.module.scss.cjs +23 -23
  150. package/dist/components/Textarea/Textarea.module.scss.js +23 -23
  151. package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
  152. package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
  153. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +22 -22
  154. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +22 -22
  155. package/dist/components/Toast/Toast.module.scss.cjs +20 -20
  156. package/dist/components/Toast/Toast.module.scss.js +20 -20
  157. package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
  158. package/dist/components/Toggle/Toggle.module.scss.js +13 -13
  159. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  160. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  161. package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
  162. package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
  163. package/dist/components/Tooltip/index.cjs +4 -3
  164. package/dist/components/Tooltip/index.d.ts +4 -1
  165. package/dist/components/Tooltip/index.d.ts.map +1 -1
  166. package/dist/components/Tooltip/index.js +4 -3
  167. package/dist/datepicker.cjs +0 -1
  168. package/dist/datepicker.js +0 -1
  169. package/dist/index.cjs +0 -1
  170. package/dist/index.d.ts +2 -3
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +0 -1
  173. package/dist/markdown.cjs +0 -1
  174. package/dist/markdown.js +0 -1
  175. package/dist/table.cjs +0 -1
  176. package/dist/table.js +0 -1
  177. package/dist/utils/seed-derivation.cjs +29 -0
  178. package/dist/utils/seed-derivation.d.ts +1 -1
  179. package/dist/utils/seed-derivation.d.ts.map +1 -1
  180. package/dist/utils/seed-derivation.js +29 -0
  181. package/fragments.json +1 -1
  182. package/package.json +18 -14
  183. package/src/components/Accordion/Accordion.contract.json +169 -0
  184. package/src/components/Alert/Alert.contract.json +157 -0
  185. package/src/components/AppShell/AppShell.contract.json +155 -0
  186. package/src/components/Avatar/Avatar.contract.json +189 -0
  187. package/src/components/Badge/Badge.contract.json +187 -0
  188. package/src/components/BentoGrid/BentoGrid.contract.json +135 -0
  189. package/src/components/Box/Box.contract.json +423 -0
  190. package/src/components/Breadcrumbs/Breadcrumbs.contract.json +143 -0
  191. package/src/components/Button/Button.contract.json +205 -0
  192. package/src/components/Button/Button.module.scss +24 -1
  193. package/src/components/ButtonGroup/ButtonGroup.contract.json +140 -0
  194. package/src/components/Card/Card.contract.json +185 -0
  195. package/src/components/Card/Card.module.scss +5 -1
  196. package/src/components/Chart/Chart.contract.json +129 -0
  197. package/src/components/Chart/index.tsx +0 -1
  198. package/src/components/Checkbox/Checkbox.contract.json +246 -0
  199. package/src/components/Chip/Chip.contract.json +212 -0
  200. package/src/components/Chip/Chip.module.scss +4 -4
  201. package/src/components/CodeBlock/CodeBlock.contract.json +388 -0
  202. package/src/components/CodeBlock/index.tsx +0 -1
  203. package/src/components/Collapsible/Collapsible.contract.json +154 -0
  204. package/src/components/ColorPicker/ColorPicker.contract.json +212 -0
  205. package/src/components/ColorPicker/index.tsx +0 -1
  206. package/src/components/Combobox/Combobox.contract.json +297 -0
  207. package/src/components/Combobox/index.tsx +7 -8
  208. package/src/components/Command/Command.contract.json +165 -0
  209. package/src/components/Command/Command.module.scss +22 -9
  210. package/src/components/ConversationList/ConversationList.contract.json +151 -0
  211. package/src/components/DataTable/DataTable.contract.json +302 -0
  212. package/src/components/DataTable/index.tsx +0 -2
  213. package/src/components/DatePicker/DatePicker.contract.json +288 -0
  214. package/src/components/DatePicker/index.tsx +0 -2
  215. package/src/components/Dialog/Dialog.contract.json +159 -0
  216. package/src/components/Drawer/Drawer.contract.json +161 -0
  217. package/src/components/Drawer/Drawer.module.scss +45 -5
  218. package/src/components/Drawer/index.tsx +66 -23
  219. package/src/components/Editor/Editor.contract.json +263 -0
  220. package/src/components/EmptyState/EmptyState.contract.json +133 -0
  221. package/src/components/Field/Field.contract.json +157 -0
  222. package/src/components/Fieldset/Fieldset.contract.json +117 -0
  223. package/src/components/Form/Form.contract.json +145 -0
  224. package/src/components/Grid/Grid.contract.json +195 -0
  225. package/src/components/Header/Header.contract.json +196 -0
  226. package/src/components/Icon/Icon.contract.json +194 -0
  227. package/src/components/Image/Image.contract.json +209 -0
  228. package/src/components/Input/Input.contract.json +344 -0
  229. package/src/components/Input/Input.module.scss +16 -6
  230. package/src/components/Link/Link.contract.json +180 -0
  231. package/src/components/List/List.contract.json +154 -0
  232. package/src/components/Listbox/Listbox.contract.json +158 -0
  233. package/src/components/Loading/Loading.contract.json +167 -0
  234. package/src/components/Markdown/Markdown.contract.json +127 -0
  235. package/src/components/Markdown/Markdown.module.scss +0 -3
  236. package/src/components/Markdown/index.tsx +0 -1
  237. package/src/components/Menu/Menu.contract.json +177 -0
  238. package/src/components/Menu/Menu.module.scss +6 -0
  239. package/src/components/Menu/index.tsx +3 -1
  240. package/src/components/Message/Message.contract.json +183 -0
  241. package/src/components/Message/Message.module.scss +2 -2
  242. package/src/components/NavigationMenu/NavigationMenu.contract.json +203 -0
  243. package/src/components/NavigationMenu/NavigationMenu.module.scss +18 -23
  244. package/src/components/Pagination/Pagination.contract.json +163 -0
  245. package/src/components/Pagination/Pagination.module.scss +1 -1
  246. package/src/components/Popover/Popover.contract.json +163 -0
  247. package/src/components/Progress/Progress.contract.json +176 -0
  248. package/src/components/Prompt/Prompt.contract.json +211 -0
  249. package/src/components/Prompt/Prompt.module.scss +117 -3
  250. package/src/components/Prompt/index.tsx +40 -0
  251. package/src/components/RadioGroup/RadioGroup.contract.json +226 -0
  252. package/src/components/ScrollArea/ScrollArea.contract.json +131 -0
  253. package/src/components/Select/Select.contract.json +269 -0
  254. package/src/components/Select/index.tsx +20 -25
  255. package/src/components/Separator/Separator.contract.json +143 -0
  256. package/src/components/Sidebar/Sidebar.contract.json +258 -0
  257. package/src/components/Sidebar/Sidebar.module.scss +1 -1
  258. package/src/components/Skeleton/Skeleton.contract.json +166 -0
  259. package/src/components/Slider/Slider.contract.json +248 -0
  260. package/src/components/Slider/index.tsx +10 -10
  261. package/src/components/Stack/Stack.contract.json +220 -0
  262. package/src/components/Table/Table.contract.json +171 -0
  263. package/src/components/Table/index.tsx +0 -2
  264. package/src/components/TableOfContents/TableOfContents.contract.json +145 -0
  265. package/src/components/TableOfContents/TableOfContents.module.scss +19 -15
  266. package/src/components/Tabs/Tabs.contract.json +159 -0
  267. package/src/components/Text/Text.contract.json +239 -0
  268. package/src/components/Textarea/Textarea.contract.json +308 -0
  269. package/src/components/Theme/Theme.contract.json +152 -0
  270. package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +165 -0
  271. package/src/components/Toast/Toast.contract.json +181 -0
  272. package/src/components/Toggle/Toggle.contract.json +231 -0
  273. package/src/components/Toggle/Toggle.module.scss +3 -3
  274. package/src/components/ToggleGroup/ToggleGroup.contract.json +206 -0
  275. package/src/components/Tooltip/Tooltip.contract.json +214 -0
  276. package/src/components/Tooltip/index.tsx +7 -3
  277. package/src/components/VisuallyHidden/VisuallyHidden.contract.json +116 -0
  278. package/src/index.ts +8 -3
  279. package/src/styles/globals.scss +6 -1
  280. package/src/tokens/_computed.scss +3 -1
  281. package/src/tokens/_density.scss +4 -4
  282. package/src/tokens/_derive.scss +52 -56
  283. package/src/tokens/_palettes.scss +20 -1
  284. package/src/tokens/_seeds.scss +2 -2
  285. package/src/tokens/_variables.scss +45 -29
  286. package/src/utils/seed-derivation.ts +23 -1
@@ -36,6 +36,9 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
36
36
  defaultOpen?: boolean;
37
37
  /** Callback when open state changes */
38
38
  onOpenChange?: (open: boolean) => void;
39
+ /** Whether clicking the trigger closes the tooltip.
40
+ * @default false */
41
+ closeOnClick?: boolean;
39
42
  /** Explicit props for the tooltip popup element (preferred over top-level HTMLAttributes for clarity) */
40
43
  contentProps?: React.HTMLAttributes<HTMLDivElement>;
41
44
  }
@@ -83,6 +86,7 @@ function TooltipRoot({
83
86
  open,
84
87
  defaultOpen,
85
88
  onOpenChange,
89
+ closeOnClick = false,
86
90
  contentProps,
87
91
  className,
88
92
  style,
@@ -113,8 +117,8 @@ function TooltipRoot({
113
117
  [children],
114
118
  );
115
119
 
116
- if (disabled) {
117
- return children;
120
+ if (disabled || !children) {
121
+ return children ?? null;
118
122
  }
119
123
 
120
124
  const {
@@ -129,7 +133,7 @@ function TooltipRoot({
129
133
  defaultOpen={defaultOpen}
130
134
  onOpenChange={onOpenChange}
131
135
  >
132
- <BaseTooltip.Trigger render={renderTrigger} />
136
+ <BaseTooltip.Trigger closeOnClick={closeOnClick} render={renderTrigger} />
133
137
  <BaseTooltip.Portal>
134
138
  <BaseTooltip.Positioner
135
139
  side={side}
@@ -0,0 +1,116 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "VisuallyHidden",
4
+ "description": "Hides content visually while keeping it accessible to screen readers. Essential for accessible icon-only buttons and supplementary text.",
5
+ "category": "navigation",
6
+ "tags": [
7
+ "accessibility",
8
+ "a11y",
9
+ "screen-reader",
10
+ "hidden",
11
+ "sr-only"
12
+ ],
13
+ "status": "stable",
14
+ "sourcePath": "src/components/VisuallyHidden/index.tsx",
15
+ "exportName": "VisuallyHidden",
16
+ "propsSummary": [
17
+ "children: node (required)",
18
+ "as: span|div (default: span)"
19
+ ],
20
+ "props": {
21
+ "children": {
22
+ "type": "node",
23
+ "description": "Content to hide visually",
24
+ "required": true
25
+ },
26
+ "as": {
27
+ "type": "enum",
28
+ "description": "HTML element to render",
29
+ "default": "span",
30
+ "required": false,
31
+ "values": [
32
+ "span",
33
+ "div"
34
+ ]
35
+ }
36
+ },
37
+ "usage": {
38
+ "when": [
39
+ "Providing accessible labels for icon-only buttons",
40
+ "Adding context that screen readers need but sighted users don't",
41
+ "Hiding decorative content while providing text alternatives",
42
+ "Skip links for keyboard navigation"
43
+ ],
44
+ "whenNot": [
45
+ "Hiding content from everyone (use display: none or conditional render)",
46
+ "Content that should be visible on focus (use focus-visible styles)",
47
+ "Temporarily hidden content (use proper ARIA attributes)",
48
+ "Lazy-loaded content (use suspense or loading states)"
49
+ ],
50
+ "guidelines": [
51
+ "Always use with icon-only interactive elements",
52
+ "Keep hidden text concise but descriptive",
53
+ "Test with screen readers to verify announcements",
54
+ "Don't overuse; visible text is often better",
55
+ "VisuallyHidden forwards DOM props and className to the rendered element"
56
+ ],
57
+ "accessibility": [
58
+ "Content is announced by screen readers",
59
+ "Content is focusable if interactive elements are inside",
60
+ "Essential for WCAG 2.1 compliance with icon-only controls",
61
+ "Must convey equivalent information to visual content"
62
+ ]
63
+ },
64
+ "examples": [
65
+ {
66
+ "name": "Icon Button Label",
67
+ "description": "Accessible label for icon-only button",
68
+ "code": "<button style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n border: '1px solid var(--fui-border-default)',\n borderRadius: '8px',\n background: 'var(--fui-color-surface-primary)',\n cursor: 'pointer'\n}}>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <VisuallyHidden>Search</VisuallyHidden>\n</button>"
69
+ },
70
+ {
71
+ "name": "Supplementary Text",
72
+ "description": "Additional context for screen readers",
73
+ "code": "<a href=\"#\" style={{ color: 'var(--fui-color-accent)' }}>\n Read more\n <VisuallyHidden> about our accessibility features</VisuallyHidden>\n</a>"
74
+ },
75
+ {
76
+ "name": "Skip Link",
77
+ "description": "Navigation aid that becomes visible on focus",
78
+ "code": "<div>\n <VisuallyHidden as=\"div\">\n <a\n href=\"#main-content\"\n style={{\n position: 'absolute',\n padding: '8px 16px',\n background: 'var(--fui-color-accent)',\n color: 'white'\n }}\n >\n Skip to main content\n </a>\n </VisuallyHidden>\n <p style={{ color: 'var(--fui-color-text-tertiary)', fontSize: '14px' }}>\n (Screen reader only: \"Skip to main content\" link)\n </p>\n</div>"
79
+ }
80
+ ],
81
+ "relations": [
82
+ {
83
+ "component": "Button",
84
+ "relationship": "child",
85
+ "note": "Use inside icon-only buttons for accessible labels"
86
+ },
87
+ {
88
+ "component": "Icon",
89
+ "relationship": "sibling",
90
+ "note": "Pair with icons to provide text alternatives"
91
+ }
92
+ ],
93
+ "contract": {
94
+ "propsSummary": [
95
+ "children: ReactNode - hidden text (required)",
96
+ "as: span|div - HTML element",
97
+ "Forwards standard DOM props (id, aria-*, data-*, className, handlers)"
98
+ ],
99
+ "a11yRules": [
100
+ "A11Y_SR_ONLY",
101
+ "A11Y_ICON_LABEL"
102
+ ]
103
+ },
104
+ "ai": {
105
+ "compositionPattern": "compound",
106
+ "subComponents": [
107
+ "Root"
108
+ ]
109
+ },
110
+ "provenance": {
111
+ "source": "migrated",
112
+ "verified": false,
113
+ "frameworkSupport": "native",
114
+ "extractedAt": "2026-03-13T23:19:06.625Z"
115
+ }
116
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
- // Import CSS variables and base styles
2
- // This ensures --fui-* variables are available when using any component
3
- import './styles/globals.scss';
1
+ // CSS variables and base styles are NOT auto-imported here.
2
+ // Consumers must import styles separately with seed configuration:
3
+ // @use '@fragments-sdk/ui/styles' with ($fui-brand: ..., $fui-neutral: ...);
4
+ // Bundling globals.scss here would compile with default seeds and
5
+ // override any consumer-configured palette.
4
6
 
5
7
  // Runtime CSS detection — warns if component styles aren't loaded
6
8
  import { checkCssLoaded } from './utils/css-warning';
@@ -404,6 +406,8 @@ export {
404
406
  type PromptVariant,
405
407
  type PromptTextareaProps,
406
408
  type PromptToolbarProps,
409
+ type PromptTabsProps,
410
+ type PromptTabProps,
407
411
  type PromptActionsProps,
408
412
  type PromptInfoProps,
409
413
  type PromptActionButtonProps,
@@ -591,6 +595,7 @@ export {
591
595
  type DrawerBodyProps,
592
596
  type DrawerFooterProps,
593
597
  type DrawerCloseProps,
598
+ type DrawerSwipeAreaProps,
594
599
  } from './components/Drawer';
595
600
 
596
601
  // Pagination
@@ -83,13 +83,18 @@ $fui-info: #3b82f6 !default;
83
83
  }
84
84
 
85
85
  // Base Element Resets
86
- :where(html) {
86
+ // Use real specificity (not :where()) for font-size so it overrides
87
+ // the browser default 16px. This makes 1rem = 14px throughout.
88
+ html {
89
+ font-size: #{$fui-base-font-size};
87
90
  scroll-behavior: smooth;
88
91
  }
89
92
 
90
93
  :where(body) {
91
94
  margin: 0;
95
+ font-size: inherit;
92
96
  font-family: var(--fui-font-sans, Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
97
+ line-height: var(--fui-line-height-normal, $fui-line-height-normal);
93
98
  background-color: var(--fui-bg-primary, #ffffff);
94
99
  color: var(--fui-text-primary, #171717);
95
100
  -webkit-font-smoothing: antialiased;
@@ -86,6 +86,7 @@ $computed-sidebar-item-height: density.px-to-rem($_density, map.get($_density, s
86
86
 
87
87
  // Accent colors (from brand seed)
88
88
  $computed-color-accent: seeds.$fui-brand;
89
+ $computed-color-on-accent: derive.contrast-color(seeds.$fui-brand);
89
90
  $computed-color-accent-hover: derive.derive-accent-hover(seeds.$fui-brand, false);
90
91
  $computed-color-accent-active: derive.derive-accent-active(seeds.$fui-brand, false);
91
92
 
@@ -153,8 +154,9 @@ $computed-backdrop: derive.derive-backdrop(false);
153
154
  // Computed: Colors - Dark Mode
154
155
  // --------------------------------------------
155
156
 
156
- // Accent colors (derive light version for dark mode)
157
+ // Accent colors dark brands lightened for visibility; on-accent handles text contrast
157
158
  $computed-dark-color-accent: derive.derive-dark-accent(seeds.$fui-brand);
159
+ $computed-dark-color-on-accent: derive.contrast-color($computed-dark-color-accent);
158
160
  $computed-dark-color-accent-hover: derive.derive-accent-hover($computed-dark-color-accent, true);
159
161
  $computed-dark-color-accent-active: derive.derive-accent-active($computed-dark-color-accent, true);
160
162
 
@@ -59,8 +59,8 @@ $density-default: (
59
59
  // Input height
60
60
  input-height: 40px,
61
61
  // ~6 units
62
- input-height-sm: 28px,
63
- // 4 units
62
+ input-height-sm: 32px,
63
+ // ~4.5 units
64
64
  input-height-lg: 44px,
65
65
  // ~6 units
66
66
  // Touch targets (baseline)
@@ -70,8 +70,8 @@ $density-default: (
70
70
  touch-lg: 44px,
71
71
  // WCAG AAA recommended
72
72
  // Sidebar navigation
73
- sidebar-item-height: 35px,
74
- // 5 units
73
+ sidebar-item-height: 36px,
74
+ // ~5 units
75
75
  );
76
76
 
77
77
  $density-relaxed: (
@@ -20,14 +20,8 @@
20
20
  /// @param {Color} $color - Color to check
21
21
  /// @return {Boolean} True if dark
22
22
  @function is-dark-color($color) {
23
- $r: math.div(color.channel($color, 'red', $space: rgb), 255);
24
- $g: math.div(color.channel($color, 'green', $space: rgb), 255);
25
- $b: math.div(color.channel($color, 'blue', $space: rgb), 255);
26
-
27
- // Relative luminance formula (simplified)
28
- $luminance: 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
29
-
30
- @return $luminance < 0.5;
23
+ // oklch lightness is perceptually uniform (0-1 range)
24
+ @return color.channel($color, 'lightness', $space: oklch) < 0.5;
31
25
  }
32
26
 
33
27
  /// Get appropriate contrast color (black or white)
@@ -52,22 +46,22 @@
52
46
  /// @param {Boolean} $is-dark - Whether in dark mode
53
47
  /// @return {Color} Hover state color
54
48
  @function derive-accent-hover($base, $is-dark: false) {
55
- $l: color.channel($base, 'lightness', $space: hsl);
49
+ $l: color.channel($base, 'lightness', $space: oklch);
56
50
 
57
51
  @if $is-dark {
58
- @if $l > 85% {
52
+ @if $l > 0.85 {
59
53
  // Very light accent on dark bg: darken for visible hover
60
- @return color.scale($base, $lightness: -10%);
54
+ @return color.adjust($base, $lightness: -0.05, $space: oklch);
61
55
  }
62
56
  // Standard dark mode: lighten for hover
63
- @return color.scale($base, $lightness: 8%);
57
+ @return color.adjust($base, $lightness: 0.04, $space: oklch);
64
58
  } @else {
65
- @if $l < 15% {
59
+ @if $l < 0.15 {
66
60
  // Very dark accent on light bg: lighten for visible hover
67
- @return color.scale($base, $lightness: 18%);
61
+ @return color.adjust($base, $lightness: 0.09, $space: oklch);
68
62
  }
69
63
  // Standard light mode: darken for hover
70
- @return color.scale($base, $lightness: -10%);
64
+ @return color.adjust($base, $lightness: -0.05, $space: oklch);
71
65
  }
72
66
  }
73
67
 
@@ -78,38 +72,36 @@
78
72
  /// @param {Boolean} $is-dark - Whether in dark mode
79
73
  /// @return {Color} Active state color
80
74
  @function derive-accent-active($base, $is-dark: false) {
81
- $l: color.channel($base, 'lightness', $space: hsl);
75
+ $l: color.channel($base, 'lightness', $space: oklch);
82
76
 
83
77
  @if $is-dark {
84
- @if $l > 85% {
78
+ @if $l > 0.85 {
85
79
  // Very light accent on dark bg: darken more for active
86
- @return color.scale($base, $lightness: -16%);
80
+ @return color.adjust($base, $lightness: -0.08, $space: oklch);
87
81
  }
88
82
  // Standard dark mode: lighten more for active
89
- @return color.scale($base, $lightness: 14%);
83
+ @return color.adjust($base, $lightness: 0.07, $space: oklch);
90
84
  } @else {
91
- @if $l < 15% {
85
+ @if $l < 0.15 {
92
86
  // Very dark accent on light bg: lighten more for active
93
- @return color.scale($base, $lightness: 28%);
87
+ @return color.adjust($base, $lightness: 0.14, $space: oklch);
94
88
  }
95
89
  // Standard light mode: darken more for active
96
- @return color.scale($base, $lightness: -18%);
90
+ @return color.adjust($base, $lightness: -0.09, $space: oklch);
97
91
  }
98
92
  }
99
93
 
100
94
  /// Derive a light variant of accent for dark mode
101
- /// Auto-lightens dark brand colors so they're visible on dark backgrounds
95
+ /// Lightens dark brand colors so the accent stands out on dark backgrounds.
96
+ /// Clamps lightness to 0.45–0.85 and chroma to 0.12 to keep it muted.
102
97
  /// @param {Color} $brand - Brand color
103
98
  /// @return {Color} Lightened accent for dark mode
104
99
  @function derive-dark-accent($brand) {
105
- @if is-dark-color($brand) {
106
- // If brand is dark, invert to light for dark mode
107
- // Use a light gray as the dark mode accent
108
- @return #f2f2f2;
109
- } @else {
110
- // If brand is already light, use it as-is or slightly adjust
111
- @return color.scale($brand, $lightness: 10%);
112
- }
100
+ $l: color.channel($brand, 'lightness', $space: oklch);
101
+ $c: color.channel($brand, 'chroma', $space: oklch);
102
+ $clamped-l: math.max(0.45, math.min($l, 0.85));
103
+ $clamped-c: math.min($c, 0.12);
104
+ @return oklch($clamped-l $clamped-c color.channel($brand, 'hue', $space: oklch));
113
105
  }
114
106
 
115
107
  // --------------------------------------------
@@ -129,9 +121,9 @@
129
121
  @for $i from 1 through 40 {
130
122
  @if wcag-contrast($adjusted, $bg) < $target {
131
123
  @if $is-dark {
132
- $adjusted: color.adjust($adjusted, $lightness: 2%);
124
+ $adjusted: color.adjust($adjusted, $lightness: 2%, $space: oklch);
133
125
  } @else {
134
- $adjusted: color.adjust($adjusted, $lightness: -2%);
126
+ $adjusted: color.adjust($adjusted, $lightness: -2%, $space: oklch);
135
127
  }
136
128
  }
137
129
  }
@@ -202,19 +194,23 @@
202
194
  /// @return {Map} Text token values
203
195
  @function derive-text($palette, $is-dark: false, $palette-name: 'stone') {
204
196
  @if $is-dark {
205
- // Dark mode: light text on dark backgrounds
197
+ // Dark mode: neutral white text on all palettes.
198
+ // Palette-tinted text (e.g. green-on-green-dark) looks muddy and reduces
199
+ // readability. Every major dark theme (Linear, Vercel, Stripe, GitHub)
200
+ // uses neutral white text regardless of background tint.
206
201
  @return (
207
- primary: get-shade($palette, 100), // Main text (light on dark)
208
- secondary: get-shade($palette, 400), // Secondary text
209
- // 90/10 mix of palette[400]/palette[500] for WCAG AAA 7:1
210
- // against palette[950] backgrounds (pure palette[500] gives ~4.1:1)
211
- tertiary: color.mix(get-shade($palette, 500), get-shade($palette, 400), 10%),
202
+ primary: #ffffff,
203
+ secondary: rgba(255, 255, 255, 0.6),
204
+ tertiary: rgba(255, 255, 255, 0.4),
212
205
  inverse: get-shade($palette, 900) // Text on light accents
213
206
  );
214
207
  }
215
208
 
216
209
  // Light mode background — stone uses white, colorful palettes use palette[50]
217
- $bg: if($palette-name != 'stone', get-shade($palette, 50), #ffffff);
210
+ $bg: #ffffff;
211
+ @if $palette-name != 'stone' {
212
+ $bg: get-shade($palette, 50);
213
+ }
218
214
 
219
215
  @return (
220
216
  primary: get-shade($palette, 900), // Main text (high contrast)
@@ -236,16 +232,16 @@
236
232
  /// @return {Map} Border token values
237
233
  @function derive-borders($palette, $is-dark: false) {
238
234
  @if $is-dark {
239
- // Dark mode: semi-transparent borders that adapt to any surface
235
+ // Dark mode: subtle white-alpha borders
240
236
  @return (
241
237
  default: rgba(255, 255, 255, 0.08),
242
- strong: rgba(255, 255, 255, 0.14)
238
+ strong: rgba(255, 255, 255, 0.15)
243
239
  );
244
240
  } @else {
245
- // Light mode: semi-transparent borders that adapt to any surface
241
+ // Light mode: reduced opacity (ChatGPT --border-light ~5%)
246
242
  @return (
247
- default: rgba(0, 0, 0, 0.08),
248
- strong: rgba(0, 0, 0, 0.14)
243
+ default: rgba(0, 0, 0, 0.05),
244
+ strong: rgba(0, 0, 0, 0.10)
249
245
  );
250
246
  }
251
247
  }
@@ -259,18 +255,18 @@
259
255
  /// @return {Map} Shadow token values
260
256
  @function derive-shadows($is-dark: false) {
261
257
  @if $is-dark {
262
- // Dark mode: reduced shadows for AI-era aesthetic
258
+ // Dark mode: near-zero shadows (Linear uses borders, not shadows)
263
259
  @return (
264
- sm: (0 1px 2px 0 rgba(0, 0, 0, 0.2)),
265
- md: (0 2px 4px -1px rgba(0, 0, 0, 0.25), 0 1px 3px -2px rgba(0, 0, 0, 0.2)),
266
- lg: (0 8px 12px -3px rgba(0, 0, 0, 0.35), 0 3px 5px -4px rgba(0, 0, 0, 0.25))
260
+ sm: (0 1px 2px 0 rgba(0, 0, 0, 0.15)),
261
+ md: (0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 1px 3px -2px rgba(0, 0, 0, 0.15)),
262
+ lg: (0 8px 12px -3px rgba(0, 0, 0, 0.25), 0 3px 5px -4px rgba(0, 0, 0, 0.18))
267
263
  );
268
264
  } @else {
269
- // Light mode: minimal shadows ("felt but not noticed")
265
+ // Light mode: flatter aesthetic (Linear/ChatGPT near-zero shadows)
270
266
  @return (
271
- sm: (0 1px 2px 0 rgba(0, 0, 0, 0.03)),
272
- md: (0 2px 4px -1px rgba(0, 0, 0, 0.06), 0 1px 3px -2px rgba(0, 0, 0, 0.04)),
273
- lg: (0 8px 12px -3px rgba(0, 0, 0, 0.08), 0 3px 5px -4px rgba(0, 0, 0, 0.05))
267
+ sm: (0 1px 2px 0 rgba(0, 0, 0, 0.02)),
268
+ md: (0 2px 4px -1px rgba(0, 0, 0, 0.04), 0 1px 3px -2px rgba(0, 0, 0, 0.03)),
269
+ lg: (0 8px 12px -3px rgba(0, 0, 0, 0.06), 0 3px 5px -4px rgba(0, 0, 0, 0.04))
274
270
  );
275
271
  }
276
272
  }
@@ -321,7 +317,7 @@
321
317
  /// @param {Color} $color - The semantic color
322
318
  /// @return {Color} Hover state color
323
319
  @function derive-semantic-hover($color) {
324
- @return color.scale($color, $lightness: -10%);
320
+ @return color.adjust($color, $lightness: -0.05, $space: oklch);
325
321
  }
326
322
 
327
323
  // --------------------------------------------
@@ -421,9 +417,9 @@
421
417
  @for $i from 1 through 40 {
422
418
  @if wcag-contrast($adjusted, $bg) < $target {
423
419
  @if $is-dark {
424
- $adjusted: color.adjust($adjusted, $lightness: 2%);
420
+ $adjusted: color.adjust($adjusted, $lightness: 2%, $space: oklch);
425
421
  } @else {
426
- $adjusted: color.adjust($adjusted, $lightness: -2%);
422
+ $adjusted: color.adjust($adjusted, $lightness: -2%, $space: oklch);
427
423
  }
428
424
  }
429
425
  }
@@ -83,6 +83,24 @@ $palette-earth: (
83
83
  950: #0a0f08 // Very dark green-gray for dark mode bg
84
84
  );
85
85
 
86
+ // --------------------------------------------
87
+ // Fragments - Rich saturated green tones
88
+ // The Fragments brand palette — deep forest greens
89
+ // --------------------------------------------
90
+ $palette-fragments: (
91
+ 50: #f0f7f3,
92
+ 100: #dceee3,
93
+ 200: #b8ddc6,
94
+ 300: #88c5a0,
95
+ 400: #5aaa7a,
96
+ 500: #3d8f60,
97
+ 600: #2d7049,
98
+ 700: #235536,
99
+ 800: #1a3025, // Dark card surface
100
+ 900: #142318, // Dark surface
101
+ 950: #0d1f17 // Darkest bg
102
+ );
103
+
86
104
  // --------------------------------------------
87
105
  // Fire - Warm red/orange tones
88
106
  // Energy, passion feel
@@ -110,6 +128,7 @@ $palettes: (
110
128
  "sand": $palette-sand,
111
129
  "earth": $palette-earth,
112
130
  "fire": $palette-fire,
131
+ "fragments": $palette-fragments,
113
132
  "wind": $palette-stone // Legacy alias — "wind" was renamed to "stone"
114
133
  );
115
134
 
@@ -118,7 +137,7 @@ $palettes: (
118
137
  // --------------------------------------------
119
138
 
120
139
  /// Get a palette map by name
121
- /// @param {String} $name - Palette name (stone, ice, sand, earth, fire)
140
+ /// @param {String} $name - Palette name (stone, ice, sand, earth, fire, fragments)
122
141
  /// @return {Map} The palette map with shades 50-950
123
142
  @function get-palette($name) {
124
143
  @if not map.has-key($palettes, $name) {
@@ -26,7 +26,7 @@
26
26
  $fui-brand: #18181b !default;
27
27
 
28
28
  /// Neutral palette name for surfaces, text, and borders
29
- /// Options: "stone" | "ice" | "earth" | "sand" | "fire"
29
+ /// Options: "stone" | "ice" | "earth" | "sand" | "fire" | "fragments"
30
30
  /// @type String
31
31
  $fui-neutral: "stone" !default;
32
32
 
@@ -45,7 +45,7 @@ $fui-radius-style: "default" !default;
45
45
  // --------------------------------------------
46
46
  // Fail fast at compile time if invalid seed values are provided.
47
47
 
48
- $_valid-neutrals: "stone", "ice", "earth", "sand", "fire";
48
+ $_valid-neutrals: "stone", "ice", "earth", "sand", "fire", "fragments";
49
49
  @if not list.index($_valid-neutrals, $fui-neutral) {
50
50
  @error "Invalid $fui-neutral: '#{$fui-neutral}'. Must be one of: #{$_valid-neutrals}";
51
51
  }