@fragments-sdk/ui 0.4.0 → 0.5.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 (94) hide show
  1. package/README.md +98 -2
  2. package/fragments.json +1 -1
  3. package/package.json +3 -2
  4. package/src/components/Accordion/Accordion.fragment.tsx +1 -1
  5. package/src/components/Alert/Alert.fragment.tsx +1 -1
  6. package/src/components/AppShell/AppShell.fragment.tsx +4 -4
  7. package/src/components/Avatar/Avatar.fragment.tsx +2 -2
  8. package/src/components/Badge/Badge.fragment.tsx +2 -2
  9. package/src/components/Badge/Badge.module.scss +1 -1
  10. package/src/components/Box/Box.fragment.tsx +1 -1
  11. package/src/components/Button/Button.fragment.tsx +2 -2
  12. package/src/components/ButtonGroup/ButtonGroup.fragment.tsx +153 -0
  13. package/src/components/Card/Card.fragment.tsx +1 -1
  14. package/src/components/Chart/Chart.fragment.tsx +213 -0
  15. package/src/components/Chart/Chart.module.scss +123 -0
  16. package/src/components/Chart/index.tsx +267 -0
  17. package/src/components/Checkbox/Checkbox.fragment.tsx +1 -1
  18. package/src/components/CodeBlock/CodeBlock.fragment.tsx +265 -6
  19. package/src/components/CodeBlock/CodeBlock.module.scss +141 -3
  20. package/src/components/CodeBlock/index.tsx +250 -36
  21. package/src/components/Collapsible/Collapsible.fragment.tsx +199 -0
  22. package/src/components/Collapsible/Collapsible.module.scss +117 -0
  23. package/src/components/Collapsible/index.tsx +219 -0
  24. package/src/components/ColorPicker/ColorPicker.fragment.tsx +196 -0
  25. package/src/components/ColorPicker/ColorPicker.module.scss +33 -23
  26. package/src/components/ColorPicker/index.tsx +34 -12
  27. package/src/components/ConversationList/ConversationList.fragment.tsx +202 -0
  28. package/src/components/ConversationList/ConversationList.module.scss +160 -0
  29. package/src/components/ConversationList/index.tsx +254 -0
  30. package/src/components/Dialog/Dialog.fragment.tsx +3 -3
  31. package/src/components/EmptyState/EmptyState.fragment.tsx +2 -2
  32. package/src/components/Field/Field.fragment.tsx +3 -3
  33. package/src/components/Fieldset/Fieldset.fragment.tsx +7 -7
  34. package/src/components/Form/Form.fragment.tsx +11 -11
  35. package/src/components/Grid/Grid.fragment.tsx +1 -1
  36. package/src/components/Header/Header.fragment.tsx +4 -4
  37. package/src/components/Header/Header.module.scss +9 -10
  38. package/src/components/Icon/Icon.fragment.tsx +2 -2
  39. package/src/components/Image/Image.fragment.tsx +2 -2
  40. package/src/components/Input/Input.fragment.tsx +1 -1
  41. package/src/components/Input/Input.module.scss +2 -2
  42. package/src/components/Link/Link.fragment.tsx +1 -1
  43. package/src/components/List/List.fragment.tsx +2 -2
  44. package/src/components/Listbox/Listbox.fragment.tsx +1 -1
  45. package/src/components/Loading/Loading.fragment.tsx +153 -0
  46. package/src/components/Loading/Loading.module.scss +256 -0
  47. package/src/components/Loading/index.tsx +236 -0
  48. package/src/components/Menu/Menu.fragment.tsx +3 -3
  49. package/src/components/Message/Message.fragment.tsx +200 -0
  50. package/src/components/Message/Message.module.scss +224 -0
  51. package/src/components/Message/index.tsx +278 -0
  52. package/src/components/Popover/Popover.fragment.tsx +4 -4
  53. package/src/components/Progress/Progress.fragment.tsx +1 -1
  54. package/src/components/Prompt/Prompt.fragment.tsx +2 -2
  55. package/src/components/RadioGroup/RadioGroup.fragment.tsx +1 -1
  56. package/src/components/RadioGroup/RadioGroup.module.scss +7 -4
  57. package/src/components/Select/Select.fragment.tsx +1 -1
  58. package/src/components/Select/Select.module.scss +8 -0
  59. package/src/components/Select/index.tsx +85 -5
  60. package/src/components/Separator/Separator.fragment.tsx +1 -1
  61. package/src/components/Sidebar/Sidebar.fragment.tsx +2 -2
  62. package/src/components/Sidebar/Sidebar.module.scss +19 -0
  63. package/src/components/Sidebar/index.tsx +52 -11
  64. package/src/components/Skeleton/Skeleton.fragment.tsx +1 -1
  65. package/src/components/Slider/Slider.fragment.tsx +201 -0
  66. package/src/components/Stack/Stack.fragment.tsx +194 -0
  67. package/src/components/Table/Table.fragment.tsx +3 -3
  68. package/src/components/Tabs/Tabs.fragment.tsx +1 -1
  69. package/src/components/Tabs/Tabs.module.scss +2 -2
  70. package/src/components/Text/Text.fragment.tsx +188 -0
  71. package/src/components/Textarea/Textarea.fragment.tsx +1 -1
  72. package/src/components/Theme/Theme.fragment.tsx +2 -2
  73. package/src/components/Theme/ThemeToggle.module.scss +13 -13
  74. package/src/components/ThinkingIndicator/ThinkingIndicator.fragment.tsx +182 -0
  75. package/src/components/ThinkingIndicator/ThinkingIndicator.module.scss +226 -0
  76. package/src/components/ThinkingIndicator/index.tsx +258 -0
  77. package/src/components/Toast/Toast.fragment.tsx +1 -1
  78. package/src/components/Toggle/Toggle.fragment.tsx +1 -1
  79. package/src/components/ToggleGroup/ToggleGroup.fragment.tsx +207 -0
  80. package/src/components/Tooltip/Tooltip.fragment.tsx +3 -3
  81. package/src/components/VisuallyHidden/VisuallyHidden.fragment.tsx +2 -2
  82. package/src/index.ts +86 -3
  83. package/src/recipes/AIChat.recipe.ts +266 -0
  84. package/src/tokens/_computed.scss +212 -0
  85. package/src/tokens/_density.scss +171 -0
  86. package/src/tokens/_derive.scss +287 -0
  87. package/src/tokens/_index.scss +39 -1
  88. package/src/tokens/_mixins.scss +41 -0
  89. package/src/tokens/_palettes.scss +185 -0
  90. package/src/tokens/_radius.scss +107 -0
  91. package/src/tokens/_seeds.scss +59 -0
  92. package/src/tokens/_variables.scss +171 -130
  93. package/src/components/ColorChip/ColorChip.module.scss +0 -165
  94. package/src/components/ColorChip/index.tsx +0 -157
