@fragments-sdk/ui 0.16.1 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/assets/ui.css +2021 -1606
  2. package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
  3. package/dist/components/Accordion/Accordion.module.scss.js +8 -8
  4. package/dist/components/Alert/Alert.module.scss.cjs +12 -12
  5. package/dist/components/Alert/Alert.module.scss.js +12 -12
  6. package/dist/components/Alert/index.cjs +2 -1
  7. package/dist/components/Alert/index.d.ts.map +1 -1
  8. package/dist/components/Alert/index.js +2 -1
  9. package/dist/components/Avatar/index.cjs +12 -4
  10. package/dist/components/Avatar/index.d.ts.map +1 -1
  11. package/dist/components/Avatar/index.js +12 -4
  12. package/dist/components/Badge/Badge.module.scss.cjs +13 -13
  13. package/dist/components/Badge/Badge.module.scss.js +13 -13
  14. package/dist/components/Button/Button.module.scss.cjs +11 -11
  15. package/dist/components/Button/Button.module.scss.js +11 -11
  16. package/dist/components/Button/index.cjs +51 -4
  17. package/dist/components/Button/index.d.ts.map +1 -1
  18. package/dist/components/Button/index.js +51 -4
  19. package/dist/components/Card/Card.module.scss.cjs +14 -14
  20. package/dist/components/Card/Card.module.scss.js +14 -14
  21. package/dist/components/Card/index.cjs +35 -2
  22. package/dist/components/Card/index.d.ts.map +1 -1
  23. package/dist/components/Card/index.js +35 -2
  24. package/dist/components/Checkbox/Checkbox.module.scss.cjs +10 -10
  25. package/dist/components/Checkbox/Checkbox.module.scss.js +10 -10
  26. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  27. package/dist/components/Chip/Chip.module.scss.js +15 -15
  28. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +21 -21
  29. package/dist/components/CodeBlock/CodeBlock.module.scss.js +21 -21
  30. package/dist/components/Collapsible/Collapsible.module.scss.cjs +10 -10
  31. package/dist/components/Collapsible/Collapsible.module.scss.js +10 -10
  32. package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
  33. package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
  34. package/dist/components/Combobox/Combobox.module.scss.cjs +24 -24
  35. package/dist/components/Combobox/Combobox.module.scss.js +24 -24
  36. package/dist/components/DataTable/DataTable.module.scss.cjs +26 -26
  37. package/dist/components/DataTable/DataTable.module.scss.js +26 -26
  38. package/dist/components/DatePicker/DatePicker.module.scss.cjs +31 -31
  39. package/dist/components/DatePicker/DatePicker.module.scss.js +31 -31
  40. package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
  41. package/dist/components/Dialog/Dialog.module.scss.js +14 -14
  42. package/dist/components/Drawer/Drawer.module.scss.cjs +26 -26
  43. package/dist/components/Drawer/Drawer.module.scss.js +26 -26
  44. package/dist/components/Editor/Editor.module.scss.cjs +17 -17
  45. package/dist/components/Editor/Editor.module.scss.js +17 -17
  46. package/dist/components/Fieldset/Fieldset.module.scss.cjs +6 -3
  47. package/dist/components/Fieldset/Fieldset.module.scss.js +6 -3
  48. package/dist/components/Fieldset/index.cjs +7 -1
  49. package/dist/components/Fieldset/index.d.ts +6 -1
  50. package/dist/components/Fieldset/index.d.ts.map +1 -1
  51. package/dist/components/Fieldset/index.js +7 -1
  52. package/dist/components/Header/Header.module.scss.cjs +42 -21
  53. package/dist/components/Header/Header.module.scss.js +42 -21
  54. package/dist/components/Header/index.cjs +121 -3
  55. package/dist/components/Header/index.d.ts +26 -3
  56. package/dist/components/Header/index.d.ts.map +1 -1
  57. package/dist/components/Header/index.js +122 -4
  58. package/dist/components/Input/Input.module.scss.cjs +27 -15
  59. package/dist/components/Input/Input.module.scss.js +27 -15
  60. package/dist/components/Input/index.cjs +20 -7
  61. package/dist/components/Input/index.d.ts +8 -2
  62. package/dist/components/Input/index.d.ts.map +1 -1
  63. package/dist/components/Input/index.js +20 -7
  64. package/dist/components/Link/Link.module.scss.cjs +10 -10
  65. package/dist/components/Link/Link.module.scss.js +10 -10
  66. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  67. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  68. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
  69. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
  70. package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
  71. package/dist/components/Pagination/Pagination.module.scss.js +7 -7
  72. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  73. package/dist/components/Popover/Popover.module.scss.js +10 -10
  74. package/dist/components/Prompt/Prompt.module.scss.cjs +14 -14
  75. package/dist/components/Prompt/Prompt.module.scss.js +14 -14
  76. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +16 -16
  77. package/dist/components/RadioGroup/RadioGroup.module.scss.js +16 -16
  78. package/dist/components/Select/Select.module.scss.cjs +17 -17
  79. package/dist/components/Select/Select.module.scss.js +17 -17
  80. package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
  81. package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
  82. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  83. package/dist/components/Slider/Slider.module.scss.js +12 -12
  84. package/dist/components/Tabs/Tabs.module.scss.cjs +9 -9
  85. package/dist/components/Tabs/Tabs.module.scss.js +9 -9
  86. package/dist/components/Textarea/Textarea.module.scss.cjs +34 -19
  87. package/dist/components/Textarea/Textarea.module.scss.js +34 -19
  88. package/dist/components/Textarea/index.cjs +36 -6
  89. package/dist/components/Textarea/index.d.ts +6 -2
  90. package/dist/components/Textarea/index.d.ts.map +1 -1
  91. package/dist/components/Textarea/index.js +36 -6
  92. package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
  93. package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
  94. package/dist/components/Toast/Toast.module.scss.cjs +22 -22
  95. package/dist/components/Toast/Toast.module.scss.js +22 -22
  96. package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
  97. package/dist/components/Toggle/Toggle.module.scss.js +13 -13
  98. package/dist/components/Toggle/index.cjs +7 -3
  99. package/dist/components/Toggle/index.d.ts.map +1 -1
  100. package/dist/components/Toggle/index.js +7 -3
  101. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  102. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  103. package/dist/index.d.ts +2 -2
  104. package/dist/index.d.ts.map +1 -1
  105. package/fragments.json +1 -1
  106. package/package.json +1 -1
  107. package/src/components/Alert/Alert.module.scss +8 -8
  108. package/src/components/Alert/index.tsx +2 -1
  109. package/src/components/Avatar/index.tsx +6 -2
  110. package/src/components/Badge/Badge.module.scss +17 -11
  111. package/src/components/Button/Button.module.scss +6 -5
  112. package/src/components/Button/index.tsx +60 -4
  113. package/src/components/Card/index.tsx +48 -3
  114. package/src/components/Checkbox/Checkbox.module.scss +16 -9
  115. package/src/components/ColorPicker/ColorPicker.module.scss +5 -13
  116. package/src/components/Combobox/Combobox.module.scss +30 -25
  117. package/src/components/DatePicker/DatePicker.module.scss +18 -28
  118. package/src/components/Editor/Editor.module.scss +23 -15
  119. package/src/components/Fieldset/Fieldset.module.scss +12 -6
  120. package/src/components/Fieldset/index.tsx +11 -1
  121. package/src/components/Header/Header.module.scss +99 -0
  122. package/src/components/Header/index.tsx +191 -10
  123. package/src/components/Input/Input.module.scss +97 -26
  124. package/src/components/Input/index.tsx +31 -12
  125. package/src/components/Listbox/Listbox.module.scss +9 -2
  126. package/src/components/RadioGroup/RadioGroup.module.scss +8 -6
  127. package/src/components/Select/Select.module.scss +10 -24
  128. package/src/components/Sidebar/Sidebar.module.scss +6 -4
  129. package/src/components/Slider/Slider.module.scss +12 -22
  130. package/src/components/Textarea/Textarea.module.scss +49 -18
  131. package/src/components/Textarea/index.tsx +43 -12
  132. package/src/components/Toast/Toast.module.scss +48 -8
  133. package/src/components/Toggle/Toggle.module.scss +21 -35
  134. package/src/components/Toggle/index.tsx +11 -3
  135. package/src/components/ToggleGroup/ToggleGroup.module.scss +23 -19
  136. package/src/index.ts +2 -0
  137. package/src/styles/globals.scss +4 -1
  138. package/src/tokens/_mixins.scss +57 -4
  139. package/src/tokens/_variables.scss +20 -1
