@fragments-sdk/ui 0.18.0 → 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 (222) 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/Button/Button.module.scss +24 -1
  184. package/src/components/Card/Card.module.scss +5 -1
  185. package/src/components/Chart/index.tsx +0 -1
  186. package/src/components/Chip/Chip.module.scss +4 -4
  187. package/src/components/CodeBlock/index.tsx +0 -1
  188. package/src/components/ColorPicker/index.tsx +0 -1
  189. package/src/components/Combobox/index.tsx +7 -8
  190. package/src/components/Command/Command.module.scss +22 -9
  191. package/src/components/DataTable/index.tsx +0 -2
  192. package/src/components/DatePicker/index.tsx +0 -2
  193. package/src/components/Drawer/Drawer.contract.json +1 -0
  194. package/src/components/Drawer/Drawer.module.scss +45 -5
  195. package/src/components/Drawer/index.tsx +66 -23
  196. package/src/components/Header/Header.contract.json +2 -0
  197. package/src/components/Input/Input.module.scss +16 -6
  198. package/src/components/Markdown/Markdown.module.scss +0 -3
  199. package/src/components/Markdown/index.tsx +0 -1
  200. package/src/components/Menu/Menu.module.scss +6 -0
  201. package/src/components/Menu/index.tsx +3 -1
  202. package/src/components/Message/Message.module.scss +2 -2
  203. package/src/components/NavigationMenu/NavigationMenu.module.scss +18 -23
  204. package/src/components/Pagination/Pagination.module.scss +1 -1
  205. package/src/components/Prompt/Prompt.module.scss +117 -3
  206. package/src/components/Prompt/index.tsx +40 -0
  207. package/src/components/Select/index.tsx +20 -25
  208. package/src/components/Sidebar/Sidebar.module.scss +1 -1
  209. package/src/components/Slider/index.tsx +10 -10
  210. package/src/components/Table/index.tsx +0 -2
  211. package/src/components/TableOfContents/TableOfContents.module.scss +19 -15
  212. package/src/components/Toggle/Toggle.module.scss +3 -3
  213. package/src/components/Tooltip/index.tsx +7 -3
  214. package/src/index.ts +8 -3
  215. package/src/styles/globals.scss +6 -1
  216. package/src/tokens/_computed.scss +3 -1
  217. package/src/tokens/_density.scss +4 -4
  218. package/src/tokens/_derive.scss +48 -55
  219. package/src/tokens/_palettes.scss +20 -1
  220. package/src/tokens/_seeds.scss +2 -2
  221. package/src/tokens/_variables.scss +45 -29
  222. package/src/utils/seed-derivation.ts +23 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fragments-sdk/ui",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "license": "MIT",
5
5
  "description": "Customizable UI components built on Base UI headless primitives",
6
6
  "author": "Conan McNicholl",
@@ -150,6 +150,9 @@
150
150
  },
151
151
  "peerDependencies": {
152
152
  "@tanstack/react-table": ">=8.0.0",
153
+ "@tiptap/extension-link": ">=2.0.0",
154
+ "@tiptap/react": ">=2.0.0",
155
+ "@tiptap/starter-kit": ">=2.0.0",
153
156
  "date-fns": ">=3.0.0",
154
157
  "react": "^18.0.0 || ^19.0.0",
155
158
  "react-colorful": ">=5.0.0",
@@ -158,10 +161,7 @@
158
161
  "react-markdown": ">=9.0.0",
159
162
  "recharts": ">=2.0.0 || >=3.0.0",
160
163
  "remark-gfm": ">=4.0.0",
161
- "shiki": ">=1.0.0",
162
- "@tiptap/react": ">=2.0.0",
163
- "@tiptap/starter-kit": ">=2.0.0",
164
- "@tiptap/extension-link": ">=2.0.0"
164
+ "shiki": ">=1.0.0"
165
165
  },