@@ -0,0 +1,171 @@
1
+ // ============================================
2
+ // @fragments/ui Density Scales
3
+ // ============================================
4
+ //
5
+ // Defines 3 density presets that control spacing and sizing.
6
+ // Each preset uses a different base unit to scale all spacing.
7
+ //
8
+ // ============================================
9
+
10
+ @use 'sass:math';
11
+ @use 'sass:map';
12
+
13
+ // --------------------------------------------
14
+ // Density Definitions
15
+ // --------------------------------------------
16
+ // Each density includes:
17
+ // - base-unit: The fundamental spacing unit
18
+ // - multipliers: Scale factors for spacing tokens
19
+
20
+ $density-compact: (
21
+ base-unit: 6px,
22
+ base-font-size: 14px,
23
+ // Button heights (more compact)
24
+ button-height-sm: 24px, // ~4 units
25
+ button-height-md: 30px, // 5 units
26
+ button-height-lg: 36px, // 6 units
27
+ // Input height
28
+ input-height: 32px, // ~5.3 units
29
+ input-height-sm: 24px, // 4 units
30
+ input-height-lg: 36px, // 6 units
31
+ // Touch targets (minimum for accessibility)
32
+ touch-sm: 24px,
33
+ touch-md: 30px,
34
+ touch-lg: 36px
35
+ );
36
+
37
+ $density-default: (
38
+ base-unit: 7px,
39
+ base-font-size: 14px,
40
+ // Button heights (current values)
41
+ button-height-sm: 28px, // 4 units
42
+ button-height-md: 36px, // ~5 units
43
+ button-height-lg: 44px, // ~6 units
44
+ // Input height
45
+ input-height: 40px, // ~6 units
46
+ input-height-sm: 28px, // 4 units
47
+ input-height-lg: 44px, // ~6 units
48
+ // Touch targets
49
+ touch-sm: 24px,
50
+ touch-md: 32px,
51
+ touch-lg: 44px
52
+ );
53
+
54
+ $density-relaxed: (
55
+ base-unit: 8px,
56
+ base-font-size: 14px,
57
+ // Button heights (more spacious)
58
+ button-height-sm: 32px, // 4 units
59
+ button-height-md: 40px, // 5 units
60
+ button-height-lg: 48px, // 6 units
61
+ // Input height
62
+ input-height: 44px, // ~5.5 units
63
+ input-height-sm: 32px, // 4 units
64
+ input-height-lg: 48px, // 6 units
65
+ // Touch targets
66
+ touch-sm: 32px,
67
+ touch-md: 40px,
68
+ touch-lg: 48px
69
+ );
70
+
71
+ // --------------------------------------------
72
+ // Density Map for Dynamic Access
73
+ // --------------------------------------------
74
+ $densities: (
75
+ "compact": $density-compact,
76
+ "default": $density-default,
77
+ "relaxed": $density-relaxed
78
+ );
79
+
80
+ // --------------------------------------------
81
+ // Helper Functions
82
+ // --------------------------------------------
83
+
84
+ /// Get a density configuration by name
85
+ /// @param {String} $name - Density name (compact, default, relaxed)
86
+ /// @return {Map} The density configuration map
87
+ @function get-density($name) {
88
+ @if not map.has-key($densities, $name) {
89
+ @warn "Unknown density '#{$name}'. Using 'default' as fallback.";
90
+ @return $density-default;
91
+ }
92
+ @return map.get($densities, $name);
93
+ }
94
+
95
+ /// Get a specific value from a density configuration
96
+ /// @param {Map} $density - A density configuration map
97
+ /// @param {String} $key - The key to retrieve
98
+ /// @return {*} The value
99
+ @function density-value($density, $key) {
100
+ @if not map.has-key($density, $key) {
101
+ @warn "Unknown density key '#{$key}'.";
102
+ @return null;
103
+ }
104
+ @return map.get($density, $key);
105
+ }
106
+
107
+ /// Derive spacing scale from base unit
108
+ /// Returns a map with spacing tokens
109
+ /// @param {Map} $density - A density configuration map
110
+ /// @return {Map} Spacing tokens
111
+ @function derive-spacing($density) {
112
+ $base: map.get($density, base-unit);
113
+ $font-size: map.get($density, base-font-size);
114
+
115
+ // Convert to rem based on font size
116
+ // 1 unit = base-unit / font-size * 1rem
117
+ $unit-rem: math.div($base, $font-size) * 1rem;
118
+
119
+ @return (
120
+ // Micro spacing (pixel-precise for tiny alignments)
121
+ px: 1px,
122
+ 0-5: $unit-rem * 0.3, // ~2px for 7px base
123
+ 0-75: $unit-rem * 0.43, // ~3px for 7px base
124
+
125
+ // Standard spacing scale
126
+ 1: $unit-rem, // 1 unit
127
+ 2: $unit-rem * 2, // 2 units
128
+ 3: $unit-rem * 3, // 3 units
129
+ 4: $unit-rem * 4, // 4 units
130
+ 5: $unit-rem * 5, // 5 units
131
+ 6: $unit-rem * 6, // 6 units
132
+ 8: $unit-rem * 8, // 8 units
133
+ 10: $unit-rem * 10, // 10 units
134
+ 12: $unit-rem * 12 // 12 units
135
+ );
136
+ }
137
+
138
+ /// Derive container padding from density
139
+ /// @param {Map} $density - A density configuration map
140
+ /// @return {Map} Padding tokens
141
+ @function derive-padding($density) {
142
+ $base: map.get($density, base-unit);
143
+ $font-size: map.get($density, base-font-size);
144
+ $unit-rem: math.div($base, $font-size) * 1rem;
145
+
146
+ @return (
147
+ // Container padding: Cards, Dialogs, Popovers
148
+ container-sm: $unit-rem * 3, // 3 units
149
+ container-md: $unit-rem * 4, // 4 units
150
+ container-lg: $unit-rem * 6, // 6 units
151
+
152
+ // Inline padding: Alerts, Toasts
153
+ inline-sm: $unit-rem * 2, // 2 units
154
+ inline-md: $unit-rem * 3, // 3 units
155
+ inline-lg: $unit-rem * 4, // 4 units
156
+
157
+ // Item padding: Accordion, Tabs, Menu items
158
+ item-sm: $unit-rem * 2, // 2 units
159
+ item-md: $unit-rem * 3, // 3 units
160
+ item-lg: $unit-rem * 4 // 4 units
161
+ );
162
+ }
163
+
164
+ /// Convert pixel value to rem based on density
165
+ /// @param {Map} $density - A density configuration map
166
+ /// @param {Number} $px - Pixel value to convert
167
+ /// @return {Number} Value in rem
168
+ @function px-to-rem($density, $px) {
169
+ $font-size: map.get($density, base-font-size);
170
+ @return math.div($px, $font-size) * 1rem;
171
+ }
@@ -0,0 +1,287 @@
1
+ // ============================================
2
+ // @fragments/ui Token Derivation Functions
3
+ // ============================================
4
+ //
5
+ // Functions that derive complete token sets from seed values.
6
+ // These enable the seed-based design system where users configure
7
+ // ~5-10 seeds and everything else derives automatically.
8
+ //
9
+ // ============================================
10
+
11
+ @use 'sass:color';
12
+ @use 'sass:math';
13
+ @use 'palettes' as *;
14
+
15
+ // --------------------------------------------
16
+ // Color Utility Functions
17
+ // --------------------------------------------
18
+
19
+ /// Check if a color is considered "dark" (luminance < 0.5)
20
+ /// @param {Color} $color - Color to check
21
+ /// @return {Boolean} True if dark
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;
31
+ }
32
+
33
+ /// Get appropriate contrast color (black or white)
34
+ /// @param {Color} $bg-color - Background color
35
+ /// @return {Color} Black or white for best contrast
36
+ @function contrast-color($bg-color) {
37
+ @if is-dark-color($bg-color) {
38
+ @return #ffffff;
39
+ } @else {
40
+ @return #000000;
41
+ }
42
+ }
43
+
44
+ // --------------------------------------------
45
+ // Accent Color Derivation
46
+ // --------------------------------------------
47
+
48
+ /// Derive hover state for accent color
49
+ /// @param {Color} $base - Base accent color
50
+ /// @param {Boolean} $is-dark - Whether in dark mode
51
+ /// @return {Color} Hover state color
52
+ @function derive-accent-hover($base, $is-dark: false) {
53
+ @if $is-dark {
54
+ // In dark mode, lighten for hover
55
+ @return color.scale($base, $lightness: 5%);
56
+ } @else {
57
+ // In light mode, darken for hover
58
+ @return color.scale($base, $lightness: -8%);
59
+ }
60
+ }
61
+
62
+ /// Derive active state for accent color
63
+ /// @param {Color} $base - Base accent color
64
+ /// @param {Boolean} $is-dark - Whether in dark mode
65
+ /// @return {Color} Active state color
66
+ @function derive-accent-active($base, $is-dark: false) {
67
+ @if $is-dark {
68
+ // In dark mode, lighten more for active
69
+ @return color.scale($base, $lightness: 10%);
70
+ } @else {
71
+ // In light mode, darken more for active
72
+ @return color.scale($base, $lightness: -15%);
73
+ }
74
+ }
75
+
76
+ /// Derive a light variant of accent for dark mode
77
+ /// Auto-lightens dark brand colors so they're visible on dark backgrounds
78
+ /// @param {Color} $brand - Brand color
79
+ /// @return {Color} Lightened accent for dark mode
80
+ @function derive-dark-accent($brand) {
81
+ @if is-dark-color($brand) {
82
+ // If brand is dark, invert to light for dark mode
83
+ // Use a light gray as the dark mode accent
84
+ @return #f2f2f2;
85
+ } @else {
86
+ // If brand is already light, use it as-is or slightly adjust
87
+ @return color.scale($brand, $lightness: 10%);
88
+ }
89
+ }
90
+
91
+ // --------------------------------------------
92
+ // Surface/Background Derivation
93
+ // --------------------------------------------
94
+
95
+ /// Derive surface/background tokens from a neutral palette
96
+ /// Maps shade levels to semantic surface tokens for visual depth layering
97
+ /// @param {Map} $palette - Neutral palette map
98
+ /// @param {Boolean} $is-dark - Whether in dark mode
99
+ /// @return {Map} Surface token values
100
+ @function derive-surfaces($palette, $is-dark: false) {
101
+ @if $is-dark {
102
+ // Dark mode: darker = more recessed, lighter = elevated
103
+ @return (
104
+ primary: get-shade($palette, 950), // Page background (darkest)
105
+ secondary: get-shade($palette, 900), // Sidebar, panels
106
+ tertiary: get-shade($palette, 800), // Content areas (lighter)
107
+ elevated: get-shade($palette, 900), // Cards (slightly lighter than page)
108
+ subtle: interpolate-shade($palette, 925), // Between primary and secondary
109
+ hover: rgba(255, 255, 255, 0.06), // Interactive hover
110
+ active: rgba(255, 255, 255, 0.08) // Interactive active
111
+ );
112
+ } @else {
113
+ // Light mode: lighter = more recessed, darker shades for depth
114
+ @return (
115
+ primary: #ffffff, // Page background (white)
116
+ secondary: get-shade($palette, 100), // Sidebar, secondary panels
117
+ tertiary: get-shade($palette, 100), // Nested sections
118
+ elevated: #ffffff, // Cards, modals (floats above)
119
+ subtle: get-shade($palette, 50), // Very subtle backgrounds
120
+ hover: rgba(0, 0, 0, 0.04), // Interactive hover
121
+ active: rgba(0, 0, 0, 0.06) // Interactive active
122
+ );
123
+ }
124
+ }
125
+
126
+ // --------------------------------------------
127
+ // Text Color Derivation
128
+ // --------------------------------------------
129
+
130
+ /// Derive text tokens from a neutral palette
131
+ /// Maps shade levels to semantic text tokens with contrast verification
132
+ /// @param {Map} $palette - Neutral palette map
133
+ /// @param {Boolean} $is-dark - Whether in dark mode
134
+ /// @return {Map} Text token values
135
+ @function derive-text($palette, $is-dark: false) {
136
+ @if $is-dark {
137
+ // Dark mode: light text on dark backgrounds
138
+ @return (
139
+ primary: get-shade($palette, 100), // Main text (light on dark)
140
+ secondary: get-shade($palette, 400), // Secondary text
141
+ tertiary: get-shade($palette, 500), // Muted text
142
+ inverse: get-shade($palette, 900) // Text on light accents
143
+ );
144
+ } @else {
145
+ // Light mode: dark text on light backgrounds
146
+ @return (
147
+ primary: get-shade($palette, 900), // Main text (high contrast)
148
+ secondary: get-shade($palette, 600), // Secondary text
149
+ tertiary: get-shade($palette, 500), // Muted/disabled text
150
+ inverse: get-shade($palette, 100) // Text on dark accents
151
+ );
152
+ }
153
+ }
154
+
155
+ // --------------------------------------------
156
+ // Border Color Derivation
157
+ // --------------------------------------------
158
+
159
+ /// Derive border tokens from a neutral palette
160
+ /// @param {Map} $palette - Neutral palette map
161
+ /// @param {Boolean} $is-dark - Whether in dark mode
162
+ /// @return {Map} Border token values
163
+ @function derive-borders($palette, $is-dark: false) {
164
+ @if $is-dark {
165
+ // Dark mode: subtle light borders
166
+ @return (
167
+ default: get-shade($palette, 800), // Subtle dark borders
168
+ strong: get-shade($palette, 700) // Prominent dark borders
169
+ );
170
+ } @else {
171
+ // Light mode: subtle dark borders
172
+ @return (
173
+ default: get-shade($palette, 200), // Subtle borders
174
+ strong: get-shade($palette, 300) // Prominent borders
175
+ );
176
+ }
177
+ }
178
+
179
+ // --------------------------------------------
180
+ // Shadow Derivation
181
+ // --------------------------------------------
182
+
183
+ /// Derive shadow tokens based on mode
184
+ /// @param {Boolean} $is-dark - Whether in dark mode
185
+ /// @return {Map} Shadow token values
186
+ @function derive-shadows($is-dark: false) {
187
+ @if $is-dark {
188
+ // Dark mode: deeper shadows for depth
189
+ @return (
190
+ sm: (0 1px 2px 0 rgba(0, 0, 0, 0.3)),
191
+ md: (0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3)),
192
+ lg: (0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.4))
193
+ );
194
+ } @else {
195
+ // Light mode: subtle shadows
196
+ @return (
197
+ sm: (0 1px 2px 0 rgba(0, 0, 0, 0.05)),
198
+ md: (0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)),
199
+ lg: (0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1))
200
+ );
201
+ }
202
+ }
203
+
204
+ // --------------------------------------------
205
+ // Scrollbar Derivation
206
+ // --------------------------------------------
207
+
208
+ /// Derive scrollbar tokens from a neutral palette
209
+ /// @param {Map} $palette - Neutral palette map
210
+ /// @param {Boolean} $is-dark - Whether in dark mode
211
+ /// @return {Map} Scrollbar token values
212
+ @function derive-scrollbar($palette, $is-dark: false) {
213
+ @if $is-dark {
214
+ @return (
215
+ track: get-shade($palette, 800),
216
+ thumb: get-shade($palette, 600),
217
+ thumb-hover: get-shade($palette, 500)
218
+ );
219
+ } @else {
220
+ @return (
221
+ track: get-shade($palette, 100),
222
+ thumb: get-shade($palette, 300),
223
+ thumb-hover: get-shade($palette, 400)
224
+ );
225
+ }
226
+ }
227
+
228
+ // --------------------------------------------
229
+ // Semantic Color Backgrounds
230
+ // --------------------------------------------
231
+
232
+ /// Derive semantic background colors (danger, success, etc.)
233
+ /// @param {Color} $color - The semantic color
234
+ /// @param {Boolean} $is-dark - Whether in dark mode
235
+ /// @return {Color} Background color with appropriate opacity
236
+ @function derive-semantic-bg($color, $is-dark: false) {
237
+ @if $is-dark {
238
+ // Dark mode: slightly higher opacity for visibility
239
+ @return rgba($color, 0.15);
240
+ } @else {
241
+ // Light mode: subtle background
242
+ @return rgba($color, 0.1);
243
+ }
244
+ }
245
+
246
+ /// Derive hover state for semantic colors (like danger-hover)
247
+ /// @param {Color} $color - The semantic color
248
+ /// @return {Color} Hover state color
249
+ @function derive-semantic-hover($color) {
250
+ @return color.scale($color, $lightness: -10%);
251
+ }
252
+
253
+ // --------------------------------------------
254
+ // Focus Ring Derivation
255
+ // --------------------------------------------
256
+
257
+ /// Derive focus ring color from brand/accent
258
+ /// @param {Color} $brand - Brand color
259
+ /// @param {Boolean} $is-dark - Whether in dark mode
260
+ /// @return {Color} Focus ring color
261
+ @function derive-focus-ring($brand, $is-dark: false) {
262
+ @if $is-dark {
263
+ // In dark mode with dark brand, use light focus ring
264
+ @if is-dark-color($brand) {
265
+ @return #f2f2f2;
266
+ }
267
+ @return $brand;
268
+ } @else {
269
+ // In light mode, use brand color
270
+ @return $brand;
271
+ }
272
+ }
273
+
274
+ // --------------------------------------------
275
+ // Backdrop Derivation
276
+ // --------------------------------------------
277
+
278
+ /// Derive backdrop/overlay colors
279
+ /// @param {Boolean} $is-dark - Whether in dark mode
280
+ /// @return {Color} Backdrop color
281
+ @function derive-backdrop($is-dark: false) {
282
+ @if $is-dark {
283
+ @return rgba(0, 0, 0, 0.8);
284
+ } @else {
285
+ @return rgba(0, 0, 0, 0.5);
286
+ }
287
+ }
@@ -1,3 +1,41 @@
1
- // Forward both variables and mixins
1
+ // ============================================
2
+ // @fragments/ui Design Tokens Index
3
+ // ============================================
4
+ //
5
+ // This module exports the complete token system.
6
+ // Import with: @use '@fragments-sdk/ui/tokens';
7
+ //
8
+ // SEED-BASED CONFIGURATION:
9
+ // Set seed variables before importing to customize your theme.
10
+ // See _seeds.scss for available options.
11
+ //
12
+ // Example:
13
+ // $fui-brand: #0066ff;
14
+ // $fui-neutral: "steel";
15
+ // @use '@fragments-sdk/ui/tokens';
16
+ //
17
+ // ============================================
18
+
19
+ // Forward seed configuration (for users to override)
20
+ @forward 'seeds';
21
+
22
+ // Forward palette definitions (for advanced customization)
23
+ @forward 'palettes';
24
+
25
+ // Forward density scales
26
+ @forward 'density';
27
+
28
+ // Forward radius styles
29
+ @forward 'radius';
30
+
31
+ // Forward derivation functions (for advanced users)
32
+ @forward 'derive';
33
+
34
+ // Forward computed values (internal use)
35
+ @forward 'computed';
36
+
37
+ // Forward main variables (includes all token definitions)
2
38
  @forward 'variables';