@@ -7,30 +7,17 @@
7
7
  .input {
8
8
  @include text-base;
9
9
  @include interactive-base;
10
+ @include field-shell;
10
11
 
11
12
  display: block;
12
13
  width: 100%;
13
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
14
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
15
- border-radius: var(--fui-radius-md, $fui-radius-md);
16
14
 
17
15
  &::placeholder {
18
16
  color: var(--fui-text-tertiary, $fui-text-tertiary);
19
17
  }
20
18
 
21
- &:hover:not(:disabled):not(:focus-visible) {
22
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
23
- }
24
-
25
19
  &:focus-visible {
26
- @include focus-ring;
27
- border-color: var(--fui-color-accent, $fui-color-accent);
28
- }
29
-
30
- &:disabled,
31
- &[data-disabled] {
32
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
33
- color: var(--fui-text-tertiary, $fui-text-tertiary);
20
+ @include field-shell-focus;
34
21
  }
35
22
  }
36
23
 
@@ -66,9 +53,17 @@
66
53
 
67
54
  &:focus-visible {
68
55
  border-color: var(--fui-color-danger, $fui-color-danger);
69
- box-shadow:
70
- 0 0 0 var(--fui-focus-ring-offset, $fui-focus-ring-offset) var(--fui-bg-primary, $fui-bg-primary),
71
- 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);
56
+ @include focus-ring-error;
57
+ }
58
+ }
59
+
60
+ // Success state — green border for validated fields (DoorDash/Stocksy pattern)
61
+ .success {
62
+ border-color: var(--fui-color-success, $fui-color-success);
63
+
64
+ &:focus-visible {
65
+ border-color: var(--fui-color-success, $fui-color-success);
66
+ @include focus-ring-success;
72
67
  }
73
68
  }
