@threadlabs/looma 0.37.6 → 0.38.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 (45) hide show
  1. package/components/ui-button/ui-button.html +20 -5
  2. package/components/ui-combobox/ui-combobox.html +24 -3
  3. package/components/ui-combobox/ui-combobox.js +18 -3
  4. package/components/ui-icon-button/ui-icon-button.html +17 -8
  5. package/components/ui-menu-item/ui-menu-item.html +6 -1
  6. package/components/ui-select/ui-select.html +12 -0
  7. package/dist/index.js +1 -1
  8. package/docs/README.md +23 -10
  9. package/docs/catalog.json +78 -31
  10. package/docs/customizer-render.mjs +36 -20
  11. package/docs/customizer.js +76 -25
  12. package/docs/documentation.css +2 -0
  13. package/docs/palette.mjs +3 -3
  14. package/docs/site.mjs +1 -1
  15. package/docs/theme-session.mjs +1 -0
  16. package/docs/theme.mjs +11 -10
  17. package/package.json +2 -2
  18. package/styles/ui-button.css +19 -9
  19. package/styles/ui-combobox.css +40 -2
  20. package/styles/ui-icon-button.css +12 -2
  21. package/styles/ui-menu-item.css +6 -1
  22. package/styles/ui-select.css +9 -0
  23. package/theme-system.css +7 -2
  24. package/vanilla/UiButton.js +1 -1
  25. package/vanilla/UiCombobox.d.ts +1 -0
  26. package/vanilla/UiCombobox.js +38 -37
  27. package/vanilla/UiIconButton.d.ts +1 -1
  28. package/vanilla/UiIconButton.js +1 -1
  29. package/vanilla/UiSelect.d.ts +1 -0
  30. package/vanilla/UiSelect.js +7 -7
  31. package/vue/UiButton.vue +30 -12
  32. package/vue/UiCombobox.d.ts +6 -0
  33. package/vue/UiCombobox.vue +70 -6
  34. package/vue/UiIconButton.d.ts +2 -2
  35. package/vue/UiIconButton.vue +23 -18
  36. package/vue/UiMenuItem.vue +6 -1
  37. package/vue/UiSelect.d.ts +6 -0
  38. package/vue/UiSelect.vue +30 -1
  39. package/vue/chunks/UiButton.js +4 -4
  40. package/vue/chunks/UiCombobox.js +72 -46
  41. package/vue/chunks/UiIconButton.js +6 -7
  42. package/vue/chunks/UiMenuItem.js +1 -1
  43. package/vue/chunks/UiSelect.js +27 -2
  44. package/vue/components.css +126 -25
  45. package/vue/editor/index.js +2 -3
@@ -7,7 +7,7 @@ const T0 = ["",[],4];
7
7
  const T1 = ["",[]];
8
8
  let P0, P1;
9
9
  const S = { n: [], t: [], f: import.meta.url, g: "ui-select", a: (host, I) => C(host, I), b: generatedInputs };
10
- const D = { g: "ui-select", props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "invalid": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "required": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "value": { "required":false, c: checkString, t: "string", j: 0, m: "s" } } };
10
+ const D = { g: "ui-select", props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "invalid": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "muted": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "required": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "value": { "required":false, c: checkString, t: "string", j: 0, m: "s" } } };
11
11
  const C = (host) => activateModule(controller, host);
12
12
 
