@tangible/ui 0.0.1 → 0.0.3

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 (135) hide show
  1. package/components/Card/Card.d.ts +1 -0
  2. package/components/Card/Card.js +17 -20
  3. package/components/Checkbox/Checkbox.d.ts +9 -0
  4. package/components/Checkbox/Checkbox.js +92 -0
  5. package/components/Checkbox/index.d.ts +2 -0
  6. package/components/Checkbox/index.js +1 -0
  7. package/components/Checkbox/types.d.ts +10 -0
  8. package/components/Checkbox/types.js +1 -0
  9. package/components/Chip/Chip.d.ts +4 -1
  10. package/components/Chip/Chip.js +32 -7
  11. package/components/ChipGroup/ChipGroup.d.ts +5 -0
  12. package/components/ChipGroup/ChipGroup.js +68 -0
  13. package/components/ChipGroup/ChipGroupContext.d.ts +3 -0
  14. package/components/ChipGroup/ChipGroupContext.js +5 -0
  15. package/components/ChipGroup/index.d.ts +3 -0
  16. package/components/ChipGroup/index.js +2 -0
  17. package/components/ChipGroup/types.d.ts +36 -0
  18. package/components/ChipGroup/types.js +1 -0
  19. package/components/Chips/Chips.d.ts +2 -0
  20. package/components/Chips/Chips.js +1 -1
  21. package/components/Combobox/Combobox.d.ts +33 -0
  22. package/components/Combobox/Combobox.js +466 -0
  23. package/components/Combobox/ComboboxContext.d.ts +8 -0
  24. package/components/Combobox/ComboboxContext.js +36 -0
  25. package/components/Combobox/index.d.ts +2 -0
  26. package/components/Combobox/index.js +1 -0
  27. package/components/Combobox/types.d.ts +204 -0
  28. package/components/Combobox/types.js +1 -0
  29. package/components/Dropdown/Dropdown.js +2 -1
  30. package/components/Field/Field.d.ts +39 -0
  31. package/components/Field/Field.js +92 -0
  32. package/components/Field/FieldContext.d.ts +16 -0
  33. package/components/Field/FieldContext.js +10 -0
  34. package/components/Field/index.d.ts +2 -0
  35. package/components/Field/index.js +1 -0
  36. package/components/Modal/Modal.d.ts +4 -4
  37. package/components/Modal/Modal.js +14 -12
  38. package/components/MoveHandle/MoveHandle.d.ts +2 -0
  39. package/components/MoveHandle/MoveHandle.js +84 -0
  40. package/components/MoveHandle/index.d.ts +2 -0
  41. package/components/MoveHandle/index.js +1 -0
  42. package/components/MoveHandle/types.d.ts +43 -0
  43. package/components/MoveHandle/types.js +1 -0
  44. package/components/MultiSelect/MultiSelect.d.ts +39 -0
  45. package/components/MultiSelect/MultiSelect.js +623 -0
  46. package/components/MultiSelect/MultiSelectContext.d.ts +20 -0
  47. package/components/MultiSelect/MultiSelectContext.js +56 -0
  48. package/components/MultiSelect/index.d.ts +2 -0
  49. package/components/MultiSelect/index.js +1 -0
  50. package/components/MultiSelect/types.d.ts +218 -0
  51. package/components/MultiSelect/types.js +3 -0
  52. package/components/Notice/Notice.d.ts +1 -1
  53. package/components/Notice/Notice.js +1 -1
  54. package/components/Progress/Progress.js +1 -1
  55. package/components/Progress/types.d.ts +7 -7
  56. package/components/Radio/Radio.d.ts +2 -0
  57. package/components/Radio/Radio.js +50 -0
  58. package/components/Radio/RadioGroup.d.ts +2 -0
  59. package/components/Radio/RadioGroup.js +54 -0
  60. package/components/Radio/RadioGroupContext.d.ts +3 -0
  61. package/components/Radio/RadioGroupContext.js +9 -0
  62. package/components/Radio/index.d.ts +8 -0
  63. package/components/Radio/index.js +6 -0
  64. package/components/Radio/types.d.ts +32 -0
  65. package/components/Radio/types.js +1 -0
  66. package/components/Rating/Rating.d.ts +5 -5
  67. package/components/Rating/Rating.js +2 -2
  68. package/components/SegmentedControl/SegmentedControl.js +20 -104
  69. package/components/SegmentedControl/types.d.ts +4 -8
  70. package/components/Select/Select.d.ts +39 -0
  71. package/components/Select/Select.js +497 -0
  72. package/components/Select/SelectContext.d.ts +20 -0
  73. package/components/Select/SelectContext.js +56 -0
  74. package/components/Select/index.d.ts +3 -0
  75. package/components/Select/index.js +1 -0
  76. package/components/Select/types.d.ts +216 -0
  77. package/components/Select/types.js +11 -0
  78. package/components/Sidebar/Sidebar.js +12 -12
  79. package/components/Sidebar/types.d.ts +5 -5
  80. package/components/StepIndicator/StepIndicator.js +1 -1
  81. package/components/StepList/StepList.js +2 -2
  82. package/components/StepList/types.d.ts +4 -4
  83. package/components/Switch/Switch.d.ts +9 -0
  84. package/components/Switch/Switch.js +91 -0
  85. package/components/Switch/index.d.ts +2 -0
  86. package/components/Switch/index.js +1 -0
  87. package/components/Switch/types.d.ts +11 -0
  88. package/components/Switch/types.js +1 -0
  89. package/components/TextInput/TextInput.d.ts +8 -0
  90. package/components/TextInput/TextInput.js +25 -0
  91. package/components/TextInput/index.d.ts +2 -0
  92. package/components/TextInput/index.js +1 -0
  93. package/components/TextInput/types.d.ts +32 -0
  94. package/components/TextInput/types.js +1 -0
  95. package/components/Textarea/Textarea.d.ts +6 -0
  96. package/components/Textarea/Textarea.js +49 -0
  97. package/components/Textarea/index.d.ts +2 -0
  98. package/components/Textarea/index.js +1 -0
  99. package/components/Textarea/types.d.ts +25 -0
  100. package/components/Textarea/types.js +1 -0
  101. package/components/index.d.ts +22 -0
  102. package/components/index.js +11 -0
  103. package/icons/icons.svg +2 -0
  104. package/icons/manifest.json +16 -0
  105. package/icons/registry.d.ts +4 -0
  106. package/icons/registry.js +2 -0
  107. package/icons/system/index.d.ts +4 -0
  108. package/icons/system/index.js +22 -0
  109. package/package.json +1 -1
  110. package/styles/all.css +1 -1
  111. package/styles/all.expanded.css +1838 -136
  112. package/styles/all.expanded.unlayered.css +1838 -136
  113. package/styles/all.unlayered.css +1 -1
  114. package/styles/components/_bundle.scss +22 -0
  115. package/styles/components/input/index.scss +5 -20
  116. package/styles/index.scss +21 -0
  117. package/styles/system/_control.scss +49 -0
  118. package/styles/system/_tokens.scss +124 -2
  119. package/styles/system/index.scss +2 -1
  120. package/styles/utilities/_index.scss +50 -0
  121. package/tui-manifest.json +907 -112
  122. package/utils/compose-events.d.ts +15 -0
  123. package/utils/compose-events.js +27 -0
  124. package/utils/hash.d.ts +15 -0
  125. package/utils/hash.js +32 -0
  126. package/utils/index.d.ts +3 -0
  127. package/utils/index.js +6 -0
  128. package/utils/is-dev.d.ts +5 -0
  129. package/utils/is-dev.js +7 -0
  130. package/utils/use-controllable-state.d.ts +19 -0
  131. package/utils/use-controllable-state.js +59 -0
  132. package/utils/use-roving-group.d.ts +33 -0
  133. package/utils/use-roving-group.js +123 -0
  134. package/utils/value-key.d.ts +16 -0
  135. package/utils/value-key.js +14 -0