74
69
 
@@ -77,8 +72,14 @@
77
72
  color: var(--fui-color-danger, $fui-color-danger);
78
73
  }
79
74
 
75
+ // Auto-detect success state via :has() — applies success color to helper
76
+ .wrapper[data-success] .helper,
77
+ .helperSuccess {
78
+ color: var(--fui-color-success, $fui-color-success);
79
+ }
80
+
80
81
  // ============================================
81
- // Input with shortcut indicator
82
+ // Input with adornments or shortcut indicator
82
83
  // ============================================
83
84
 
84
85
  .inputContainer {
@@ -92,6 +93,64 @@
92
93
  }
93
94
  }
94
95
 
96
+ // Adornment container — wraps input with start/end adornments inside field-shell border
97
+ .hasAdornment {
98
+ @include field-shell;
99
+
100
+ gap: var(--fui-space-2, $fui-space-2);
101
+ padding: 0 var(--fui-space-3, $fui-space-3);
102
+ border-radius: var(--fui-radius-md, $fui-radius-md);
103
+
104
+ &:focus-within {
105
+ @include field-shell-focus;
106
+ }
107
+
108
+ // Strip the input's own shell when inside adornment container
109
+ .input {
110
+ border: none;
111
+ background: transparent;
112
+ padding: 0;
113
+ box-shadow: none;
114
+
115
+ &:focus-visible {
116
+ outline: none;
117
+ box-shadow: none;
118
+ }
119
+ }
120
+
121
+ // Error state on adornment container
122
+ &:has(.error) {
123
+ border-color: var(--fui-color-danger, $fui-color-danger);
124
+
125
+ &:focus-within {
126
+ border-color: var(--fui-color-danger, $fui-color-danger);
127
+ @include focus-ring-error;
128
+ }
129
+ }
130
+
131
+ // Success state on adornment container
132
+ &:has(.success) {
133
+ border-color: var(--fui-color-success, $fui-color-success);
134
+
135
+ &:focus-within {
136
+ border-color: var(--fui-color-success, $fui-color-success);
137
+ @include focus-ring-success;
138
+ }
139
+ }
140
+ }
141
+
142
+ .adornment {
143
+ display: flex;
144
+ align-items: center;
145
+ flex-shrink: 0;
146
+ color: var(--fui-text-secondary, $fui-text-secondary);
147
+
148
+ svg {
149
+ width: 1rem;
150
+ height: 1rem;
151
+ }
152
+ }
153
+
95
154
  // Kept as fallback for direct usage