39
+
40
+ // Forward mixins
3
41
  @forward 'mixins';
@@ -150,3 +150,44 @@
150
150
  0 0 0 var(--fui-focus-ring-offset, #{$fui-focus-ring-offset}) var(--fui-bg-primary, #{$fui-bg-primary}),
151
151
  0 0 0 calc(var(--fui-focus-ring-offset, #{$fui-focus-ring-offset}) + var(--fui-focus-ring-width, #{$fui-focus-ring-width})) var(--fui-color-danger, #{$fui-color-danger});
152
152
  }
153
+
154
+ // ============================================
155
+ // Size Variant Mixins
156
+ // ============================================
157
+
158
+ /// Control size mixin for standardized sizing across buttons, inputs, selects
159
+ /// @param {String} $size - Size variant: 'sm', 'md', or 'lg'
160
+ /// @param {String} $component - Component type: 'button', 'input', or 'select'
161
+ @mixin control-size($size, $component: 'button') {
162
+ @if $size == 'sm' {
163
+ @if $component == 'input' {
164
+ height: var(--fui-input-height-sm, #{$fui-input-height-sm});
165
+ padding: 0 var(--fui-space-2, #{$fui-space-2});
166
+ font-size: var(--fui-font-size-xs, #{$fui-font-size-xs});
167
+ } @else {
168
+ height: var(--fui-button-height-sm, #{$fui-button-height-sm});
169
+ padding: 0 var(--fui-space-2, #{$fui-space-2});
170
+ font-size: var(--fui-font-size-xs, #{$fui-font-size-xs});
171
+ }
172
+ } @else if $size == 'md' {
173
+ @if $component == 'input' {
174
+ height: var(--fui-input-height, #{$fui-input-height});
175
+ padding: 0 var(--fui-space-3, #{$fui-space-3});
176
+ font-size: var(--fui-font-size-sm, #{$fui-font-size-sm});
177
+ } @else {
178
+ height: var(--fui-button-height-md, #{$fui-button-height-md});
179
+ padding: 0 var(--fui-space-4, #{$fui-space-4});
180
+ font-size: var(--fui-font-size-sm, #{$fui-font-size-sm});
181
+ }
182
+ } @else if $size == 'lg' {
183
+ @if $component == 'input' {
184
+ height: var(--fui-input-height-lg, #{$fui-input-height-lg});
185
+ padding: 0 var(--fui-space-4, #{$fui-space-4});
186
+ font-size: var(--fui-font-size-base, #{$fui-font-size-base});
187
+ } @else {
188
+ height: var(--fui-button-height-lg, #{$fui-button-height-lg});
189
+ padding: 0 var(--fui-space-5, #{$fui-space-5});
190
+ font-size: var(--fui-font-size-base, #{$fui-font-size-base});
191
+ }
192
+ }
193
+ }