166
166
  "peerDependenciesMeta": {
167
167
  "react-markdown": {
@@ -202,18 +202,18 @@
202
202
  "defaultOptIn": true
203
203
  },
204
204
  "dependencies": {
205
- "@base-ui/react": "^1.0.0",
205
+ "@base-ui/react": "^1.3.0",
206
206
  "@phosphor-icons/react": "^2.1.10",
207
207
  "@scarf/scarf": "^1.4.0"
208
208
  },
209
209
  "devDependencies": {
210
210
  "@tanstack/react-table": "^8.21.3",
211
- "@tiptap/extension-link": "^2.11.0",
212
- "@tiptap/react": "^2.11.0",
213
- "@tiptap/starter-kit": "^2.11.0",
214
211
  "@testing-library/jest-dom": "^6.6.0",
215
212
  "@testing-library/react": "^16.1.0",
216
213
  "@testing-library/user-event": "^14.5.0",
214
+ "@tiptap/extension-link": "^2.11.0",
215
+ "@tiptap/react": "^2.11.0",
216
+ "@tiptap/starter-kit": "^2.11.0",
217
217
  "@types/node": "^22.0.0",
218
218
  "@types/react": "^19.0.0",
219
219
  "@types/react-dom": "^19.0.0",
@@ -230,7 +230,8 @@
230
230
  "vite": "^6.0.0",
231
231
  "vitest": "^2.1.8",
232
232
  "vitest-axe": "^0.1.0",
233
- "@fragments-sdk/core": "2.0.0"
233
+ "@fragments-sdk/core": "2.0.0",
234
+ "@fragments-sdk/compiler": "0.2.0"
234
235
  },
235
236
  "files": [
236
237
  "src",
@@ -245,11 +246,14 @@
245
246
  "fragments.json"
246
247
  ],
247
248
  "scripts": {
248
- "cli:ensure": "test -f ../../packages/cli/dist/bin.js || pnpm --filter @fragments-sdk/cli build",
249
- "dev": "pnpm run cli:ensure && node ../../packages/cli/dist/bin.js build",
250
- "build": "pnpm run cli:ensure && node ../../packages/cli/dist/bin.js build && vite build && tsc -p tsconfig.build.json",
249
+ "dev": "node ../../packages/compiler/dist/bin.js build",
250
+ "build": "pnpm run build:fragments",
251
+ "build:fragments": "node ../../packages/compiler/dist/bin.js build --if-needed",
252
+ "check:fragments": "node ../../packages/compiler/dist/bin.js build --check",
253
+ "build:dist": "vite build && tsc -p tsconfig.build.json",
254
+ "build:publish": "pnpm run build:fragments && pnpm run build:dist",
251
255
  "lint": "eslint src",
252
- "validate": "pnpm run cli:ensure && node ../../packages/cli/dist/bin.js validate",
256
+ "validate": "node ../../packages/cli/dist/bin.js validate",
253
257
  "test": "vitest run"
254
258
  },
255
259
  "module": "dist/index.js"
@@ -39,10 +39,33 @@
39
39
  font-size: var(--fui-font-size-base, $fui-font-size-base);
40
40
  }
41
41
 
42
+ // ============================================
43
+ // Optical alignment: icon + text combinations
44
+ // ============================================
45
+ // Icons (SVGs) have built-in whitespace that makes symmetric padding look
46
+ // uneven. When an icon leads or trails text, reduce padding on the icon
47
+ // side so the content appears optically centered.
48
+ //
49
+ // Uses :has() + :first-child/:last-child to detect icon position without
50
+ // JS. The negative margin pulls the icon into the padding zone, compensating
51
+ // for the icon's inherent visual whitespace.
52
+
53
+ .button:not(.icon) {
54
+ > svg:first-child:not(:last-child) {
55
+ // Leading icon: pull left to optically balance
56
+ margin-left: calc(var(--fui-space-1, $fui-space-1) * -0.5);
57
+ }
58
+
59
+ > svg:last-child:not(:first-child) {
60
+ // Trailing icon: pull right to optically balance
61
+ margin-right: calc(var(--fui-space-1, $fui-space-1) * -0.5);
62
+ }
63
+ }
64
+
42
65
  // Variants