96
155
  .hasShortcut {
97
156
  padding-right: var(--fui-space-12, 3rem);
@@ -104,18 +163,26 @@
104
163
  transform: translateY(-50%);
105
164
  display: inline-flex;
106
165
  align-items: center;
166
+ justify-content: center;
107
167
  gap: calc(var(--fui-space-px, $fui-space-px) * 2);
108
- padding:
109
- calc(var(--fui-space-px, $fui-space-px) * 2)
110
- calc(var(--fui-space-px, $fui-space-px) * 6);
111
- font-size: var(--fui-font-size-xs, $fui-font-size-xs);
112
- font-family: var(--fui-font-mono, $fui-font-mono);
113
- color: var(--fui-text-secondary, $fui-text-secondary);
114
- background: var(--fui-bg-subtle, $fui-bg-subtle);
168
+ min-width: 1.25rem;
169
+ height: 1.25rem;
170
+ padding: 0 var(--fui-space-1, $fui-space-1);
171
+ font-size: var(--fui-font-size-2xs, $fui-font-size-2xs);
172
+ font-family: var(--fui-font-sans, $fui-font-sans);
173
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
174
+ line-height: 1;
175
+ letter-spacing: 0.02em;
176
+ color: var(--fui-text-tertiary, $fui-text-tertiary);
177
+ background: var(--fui-bg-elevated, $fui-bg-elevated);
115
178
  border: 1px solid var(--fui-border-default, $fui-border-default);
179
+ border-bottom-width: 2px;
116
180
  border-radius: var(--fui-radius-sm, $fui-radius-sm);
181
+ box-shadow:
182
+ inset 0 0.5px 0 color-mix(in srgb, white 6%, transparent);
117
183
  pointer-events: none;
118
184
  white-space: nowrap;
185
+ user-select: none;
119
186
  }
120
187
 
121
188
  // ============================================
@@ -136,6 +203,10 @@
136
203
  .input[aria-invalid] {
137
204
  border-color: var(--fui-color-danger, $fui-color-danger);
138
205
  }
206
+
207
+ .success {
208
+ border-color: var(--fui-color-success, $fui-color-success);
209
+ }
139
210
  }
140
211
 
141
212
  // ============================================
@@ -29,12 +29,18 @@ export interface InputProps extends Omit<
29
29
  disabled?: boolean;
30
30
  /** Show error styling */
31
31
  error?: boolean;
32
+ /** Show success styling */
33
+ success?: boolean;
32
34
  /** Visible label text */
33
35
  label?: string;
34
36
  /** Whether the field is required */
35
37
  required?: boolean;
36
38
  /** Helper text shown below the input */
37
39
  helperText?: string;
40
+ /** Content rendered before the input (e.g., icon or prefix text) */
41
+ startAdornment?: React.ReactNode;
42
+ /** Content rendered after the input (e.g., icon or suffix text) */
43
+ endAdornment?: React.ReactNode;
38
44
  /** Keyboard shortcut hint displayed inside the input (e.g., "⌘K"). */
39
45
  shortcut?: string;
40
46
  /** Whether the shortcut should also register a global focus hotkey.
@@ -44,8 +50,8 @@ export interface InputProps extends Omit<
44
50
  onChange?: (value: string) => void;
45
51
  /** Alias for onChange (value-first callback) */
46
52
  onValueChange?: (value: string) => void;
47
- onBlur?: () => void;
48
- onFocus?: () => void;
53
+ onBlur?: React.FocusEventHandler<HTMLInputElement>;
54
+ onFocus?: React.FocusEventHandler<HTMLInputElement>;
49
55
  onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
50
56
  /** Props applied to the wrapper element */
51
57
  rootProps?: React.HTMLAttributes<HTMLDivElement>;
@@ -86,9 +92,12 @@ const InputRoot = React.forwardRef<HTMLInputElement, InputProps>(
86
92
  size = 'md',
87
93
  disabled = false,
88
94
  error = false,
95
+ success = false,
89
96
  required = false,
90
97
  label,
91
98
  helperText,
99
+ startAdornment,
100
+ endAdornment,
92
101
  shortcut,
93
102
  shortcutBehavior = 'display-only',
94
103
  onChange,
@@ -149,17 +158,24 @@ const InputRoot = React.forwardRef<HTMLInputElement, InputProps>(
149
158
  return () => document.removeEventListener('keydown', handler);
150
159
  }, [shortcut, shortcutBehavior]);
151
160
 
