@fragments-sdk/ui 0.16.1 → 0.17.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 (132) hide show
  1. package/dist/assets/ui.css +1880 -1602
  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 +21 -21
  53. package/dist/components/Header/Header.module.scss.js +21 -21
  54. package/dist/components/Input/Input.module.scss.cjs +27 -15
  55. package/dist/components/Input/Input.module.scss.js +27 -15
  56. package/dist/components/Input/index.cjs +20 -7
  57. package/dist/components/Input/index.d.ts +8 -2
  58. package/dist/components/Input/index.d.ts.map +1 -1
  59. package/dist/components/Input/index.js +20 -7
  60. package/dist/components/Link/Link.module.scss.cjs +10 -10
  61. package/dist/components/Link/Link.module.scss.js +10 -10
  62. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  63. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  64. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
  65. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
  66. package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
  67. package/dist/components/Pagination/Pagination.module.scss.js +7 -7
  68. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  69. package/dist/components/Popover/Popover.module.scss.js +10 -10
  70. package/dist/components/Prompt/Prompt.module.scss.cjs +14 -14
  71. package/dist/components/Prompt/Prompt.module.scss.js +14 -14
  72. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +16 -16
  73. package/dist/components/RadioGroup/RadioGroup.module.scss.js +16 -16
  74. package/dist/components/Select/Select.module.scss.cjs +17 -17
  75. package/dist/components/Select/Select.module.scss.js +17 -17
  76. package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
  77. package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
  78. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  79. package/dist/components/Slider/Slider.module.scss.js +12 -12
  80. package/dist/components/Tabs/Tabs.module.scss.cjs +9 -9
  81. package/dist/components/Tabs/Tabs.module.scss.js +9 -9
  82. package/dist/components/Textarea/Textarea.module.scss.cjs +34 -19
  83. package/dist/components/Textarea/Textarea.module.scss.js +34 -19
  84. package/dist/components/Textarea/index.cjs +36 -6
  85. package/dist/components/Textarea/index.d.ts +6 -2
  86. package/dist/components/Textarea/index.d.ts.map +1 -1
  87. package/dist/components/Textarea/index.js +36 -6
  88. package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
  89. package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
  90. package/dist/components/Toast/Toast.module.scss.cjs +22 -22
  91. package/dist/components/Toast/Toast.module.scss.js +22 -22
  92. package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
  93. package/dist/components/Toggle/Toggle.module.scss.js +13 -13
  94. package/dist/components/Toggle/index.cjs +7 -3
  95. package/dist/components/Toggle/index.d.ts.map +1 -1
  96. package/dist/components/Toggle/index.js +7 -3
  97. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  98. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  99. package/dist/index.d.ts +1 -1
  100. package/dist/index.d.ts.map +1 -1
  101. package/fragments.json +1 -1
  102. package/package.json +1 -1
  103. package/src/components/Alert/Alert.module.scss +8 -8
  104. package/src/components/Alert/index.tsx +2 -1
  105. package/src/components/Avatar/index.tsx +6 -2
  106. package/src/components/Badge/Badge.module.scss +17 -11
  107. package/src/components/Button/Button.module.scss +6 -5
  108. package/src/components/Button/index.tsx +60 -4
  109. package/src/components/Card/index.tsx +48 -3
  110. package/src/components/Checkbox/Checkbox.module.scss +16 -9
  111. package/src/components/ColorPicker/ColorPicker.module.scss +5 -13
  112. package/src/components/Combobox/Combobox.module.scss +30 -25
  113. package/src/components/DatePicker/DatePicker.module.scss +18 -28
  114. package/src/components/Editor/Editor.module.scss +23 -15
  115. package/src/components/Fieldset/Fieldset.module.scss +12 -6
  116. package/src/components/Fieldset/index.tsx +11 -1
  117. package/src/components/Input/Input.module.scss +97 -26
  118. package/src/components/Input/index.tsx +31 -12
  119. package/src/components/Listbox/Listbox.module.scss +9 -2
  120. package/src/components/RadioGroup/RadioGroup.module.scss +8 -6
  121. package/src/components/Select/Select.module.scss +10 -24
  122. package/src/components/Slider/Slider.module.scss +12 -22
  123. package/src/components/Textarea/Textarea.module.scss +49 -18
  124. package/src/components/Textarea/index.tsx +43 -12
  125. package/src/components/Toast/Toast.module.scss +48 -8
  126. package/src/components/Toggle/Toggle.module.scss +21 -35
  127. package/src/components/Toggle/index.tsx +11 -3
  128. package/src/components/ToggleGroup/ToggleGroup.module.scss +23 -19
  129. package/src/index.ts +1 -0
  130. package/src/styles/globals.scss +4 -1
  131. package/src/tokens/_mixins.scss +57 -4
  132. package/src/tokens/_variables.scss +20 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fragments-sdk/ui",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "license": "MIT",