@@ -2,24 +2,35 @@
2
2
  @use "../../components/Avatar/styles" as avatar;
3
3
  @use "../../components/Button/styles" as button;
4
4
  @use "../../components/Card/styles" as card;
5
+ @use "../../components/Checkbox/styles" as checkbox;
5
6
  @use "../../components/Chip/styles" as chip;
7
+ @use "../../components/ChipGroup/styles" as chipgroup;
8
+ @use "../../components/Combobox/styles" as combobox;
6
9
  @use "../../components/ContentIndicator/styles" as contentindicator;
7
10
  @use "../../components/Dropdown/styles" as dropdown;
11
+ @use "../../components/Field/styles" as field;
12
+ @use "../../components/MultiSelect/styles" as multiselect;
13
+ @use "../../components/Select/styles" as select;
8
14
  @use "./input/index" as input;
9
15
  @use "../../components/Icon/styles" as icon;
10
16
  @use "../../components/IconButton/styles" as iconbutton;
11
17
  @use "../../components/Modal/styles" as modal;
18
+ @use "../../components/MoveHandle/styles" as movehandle;
12
19
  @use "../../components/Notice/styles" as notice;
13
20
  @use "../../components/OverlapStack/styles" as overlapstack;
14
21
  @use "../../components/Pager/styles" as pager;