161
+ const hasAdornment = !!(startAdornment || endAdornment);
162
+
152
163
  const inputClasses = [
153
164
  styles.input,
154
165
  styles[size],
155
166
  error && styles.error,
167
+ success && styles.success,
156
168
  shortcut && styles.hasShortcut,
157
169
  inputClassName,
158
170
  ]
159
171
  .filter(Boolean)
160
172
  .join(' ');
161
173
 
162
- const helperClasses = [styles.helper, error && styles.helperError]
174
+ const helperClasses = [
175
+ styles.helper,
176
+ error && styles.helperError,
177
+ success && styles.helperSuccess,
178
+ ]
163
179
  .filter(Boolean)
164
180
  .join(' ');
165
181
 
@@ -180,8 +196,8 @@ const InputRoot = React.forwardRef<HTMLInputElement, InputProps>(
180
196
  onChange?.(e.target.value);
181
197
  onValueChange?.(e.target.value);
182
198
  },
183
- onBlur: () => onBlur?.(),
184
- onFocus: () => onFocus?.(),
199
+ onBlur: (e: React.FocusEvent<HTMLInputElement>) => onBlur?.(e),
200
+ onFocus: (e: React.FocusEvent<HTMLInputElement>) => onFocus?.(e),
185
201
  onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => onKeyDown?.(e),
186
202
  'aria-label': ariaLabel,
187
203
  'aria-labelledby': ariaLabelledBy,
@@ -206,14 +222,16 @@ const InputRoot = React.forwardRef<HTMLInputElement, InputProps>(
206
222
  />
207
223
  );
208
224
 
209
- const content = shortcut ? (
210
- <div className={styles.inputContainer}>
211
- {withFieldWrapper ? inputElement : fieldlessInputElement}
212
- <kbd className={styles.shortcut}>{shortcut}</kbd>
225
+ const rawInput = withFieldWrapper ? inputElement : fieldlessInputElement;
226
+
227
+ const content = (hasAdornment || shortcut) ? (
228
+ <div className={[styles.inputContainer, hasAdornment && styles.hasAdornment].filter(Boolean).join(' ')}>
229
+ {startAdornment && <span className={styles.adornment}>{startAdornment}</span>}
230
+ {rawInput}
231
+ {endAdornment && <span className={styles.adornment}>{endAdornment}</span>}
232
+ {shortcut && <kbd className={styles.shortcut}>{shortcut}</kbd>}
213
233
  </div>
214
- ) : (
215
- withFieldWrapper ? inputElement : fieldlessInputElement
216
- );
234
+ ) : rawInput;
217
235
 