43
66
  .primary {
44
67
  background-color: var(--fui-color-accent, $fui-color-accent);
45
- color: var(--fui-text-inverse, $fui-text-inverse);
68
+ color: var(--fui-color-on-accent, $fui-color-on-accent);
46
69
  border: 1px solid transparent;
47
70
 
48
71
  &:hover:not(:disabled) {
@@ -76,10 +76,14 @@
76
76
  }
77
77
 
78
78
  .description {
79
- margin: var(--fui-space-1, $fui-space-1) 0 0;
79
+ margin: 0 0 var(--fui-space-1, $fui-space-1) 0;
80
80
  font-size: var(--fui-font-size-sm, $fui-font-size-sm);
81
81
  color: var(--fui-text-secondary, $fui-text-secondary);
82
82
  line-height: var(--fui-line-height-normal, $fui-line-height-normal);
83
+
84
+ &:last-child {
85
+ margin-bottom: 0;
86
+ }
83
87
  }
84
88
 
85
89
  .body {
@@ -3,7 +3,6 @@
3
3
  import * as React from 'react';
4
4
  import { mergeAriaIds } from '../../utils/aria';
5
5
  import styles from './Chart.module.scss';
6
- import '../../styles/globals.scss';
7
6
 
8
7
  // ============================================
9
8
  // Types (self-owned — no external dependency for types)
@@ -62,7 +62,7 @@
62
62
 
63
63
  &.selected {
64
64
  background-color: var(--fui-color-accent, $fui-color-accent);
65
- color: var(--fui-text-inverse, $fui-text-inverse);
65
+ color: var(--fui-color-on-accent, $fui-color-on-accent);
66
66
 
67
67
  &:hover:not(:disabled) {
68
68
  background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
@@ -90,7 +90,7 @@
90
90
 
91
91
  &.selected {
92
92
  background-color: var(--fui-color-accent, $fui-color-accent);
93
- color: var(--fui-text-inverse, $fui-text-inverse);
93
+ color: var(--fui-color-on-accent, $fui-color-on-accent);
94
94
  border-color: var(--fui-color-accent, $fui-color-accent);
95
95
 
96
96
  &:hover:not(:disabled) {
@@ -119,7 +119,7 @@
119
119
 
120
120
  &.selected {
121
121
  background-color: var(--fui-color-accent, $fui-color-accent);
122
- color: var(--fui-text-inverse, $fui-text-inverse);
122
+ color: var(--fui-color-on-accent, $fui-color-on-accent);
123
123
 
124
124
  &:hover:not(:disabled) {
125
125
  background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
@@ -245,7 +245,7 @@
245
245
 
246
246
  .selected + .remove {
247
247
  background-color: var(--fui-color-accent, $fui-color-accent);
248
- color: var(--fui-text-inverse, $fui-text-inverse);
248
+ color: var(--fui-color-on-accent, $fui-color-on-accent);
249
249
  border-left-color: transparent;
250
250
 
251
251
  &:hover:not(:disabled) {
@@ -29,7 +29,6 @@ async function loadShikiDeps() {
29
29
  }
30
30
  import { TabsRoot, TabsList, Tab, TabsPanel } from "../Tabs";
31
31
  import styles from "./CodeBlock.module.scss";
32
- import "../../styles/globals.scss";
33
32
 
34
33
  export type CodeBlockLanguage =
35
34
  | "tsx"
@@ -25,7 +25,6 @@ function loadColorfulDeps() {
25
25
  import { Field } from '@base-ui/react/field';
26
26
  import { Input } from '../Input';
27
27
  import styles from './ColorPicker.module.scss';
28
- import '../../styles/globals.scss';
29
28
 
30
29
  export interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'> {
31
30
  /** Label text above the picker */
@@ -277,7 +277,7 @@ const ComboboxRoot = React.forwardRef<HTMLDivElement, ComboboxProps>(function Co
277
277
  [placeholder, multiple, selectedValues, itemsVersion, incrementItemsVersion, explicitTriggerCount, registerTrigger, size]
278
278
  );
279
279
 
280
- const { labelId, helperId, errorId, hasError, errorMessage } = useFormFieldIds('combobox', { label, helperText, error });
280
+ const { helperId, errorId, hasError, errorMessage } = useFormFieldIds('combobox', { label, helperText, error });
281
281
 
282
282
  const wrapperClasses = [styles.wrapper, className].filter(Boolean).join(' ');
283
283
  const helperClasses = [styles.helper, hasError && styles.helperError]
@@ -286,7 +286,6 @@ const ComboboxRoot = React.forwardRef<HTMLDivElement, ComboboxProps>(function Co
286
286
 
287
287
  const wrapperContent = (inner: React.ReactNode) => (
288
288
  <div ref={ref} className={wrapperClasses}>
289
- {label && <span id={labelId} className={styles.label}>{label}</span>}
290
289
  {inner}
291
290
  {helperText && (
292
291
  <span id={helperId} className={helperClasses}>{helperText}</span>
@@ -324,9 +323,9 @@ const ComboboxRoot = React.forwardRef<HTMLDivElement, ComboboxProps>(function Co
324
323
  multiple
325
324
  autoHighlight={autoHighlight}
326
325
  itemToStringLabel={itemToStringLabel}
327
- aria-labelledby={labelId}
328
326
  aria-describedby={mergeAriaIds(errorId, helperId)}
329
327
  >
328
+ {label && <BaseCombobox.Label className={styles.label}>{label}</BaseCombobox.Label>}
330
329
  {children}
331
330
  </BaseCombobox.Root>
332
331
  )}
@@ -360,9 +359,9 @@ const ComboboxRoot = React.forwardRef<HTMLDivElement, ComboboxProps>(function Co
360
359
  multiple={false}
361
360
  autoHighlight={autoHighlight}
362
361
  itemToStringLabel={itemToStringLabel}
363
- aria-labelledby={labelId}
364
362
  aria-describedby={mergeAriaIds(errorId, helperId)}
365
363
  >
364
+ {label && <BaseCombobox.Label className={styles.label}>{label}</BaseCombobox.Label>}
366
365
  {children}
367
366
  </BaseCombobox.Root>
368
367
  )}
@@ -380,7 +379,7 @@ function ComboboxInput({ className, showTrigger = true, ...htmlProps }: Combobox
380
379
 
381
380
  if (context.multiple) {
382
381
  return (
383
- <div className={wrapperClasses}>
382
+ <BaseCombobox.InputGroup className={wrapperClasses}>
384
383
  {context.selectedValues.length > 0 && (
385
384
  <BaseCombobox.Chips className={styles.chips}>
386
385
  {context.selectedValues.map((chipValue) => (
@@ -405,12 +404,12 @@ function ComboboxInput({ className, showTrigger = true, ...htmlProps }: Combobox
405
404
  <ChevronDownIcon />
406
405
  </BaseCombobox.Trigger>
407
406
  )}
408
- </div>
407
+ </BaseCombobox.InputGroup>
409
408
  );
410
409
  }
411
410
 
412
411
  return (
413
- <div className={wrapperClasses}>
412
+ <BaseCombobox.InputGroup className={wrapperClasses}>
414
413
  <BaseCombobox.Input
415
414
  placeholder={context.placeholder}
416
415
  {...htmlProps}
@@ -421,7 +420,7 @@ function ComboboxInput({ className, showTrigger = true, ...htmlProps }: Combobox
421
420
  <ChevronDownIcon />
422
421
  </BaseCombobox.Trigger>
423
422
  )}
424
- </div>
423
+ </BaseCombobox.InputGroup>
425
424
  );
426
425
  }
427
426
 
@@ -19,33 +19,46 @@
19
19
  // ============================================
20
20
 
21
21
  .inputWrapper {
22
+ @include field-shell;
23
+
22
24
  display: flex;
23
25
  align-items: center;
24
- gap: var(--fui-space-2, 0.5rem);
25
- padding: var(--fui-space-2, 0.5rem) var(--fui-space-4, 1rem);
26
- border-bottom: 1px solid var(--fui-border);
26
+ gap: var(--fui-space-2, $fui-space-2);
27
+ padding: 0 var(--fui-space-2, $fui-space-2);
28
+ margin: var(--fui-space-2, $fui-space-2);
29
+ height: var(--fui-input-height, $fui-input-height);
30
+
31
+ &:focus-within {
32
+ @include field-shell-focus;
33
+ }
27
34
 
28
35
  svg {
29
36
  flex-shrink: 0;
30
37
  width: 1rem;
31
38
  height: 1rem;
32
- color: var(--fui-text-secondary);
39
+ color: var(--fui-text-secondary, $fui-text-secondary);
33
40
  }
34
41
  }
35
42
 
36
43
  .input {
37
44
  @include text-base;
38
45
 
39
- width: 100%;
46
+ flex: 1;
40
47
  border: none;
41
48
  background: transparent;
42
49
  outline: none;
43
- font-size: var(--fui-font-size-sm, 0.875rem);
44
- color: var(--fui-text-primary);
45
- padding: var(--fui-space-1, 0.25rem) 0;
50
+ font-size: var(--fui-font-size-sm, $fui-font-size-sm);
51
+ color: var(--fui-text-primary, $fui-text-primary);
52
+ padding: 0;
46
53
 
47
54
  &::placeholder {
48
- color: var(--fui-text-tertiary);
55
+ color: var(--fui-text-tertiary, $fui-text-tertiary);
56
+ }
57
+
58
+ &:focus,
59
+ &:focus-visible {
60
+ outline: none;
61
+ box-shadow: none;
49
62
  }
50
63
  }
51
64
 
@@ -1,8 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- // Import globals to ensure CSS variables are defined
5
- import '../../styles/globals.scss';
6
4
  import styles from './DataTable.module.scss';
7
5
  import { Checkbox } from '../Checkbox';
8
6
 
@@ -4,8 +4,6 @@ import * as React from 'react';
4
4
  import { Popover as BasePopover } from '@base-ui/react/popover';
5
5
  import { useFormFieldIds, type FormFieldProps } from '../../utils/aria';
6
6
  import styles from './DatePicker.module.scss';
7
- // Import globals to ensure CSS variables are defined
8
- import '../../styles/globals.scss';
9
7
 
10
8
  // ============================================
11
9
  // Types (self-owned — no external dependency for types)
@@ -138,6 +138,7 @@
138
138
  "Trigger",
139
139
  "Content",
140
140
  "Close",
141
+ "SwipeArea",
141
142
  "Header",
142
143
  "Title",
143
144
  "Description",
@@ -22,6 +22,18 @@
22
22
  }
23
23
  }
24
24
 
25
+ // Viewport positioning container
26
+ .viewport {
27
+ position: fixed;
28
+ inset: 0;
29
+ z-index: 51;
30
+ pointer-events: none;
31
+
32
+ &[data-open] {
33
+ pointer-events: auto;
34
+ }
35
+ }
36
+
25
37
  // The popup panel
26
38
  .popup {
27
39
  @include surface-elevated;
@@ -33,6 +45,7 @@
33
45
  flex-direction: column;
34
46
  box-shadow: var(--fui-shadow-md, $fui-shadow-md);
35
47
  overflow-y: auto;
48
+ pointer-events: auto;
36
49
 
37
50
  // Animation
38
51
  transition:
@@ -47,14 +60,18 @@
47
60
  }
48
61
 
49
62
  // ============================================
50
- // Side positioning
63
+ // Side positioning — swipe-aware transforms
51
64
  // ============================================
52
65
 
53
66
  .side-right {
54
67
  top: 0;
55
68
  right: 0;
56
69
  bottom: 0;
57
- transform: translateX(100%);
70
+ transform: translateX(calc(100% + var(--drawer-swipe-movement-x, 0px)));
71
+
72
+ &[data-open] {
73
+ transform: translateX(var(--drawer-swipe-movement-x, 0px));
74
+ }
58
75
 
59
76
  &[data-starting-style],
60
77
  &[data-ending-style] {
@@ -66,7 +83,11 @@
66
83
  top: 0;
67
84
  left: 0;
68
85
  bottom: 0;
69
- transform: translateX(-100%);
86
+ transform: translateX(calc(-100% + var(--drawer-swipe-movement-x, 0px)));
87
+
88
+ &[data-open] {
89
+ transform: translateX(var(--drawer-swipe-movement-x, 0px));
90
+ }
70
91
 
71
92
  &[data-starting-style],
72
93
  &[data-ending-style] {
@@ -78,7 +99,11 @@
78
99
  top: 0;
79
100
  left: 0;
80
101
  right: 0;
81
- transform: translateY(-100%);
102
+ transform: translateY(calc(-100% + var(--drawer-swipe-movement-y, 0px)));
103
+
104
+ &[data-open] {
105
+ transform: translateY(var(--drawer-swipe-movement-y, 0px));
106
+ }
82
107
 
83
108
  &[data-starting-style],
84
109
  &[data-ending-style] {
@@ -90,7 +115,11 @@
90
115
  bottom: 0;
91
116
  left: 0;
92
117
  right: 0;
93
- transform: translateY(100%);
118
+ transform: translateY(calc(100% + var(--drawer-swipe-movement-y, 0px)));
119
+
120
+ &[data-open] {
121
+ transform: translateY(var(--drawer-swipe-movement-y, 0px));
122
+ }
94
123
 
95
124
  &[data-starting-style],
96
125
  &[data-ending-style] {
@@ -98,6 +127,11 @@
98
127
  }
99
128
  }
100
129
 
130
+ // Disable transition during active swipe for instant feedback
131
+ .popup[data-swiping] {
132
+ transition-duration: 0s;
133
+ }
134
+
101
135
  // ============================================
102
136
  // Size variants — width for left/right, height for top/bottom
103
137
  // ============================================
@@ -194,6 +228,12 @@
194
228
  }
195
229
  }
196
230
 
231
+ // SwipeArea — invisible gesture zone at screen edge
232
+ .swipeArea {
233
+ position: fixed;
234
+ z-index: 49;
235
+ }
236
+
197
237
  // ============================================
198
238
  // Accessibility: Reduced Motion
199
239
  // ============================================
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { Dialog as BaseDialog } from '@base-ui/react/dialog';
4
+ import { Drawer as BaseDrawer } from '@base-ui/react/drawer';
5
5
  import styles from './Drawer.module.scss';
6
6
 
7
7
  // ============================================
@@ -10,6 +10,7 @@ import styles from './Drawer.module.scss';
10
10
 
11
11
  /**
12
12
  * Slide-in panel for navigation, forms, or supplementary content.
13
+ * Now backed by Base UI's stable Drawer (v1.3.0) with native swipe gestures.
13
14
  * @see https://usefragments.com/components/drawer
14
15
  */
15
16
  export interface DrawerProps {
@@ -20,9 +21,18 @@ export interface DrawerProps {
20
21
  defaultOpen?: boolean;
21
22
  /** Called when open state changes */
22
23
  onOpenChange?: (open: boolean) => void;
24
+ /** Called after open/close animation completes */
25
+ onOpenChangeComplete?: (open: boolean) => void;
23
26
  /** Whether the drawer blocks interaction with the rest of the page.
24
27
  * @default true */
25
- modal?: boolean;
28
+ modal?: boolean | 'trap-focus';
29
+ /** Swipe direction to dismiss.
30
+ * @default derived from `side` prop on Content */
31
+ swipeDirection?: 'up' | 'down' | 'left' | 'right';
32
+ /** Preset snap-point heights for bottom-sheet drawers */
33
+ snapPoints?: number[];
34
+ /** Disable outside-click dismissal */
35
+ disablePointerDismissal?: boolean;
26
36
  }
27
37
 
28
38
  export interface DrawerContentProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -70,6 +80,13 @@ export interface DrawerCloseProps extends React.ButtonHTMLAttributes<HTMLButtonE
70
80
  asChild?: boolean;
71
81
  }
72
82
 
83
+ export interface DrawerSwipeAreaProps extends React.HTMLAttributes<HTMLDivElement> {
84
+ /** Swipe direction to open the drawer */
85
+ swipeDirection?: 'up' | 'down' | 'left' | 'right';
86
+ /** Disable swipe detection */
87
+ disabled?: boolean;
88
+ }
89
+
73
90
  function getAsChildElement(children: React.ReactNode, componentName: string): React.ReactElement {
74
91
  if (!React.isValidElement(children)) {
75
92
  throw new Error(`${componentName} with asChild requires a single valid React element child.`);
@@ -110,17 +127,25 @@ function DrawerRoot({
110
127
  open,
111
128
  defaultOpen,
112
129
  onOpenChange,
130
+ onOpenChangeComplete,
113
131
  modal = true,
132
+ swipeDirection,
133
+ snapPoints,
134
+ disablePointerDismissal,
114
135
  }: DrawerProps) {
115
136
  return (
116
- <BaseDialog.Root
137
+ <BaseDrawer.Root
117
138
  open={open}
118
139
  defaultOpen={defaultOpen}
119
140
  onOpenChange={onOpenChange}
141
+ onOpenChangeComplete={onOpenChangeComplete}
120
142
  modal={modal}
143
+ swipeDirection={swipeDirection}
144
+ snapPoints={snapPoints}
145
+ disablePointerDismissal={disablePointerDismissal}
121
146
  >
122
147
  {children}
123
- </BaseDialog.Root>
148
+ </BaseDrawer.Root>
124
149
  );
125
150
  }
126
151
 
@@ -133,16 +158,16 @@ function DrawerTrigger({
133
158
  if (asChild) {
134
159
  const child = getAsChildElement(children, 'Drawer.Trigger');
135
160
  return (
136
- <BaseDialog.Trigger {...htmlProps} className={className} render={child}>
161
+ <BaseDrawer.Trigger {...htmlProps} className={className} render={child}>
137
162
  {null}
138
- </BaseDialog.Trigger>
163
+ </BaseDrawer.Trigger>
139
164
  );
140
165
  }
141
166
 
142
167
  return (
143
- <BaseDialog.Trigger {...htmlProps} className={className}>
168
+ <BaseDrawer.Trigger {...htmlProps} className={className}>
144
169
  {children}
145
- </BaseDialog.Trigger>
170
+ </BaseDrawer.Trigger>
146
171
  );
147
172
  }
148
173
 
@@ -165,12 +190,16 @@ function DrawerContent({
165
190
  .join(' ');
166
191
 
167
192
  return (
168
- <BaseDialog.Portal>
169
- {backdrop && <BaseDialog.Backdrop className={styles.backdrop} />}
170
- <BaseDialog.Popup initialFocus={initialFocus} {...htmlProps} data-side={side} className={popupClasses}>
171
- {children}
172
- </BaseDialog.Popup>
173
- </BaseDialog.Portal>
193
+ <BaseDrawer.Portal>
194
+ {backdrop && <BaseDrawer.Backdrop className={styles.backdrop} />}
195
+ <BaseDrawer.Viewport className={styles.viewport}>
196
+ <BaseDrawer.Popup initialFocus={initialFocus} {...htmlProps} data-side={side} className={popupClasses}>
197
+ <BaseDrawer.Content>
198
+ {children}
199
+ </BaseDrawer.Content>
200
+ </BaseDrawer.Popup>
201
+ </BaseDrawer.Viewport>
202
+ </BaseDrawer.Portal>
174
203
  );
175
204
  }
176
205
 
@@ -181,15 +210,15 @@ function DrawerHeader({ children, className, ...htmlProps }: DrawerHeaderProps)
181
210
 
182
211
  function DrawerTitle({ children, className, ...htmlProps }: DrawerTitleProps) {
183
212
  const classes = [styles.title, className].filter(Boolean).join(' ');
184
- return <BaseDialog.Title {...htmlProps} className={classes}>{children}</BaseDialog.Title>;
213
+ return <BaseDrawer.Title {...htmlProps} className={classes}>{children}</BaseDrawer.Title>;
185
214
  }
186
215
 
187
216
  function DrawerDescription({ children, className, ...htmlProps }: DrawerDescriptionProps) {
188
217
  const classes = [styles.description, className].filter(Boolean).join(' ');
189
218
  return (
190
- <BaseDialog.Description {...htmlProps} className={classes}>
219
+ <BaseDrawer.Description {...htmlProps} className={classes}>
191
220
  {children}
192
- </BaseDialog.Description>
221
+ </BaseDrawer.Description>
193
222
  );
194
223
  }
195
224
 
@@ -206,35 +235,47 @@ function DrawerFooter({ children, className, ...htmlProps }: DrawerFooterProps)
206
235
  function DrawerClose({ children, asChild, className, ...htmlProps }: DrawerCloseProps) {
207
236
  if (!children) {
208
237
  return (
209
- <BaseDialog.Close
238
+ <BaseDrawer.Close
210
239
  {...htmlProps}
211
240
  data-drawer-close
212
241
  aria-label="Close drawer"
213
242
  className={[styles.close, className].filter(Boolean).join(' ')}
214
243
  >
215
244
  <CloseIcon />
216
- </BaseDialog.Close>
245
+ </BaseDrawer.Close>
217
246
  );
218
247
  }
219
248
 
220
249
  if (asChild) {
221
250
  const child = getAsChildElement(children, 'Drawer.Close');
222
251
  return (
223
- <BaseDialog.Close
252
+ <BaseDrawer.Close
224
253
  {...htmlProps}
225
254
  data-drawer-close
226
255
  className={className}
227
256
  render={child}
228
257
  >
229
258
  {null}
230
- </BaseDialog.Close>
259
+ </BaseDrawer.Close>
231
260
  );
232
261
  }
233
262
 
234
263
  return (
235
- <BaseDialog.Close {...htmlProps} data-drawer-close className={className}>
264
+ <BaseDrawer.Close {...htmlProps} data-drawer-close className={className}>
236
265
  {children}
237
- </BaseDialog.Close>
266
+ </BaseDrawer.Close>
267
+ );
268
+ }
269
+
270
+ function DrawerSwipeArea({ swipeDirection, disabled, className, ...htmlProps }: DrawerSwipeAreaProps) {
271
+ const classes = [styles.swipeArea, className].filter(Boolean).join(' ');
272
+ return (
273
+ <BaseDrawer.SwipeArea
274
+ {...htmlProps}
275
+ swipeDirection={swipeDirection}
276
+ disabled={disabled}
277
+ className={classes}
278
+ />
238
279
  );
239
280
  }
240
281
 
@@ -251,6 +292,7 @@ export const Drawer = Object.assign(DrawerRoot, {
251
292
  Body: DrawerBody,
252
293
  Footer: DrawerFooter,
253
294
  Close: DrawerClose,
295
+ SwipeArea: DrawerSwipeArea,
254
296
  });
255
297
 
256
298
  // Re-export individual components for tree-shaking
@@ -264,4 +306,5 @@ export {
264
306
  DrawerBody,
265
307
  DrawerFooter,
266
308
  DrawerClose,
309
+ DrawerSwipeArea,
267
310
  };
@@ -174,6 +174,8 @@
174
174
  "Brand",
175
175
  "Nav",
176
176
  "NavItem",
177
+ "MobileNav",
178
+ "MobileNavLink",
177
179
  "NavMenu",
178
180
  "NavMenuItem",
179
181
  "Search",