22
+ @use "../../components/Radio/styles" as radio;
15
23
  @use "../../components/Rating/styles" as rating;
16
24
  @use "../../components/Progress/styles" as progress;
17
25
  @use "../../components/SegmentedControl/styles" as segmentedcontrol;
26
+ @use "../../components/Switch/styles" as switch;
18
27
  @use "../../components/Sidebar/styles" as sidebar;
19
28
  @use "../../components/StepIndicator/styles" as stepindicator;
20
29
  @use "../../components/StepList/styles" as steplist;
21
30
  @use "../../components/Table/styles" as table;
22
31
  @use "../../components/Tabs/styles" as tabs;
32
+ @use "../../components/Textarea/styles" as textarea;
33
+ @use "../../components/TextInput/styles" as textinput;
23
34
  @use "../../components/Toolbar/styles" as toolbar;
24
35
  @use "../../components/Tooltip/styles" as tooltip;
25
36
 
@@ -28,24 +39,35 @@
28
39
  @include avatar.styles();
29
40
  @include button.styles();
30
41
  @include card.styles();
42
+ @include checkbox.styles();
31
43
  @include chip.styles();
44
+ @include chipgroup.styles();
45
+ @include combobox.styles();
32
46
  @include contentindicator.styles();
33
47
  @include dropdown.styles();
48
+ @include field.styles();
49
+ @include multiselect.styles();
50
+ @include select.styles();
34
51
  @include input.styles();
35
52
  @include icon.styles();
36
53
  @include iconbutton.styles();
37
54
  @include modal.styles();
55
+ @include movehandle.styles();
38
56
  @include notice.styles();
39
57
  @include overlapstack.styles();
40
58
  @include pager.styles();
59
+ @include radio.styles();
41
60
  @include rating.styles();
42
61
  @include progress.styles();
43
62
  @include segmentedcontrol.styles();
63
+ @include switch.styles();
44
64
  @include sidebar.styles();
45
65
  @include stepindicator.styles();
46
66
  @include steplist.styles();
47
67
  @include table.styles();
48
68
  @include tabs.styles();
69
+ @include textarea.styles();
70
+ @include textinput.styles();
49
71
  @include toolbar.styles();
50
72
  @include tooltip.styles();
51
73
  }
@@ -22,7 +22,6 @@
22
22
 
23
23
  // Structural (not tokenised)
24
24
  $_spacing-inline: 0.5em;