13
13
  export function createUiSelect(options = {}, html) {
@@ -19,7 +19,7 @@ export function createUiSelect(options = {}, html) {
19
19
  }
20
20
  element.setAttribute("data-component", "ui-select");
21
21
  element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
22
- const v = [null, null, null, null, null];
22
+ const v = [null, null, null, null, null, null];
23
23
  const B = acceptProps(element, D, S.n, v, componentProps, [], html);
24
24
  const m1 = (d) => {
25
25
  const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
@@ -35,8 +35,8 @@ export function createUiSelect(options = {}, html) {
35
35
  const s0 = toAttribute(x0, "disabled");
36
36
  if (s0 !== r.v0) writeAttribute(r.n, "disabled", r.v0 = s0);
37
37
  }
38
- if (c & 4) {
39
- const x1 = v[2];
38
+ if (c & 8) {
39
+ const x1 = v[3];
40
40
  const s1 = toAttribute(x1, "required");
41
41
  if (s1 !== r.v1) writeAttribute(r.n, "required", r.v1 = s1);
42
42
  }
@@ -45,8 +45,8 @@ export function createUiSelect(options = {}, html) {
45
45
  const s2 = toAttribute(x2, "aria-invalid");
46
46
  if (s2 !== r.v2) writeAttribute(r.n, "aria-invalid", r.v2 = s2);
47
47
  }
48
- if (c & 8) {
49
- const x3 = hostState(["size"], [v[3]]);
48
+ if (c & 20) {
49
+ const x3 = hostState(["muted","size"], [v[2], v[4]]);
50
50
  const s3 = x3;
51
51
  if (s3 !== r.v3) writeAttribute(r.n, "data-ui-select-state", (r.v3 = s3) === "" ? null : s3);
52
52
  }
@@ -62,4 +62,4 @@ export function createUiSelect(options = {}, html) {
62
62
  manageProps(I);
63
63
  return element;
64
64
  }
65
- defineComponent("ui-select", createUiSelect, ["disabled","invalid","required","size","value"]);
65
+ defineComponent("ui-select", createUiSelect, ["disabled","invalid","muted","required","size","value"]);
package/vue/UiButton.vue CHANGED
@@ -145,7 +145,7 @@ const propValidityContract = {
145
145
  description:
146
146
  'Which colour the button speaks in. It applies to every variant, so an outline, a ghost, and a solid in the same tone are the same action at three volumes:\n tone="danger" variant="outline" is a destructive secondary action. neutral is the quiet one, for a button that should not claim a colour. The field\n variant always uses neutral field colors.',
147
147
  values: ['accent', 'neutral', 'danger', 'success', 'warning', 'info'],
148
- default: 'accent',
148
+ default: 'neutral',
149
149
  },
150
150
  type: {
151
151
  type: { kind: 'terminal', name: 'keyword' },
@@ -212,7 +212,7 @@ const acceptedProps: Record<string, unknown> = {
212
212
  square: false,
213
213
  stretch: false,
214
214
  target: null,
215
- tone: 'accent',
215
+ tone: 'neutral',
216
216
  type: 'button',
217
217
  variant: 'outline',
218
218
  }
@@ -227,7 +227,7 @@ const inputTracking = vuePropInputs(acceptedProps, {
227
227
  size: 'md',
228
228
  square: false,
229
229
  stretch: false,
230
- tone: 'accent',
230
+ tone: 'neutral',
231
231
  type: 'button',
232
232
  variant: 'outline',
233
233
  }, (name, value, source, values) => {
@@ -1039,8 +1039,6 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1039
1039
  /* A link is never :enabled, so interactive states test "not unavailable" instead: for a button that
1040
1040
  is exactly :enabled, at the same specificity, and it also matches a link that can be followed. */
1041
1041
 
1042
- /* A neutral card encloses content quietly; ordinary outlines keep their action-tone edge. */
1043
-
1044
1042
  /* Pressed reads as pressed in: the highlight goes, and the shadow moves inside. */
1045
1043
 
1046
1044
  /* Tone is the colour, variant is the volume. Every pairing works: a danger outline is a
@@ -1050,9 +1048,6 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1050
1048
 
1051
1049
  /* Tints derive from the text colour, not a surface token, so hover and press show on any background. */
1052
1050
 
1053
- /* Pressed, or holding its menu open, a ghost button sinks slightly: a light surface with a faint
1054
- edge and a soft inner shadow. Lighter than hover, so an open menu's trigger never reads as heavy. */
1055
-
1056
1051
  /* A soft halo that transitions in with the other box-shadow changes, layered on the raised shadow. */
1057
1052
 
1058
1053
  /* A loading action stays visually active; only an explicitly disabled action takes the
@@ -1257,6 +1252,7 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1257
1252
  border-color: var(--ui-button-hover-border, var(--_tone-hover));
1258
1253
  background-color: var(--ui-button-hover-surface, oklch(from var(--_tone) l c h / 12%));
1259
1254
  }
1255
+
1260
1256
  :global(:scope[data-appearance="card"][data-tone="neutral"]:where([data-hn-ui-button])) {
1261
1257
  border-color: var(--ui-button-border, var(--ui-border));
1262
1258
  }
@@ -1264,6 +1260,12 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1264
1260
  :global(:scope[data-appearance="card"][data-tone="neutral"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1265
1261
  border-color: var(--ui-button-hover-border, var(--ui-border-strong));
1266
1262
  }
1263
+
1264
+ :global(:scope[data-appearance="card"][aria-pressed="true"]:where([data-hn-ui-button])) {
1265
+ background-color: var(--ui-selection-surface);
1266
+ border-color: var(--ui-selection-border);
1267
+ color: var(--ui-selection-text);
1268
+ }
1267
1269
  :global(:scope:active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1268
1270
  scale: var(--ui-press-scale, 1);
1269
1271
  background-color: var(--ui-button-active-surface, oklch(from var(--_tone) l c h / 18%));
@@ -1308,6 +1310,24 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1308
1310
  background-color: var(--ui-button-surface, var(--ui-neutral-surface));
1309
1311
  color: var(--ui-button-text, var(--ui-text));
1310
1312
  }
1313
+ :global(:scope[data-tone="neutral"][data-appearance="outline"]:where([data-hn-ui-button])) {
1314
+ border-color: var(--ui-button-border, var(--ui-control-border));
1315
+ background-color: var(--ui-button-surface, transparent);
1316
+ }
1317
+ :global(:scope[data-tone="neutral"][data-appearance="outline"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1318
+ border-color: var(
1319
+ --ui-button-hover-border,
1320
+ var(--ui-control-border-hover, var(--ui-control-border))
1321
+ );
1322
+ background-color: var(--ui-button-hover-surface, var(--ui-neutral-hover));
1323
+ }
1324
+ :global(:scope[data-tone="neutral"][data-appearance="outline"]:active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1325
+ border-color: var(
1326
+ --ui-button-hover-border,
1327
+ var(--ui-control-border-hover, var(--ui-control-border))
1328
+ );
1329
+ background-color: var(--ui-button-active-surface, var(--ui-neutral-active));
1330
+ }
1311
1331
  :global(:scope[data-tone="neutral"][data-appearance="solid"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1312
1332
  background-color: var(--ui-button-hover-surface, var(--ui-neutral-hover));
1313
1333
  }
@@ -1400,11 +1420,9 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1400
1420
  background-color: var(--ui-button-ghost-hover-surface, oklch(from var(--_tone) l c h / 10%));
1401
1421
  border-color: transparent;
1402
1422
  }
1423
+
1403
1424
  :global(:scope[data-appearance="ghost"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1404
- background-color: var(
1405
- --ui-button-ghost-active-surface,
1406
- color-mix(in oklch, var(--ui-surface), var(--_tone) 3%)
1407
- );
1425
+ background-color: var(--ui-button-ghost-active-surface, oklch(from var(--_tone) l c h / 18%));
1408
1426
  border-color: transparent;
1409
1427
  box-shadow:
1410
1428
  inset 0 0 0 1px oklch(from var(--_tone) l c h / 10%),
@@ -95,6 +95,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
95
95
  multiple: {
96
96
  type: PropType<boolean | null>;
97
97
  };
98
+ muted: {
99
+ type: PropType<boolean | null>;
100
+ };
98
101
  name: {
99
102
  type: PropType<string | null>;
100
103
  };
@@ -334,6 +337,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
334
337
  multiple: {
335
338
  type: PropType<boolean | null>;
336
339
  };
340
+ muted: {
341
+ type: PropType<boolean | null>;
342
+ };
337
343
  name: {
338
344
  type: PropType<string | null>;
339
345
  };
@@ -192,6 +192,14 @@ const propValidityContract = {
192
192
  'Lets the user choose several options. Each choice becomes a removable badge before the input, the list stays open between picks, and choosing a checked\n option removes it. items-change then reports the whole list of items, and selected-values-change the list of their values; use selectedValues or items,\n not value, in this mode.',
193
193
  default: false,
194
194
  },
195
+ muted: {
196
+ type: { kind: 'terminal', name: 'boolean' },
197
+ required: false,
198
+ target: { attribute: 'muted' },
199
+ description:
200
+ 'Shows the selected field value with supporting-text emphasis, for an inherited or default choice. Suggestions keep normal emphasis and the field stays interactive.',
201
+ default: false,
202
+ },
195
203
  name: {
196
204
  type: { kind: 'terminal', name: 'string' },
197
205
  required: false,
@@ -204,7 +212,8 @@ const propValidityContract = {
204
212
  type: { kind: 'terminal', name: 'boolean' },
205
213
  required: false,
206
214
  target: { attribute: 'openonfocus' },
207
- description: 'Opens suggestions when the input receives focus, before typing.',
215
+ description:
216
+ 'Opens suggestions when the input receives focus or is clicked. A committed selection shows all choices until typing filters them; an explicitly supplied query keeps its filtering.',
208
217
  default: false,
209
218
  },
210
219
  placeholder: {
@@ -310,6 +319,7 @@ const props = defineProps({
310
319
  labelVisibility: { type: null as unknown as PropType<'visible' | 'sr-only' | null> },
311
320
  loading: { type: null as unknown as PropType<boolean | null> },
312
321
  multiple: { type: null as unknown as PropType<boolean | null> },
322
+ muted: { type: null as unknown as PropType<boolean | null> },
313
323
  name: { type: null as unknown as PropType<string | null> },
314
324
  openOnFocus: { type: null as unknown as PropType<boolean | null> },
315
325
  placeholder: { type: null as unknown as PropType<string | null> },
@@ -339,6 +349,7 @@ const acceptedProps: Record<string, unknown> = {
339
349
  labelVisibility: 'visible',
340
350
  loading: false,
341
351
  multiple: false,
352
+ muted: false,
342
353
  name: '',
343
354
  openOnFocus: false,
344
355
  placeholder: '',
@@ -366,6 +377,7 @@ const inputTracking = vuePropInputs(acceptedProps, {
366
377
  labelVisibility: 'visible',
367
378
  loading: false,
368
379
  multiple: false,
380
+ muted: false,
369
381
  name: '',
370
382
  openOnFocus: false,
371
383
  placeholder: '',
@@ -445,6 +457,8 @@ const inputTracking = vuePropInputs(acceptedProps, {
445
457
  return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
446
458
  case 'multiple':
447
459
  return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
460
+ case 'muted':
461
+ return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
448
462
  case 'name':
449
463
  return checkPropInput(value, { kind: 'terminal', name: 'string' }, true, true)
450
464
  case 'openOnFocus':
@@ -572,6 +586,11 @@ const checkedProps = computed(() => {
572
586
  props['multiple'],
573
587
  props[BINDING_INPUTS_PROP],
574
588
  ) as boolean,
589
+ muted: propInputs.value<boolean | null>(
590
+ 'muted',
591
+ props['muted'],
592
+ props[BINDING_INPUTS_PROP],
593
+ ) as boolean,
575
594
  name: propInputs.value<string | null>(
576
595
  'name',
577
596
  props['name'],
@@ -1085,6 +1104,7 @@ const hostState = computed(() =>
1085
1104
  [
1086
1105
  checkedProps.value.size && 'size',
1087
1106
  checkedProps.value.size != null && `size=${encodeURIComponent(checkedProps.value.size)}`,
1107
+ checkedProps.value.muted && 'muted',
1088
1108
  validationStatus.value && 'validationStatus',
1089
1109
  `validationStatus=${encodeURIComponent(validationStatus.value)}`,
1090
1110
  checkedProps.value.invalid && 'invalid',
@@ -1711,6 +1731,7 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
1711
1731
  'labelVisibility',
1712
1732
  'loading',
1713
1733
  'multiple',
1734
+ 'muted',
1714
1735
  'name',
1715
1736
  'openOnFocus',
1716
1737
  'placeholder',
@@ -1783,6 +1804,7 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
1783
1804
  :data-ui-combobox-prop-label-visibility="reflectedProp('labelVisibility', 'label-visibility', checkedProps.labelVisibility, undefined, false)"
1784
1805
  :data-ui-combobox-prop-loading="reflectedProp('loading', 'loading', checkedProps.loading, undefined, false)"
1785
1806
  :data-ui-combobox-prop-multiple="reflectedProp('multiple', 'multiple', checkedProps.multiple, undefined, false)"
1807
+ :data-ui-combobox-prop-muted="reflectedProp('muted', 'muted', checkedProps.muted, undefined, false)"
1786
1808
  :data-ui-combobox-prop-name="reflectedProp('name', 'name', checkedProps.name, undefined, false)"
1787
1809
  :data-ui-combobox-prop-open-on-focus="reflectedProp('openOnFocus', 'open-on-focus', checkedProps.openOnFocus, undefined, false)"
1788
1810
  :data-ui-combobox-prop-placeholder="reflectedProp('placeholder', 'placeholder', checkedProps.placeholder, undefined, false)"
@@ -1806,9 +1828,9 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
1806
1828
  <div class="control" data-hn-ui-combobox>
1807
1829
  <div class="field" data-hn-ui-combobox ref="fieldElement">
1808
1830
  <div class="entry" data-hn-ui-combobox>
1809
- <slot name="start" />{{ ' ' }}<template v-if="checkedProps.multiple">{{
1810
- ' '
1811
- }}<KeyedBoundary><button
1831
+ <span class="start" data-hn-ui-combobox><slot name="start" /></span>{{ ' ' }}<template
1832
+ v-if="checkedProps.multiple"
1833
+ >{{ ' ' }}<KeyedBoundary><button
1812
1834
  v-for="(item, index) in uniqueKeys(internalItems, (item, index, loop) => item.id)"
1813
1835
  :key="item.id"
1814
1836
  class="item"
@@ -2190,6 +2212,21 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2190
2212
  flex: 1 1 auto;
2191
2213
  min-inline-size: 0;
2192
2214
  }
2215
+ :global(.start:where([data-hn-ui-combobox])) {
2216
+ display: flex !important;
2217
+ align-items: center !important;
2218
+ flex: none;
2219
+ padding-inline-start: var(--ui-space-3) !important;
2220
+ }
2221
+ :global(.start:empty:where([data-hn-ui-combobox])) {
2222
+ display: none !important;
2223
+ }
2224
+ :global(:scope[data-ui-combobox-state~="size=sm"] .start:where([data-hn-ui-combobox])) {
2225
+ padding-inline-start: var(--ui-space-2) !important;
2226
+ }
2227
+ :global(:scope[data-ui-combobox-state~="size=lg"] .start:where([data-hn-ui-combobox])) {
2228
+ padding-inline-start: var(--ui-space-4) !important;
2229
+ }
2193
2230
  :global(.help:where([data-hn-ui-combobox])) {
2194
2231
  flex: none;
2195
2232
  display: inline-flex !important;
@@ -2229,6 +2266,11 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2229
2266
  block-size: var(--ui-icon-size-sm);
2230
2267
  }
2231
2268
 
2269
+ :global(:scope[data-ui-combobox-state~="muted"]
2270
+ input:not(:disabled):where([data-hn-ui-combobox])) {
2271
+ color: var(--ui-text-secondary);
2272
+ }
2273
+
2232
2274
  :global(input:where([data-hn-ui-combobox])::selection) {
2233
2275
  background: color-mix(in srgb, var(--ui-accent-solid) 20%, transparent);
2234
2276
  color: inherit;
@@ -2322,7 +2364,7 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2322
2364
  border-radius: var(--_ui-combobox-popup-radius, var(--ui-overlay-radius, var(--ui-radius-md)));
2323
2365
  background: var(
2324
2366
  --_ui-combobox-popup-surface,
2325
- var(--ui-overlay-surface, var(--ui-surface-elevated))
2367
+ var(--ui-material-content, var(--ui-surface-elevated))
2326
2368
  );
2327
2369
  color: var(--ui-text-primary);
2328
2370
  box-shadow: var(
@@ -2522,6 +2564,23 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2522
2564
  flex: 1 1 auto;
2523
2565
  min-inline-size: 0;
2524
2566
  }
2567
+ :global(.start:where(:scope, :scope *):where([data-hn-ui-combobox])) {
2568
+ display: flex !important;
2569
+ align-items: center !important;
2570
+ flex: none;
2571
+ padding-inline-start: var(--ui-space-3) !important;
2572
+ }
2573
+ :global(.start:empty:where(:scope, :scope *):where([data-hn-ui-combobox])) {
2574
+ display: none !important;
2575
+ }
2576
+ :global(:where(.ui-combobox)[data-ui-combobox-state~="size=sm"]
2577
+ .start:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-combobox"]))):where([data-hn-ui-combobox])) {
2578
+ padding-inline-start: var(--ui-space-2) !important;
2579
+ }
2580
+ :global(:where(.ui-combobox)[data-ui-combobox-state~="size=lg"]
2581
+ .start:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-combobox"]))):where([data-hn-ui-combobox])) {
2582
+ padding-inline-start: var(--ui-space-4) !important;
2583
+ }
2525
2584
  :global(.help:where(:scope, :scope *):where([data-hn-ui-combobox])) {
2526
2585
  flex: none;
2527
2586
  display: inline-flex !important;
@@ -2561,6 +2620,11 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2561
2620
  block-size: var(--ui-icon-size-sm);
2562
2621
  }
2563
2622
 
2623
+ :global(:where(.ui-combobox)[data-ui-combobox-state~="muted"]
2624
+ input:not(:disabled):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-combobox"]))):where([data-hn-ui-combobox])) {
2625
+ color: var(--ui-text-secondary);
2626
+ }
2627
+
2564
2628
  :global(input:where(:not([data-hn], [data-slotted]:not([data-slotted~="ui-combobox"]))):where(:scope, :scope
2565
2629
  *):where([data-hn-ui-combobox])::selection) {
2566
2630
  background: color-mix(in srgb, var(--ui-accent-solid) 20%, transparent);
@@ -2658,7 +2722,7 @@ useComponentHost(() => import('../components/ui-combobox/ui-combobox.js'), {
2658
2722
  border-radius: var(--_ui-combobox-popup-radius, var(--ui-overlay-radius, var(--ui-radius-md)));
2659
2723
  background: var(
2660
2724
  --_ui-combobox-popup-surface,
2661
- var(--ui-overlay-surface, var(--ui-surface-elevated))
2725
+ var(--ui-material-content, var(--ui-surface-elevated))
2662
2726
  );
2663
2727
  color: var(--ui-text-primary);
2664
2728
  box-shadow: var(
@@ -39,7 +39,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
39
39
  type: PropType<"sm" | "md" | "lg" | null>;
40
40
  };
41
41
  tone: {
42
- type: PropType<"auto" | "accent" | "neutral" | "danger" | "success" | "warning" | "info" | null>;
42
+ type: PropType<"accent" | "neutral" | "danger" | "success" | "warning" | "info" | null>;
43
43
  };
44
44
  variant: {
45
45
  type: PropType<"ghost" | "outline" | "solid" | null>;
@@ -82,7 +82,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
82
82
  type: PropType<"sm" | "md" | "lg" | null>;
83
83
  };
84
84
  tone: {
85
- type: PropType<"auto" | "accent" | "neutral" | "danger" | "success" | "warning" | "info" | null>;
85
+ type: PropType<"accent" | "neutral" | "danger" | "success" | "warning" | "info" | null>;
86
86
  };
87
87
  variant: {
88
88
  type: PropType<"ghost" | "outline" | "solid" | null>;
@@ -125,16 +125,16 @@ const propValidityContract = {
125
125
  required: false,
126
126
  target: { attribute: 'tone' },
127
127
  description:
128
- 'Colour for every variant. auto preserves the existing variant-specific default. When omitted, ghost and outline keep their neutral appearance and solid\n keeps its accent fill. Set accent for a coloured action or neutral for a quiet one. danger, success, warning and info share Button\'s intent colors. Native\n aria-pressed="true" keeps an outline toggle visibly pressed; the consumer owns that state.',
129
- values: ['auto', 'accent', 'neutral', 'danger', 'success', 'warning', 'info'],
130
- default: 'auto',
128
+ 'Colour for every variant. The default neutral shares the quiet control family with fields and text buttons. Choose accent explicitly for a coloured action,\n or primary for solid accent. danger, success, warning and info share Button\'s intent colors. Native aria-pressed="true" keeps an outline toggle visibly\n pressed; the consumer owns that state.',
129
+ values: ['accent', 'neutral', 'danger', 'success', 'warning', 'info'],
130
+ default: 'neutral',
131
131
  },
132
132
  variant: {
133
133
  type: { kind: 'terminal', name: 'keyword' },
134
134
  required: false,
135
135
  target: { attribute: 'variant' },
136
136
  description:
137
- 'Emphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with the\n accent colour, for the one primary action in a group.',
137
+ 'Emphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with its\n chosen tone.',
138
138
  values: ['ghost', 'outline', 'solid'],
139
139
  default: 'ghost',
140
140
  },
@@ -158,7 +158,7 @@ const props = defineProps({
158
158
  size: { type: null as unknown as PropType<'sm' | 'md' | 'lg' | null> },
159
159
  tone: {
160
160
  type: null as unknown as PropType<
161
- 'auto' | 'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' | null
161
+ 'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' | null
162
162
  >,
163
163
  },
164
164
  variant: { type: null as unknown as PropType<'ghost' | 'outline' | 'solid' | null> },
@@ -176,7 +176,7 @@ const acceptedProps: Record<string, unknown> = {
176
176
  revealed: false,
177
177
  round: false,
178
178
  size: 'md',
179
- tone: 'auto',
179
+ tone: 'neutral',
180
180
  variant: 'ghost',
181
181
  }
182
182
  const inputTracking = vuePropInputs(acceptedProps, {
@@ -190,7 +190,7 @@ const inputTracking = vuePropInputs(acceptedProps, {
190
190
  revealed: false,
191
191
  round: false,
192
192
  size: 'md',
193
- tone: 'auto',
193
+ tone: 'neutral',
194
194
  variant: 'ghost',
195
195
  }, (name, value, source, values) => {
196
196
  switch (name) {
@@ -281,16 +281,11 @@ const checkedProps = computed(() => {
281
281
  props['size'],
282
282
  props[BINDING_INPUTS_PROP],
283
283
  ) as 'sm' | 'md' | 'lg',
284
- tone: propInputs.value<
285
- 'auto' | 'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' | null
286
- >('tone', props['tone'], props[BINDING_INPUTS_PROP]) as
287
- | 'auto'
288
- | 'accent'
289
- | 'neutral'
290
- | 'danger'
291
- | 'success'
292
- | 'warning'
293
- | 'info',
284
+ tone: propInputs.value<'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' | null>(
285
+ 'tone',
286
+ props['tone'],
287
+ props[BINDING_INPUTS_PROP],
288
+ ) as 'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info',
294
289
  variant: propInputs.value<'ghost' | 'outline' | 'solid' | null>(
295
290
  'variant',
296
291
  props['variant'],
@@ -557,7 +552,7 @@ useComponentHost(() => import('../components/ui-icon-button/ui-icon-button.js'),
557
552
  inherits: false;
558
553
  }
559
554
 
560
- /* Omitted tone retains the existing accent solid; explicit neutral is additive. */
555
+ /* Neutral actions share the same quiet surface and border roles as fields. */
561
556
 
562
557
  /* At rest an anticipatory button shows only its guide dot. The icon grows into place when
563
558
  proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
@@ -691,6 +686,10 @@ useComponentHost(() => import('../components/ui-icon-button/ui-icon-button.js'),
691
686
  :global(:scope[data-tone="neutral"]:where([data-hn-ui-icon-button])) {
692
687
  --_tone-highlight: var(--ui-neutral-highlight, none);
693
688
  --_tone-glow: var(--ui-neutral-glow, 0 0 transparent);
689
+ --_icon-button-outline-surface: transparent;
690
+ --_icon-button-border: var(--ui-control-border);
691
+ --_icon-button-hover-border: var(--ui-control-border-hover, var(--ui-control-border));
692
+ --_icon-button-text: var(--ui-text);
694
693
  --_icon-button-solid-surface: var(--ui-neutral-surface);
695
694
  --_icon-button-solid-hover-surface: var(--ui-neutral-hover);
696
695
  --_icon-button-solid-text: var(--ui-text);
@@ -891,6 +890,12 @@ useComponentHost(() => import('../components/ui-icon-button/ui-icon-button.js'),
891
890
  var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)))
892
891
  );
893
892
  }
893
+ :global(:scope[data-tone="neutral"][data-appearance="outline"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button])) {
894
+ background-color: var(--ui-icon-button-hover-surface, var(--ui-neutral-hover));
895
+ }
896
+ :global(:scope[data-tone="neutral"][data-appearance="outline"]:active:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button])) {
897
+ background-color: var(--ui-icon-button-active-surface, var(--ui-neutral-active));
898
+ }
894
899
 
895
900
  :global(:scope[data-appearance="solid"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button])) {
896
901
  background-color: var(
@@ -517,7 +517,12 @@ useComponentHost(() => import('../components/ui-menu-item/ui-menu-item.js'), {
517
517
  }
518
518
 
519
519
  :global(:scope:is(:hover, :focus-visible):not([aria-disabled="true"]):where([data-hn-ui-menu-item])) {
520
- background: var(--ui-menu-item-hover-surface, var(--ui-surface-subtle));
520
+ background: var(--ui-menu-item-hover-surface, var(--ui-accent-subtle));
521
+ }
522
+
523
+ :global(:scope[aria-checked="true"]:not([aria-disabled="true"]):where([data-hn-ui-menu-item])) {
524
+ background: var(--ui-selection-surface);
525
+ color: var(--ui-selection-text);
521
526
  }
522
527
 
523
528
  :global(:scope:focus-visible:where([data-hn-ui-menu-item])) {
package/vue/UiSelect.d.ts CHANGED
@@ -11,6 +11,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
11
11
  invalid: {
12
12
  type: PropType<boolean | null>;
13
13
  };
14
+ muted: {
15
+ type: PropType<boolean | null>;
16
+ };
14
17
  required: {
15
18
  type: PropType<boolean | null>;
16
19
  };
@@ -35,6 +38,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
35
38
  invalid: {
36
39
  type: PropType<boolean | null>;
37
40
  };
41
+ muted: {
42
+ type: PropType<boolean | null>;
43
+ };
38
44
  required: {
39
45
  type: PropType<boolean | null>;
40
46
  };
package/vue/UiSelect.vue CHANGED
@@ -41,6 +41,14 @@ const propValidityContract = {
41
41
  description: 'Exposes invalid state to assistive technology and styling.',
42
42
  default: false,
43
43
  },
44
+ muted: {
45
+ type: { kind: 'terminal', name: 'boolean' },
46
+ required: false,
47
+ target: { attribute: 'muted' },
48
+ description:
49
+ 'Shows the selected value with supporting-text emphasis, for an inherited or default choice. The select remains interactive and its options retain normal\n emphasis.',
50
+ default: false,
51
+ },
44
52
  required: {
45
53
  type: { kind: 'terminal', name: 'boolean' },
46
54
  required: false,
@@ -69,6 +77,7 @@ const propValidityContract = {
69
77
  const props = defineProps({
70
78
  disabled: { type: null as unknown as PropType<boolean | null> },
71
79
  invalid: { type: null as unknown as PropType<boolean | null> },
80
+ muted: { type: null as unknown as PropType<boolean | null> },
72
81
  required: { type: null as unknown as PropType<boolean | null> },
73
82
  size: { type: null as unknown as PropType<'sm' | 'md' | 'lg' | null> },
74
83
  value: { type: null as unknown as PropType<string | null> },
@@ -78,6 +87,7 @@ const props = defineProps({
78
87
  const acceptedProps: Record<string, unknown> = {
79
88
  disabled: false,
80
89
  invalid: false,
90
+ muted: false,
81
91
  required: false,
82
92
  size: 'md',
83
93
  value: null,
@@ -85,6 +95,7 @@ const acceptedProps: Record<string, unknown> = {
85
95
  const inputTracking = vuePropInputs(acceptedProps, {
86
96
  disabled: false,
87
97
  invalid: false,
98
+ muted: false,
88
99
  required: false,
89
100
  size: 'md',
90
101
  }, (name, value, source, values) => {
@@ -93,6 +104,8 @@ const inputTracking = vuePropInputs(acceptedProps, {
93
104
  return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
94
105
  case 'invalid':
95
106
  return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
107
+ case 'muted':
108
+ return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
96
109
  case 'required':
97
110
  return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
98
111
  case 'size':
@@ -119,6 +132,11 @@ const checkedProps = computed(() => {
119
132
  props['invalid'],
120
133
  props[BINDING_INPUTS_PROP],
121
134
  ) as boolean,
135
+ muted: propInputs.value<boolean | null>(
136
+ 'muted',
137
+ props['muted'],
138
+ props[BINDING_INPUTS_PROP],
139
+ ) as boolean,
122
140
  required: propInputs.value<boolean | null>(
123
141
  'required',
124
142
  props['required'],
@@ -164,6 +182,7 @@ checkHydratedRoot('select', 'ui-select')
164
182
  /** The values the styles' :host() and :state() rules test. */
165
183
  const hostState = computed(() =>
166
184
  [
185
+ checkedProps.value.muted && 'muted',
167
186
  checkedProps.value.size && 'size',
168
187
  checkedProps.value.size != null && `size=${encodeURIComponent(checkedProps.value.size)}`,
169
188
  ].filter(Boolean).join(' ')
@@ -189,7 +208,7 @@ useComponentHost(() => import('../components/ui-select/ui-select.js'), {
189
208
  ? (incoming[name] ?? incoming[kebab] ?? null)
190
209
  : null
191
210
  },
192
- propNames: ['disabled', 'invalid', 'required', 'size', 'value'],
211
+ propNames: ['disabled', 'invalid', 'muted', 'required', 'size', 'value'],
193
212
  propValidity: (name: string) =>
194
213
  propValidityState({ contract: propValidityContract, values: { ...props } }, name),
195
214
  })
@@ -207,6 +226,7 @@ useComponentHost(() => import('../components/ui-select/ui-select.js'), {
207
226
  v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
208
227
  :data-ui-select-prop-disabled="reflectedProp('disabled', 'disabled', checkedProps.disabled, undefined, false)"
209
228
  :data-ui-select-prop-invalid="reflectedProp('invalid', 'invalid', checkedProps.invalid, undefined, false)"
229
+ :data-ui-select-prop-muted="reflectedProp('muted', 'muted', checkedProps.muted, undefined, false)"
210
230
  :data-ui-select-prop-required="reflectedProp('required', 'required', checkedProps.required, undefined, false)"
211
231
  :data-ui-select-prop-size="reflectedProp('size', 'size', checkedProps.size, undefined, false)"
212
232
  :data-ui-select-prop-value="reflectedProp('value', 'value', checkedProps.value, undefined, false)"
@@ -319,6 +339,15 @@ useComponentHost(() => import('../components/ui-select/ui-select.js'), {
319
339
  background-size: 1.125rem 1.125rem, 100% 100%;
320
340
  }
321
341
 
342
+ :global(:scope[data-ui-select-state~="muted"]:where([data-hn-ui-select])) {
343
+ color: var(--ui-text-secondary);
344
+ }
345
+ :global(:scope[data-ui-select-state~="muted"] :where(:not([data-hn-ui-select])):is(option)),
346
+ :global(:scope[data-ui-select-state~="muted"] :where(:not([data-hn-ui-select])):is(optgroup)) {
347
+ color: var(--ui-text-primary);
348
+ background-color: var(--ui-control-surface);
349
+ }
350
+
322
351
  :global(:scope:hover:not(:focus):not(:disabled):not([aria-invalid="true"]):not(:is(:user-invalid, [data-user-invalid])):where([data-hn-ui-select])) {
323
352
  border-color: var(
324
353
  --ui-select-border-hover,
@@ -335,7 +335,7 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
335
335
  "warning",
336
336
  "info"
337
337
  ],
338
- default: "accent"
338
+ default: "neutral"
339
339
  },
340
340
  type: {
341
341
  type: {
@@ -387,7 +387,7 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
387
387
  square: false,
388
388
  stretch: false,
389
389
  target: null,
390
- tone: "accent",
390
+ tone: "neutral",
391
391
  type: "button",
392
392
  variant: "outline"
393
393
  }, {
@@ -401,7 +401,7 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
401
401
  size: "md",
402
402
  square: false,
403
403
  stretch: false,
404
- tone: "accent",
404
+ tone: "neutral",
405
405
  type: "button",
406
406
  variant: "outline"
407
407
  }, (name, value, source, values) => {
@@ -894,6 +894,6 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
894
894
  }]]);
895
895
  };
896
896
  }
897
- }), [["__scopeId", "data-v-f04ec716"]]);
897
+ }), [["__scopeId", "data-v-1eb598b9"]]);
898
898
  //#endregion
899
899
  export { UiButton_default as t };