5
5
  "description": "Customizable UI components built on Base UI headless primitives",
6
6
  "author": "Conan McNicholl",
@@ -14,26 +14,26 @@
14
14
 
15
15
  // Severity variants
16
16
  .info {
17
- background-color: var(--fui-color-info-bg, $fui-color-info-bg);
18
- border: 1px solid var(--fui-color-info, $fui-color-info);
17
+ background: color-mix(in srgb, var(--fui-color-info, #{$fui-color-info}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
18
+ border: 1px solid color-mix(in srgb, var(--fui-color-info, #{$fui-color-info}) 40%, transparent);
19
19
  color: var(--fui-color-info-text, $fui-color-info-text);
20
20
  }
21
21
 
22
22
  .success {
23
- background-color: var(--fui-color-success-bg, $fui-color-success-bg);
24
- border: 1px solid var(--fui-color-success, $fui-color-success);
23
+ background: color-mix(in srgb, var(--fui-color-success, #{$fui-color-success}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
24
+ border: 1px solid color-mix(in srgb, var(--fui-color-success, #{$fui-color-success}) 40%, transparent);
25
25
  color: var(--fui-color-success-text, $fui-color-success-text);
26
26
  }
27
27
 
28
28
  .warning {
29
- background-color: var(--fui-color-warning-bg, $fui-color-warning-bg);
30
- border: 1px solid var(--fui-color-warning, $fui-color-warning);
29
+ background: color-mix(in srgb, var(--fui-color-warning, #{$fui-color-warning}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
30
+ border: 1px solid color-mix(in srgb, var(--fui-color-warning, #{$fui-color-warning}) 40%, transparent);
31
31
  color: var(--fui-color-warning-text, $fui-color-warning-text);
32
32
  }
33
33
 
34
34
  .error {
35
- background-color: var(--fui-color-danger-bg, $fui-color-danger-bg);
36
- border: 1px solid var(--fui-color-danger, $fui-color-danger);
35
+ background: color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
36
+ border: 1px solid color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 40%, transparent);
37
37
  color: var(--fui-color-danger-text, $fui-color-danger-text);
38
38
  }
39
39
 
@@ -117,6 +117,7 @@ function AlertRoot({
117
117
  const classes = [styles.alert, styles[severity], className]
118
118
  .filter(Boolean)
119
119
  .join(' ');
120
+ const role = severity === 'warning' || severity === 'error' ? 'alert' : 'status';
120
121
 
121
122
  const contextValue: AlertContextValue = {
122
123
  severity,
@@ -129,7 +130,7 @@ function AlertRoot({
129
130
  <AlertContext.Provider value={contextValue}>
130
131
  <div
131
132
  {...htmlProps}
132
- role="alert"
133
+ role={role}
133
134
  aria-labelledby={titleId}
134
135
  aria-describedby={descId}
135
136
  className={classes}
@@ -243,8 +243,12 @@ function AvatarGroup({
243
243
  return child;
244
244
  })}
245
245
  {overflowCount > 0 && (
246
- <div className={[styles.avatar, styles[size], styles.overflow].join(' ')}>
247
- <span className={styles.initials}>+{overflowCount}</span>
246
+ <div
247
+ className={[styles.avatar, styles[size], styles.overflow].join(' ')}
248
+ role="img"
249
+ aria-label={`${overflowCount} more ${overflowCount === 1 ? 'person' : 'people'}`}
250
+ >
251
+ <span className={styles.initials} aria-hidden="true">+{overflowCount}</span>
248
252
  </div>
249
253
  )}
250
254
  </div>
@@ -36,22 +36,26 @@
36
36
  }
37
37
 
38
38
  .success {
39
- background-color: var(--fui-color-success-bg, $fui-color-success-bg);
39
+ background: color-mix(in srgb, var(--fui-color-success, #{$fui-color-success}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
40
+ border: 1px solid color-mix(in srgb, var(--fui-color-success, #{$fui-color-success}) 40%, transparent);
40
41
  color: var(--fui-color-success-text, $fui-color-success-text);
41
42
  }
42
43
 
43
44
  .warning {
44
- background-color: var(--fui-color-warning-bg, $fui-color-warning-bg);
45
+ background: color-mix(in srgb, var(--fui-color-warning, #{$fui-color-warning}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
46
+ border: 1px solid color-mix(in srgb, var(--fui-color-warning, #{$fui-color-warning}) 40%, transparent);
45
47
  color: var(--fui-color-warning-text, $fui-color-warning-text);
46
48
  }
47
49
 
48
50
  .error {
49
- background-color: var(--fui-color-danger-bg, $fui-color-danger-bg);
51
+ background: color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
52
+ border: 1px solid color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 40%, transparent);
50
53
  color: var(--fui-color-danger-text, $fui-color-danger-text);
51
54
  }
52
55
 
53
56
  .info {
54
- background-color: var(--fui-color-info-bg, $fui-color-info-bg);
57
+ background: color-mix(in srgb, var(--fui-color-info, #{$fui-color-info}) 15%, var(--fui-bg-elevated, #{$fui-bg-elevated}));
58
+ border: 1px solid color-mix(in srgb, var(--fui-color-info, #{$fui-color-info}) 40%, transparent);
55
59
  color: var(--fui-color-info-text, $fui-color-info-text);
56
60
  }
57
61
 
@@ -78,21 +82,23 @@
78
82
  align-items: center;
79
83
  }
80
84
 
85
+ // Asymmetric padding when removable — tighter on right side near the × button
86
+ .badge:has(.remove) {
87
+ padding: var(--fui-space-0-5, $fui-space-0-5) var(--fui-space-1, $fui-space-1) var(--fui-space-0-5, $fui-space-0-5) var(--fui-space-2, $fui-space-2);
88
+ }
89
+
81
90
  .remove {
82
91
  @include button-reset;
83
92
  @include interactive-base;
84
93
  @include touch-target;
85
94
 
86
- padding: 0 var(--fui-space-0-5, $fui-space-0-5);
87
- font-size: var(--fui-font-size-sm, $fui-font-size-sm);
95
+ margin-left: calc(-1 * var(--fui-space-0-5, $fui-space-0-5));
96
+ padding: 0;
97
+ font-size: inherit;
88
98
  color: inherit;
89
99
  opacity: 0.6;
90
100
  line-height: 1;
91
- border-radius: var(--fui-space-0-5, $fui-space-0-5);
92
-
93
- .sm & {
94
- font-size: var(--fui-font-size-xs, $fui-font-size-xs);
95
- }
101
+ border-radius: var(--fui-radius-full, $fui-radius-full);
96
102
 
97
103
  &:hover {
98
104
  opacity: 1;
@@ -86,17 +86,18 @@
86
86
  }
87
87
 
88
88
  .danger {
89
- background-color: var(--fui-color-danger, $fui-color-danger);
90
- color: var(--fui-text-inverse, $fui-text-inverse);
91
- border: 1px solid transparent;
89
+ background-color: var(--fui-color-danger-bg, $fui-color-danger-bg);
90
+ color: var(--fui-color-danger-text, $fui-color-danger-text);
91
+ border: 1px solid color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 40%, transparent);
92
92
 
93
93
  &:hover:not(:disabled) {
94
- background-color: var(--fui-color-danger-hover, $fui-color-danger-hover);
94
+ background-color: color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 22%, transparent);
95
+ border-color: color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 55%, transparent);
95
96
  }
96
97
 
97
98
  &:active:not(:disabled),
98
99
  &[data-pressed] {
99
- background-color: var(--fui-color-danger-hover, $fui-color-danger-hover);
100
+ background-color: color-mix(in srgb, var(--fui-color-danger, #{$fui-color-danger}) 28%, transparent);
100
101
  }
101
102
  }
102
103
 
@@ -4,6 +4,18 @@ import * as React from 'react';
4
4
  import { Button as BaseButton } from '@base-ui/react/button';
5
5
  import styles from './Button.module.scss';
6
6
 
7
+ function composeEventHandlers<T extends (...args: any[]) => void>(
8
+ childHandler: T | undefined,
9
+ parentHandler: T | undefined
10
+ ) {
11
+ if (!childHandler) return parentHandler;
12
+ if (!parentHandler) return childHandler;
13
+ return ((...args: Parameters<T>) => {
14
+ childHandler(...args);
15
+ parentHandler(...args);
16
+ }) as T;
17
+ }
18
+
7
19
  /**
8
20
  * Button props.
9
21
  * @see https://usefragments.com/components/button
@@ -82,12 +94,56 @@ const ButtonRoot = React.forwardRef<
82
94
 
83
95
  // asChild: merge button styling onto child element (e.g. Next.js Link)
84
96
  if (asChild && React.isValidElement(children)) {
85
- const { as: _as, ...childProps } = rest as ButtonProps & { as?: 'a' | 'button' };
86
- return React.cloneElement(children as React.ReactElement<Record<string, unknown>>, {
97
+ const {
98
+ as: _as,
99
+ disabled,
100
+ style,
101
+ onClick,
102
+ onKeyDown,
103
+ ...childProps
104
+ } = rest as React.ButtonHTMLAttributes<HTMLButtonElement>
105
+ & React.AnchorHTMLAttributes<HTMLAnchorElement>
106
+ & { as?: 'a' | 'button'; disabled?: boolean };
107
+ const childElement = children as React.ReactElement<Record<string, unknown>>;
108
+ const childElementProps = childElement.props as Record<string, unknown>;
109
+ const isIntrinsicButton = typeof childElement.type === 'string' && childElement.type === 'button';
110
+ const isDisabled = Boolean(disabled);
111
+
112
+ const mergedProps: Record<string, unknown> = {
87
113
  ...childProps,
88
- className: [classNames, (children.props as Record<string, unknown>).className].filter(Boolean).join(' '),
114
+ className: [classNames, childElementProps.className].filter(Boolean).join(' '),
115
+ style: { ...(style as React.CSSProperties | undefined), ...(childElementProps.style as React.CSSProperties | undefined) },
89
116
  ref,
90
- });
117
+ };
118
+
119
+ if (isIntrinsicButton) {
120
+ mergedProps.disabled = isDisabled;
121
+ } else if (isDisabled) {
122
+ mergedProps['aria-disabled'] = true;
123
+ mergedProps['data-disabled'] = '';
124
+ mergedProps.tabIndex = -1;
125
+ mergedProps.onClick = (event: React.MouseEvent<HTMLElement>) => {
126
+ event.preventDefault();
127
+ event.stopPropagation();
128
+ };
129
+ mergedProps.onKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
130
+ if (event.key === 'Enter' || event.key === ' ') {
131
+ event.preventDefault();
132
+ event.stopPropagation();
133
+ }
134
+ };
135
+ } else {
136
+ mergedProps.onClick = composeEventHandlers(
137
+ childElementProps.onClick as ((event: React.MouseEvent<HTMLElement>) => void) | undefined,
138
+ onClick as ((event: React.MouseEvent<HTMLElement>) => void) | undefined
139
+ );
140
+ mergedProps.onKeyDown = composeEventHandlers(
141
+ childElementProps.onKeyDown as ((event: React.KeyboardEvent<HTMLElement>) => void) | undefined,
142
+ onKeyDown as ((event: React.KeyboardEvent<HTMLElement>) => void) | undefined
143
+ );
144
+ }
145
+
146
+ return React.cloneElement(childElement, mergedProps);
91
147
  }
92
148
 
93
149
  // Render as anchor
@@ -68,6 +68,17 @@ const paddingMap = {
68
68
  lg: styles.paddingLg,
69
69
  };
70
70
 
71
+ function composeEventHandlers<E extends { defaultPrevented: boolean }>(
72
+ userHandler: ((event: E) => void) | undefined,
73
+ internalHandler: (event: E) => void
74
+ ) {
75
+ return (event: E) => {
76
+ userHandler?.(event);
77
+ if (event.defaultPrevented) return;
78
+ internalHandler(event);
79
+ };
80
+ }
81
+
71
82
  // ============================================
72
83
  // Components
73
84
  // ============================================
@@ -83,8 +94,17 @@ function CardRoot({
83
94
  }: CardProps) {
84
95
  // Resolve alias: "outline" → "outlined"
85
96
  const variant = variantProp === 'outline' ? 'outlined' : variantProp;
86
-
87
- const isInteractive = typeof htmlProps.onClick === 'function';
97
+ const {
98
+ onKeyDown,
99
+ onKeyUp,
100
+ role,
101
+ tabIndex,
102
+ ...elementProps
103
+ } = htmlProps;
104
+
105
+ const isInteractive = typeof elementProps.onClick === 'function';
106
+ const resolvedRole = isInteractive ? role ?? 'button' : role;
107
+ const resolvedTabIndex = isInteractive ? tabIndex ?? 0 : tabIndex;
88
108
 
89
109
  const classes = [
90
110
  styles.card,
@@ -105,7 +125,32 @@ function CardRoot({
105
125
  return (
106
126
  <CardContext.Provider value={contextValue}>
107
127
  <Component
108
- {...htmlProps}
128
+ {...elementProps}
129
+ role={resolvedRole}
130
+ tabIndex={resolvedTabIndex}
131
+ onKeyDown={
132
+ isInteractive && resolvedRole === 'button'
133
+ ? composeEventHandlers(onKeyDown, (event: React.KeyboardEvent<HTMLElement>) => {
134
+ if (event.key === 'Enter') {
135
+ event.preventDefault();
136
+ event.currentTarget.click();
137
+ }
138
+ if (event.key === ' ') {
139
+ event.preventDefault();
140
+ }
141
+ })
142
+ : onKeyDown
143
+ }
144
+ onKeyUp={
145
+ isInteractive && resolvedRole === 'button'
146
+ ? composeEventHandlers(onKeyUp, (event: React.KeyboardEvent<HTMLElement>) => {
147
+ if (event.key === ' ') {
148
+ event.preventDefault();
149
+ event.currentTarget.click();
150
+ }
151
+ })
152
+ : onKeyUp
153
+ }
109
154
  className={classes}
110
155
  style={style}
111
156
  >
@@ -29,25 +29,26 @@
29
29
  width: 1rem;
30
30
  height: 1rem;
31
31
  margin-top: 0;
32
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
33
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
32
+ background-color: var(--fui-field-bg, $fui-bg-elevated);
33
+ border: 1px solid var(--fui-field-border, $fui-border-strong);
34
34
  border-radius: var(--fui-radius-sm, $fui-radius-sm);
35
35
  cursor: inherit;
36
36
 
37
37
  &:hover:not([data-disabled]) {
38
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
38
+ border-color: var(--fui-field-border-hover, $fui-text-tertiary);
39
39
  }
40
40
 
41
41
  &[data-checked],
42
42
  &[data-indeterminate] {
43
- background-color: var(--fui-color-accent, $fui-color-accent);
44
- border-color: var(--fui-color-accent, $fui-color-accent);
43
+ background-color: var(--fui-field-selection-bg, $fui-bg-hover);
44
+ border-color: var(--fui-field-selection-border, $fui-color-accent);
45
+ box-shadow: inset 0 0 0 1px var(--fui-field-selection-border, $fui-color-accent);
45
46
  }
46
47
 
47
48
  &[data-checked]:hover:not([data-disabled]),
48
49
  &[data-indeterminate]:hover:not([data-disabled]) {
49
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
50
- border-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
50
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
51
+ border-color: var(--fui-field-selection-border, $fui-color-accent);
51
52
  }
52
53
 
53
54
  &[data-invalid] {
@@ -56,8 +57,9 @@
56
57
 
57
58
  &[data-invalid][data-checked],
58
59
  &[data-invalid][data-indeterminate] {
59
- background-color: var(--fui-color-danger, $fui-color-danger);
60
+ background-color: var(--fui-color-danger-bg, $fui-color-danger-bg);
60
61
  border-color: var(--fui-color-danger, $fui-color-danger);
62
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fui-color-danger, $fui-color-danger) 35%, transparent);
61
63
  }
62
64
  }
63
65
 
@@ -82,7 +84,7 @@
82
84
  display: flex;
83
85
  align-items: center;
84
86
  justify-content: center;
85
- color: var(--fui-text-inverse, $fui-text-inverse);
87
+ color: var(--fui-color-accent, $fui-color-accent);
86
88
 
87
89
  svg {
88
90
  width: 0.75rem;
@@ -101,6 +103,11 @@
101
103
  opacity: 1;
102
104
  transform: scale(1);
103
105
  }
106
+
107
+ [data-invalid][data-checked] > &,
108
+ [data-invalid][data-indeterminate] > & {
109
+ color: var(--fui-color-danger, $fui-color-danger);
110
+ }
104
111
  }
105
112
 
106
113
  // Size variant indicators
@@ -58,20 +58,12 @@
58
58
  @include button-reset;
59
59
  @include interactive-base;
60
60
  @include min-target-size;
61
+ @include field-shell;
62
+
61
63
  width: var(--fui-input-height, $fui-input-height);
62
64
  height: var(--fui-input-height, $fui-input-height);
63
- border: 1px solid var(--fui-border, $fui-border);
64
- border-radius: var(--fui-radius-sm, $fui-radius-sm);
65
65
  flex-shrink: 0;
66
66
 
67
- &:hover:not(:disabled) {
68
- border-color: var(--fui-border-strong, $fui-border-strong);
69
- }
70
-
71
- &:focus-visible {
72
- @include focus-ring;
73
- }
74
-
75
67
  &:disabled {
76
68
  opacity: 0.5;
77
69
  cursor: not-allowed;
@@ -96,10 +88,10 @@
96
88
  }
97
89
 
98
90
  .popup {
99
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
100
- border: 1px solid var(--fui-border, $fui-border);
91
+ @include surface-elevated;
92
+
93
+ border-color: var(--fui-form-group-border, $fui-border);
101
94
  border-radius: var(--fui-radius-lg, $fui-radius-lg);
102
- box-shadow: var(--fui-shadow-md, $fui-shadow-md);
103
95
  padding: var(--fui-space-2, $fui-space-2);
104
96
 
105
97
  // react-colorful styling overrides
@@ -8,6 +8,10 @@
8
8
  // Size variants for input wrapper
9
9
  .inputWrapperSm {
10
10
  min-height: var(--fui-input-height-sm, $fui-input-height-sm);
11
+
12
+ .trigger {
13
+ width: calc(var(--fui-input-height-sm, $fui-input-height-sm) - var(--fui-space-1, $fui-space-1));
14
+ }
11
15
  }
12
16
 
13
17
  .inputWrapperMd {
@@ -16,10 +20,16 @@
16
20
 
17
21
  .inputWrapperLg {
18
22
  min-height: var(--fui-input-height-lg, $fui-input-height-lg);
23
+
24
+ .trigger {
25
+ width: calc(var(--fui-input-height-lg, $fui-input-height-lg) - var(--fui-space-1, $fui-space-1));
26
+ }
19
27
  }
20
28
 
21
29
  // Input + trigger wrapper
22
30
  .inputWrapper {
31
+ @include field-shell;
32
+
23
33
  display: inline-flex;
24
34
  align-items: center;
25
35
  flex-wrap: wrap;
@@ -27,26 +37,15 @@
27
37
  width: 100%;
28
38
  min-width: 10rem;
29
39
  min-height: var(--fui-input-height, $fui-input-height);
30
- padding: var(--fui-space-1, $fui-space-1);
31
- padding-right: 0;
32
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
33
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
34
- border-radius: var(--fui-radius-md, $fui-radius-md);
35
- transition:
36
- border-color var(--fui-transition-fast, $fui-transition-fast),
37
- box-shadow var(--fui-transition-fast, $fui-transition-fast);
38
-
39
- &:hover:not(:has([data-disabled])) {
40
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
41
- }
40
+ padding: calc(var(--fui-space-px, $fui-space-px) * 2);
41
+ padding-right: var(--fui-space-1, $fui-space-1);
42
42
 
43
43
  &:focus-within {
44
- @include focus-ring;
45
- border-color: var(--fui-color-accent, $fui-color-accent);
44
+ @include field-shell-focus;
46
45
  }
47
46
 
48
47
  &:has([data-disabled]) {
49
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
48
+ background-color: var(--fui-field-bg-disabled, $fui-bg-tertiary);
50
49
  color: var(--fui-text-tertiary, $fui-text-tertiary);
51
50
  }
52
51
  }
@@ -98,11 +97,12 @@
98
97
  gap: var(--fui-space-0-5, $fui-space-0-5);
99
98
  height: var(--fui-target-size-min, $fui-target-size-min);
100
99
  padding: 0 var(--fui-space-2, $fui-space-2);
101
- background-color: transparent;
102
- border: 1px solid var(--fui-border, $fui-border);
100
+ background-color: var(--fui-bg-secondary, $fui-bg-secondary);
101
+ border: 1px solid var(--fui-form-group-border, $fui-border);
103
102
  border-radius: var(--fui-radius-full, $fui-radius-full);
104
103
  font-size: var(--fui-font-size-2xs, $fui-font-size-2xs);
105
104
  line-height: 1;
105
+ color: var(--fui-text-secondary, $fui-text-secondary);
106
106
  white-space: nowrap;
107
107
  max-width: 12rem;
108
108
  }
@@ -140,22 +140,25 @@
140
140
  // Chevron trigger button
141
141
  .trigger {
142
142
  @include button-reset;
143
+ @include touch-target;
143
144
 
144
145
  display: flex;
145
146
  align-items: center;
146
147
  justify-content: center;
147
148
  flex-shrink: 0;
148
- align-self: stretch;
149
- width: 2rem;
149
+ width: calc(var(--fui-input-height, $fui-input-height) - var(--fui-space-1, $fui-space-1));
150
150
  margin-left: auto;
151
151
  color: var(--fui-text-secondary, $fui-text-secondary);
152
152
  cursor: pointer;
153
- border-radius: 0 var(--fui-radius-md, $fui-radius-md) var(--fui-radius-md, $fui-radius-md) 0;
154
- transition: color var(--fui-transition-fast, $fui-transition-fast);
155
- margin-inline-end: var(--fui-space-2, $fui-space-2);
153
+ border-radius: calc(var(--fui-radius-md, $fui-radius-md) - 2px);
154
+ transition:
155
+ color var(--fui-transition-fast, $fui-transition-fast),
156
+ background-color var(--fui-transition-fast, $fui-transition-fast);
157
+ margin-inline-end: calc(var(--fui-space-px, $fui-space-px) * 2);
156
158
 
157
159
  &:hover {
158
160
  color: var(--fui-text-primary, $fui-text-primary);
161
+ background-color: var(--fui-bg-hover, $fui-bg-hover);
159
162
  }
160
163
 
161
164
  &[data-disabled] {
@@ -185,6 +188,8 @@
185
188
  @include surface-elevated;
186
189
  @include popup-container;
187
190
 
191
+ border-color: var(--fui-form-group-border, $fui-border);
192
+
188
193
  // Item height derived from text-base font + vertical padding
189
194
  --_item-h: calc(
190
195
  var(--fui-font-size-sm, #{$fui-font-size-sm}) *
@@ -230,12 +235,11 @@
230
235
  }
231
236
 
232
237
  &[data-selected] {
233
- background-color: var(--fui-color-accent, $fui-color-accent);
234
- color: var(--fui-text-inverse, $fui-text-inverse);
238
+ @include popup-item-selected;
235
239
 
236
240
  &[data-highlighted],
237
241
  &:hover:not([data-disabled]) {
238
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
242
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
239
243
  }
240
244
  }
241
245
 
@@ -253,6 +257,7 @@
253
257
  width: 1rem;
254
258
  height: 1rem;
255
259
  margin-left: auto;
260
+ color: var(--fui-color-accent, $fui-color-accent);
256
261
 
257
262
  svg {
258
263
  width: 0.875rem;
@@ -12,30 +12,18 @@
12
12
  @include button-reset;
13
13
  @include interactive-base;
14
14
  @include text-base;
15
+ @include field-shell;
16
+ @include control-size('md', 'input');
15
17
 
16
18
  display: inline-flex;
17
19
  align-items: center;
18
20
  gap: var(--fui-space-2, $fui-space-2);
19
21
  width: 100%;
20
22
  min-width: 10rem;
21
- height: var(--fui-input-height, $fui-input-height);
22
- padding: 0 var(--fui-space-3, $fui-space-3);
23
- background-color: var(--fui-bg-elevated, $fui-bg-elevated);
24
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
25
- border-radius: var(--fui-radius-md, $fui-radius-md);
26
23
  text-align: left;
27
24
 
28
- &:hover:not([data-disabled]) {
29
- border-color: var(--fui-text-tertiary, $fui-text-tertiary);
30
- }
31
-
32
25
  &[data-popup-open] {
33
- border-color: var(--fui-color-accent, $fui-color-accent);
34
- }
35
-
36
- &[data-disabled] {
37
- background-color: var(--fui-bg-tertiary, $fui-bg-tertiary);
38
- color: var(--fui-text-tertiary, $fui-text-tertiary);
26
+ border-color: var(--fui-field-border-focus, $fui-color-accent);
39
27
  }
40
28
  }
41
29
 
@@ -80,6 +68,7 @@
80
68
  .popup {
81
69
  @include surface-elevated;
82
70
 
71
+ border-color: var(--fui-form-group-border, $fui-border);
83
72
  padding: var(--fui-space-3, $fui-space-3);
84
73
  box-shadow: var(--fui-shadow-md, $fui-shadow-md);
85
74
 
@@ -250,15 +239,16 @@
250
239
  // ============================================
251
240
 
252
241
  .today > .dayButton {
253
- border: 1px solid var(--fui-border-strong, $fui-border-strong);
242
+ box-shadow: inset 0 0 0 1px var(--fui-field-border, $fui-border-strong);
243
+ background-color: color-mix(in srgb, var(--fui-bg-hover, $fui-bg-hover) 55%, transparent);
254
244
  }
255
245
 
256
246
  .selected > .dayButton {
257
- background-color: var(--fui-color-accent, $fui-color-accent);
258
- color: var(--fui-text-inverse, $fui-text-inverse);
247
+ @include popup-item-selected;
248
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
259
249
 
260
250
  &:hover {
261
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
251
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
262
252
  }
263
253
  }
264
254
 
@@ -292,7 +282,7 @@
292
282
  content: '';
293
283
  position: absolute;
294
284
  inset: 2px 0;
295
- background-color: var(--fui-bg-hover, $fui-bg-hover);
285
+ background-color: color-mix(in srgb, var(--fui-color-accent, $fui-color-accent) 10%, transparent);
296
286
  z-index: 0;
297
287
  }
298
288
 
@@ -309,18 +299,18 @@
309
299
  content: '';
310
300
  position: absolute;
311
301
  inset: 2px 0 2px 50%;
312
- background-color: var(--fui-bg-hover, $fui-bg-hover);
302
+ background-color: color-mix(in srgb, var(--fui-color-accent, $fui-color-accent) 10%, transparent);
313
303
  z-index: 0;
314
304
  }
315
305
 
316
306
  > .dayButton {
317
307
  position: relative;
318
308
  z-index: 1;
319
- background-color: var(--fui-color-accent, $fui-color-accent);
320
- color: var(--fui-text-inverse, $fui-text-inverse);
309
+ @include popup-item-selected;
310
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
321
311
 
322
312
  &:hover {
323
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
313
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
324
314
  }
325
315
  }
326
316
 
@@ -335,18 +325,18 @@
335
325
  content: '';
336
326
  position: absolute;
337
327
  inset: 2px 50% 2px 0;
338
- background-color: var(--fui-bg-hover, $fui-bg-hover);
328
+ background-color: color-mix(in srgb, var(--fui-color-accent, $fui-color-accent) 10%, transparent);
339
329
  z-index: 0;
340
330
  }
341
331
 
342
332
  > .dayButton {
343
333
  position: relative;
344
334
  z-index: 1;
345
- background-color: var(--fui-color-accent, $fui-color-accent);
346
- color: var(--fui-text-inverse, $fui-text-inverse);
335
+ @include popup-item-selected;
336
+ font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
347
337
 
348
338
  &:hover {
349
- background-color: var(--fui-color-accent-hover, $fui-color-accent-hover);
339
+ background-color: var(--fui-field-selection-bg-hover, $fui-bg-hover);
350
340
  }
351
341
  }
352
342
  }