25
- $_height: calc(2em - (2 * var(--#{sys.$prefix}border-width)));
26
25
 
27
26
  // ---------------------------------------------------------------------------
28
27
  // Labels
@@ -65,17 +64,15 @@
65
64
  --_border-invalid: var(--#{sys.$prefix}input-border-invalid, var(--#{sys.$prefix}theme-danger-base));
66
65
  --_radius: var(--#{sys.$prefix}input-radius, var(--#{sys.$prefix}radius-md));
67
66
 
68
- font-size: var(--#{sys.$prefix}typography-size-sm);
67
+ @include sys.control-sizing(sys.$prefix);
68
+
69
69
  font-family: inherit;
70
- box-sizing: content-box;
71
70
  border: var(--#{sys.$prefix}border-width) solid var(--_border);
72
71
  border-radius: var(--_radius);
73
72
  appearance: none;
74
73
  background-color: var(--_bg);
75
74
  color: var(--_fg);
76
- height: $_height;
77
75
  padding-inline: $_spacing-inline;
78
- padding-block: 0;
79
76
  min-width: 1px;
80
77
 
81
78
  transition-duration: var(--#{sys.$prefix}motion-duration);
@@ -93,22 +90,11 @@
93
90
  cursor: not-allowed;
94
91
  }
95
92
 
96
- &:invalid {
93
+ &:invalid,
94
+ &[aria-invalid="true"] {
97
95
  --_border: var(--_border-invalid);
98
96
  }
99
97
  }
100
-
101
- // ---------------------------------------------------------------------------
102
- // Search input with icon
103
- // ---------------------------------------------------------------------------
104
- :where(.#{sys.$prefix}interface) :is(input[type="search"], input[type="search"].#{sys.$prefix}input) {
105
- padding-inline-start: 2.5em !important;
106
- background-image: url('data:image/svg+xml;utf8,<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M8 16a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8ZM8 2a6 6 0 1 0 6 6 6.006 6.006 0 0 0-6-6ZM19 20a1 1 0 0 1-.707-.293l-4-4a1 1 0 0 1 1.414-1.414l4 4A1 1 0 0 1 19 20Z" fill="%231F2A37"/></svg>');
107
- background-repeat: no-repeat;
108
- background-position: 0.75em 50%;
109
- background-size: 1em;
110
- }
111
-
112
98
  // ---------------------------------------------------------------------------
113
99
  // Select with dropdown arrow
114
100
  // ---------------------------------------------------------------------------
@@ -157,7 +143,7 @@
157
143
  :where(.#{sys.$prefix}interface) .#{sys.$prefix}toggle {
158
144
  // Internal tokens
159
145
  --_accent: var(--#{sys.$prefix}input-accent, var(--#{sys.$prefix}theme-primary-base));
160
- --_track-off: var(--#{sys.$prefix}palette-color-gray-300);
146
+ --_track-off: var(--#{sys.$prefix}theme-secondary-soft);
161
147
 
162
148
  input[type="checkbox"] {
163
149
  position: absolute;
@@ -236,7 +222,6 @@
236
222
 
237
223
  font-size: var(--#{sys.$prefix}typography-size-sm);
238
224
  font-family: inherit;
239
- box-sizing: content-box;
240
225
  border: var(--#{sys.$prefix}border-width) solid var(--_border);
241
226
  border-radius: var(--_radius);
242
227
  background-color: var(--_bg);
package/styles/index.scss CHANGED
@@ -10,6 +10,18 @@
10
10
  @include sys.emit-color-roles-dark(sys.$prefix);
11
11
  @include sys.emit-color-roles-auto(sys.$prefix);
12
12
 
13
+ @include sys.emit-accent-roles(sys.$prefix);
14
+ @include sys.emit-accent-roles-dark(sys.$prefix);
15
+ @include sys.emit-accent-roles-auto(sys.$prefix);
16
+
17
+ // Reduced motion: kill all token-driven transitions/animations globally.
18
+ // Components using --tui-motion-duration get instant transitions for free.
19
+ @media (prefers-reduced-motion: reduce) {
20
+ :where(.#{sys.$prefix}interface) {
21
+ --#{sys.$prefix}motion-duration: 0ms;
22
+ }
23
+ }
24
+
13
25
  .#{sys.$prefix}interface {
14
26
  --#{sys.$prefix}spacing-base: 4px;
15
27
  @include sys.emit-spacing-primitives(#{sys.$prefix});
@@ -39,6 +51,7 @@
39
51
  0 2px 4px rgba(var(--#{sys.$prefix}shadow-color), 0.06);
40
52
  --#{sys.$prefix}shadow-lg: 0 10px 15px rgba(var(--#{sys.$prefix}shadow-color), 0.1),
41
53
  0 4px 6px rgba(var(--#{sys.$prefix}shadow-color), 0.05);
54
+ --#{sys.$prefix}shadow-dropdown: 0 4px 12px rgba(var(--#{sys.$prefix}shadow-color), 0.15);
42
55
  }
43
56
  @layer resets {
44
57
  .#{sys.$prefix}interface {
@@ -52,6 +65,14 @@
52
65
  color: var(--#{sys.$prefix}color-fg);
53
66
  }
54
67
 
68
+ // Universal border-box — all TUI elements use border-box sizing.
69
+ &,
70
+ *,
71
+ *::before,
72
+ *::after {
73
+ box-sizing: border-box;
74
+ }
75
+
55
76
  // Button element reset — kill common theme button styling
56
77
  button,
57
78
  [type="button"],
@@ -0,0 +1,49 @@
1
+ @use "constants" as sys;
2
+
3
+ // =============================================================================
4
+ // Control Sizing Mixin
5
+ // =============================================================================
6
+ //
7
+ // Unified height formula for all form controls (TextInput, Select, MultiSelect,
8
+ // Combobox). Include on the element that owns the control's visible box.
9
+ //
10
+ // Sets font-size, padding-block, and min-height. The consumer handles
11
+ // padding-inline, border, and everything else.
12
+ // Assumes border-box (set globally in the resets layer).
13
+ //
14
+ // Resulting heights (spacing-xxs = 4px):
15
+ // sm → 14px font → 36px
16
+ // md → 16px font → 40px (default)
17
+ // lg → 20px font → 48px
18
+ //
19
+ // Override from consuming context (e.g. Fields for WordPress):
20
+ // .my-context .tui-interface {
21
+ // --tui-control-height-sm: 32px;
22
+ // --tui-control-height-md: 36px;
23
+ // --tui-control-height-lg: 44px;
24
+ // }
25
+ //
26
+ // Usage:
27
+ // .tui-select__trigger { @include sys.control-sizing(sys.$prefix); }
28
+ //
29
+ // =============================================================================
30
+
31
+ @mixin control-sizing($prefix) {
32
+ --_fs: var(--#{$prefix}typography-size-md);
33
+ --_py: var(--#{$prefix}spacing-xxs);
34
+ --_height: calc(2em + 2 * var(--_py));
35
+
36
+ font-size: var(--_fs);
37
+ padding-block: var(--_py);
38
+ min-height: var(--#{$prefix}control-height-md, var(--_height));
39
+
40
+ &.is-size-sm {
41
+ --_fs: var(--#{$prefix}typography-size-sm);
42
+ min-height: var(--#{$prefix}control-height-sm, var(--_height));
43
+ }
44
+
45
+ &.is-size-lg {
46
+ --_fs: var(--#{$prefix}typography-size-lg);
47
+ min-height: var(--#{$prefix}control-height-lg, var(--_height));
48
+ }
49
+ }
@@ -26,6 +26,9 @@ $brand: 'blue';
26
26
  }
27
27
  @mixin emit-color-roles($prefix:'#{$prefix}', $brand:'blue', $neutral:'gray') {
28
28
  :where(.#{$prefix}interface) {
29
+ /* UA chrome: native controls, scrollbars render in light mode */
30
+ color-scheme: light;
31
+
29
32
  /* ========================
30
33
  PRIMITIVES
31
34
  ======================== */
@@ -59,13 +62,15 @@ $brand: 'blue';
59
62
 
60
63
  /* Neutral: surfaces */
61
64
  --#{$prefix}color-bg: #fff;
62
- --#{$prefix}color-bg-surface: #{pf.tone($neutral, 25)};
65
+ --#{$prefix}color-bg-surface: #{pf.tone($neutral, 25)};
66
+ --#{$prefix}color-bg-muted: #{pf.tone($neutral, 100)};
63
67
  --#{$prefix}color-bg-elevated: #fff;
64
68
  --#{$prefix}color-bg-inverted: #{pf.tone($neutral, 900)};
65
69
  --#{$prefix}color-bg-overlay: rgba(0, 0, 0, var(--#{$prefix}opacity-backdrop));
66
70
 
67
71
  /* Neutral: text */
68
72
  --#{$prefix}color-fg: #{pf.tone($neutral, 900)};
73
+ --#{$prefix}color-fg-secondary: #{pf.tone($neutral, 600)};
69
74
  --#{$prefix}color-fg-muted: #{pf.tone($neutral, 500)};
70
75
  --#{$prefix}color-fg-on-accent: #fff;
71
76
  --#{$prefix}color-fg-inverted: #{pf.tone($neutral, 25)};
@@ -139,15 +144,20 @@ $brand: 'blue';
139
144
 
140
145
  // Private: actual dark override declarations
141
146
  @mixin _dark-overrides($prefix:'tui-', $brand:'blue', $neutral:'gray') {
147
+ /* UA chrome: native controls, scrollbars render in dark mode */
148
+ color-scheme: dark;
149
+
142
150
  /* Backgrounds */
143
151
  --#{$prefix}color-bg: #{pf.tone($neutral, 900)};
144
152
  --#{$prefix}color-bg-surface: #{pf.tone($neutral, 800)};
145
- --#{$prefix}color-bg-elevated: #{pf.tone($neutral, 700)};
153
+ --#{$prefix}color-bg-muted: #{pf.tone($neutral, 700)};
154
+ --#{$prefix}color-bg-elevated: #{pf.tone($neutral, 900)};
146
155
  --#{$prefix}color-bg-inverted: #{pf.tone($neutral, 50)};
147
156
  --#{$prefix}color-bg-overlay: rgba(0, 0, 0, 0.7);
148
157
 
149
158
  /* Text */
150
159
  --#{$prefix}color-fg: #{pf.tone($neutral, 50)};
160
+ --#{$prefix}color-fg-secondary: #{pf.tone($neutral, 300)};
151
161
  --#{$prefix}color-fg-muted: #{pf.tone($neutral, 400)};
152
162
  --#{$prefix}color-fg-on-accent: #fff;
153
163
  --#{$prefix}color-fg-inverted: #{pf.tone($neutral, 900)};
@@ -213,6 +223,118 @@ $brand: 'blue';
213
223
  }
214
224
  }
215
225
 
226
+ // ==========================================================================
227
+ // Accent Roles (compact, OKLCH-derived)
228
+ // ==========================================================================
229
+ //
230
+ // For concepts that need their own colour identity but don't warrant a full
231
+ // 7-step scale (section, page, step, or any future accent slot).
232
+ //
233
+ // Public API per accent (component-safe):
234
+ // --tui-theme-{name}-base Primary fill (buttons, active states)
235
+ // --tui-theme-{name}-soft Tinted surface (chips, badges, subtle panels)
236
+ // --tui-theme-{name}-border Border for soft surfaces
237
+ // --tui-theme-{name}-on-base Foreground on base
238
+ // --tui-theme-{name}-on-soft Foreground on soft
239
+ //
240
+ // Components must only consume these role tokens, not the palette anchors.
241
+ //
242
+ // Primitives (swizzlable by consumers, OKLCH path only):
243
+ // --tui-palette-{name}-c OKLCH chroma (cap at ≤ 0.20)
244
+ // --tui-palette-{name}-h OKLCH hue (0–360)
245
+ //
246
+ // Two strategies for defining accents:
247
+ //
248
+ // Path A — map from existing core families (no OKLCH needed):
249
+ // .my-context {
250
+ // --tui-theme-section-base: var(--tui-theme-warning-base);
251
+ // --tui-theme-section-soft: var(--tui-theme-warning-subtle);
252
+ // --tui-theme-section-border: var(--tui-theme-warning-soft);
253
+ // --tui-theme-section-on-base: var(--tui-color-fg-on-accent);
254
+ // --tui-theme-section-on-soft: var(--tui-color-fg);
255
+ // }
256
+ //
257
+ // Path B — derive from OKLCH anchors (true custom accent):
258
+ // Uses @supports guard with Path A fallback. No silent failures.
259
+ //
260
+ // ==========================================================================
261
+
262
+ // Each accent: OKLCH anchors (c, h) + fallback core family for @supports guard
263
+ $accent-defaults: (
264
+ section: (c: 0.17, h: 55, fallback: warning), // warm orange/amber
265
+ page: (c: 0.15, h: 280, fallback: primary), // purple
266
+ step: (c: 0.14, h: 200, fallback: info), // teal-blue
267
+ ) !default;
268
+
269
+ // Emit accent role tokens with @supports progressive enhancement.
270
+ // Fallback (all browsers): maps role tokens from core family scales.
271
+ // Enhancement (oklch browsers): overrides with OKLCH-derived values.
272
+ @mixin emit-accent-roles($prefix, $accents: $accent-defaults) {
273
+ // --- Fallback: map from core families (works everywhere) ---
274
+ :where(.#{$prefix}interface) {
275
+ @each $name, $values in $accents {
276
+ $family: map.get($values, fallback);
277
+
278
+ /* Accent: #{$name} (fallback → #{$family}) */
279
+ --#{$prefix}theme-#{$name}-base: var(--#{$prefix}theme-#{$family}-base);
280
+ --#{$prefix}theme-#{$name}-soft: var(--#{$prefix}theme-#{$family}-subtle);
281
+ --#{$prefix}theme-#{$name}-border: var(--#{$prefix}theme-#{$family}-soft);
282
+ --#{$prefix}theme-#{$name}-on-base: var(--#{$prefix}color-fg-on-accent);
283
+ --#{$prefix}theme-#{$name}-on-soft: var(--#{$prefix}color-fg);
284
+ }
285
+ }
286
+
287
+ // --- Enhancement: OKLCH-derived (modern browsers) ---
288
+ @supports (color: oklch(0.5 0.1 0)) {
289
+ :where(.#{$prefix}interface) {
290
+ @each $name, $values in $accents {
291
+ $c: map.get($values, c);
292
+ $h: map.get($values, h);
293
+
294
+ /* Accent: #{$name} (OKLCH c=#{$c} h=#{$h}) */
295
+ --#{$prefix}palette-#{$name}-c: #{$c};
296
+ --#{$prefix}palette-#{$name}-h: #{$h};
297
+
298
+ --#{$prefix}theme-#{$name}-base: oklch(0.62 var(--#{$prefix}palette-#{$name}-c) var(--#{$prefix}palette-#{$name}-h));
299
+ --#{$prefix}theme-#{$name}-soft: oklch(0.92 calc(var(--#{$prefix}palette-#{$name}-c) * 0.55) var(--#{$prefix}palette-#{$name}-h));
300
+ --#{$prefix}theme-#{$name}-border: oklch(0.80 calc(var(--#{$prefix}palette-#{$name}-c) * 0.45) var(--#{$prefix}palette-#{$name}-h));
301
+ --#{$prefix}theme-#{$name}-on-base: oklch(0.98 0 0);
302
+ --#{$prefix}theme-#{$name}-on-soft: var(--#{$prefix}color-fg);
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ // Private: dark mode accent OKLCH overrides (swap L values, tighten chroma).
309
+ // Fallback path needs no dark override — core family vars already handle it.
310
+ @mixin _accent-dark-overrides($prefix, $accents: $accent-defaults) {
311
+ @supports (color: oklch(0.5 0.1 0)) {
312
+ @each $name, $_ in $accents {
313
+ --#{$prefix}theme-#{$name}-base: oklch(0.72 var(--#{$prefix}palette-#{$name}-c) var(--#{$prefix}palette-#{$name}-h));
314
+ --#{$prefix}theme-#{$name}-soft: oklch(0.30 calc(var(--#{$prefix}palette-#{$name}-c) * 0.35) var(--#{$prefix}palette-#{$name}-h));
315
+ --#{$prefix}theme-#{$name}-border: oklch(0.38 calc(var(--#{$prefix}palette-#{$name}-c) * 0.30) var(--#{$prefix}palette-#{$name}-h));
316
+ --#{$prefix}theme-#{$name}-on-base: oklch(0.18 0 0);
317
+ --#{$prefix}theme-#{$name}-on-soft: var(--#{$prefix}color-fg);
318
+ }
319
+ }
320
+ }
321
+
322
+ // Public: explicit dark mode (data-theme="dark")
323
+ @mixin emit-accent-roles-dark($prefix, $accents: $accent-defaults) {
324
+ :where(.#{$prefix}interface)[data-theme="dark"] {
325
+ @include _accent-dark-overrides($prefix, $accents);
326
+ }
327
+ }
328
+
329
+ // Public: auto mode - respects system preference (data-theme="auto")
330
+ @mixin emit-accent-roles-auto($prefix, $accents: $accent-defaults) {
331
+ @media (prefers-color-scheme: dark) {
332
+ :where(.#{$prefix}interface)[data-theme="auto"] {
333
+ @include _accent-dark-overrides($prefix, $accents);
334
+ }
335
+ }
336
+ }
337
+
216
338
  @mixin emit-spacing-primitives($prefix, $steps: $spacing-steps) {
217
339
  @each $n in $steps {
218
340
  --#{$prefix}palette-spacing-#{$n}: calc(var(--#{$prefix}spacing-base) * #{$n});
@@ -1,4 +1,5 @@
1
1
  @forward "constants";
2
2
  @forward "palettes";
3
3
  @forward "tokens";
4
- @forward "motion";
4
+ @forward "motion";
5
+ @forward "control";
@@ -343,6 +343,56 @@
343
343
  border-right-style: solid !important;
344
344
  }
345
345
 
346
+ // ---------------------------
347
+ // Input reset — strip browser-specific pseudo-elements
348
+ // ---------------------------
349
+ // Opt-in: apply when you're replacing native chrome with your own UI.
350
+ // Works on the input directly or on a wrapper (e.g. tui-input-group).
351
+ .#{sys.$prefix}input-reset {
352
+ // Search: cancel button, results decorations
353
+ &::-webkit-search-decoration,
354
+ &::-webkit-search-cancel-button,
355
+ &::-webkit-search-results-button,
356
+ &::-webkit-search-results-decoration,
357
+ input::-webkit-search-decoration,
358
+ input::-webkit-search-cancel-button,
359
+ input::-webkit-search-results-button,
360
+ input::-webkit-search-results-decoration {
361
+ display: none !important;
362
+ -webkit-appearance: none !important;
363
+ }
364
+
365
+ // Number: spinner buttons
366
+ &::-webkit-inner-spin-button,
367
+ &::-webkit-outer-spin-button,
368
+ input::-webkit-inner-spin-button,
369
+ input::-webkit-outer-spin-button {
370
+ -webkit-appearance: none !important;
371
+ margin: 0 !important;
372
+ }
373
+ &[type="number"],
374
+ input[type="number"] {
375
+ -moz-appearance: textfield !important;
376
+ }
377
+
378
+ // Date/time: picker indicator
379
+ &::-webkit-calendar-picker-indicator,
380
+ input::-webkit-calendar-picker-indicator {
381
+ display: none !important;
382
+ -webkit-appearance: none !important;
383
+ }
384
+
385
+ // Color: swatch
386
+ &::-webkit-color-swatch-wrapper,
387
+ input::-webkit-color-swatch-wrapper {
388
+ padding: 0 !important;
389
+ }
390
+ &::-webkit-color-swatch,
391
+ input::-webkit-color-swatch {
392
+ border: none !important;
393
+ }
394
+ }
395
+
346
396
  // ---------------------------
347
397
  // Border color utilities (semantic-only)
348
398
  // ---------------------------