218
236
  if (!withFieldWrapper) {
219
237
  return (
@@ -243,6 +261,7 @@ const InputRoot = React.forwardRef<HTMLInputElement, InputProps>(
243
261
  {...rootProps}
244
262
  disabled={disabled}
245
263
  invalid={error}
264
+ data-success={success || undefined}
246
265
  className={[wrapperClasses, rootProps?.className].filter(Boolean).join(' ')}
247
266
  style={{ ...(rootProps?.style ?? {}), ...(style ?? {}) }}
248
267
  >
@@ -12,6 +12,7 @@
12
12
  min-width: 12rem;
13
13
  max-height: 320px;
14
14
  overflow-y: auto;
15
+ border-color: var(--fui-form-group-border, $fui-border);
15
16
 
16
17
  &:focus-visible {
17
18
  @include focus-ring;
@@ -38,11 +39,17 @@
38
39
  }
39
40
 
40
41
  .itemSelected {
41
- background-color: var(--fui-bg-hover, $fui-bg-hover);
42
+ @include popup-item-selected;
42
43
  }
43
44
 
44
45
  .itemActive {
45
- background-color: var(--fui-bg-hover, $fui-bg-hover);
46
+ &:not(.itemSelected) {
47
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
48
+ }
49
+ }
50
+
51
+ .itemActive.itemSelected {
52
+ @include popup-item-selected;
46
53
  }
47
54
 
48
55
  .itemDisabled {
@@ -55,22 +55,24 @@
55
55
  width: 1rem;
56
56
  height: 1rem;
57
57
  margin-top: 0;
58
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
59
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
58
+ background-color: var(--fui-field-bg, $fui-bg-elevated);
59
+ border: 1px solid var(--fui-field-border, $fui-border-strong);
60
60
  border-radius: var(--fui-radius-full, $fui-radius-full);
61
61
  cursor: inherit;
62
62
 
63
63
  &:hover:not([data-disabled]) {
64
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
64
+ border-color: var(--fui-field-border-hover, $fui-text-tertiary);
65
65
  }
66
66
 
67
67
  &[data-checked] {
68
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
69
- border-color: var(--fui-color-accent, $fui-color-accent);
68
+ background-color: var(--fui-field-selection-bg, $fui-bg-hover);
69
+ border-color: var(--fui-field-selection-border, $fui-color-accent);
70
+ box-shadow: inset 0 0 0 1px var(--fui-field-selection-border, $fui-color-accent);
70
71
  }
71
72
 
72
73
  &[data-checked]:hover:not([data-disabled]) {
73
- border-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
74
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
75
+ border-color: var(--fui-field-selection-border, $fui-color-accent);
74
76
  }
75
77
 
76
78
  &[data-invalid] {
@@ -9,6 +9,8 @@
9
9
  @include button-reset;
10
10
  @include interactive-base;
11
11
  @include text-base;
12
+ @include field-shell;
13
+ @include control-size('md', 'input');
12
14
 
13
15
  display: inline-flex;
14
16
  align-items: center;
@@ -16,38 +18,20 @@
16
18
  gap: var(--fui-space-2, $fui-space-2);
17
19
  width: 100%;
18
20
  min-width: 10rem;
19
- height: var(--fui-input-height, $fui-input-height);
20
- padding: 0 var(--fui-space-3, $fui-space-3);
21
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
22
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
23
- border-radius: var(--fui-radius-md, $fui-radius-md);
24
21
  text-align: left;
25
22
 
26
- &:hover:not([data-disabled]) {
27
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
28
- }
29
-
30
23
  &[data-popup-open] {
31
- border-color: var(--fui-color-accent, $fui-color-accent);
32
- }
33
-
34
- &[data-disabled] {
35
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
36
- color: var(--fui-text-tertiary, $fui-text-tertiary);
24
+ border-color: var(--fui-field-border-focus, $fui-color-accent);
37
25
  }
38
26
  }
39
27
 
40
28
  // Trigger size variants
41
29
  .triggerSm {
42
- height: var(--fui-input-height-sm, $fui-input-height-sm);
43
- padding: 0 var(--fui-space-2, $fui-space-2);
44
- font-size: var(--fui-font-size-xs, $fui-font-size-xs);
30
+ @include control-size('sm', 'input');
45
31
  }
46
32
 
47
33
  .triggerLg {
48
- height: var(--fui-input-height-lg, $fui-input-height-lg);
49
- padding: 0 var(--fui-space-4, $fui-space-4);
50
- font-size: var(--fui-font-size-base, $fui-font-size-base);
34
+ @include control-size('lg', 'input');
51
35
  }
52
36
 
53
37
  // Value display
@@ -99,6 +83,8 @@
99
83
  @include surface-elevated;
100
84
  @include popup-container;
101
85
 
86
+ border-color: var(--fui-form-group-border, $fui-border);
87
+
102
88
  // Item height derived from text-base font + vertical padding
103
89
  --_item-h: calc(
104
90
  var(--fui-font-size-sm, #{$fui-font-size-sm}) * var(--fui-line-height-normal, #{$fui-line-height-normal}) +
@@ -143,11 +129,10 @@
143
129
  }
144
130
 
145
131
  &[data-selected] {
146
- background-color: var(--fui-color-accent, $fui-color-accent);
147
- color: var(--fui-text-inverse, $fui-text-inverse);
132
+ @include popup-item-selected;
148
133
 
149
134
  &[data-highlighted] {
150
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
135
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
151
136
  }
152
137
  }
153
138
 
@@ -165,6 +150,7 @@
165
150
  width: 1rem;
166
151
  height: 1rem;
167
152
  margin-left: auto;
153
+ color: var(--fui-color-accent, $fui-color-accent);
168
154
 
169
155
  svg {
170
156
  width: 0.875rem;
@@ -226,6 +226,7 @@
226
226
 
227
227
  .itemWrapper {
228
228
  list-style: none;
229
+ width: 100%;
229
230
  }
230
231
 
231
232
  .item {
@@ -235,8 +236,9 @@
235
236
 
236
237
  display: flex;
237
238
  align-items: center;
238
- gap: var(--fui-space-3, $fui-space-3);
239
- padding: var(--fui-space-1, $fui-space-1) var(--fui-space-2, $fui-space-2);
239
+ width: 100%;
240
+ gap: var(--fui-sidebar-item-gap, var(--fui-space-2, $fui-space-2));
241
+ padding: var(--fui-sidebar-item-padding-y, var(--fui-space-1, $fui-space-1)) var(--fui-sidebar-item-padding-x, var(--fui-space-2, $fui-space-2));
240
242
  border-radius: var(--fui-radius-md, $fui-radius-md);
241
243
  color: var(--fui-text-secondary, $fui-text-secondary);
242
244
  text-decoration: none;
@@ -635,8 +637,8 @@
635
637
  .skeletonItem {
636
638
  display: flex;
637
639
  align-items: center;
638
- gap: var(--fui-space-3, $fui-space-3);
639
- padding: var(--fui-space-1, $fui-space-1) var(--fui-space-2, $fui-space-2);
640
+ gap: var(--fui-sidebar-item-gap, var(--fui-space-2, $fui-space-2));
641
+ padding: var(--fui-sidebar-item-padding-y, var(--fui-space-1, $fui-space-1)) var(--fui-sidebar-item-padding-x, var(--fui-space-2, $fui-space-2));
640
642
  min-height: var(--fui-sidebar-item-height, $fui-sidebar-item-height);
641
643
  }
642
644
 
@@ -39,7 +39,8 @@
39
39
  position: relative;
40
40
  height: var(--fui-slider-track-height, $fui-slider-track-height);
41
41
  width: 100%;
42
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
42
+ background-color: var(--fui-form-group-bg, $fui-bg-secondary);
43
+ box-shadow: inset 0 0 0 1px var(--fui-form-group-border, $fui-border);
43
44
  border-radius: var(--fui-radius-full, $fui-radius-full);
44
45
  cursor: pointer;
45
46
 
@@ -52,7 +53,7 @@
52
53
  .indicator {
53
54
  position: absolute;
54
55
  height: 100%;
55
- background-color: var(--fui-color-accent, $fui-color-accent);
56
+ background-color: var(--fui-field-selection-border, $fui-color-accent);
56
57
  border-radius: var(--fui-radius-full, $fui-radius-full);
57
58
  }
58
59
 
@@ -63,20 +64,21 @@
63
64
  width: var(--fui-slider-thumb-size, $fui-slider-thumb-size);
64
65
  height: var(--fui-slider-thumb-size, $fui-slider-thumb-size);
65
66
  background-color: var(--fui-bg-primary, $fui-bg-primary);
66
- border: var(--fui-slider-thumb-border, $fui-slider-thumb-border) solid var(--fui-color-accent, $fui-color-accent);
67
+ border: 1px solid var(--fui-field-selection-border, $fui-color-accent);
67
68
  border-radius: var(--fui-radius-full, $fui-radius-full);
69
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.14);
68
70
  cursor: grab;
69
71
  transition:
70
- transform var(--fui-transition-fast, $fui-transition-fast),
72
+ border-color var(--fui-transition-fast, $fui-transition-fast),
71
73
  box-shadow var(--fui-transition-fast, $fui-transition-fast);
72
74
 
73
75
  &:hover {
74
- transform: scale(1.1);
76
+ border-color: color-mix(in srgb, var(--fui-color-accent, $fui-color-accent) 58%, transparent);
75
77
  }
76
78
 
77
79
  &:active {
78
80
  cursor: grabbing;
79
- transform: scale(1.05);
81
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.18);
80
82
  }
81
83
 
82
84
  &:focus-visible {
@@ -107,25 +109,13 @@
107
109
  white-space: nowrap;
108
110
  padding: var(--fui-space-1, $fui-space-1) var(--fui-space-2, $fui-space-2);
109
111
  border-radius: var(--fui-radius-md, $fui-radius-md);
110
- background: var(--fui-tooltip-bg, $fui-tooltip-bg);
111
- color: var(--fui-tooltip-text, $fui-tooltip-text);
112
+ background: var(--fui-form-group-bg, $fui-bg-secondary);
113
+ color: var(--fui-text-secondary, $fui-text-secondary);
114
+ border: 1px solid var(--fui-form-group-border, $fui-border);
112
115
  font-family: var(--fui-font-mono, $fui-font-mono);
113
116
  font-size: var(--fui-font-size-xs, $fui-font-size-xs);
114
117
  line-height: 1;
115
- box-shadow: var(--fui-tooltip-shadow, $fui-tooltip-shadow);
116
-
117
- &::after {
118
- content: '';
119
- position: absolute;
120
- top: 100%;
121
- left: 50%;
122
- transform: translateX(-50%);
123
- width: 0;
124
- height: 0;
125
- border-left: 5px solid transparent;
126
- border-right: 5px solid transparent;
127
- border-top: 5px solid var(--fui-tooltip-bg, $fui-tooltip-bg);
128
- }
118
+ box-shadow: var(--fui-shadow-sm, $fui-shadow-sm);
129
119
  }
130
120
 
131
121
  // ============================================
@@ -7,14 +7,12 @@
7
7
  .textarea {
8
8
  @include text-base;
9
9
  @include interactive-base;
10
+ @include field-shell;
10
11
 
11
12
  display: block;
12
13
  width: 100%;
13
14
  min-height: var(--fui-input-height, $fui-input-height);
14
15
  padding: var(--fui-space-2, $fui-space-2) var(--fui-space-3, $fui-space-3);
15
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
16
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
17
- border-radius: var(--fui-radius-md, $fui-radius-md);
18
16
  line-height: var(--fui-line-height-normal, $fui-line-height-normal);
19
17
  font-family: inherit;
20
18
 
@@ -22,19 +20,8 @@
22
20
  color: var(--fui-text-tertiary, $fui-text-tertiary);
23
21
  }
24
22
 
25
- &:hover:not(:disabled):not(:focus-visible) {
26
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
27
- }
28
-
29
23
  &:focus-visible {
30
- @include focus-ring;
31
- border-color: var(--fui-color-accent, $fui-color-accent);
32
- }
33
-
34
- &:disabled,
35
- &[data-disabled] {
36
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
37
- color: var(--fui-text-tertiary, $fui-text-tertiary);
24
+ @include field-shell-focus;
38
25
  }
39
26
  }
40
27
 
@@ -77,9 +64,17 @@
77
64
 
78
65
  &:focus-visible {
79
66
  border-color: var(--fui-color-danger, $fui-color-danger);
80
- box-shadow:
81
- 0 0 0 var(--fui-focus-ring-offset, $fui-focus-ring-offset) var(--fui-bg-primary, $fui-bg-primary),
82
- 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);
67
+ @include focus-ring-error;
68
+ }
69
+ }
70
+
71
+ // Success state — green border for validated fields
72
+ .success {
73
+ border-color: var(--fui-color-success, $fui-color-success);
74
+
75
+ &:focus-visible {
76
+ border-color: var(--fui-color-success, $fui-color-success);
77
+ @include focus-ring-success;
83
78
  }
84
79
  }
85
80
 
@@ -88,6 +83,38 @@
88
83
  color: var(--fui-color-danger, $fui-color-danger);
89
84
  }
90
85
 
86
+ // Auto-detect success state
87
+ .wrapper[data-success] .helper,
88
+ .helperSuccess {
89
+ color: var(--fui-color-success, $fui-color-success);
90
+ }
91
+
92
+ // Footer row — helper + character counter side by side
93
+ .footer {
94
+ display: flex;
95
+ justify-content: space-between;
96
+ align-items: baseline;
97
+ gap: var(--fui-space-2, $fui-space-2);
98
+ min-height: calc(var(--fui-font-size-xs, #{$fui-font-size-xs}) * var(--fui-line-height-normal, #{$fui-line-height-normal}) + var(--fui-space-1, #{$fui-space-1}));
99
+
100
+ &:empty {
101
+ display: none;
102
+ }
103
+ }
104
+
105
+ // Character counter
106
+ .charCount {
107
+ @include helper-text;
108
+ margin-top: var(--fui-space-1, $fui-space-1);
109
+ margin-left: auto;
110
+ font-family: var(--fui-font-mono, $fui-font-mono);
111
+ white-space: nowrap;
112
+ }
113
+
114
+ .charCountOver {
115
+ color: var(--fui-color-danger, $fui-color-danger);
116
+ }
117
+
91
118
  // ============================================
92
119
  // Accessibility: High Contrast Mode
93
120
  // ============================================
@@ -106,6 +133,10 @@
106
133
  .textarea[aria-invalid] {
107
134
  border-color: var(--fui-color-danger, $fui-color-danger);
108
135
  }
136
+
137
+ .success {
138
+ border-color: var(--fui-color-success, $fui-color-success);
139
+ }
109
140
  }
110
141
 
111
142
  // ============================================