@threadlabs/looma 0.23.15 → 0.23.16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.23.15",
3
+ "version": "0.23.16",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -215,6 +215,29 @@
215
215
  min-block-size: var(--ui-icon-button-size, var(--_size));
216
216
  }
217
217
 
218
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
219
+ :scope[data-ui-icon-button-state~="matchButton"] {
220
+ --_size: var(--ui-control-size-md);
221
+ block-size: auto;
222
+ align-self: stretch;
223
+ }
224
+
225
+ :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=sm"] {
226
+ --_size: var(--ui-control-size-sm);
227
+ }
228
+
229
+ :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=lg"] {
230
+ --_size: var(--ui-control-size-lg);
231
+ }
232
+
233
+ @media (pointer: coarse) {
234
+ :scope[data-ui-icon-button-state~="matchButton"] {
235
+ inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
236
+ min-inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
237
+ min-block-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
238
+ }
239
+ }
240
+
218
241
  :scope[data-ui-icon-button-state~="round"] {
219
242
  border-radius: var(--ui-radius-round);
220
243
  }
@@ -340,6 +363,11 @@
340
363
  @media (pointer: coarse) {
341
364
  }
342
365
 
366
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
367
+
368
+ @media (pointer: coarse) {
369
+ }
370
+
343
371
  @media (prefers-reduced-motion: reduce) {
344
372
  }
345
373
 
@@ -10,6 +10,7 @@ export interface UiIconButtonProps {
10
10
  disabled?: boolean | null;
11
11
  label?: string | null;
12
12
  loading?: boolean | null;
13
+ matchButton?: boolean | null;
13
14
  pending?: boolean | null;
14
15
  round?: boolean | null;
15
16
  size?: "sm" | "md" | "lg" | null;
@@ -3,7 +3,7 @@ import { manageComponentLifecycle } from "@nextwebwg/html-next/runtime";
3
3
  import * as controller from "../components/ui-icon-button/ui-icon-button.js";
4
4
  import "../styles/ui-icon-button.css";
5
5
 
6
- const definition = {...{"contract":{"tag":"ui-icon-button","props":{"anticipatory":{"type":"boolean","required":false,"target":{"attribute":"anticipatory"},"default":false},"disabled":{"type":"boolean","required":false,"target":{"attribute":"disabled"},"default":false},"label":{"type":"string","required":false,"target":{"attribute":"aria-label"}},"loading":{"type":"boolean","required":false,"target":{"attribute":"loading"},"default":false},"pending":{"type":"boolean","required":false,"target":{"attribute":"pending"},"default":false},"round":{"type":"boolean","required":false,"target":{"attribute":"round"},"default":false},"size":{"type":{"kind":"terminal","name":"keyword"},"values":["sm","md","lg"],"required":false,"target":{"attribute":"size"},"default":"md"},"variant":{"type":{"kind":"terminal","name":"keyword"},"values":["ghost","outline","solid"],"required":false,"target":{"attribute":"variant"},"default":"ghost"}}},"template":{"kind":"element","name":"button","attributes":[{"kind":"attribute","name":"disabled","expression":"disabled","expressionPlan":{"source":"disabled","ast":{"kind":"id","name":"disabled"},"dependencies":["disabled"]}},{"kind":"literal","name":"type","value":"button"},{"kind":"attribute","name":"aria-label","expression":"label","expressionPlan":{"source":"label","ast":{"kind":"id","name":"label"},"dependencies":["label"]}},{"kind":"attribute","name":"aria-disabled","expression":"{ true: 'true', false: null }[format('%s', loading or pending)]","expressionPlan":{"source":"{ true: 'true', false: null }[format('%s', loading or pending)]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"literal","value":"true"}},{"key":"false","value":{"kind":"literal","value":null}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}}]}},"dependencies":["loading","pending"]}},{"kind":"attribute","name":"aria-busy","expression":"loading or pending","expressionPlan":{"source":"loading or pending","ast":{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}},"dependencies":["loading","pending"]}}],"children":[{"kind":"element","name":"ui-spinner","attributes":[{"kind":"literal","name":"size","value":"sm"}],"children":[],"flow":{"kind":"if","test":"loading or pending","testPlan":{"source":"loading or pending","ast":{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}},"dependencies":["loading","pending"]}}},{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"class","value":"content"}],"children":[{"kind":"slot"}]}]},"declarations":[],"root":{"kind":"native","element":"button","choices":["button"]}},source:{file:import.meta.url},css:""};
6
+ const definition = {...{"contract":{"tag":"ui-icon-button","props":{"anticipatory":{"type":"boolean","required":false,"target":{"attribute":"anticipatory"},"default":false},"disabled":{"type":"boolean","required":false,"target":{"attribute":"disabled"},"default":false},"label":{"type":"string","required":false,"target":{"attribute":"aria-label"}},"loading":{"type":"boolean","required":false,"target":{"attribute":"loading"},"default":false},"matchButton":{"type":"boolean","required":false,"target":{"attribute":"data-match-button"},"default":false},"pending":{"type":"boolean","required":false,"target":{"attribute":"pending"},"default":false},"round":{"type":"boolean","required":false,"target":{"attribute":"round"},"default":false},"size":{"type":{"kind":"terminal","name":"keyword"},"values":["sm","md","lg"],"required":false,"target":{"attribute":"size"},"default":"md"},"variant":{"type":{"kind":"terminal","name":"keyword"},"values":["ghost","outline","solid"],"required":false,"target":{"attribute":"variant"},"default":"ghost"}}},"template":{"kind":"element","name":"button","attributes":[{"kind":"attribute","name":"disabled","expression":"disabled","expressionPlan":{"source":"disabled","ast":{"kind":"id","name":"disabled"},"dependencies":["disabled"]}},{"kind":"literal","name":"type","value":"button"},{"kind":"attribute","name":"aria-label","expression":"label","expressionPlan":{"source":"label","ast":{"kind":"id","name":"label"},"dependencies":["label"]}},{"kind":"attribute","name":"data-match-button","expression":"matchButton","expressionPlan":{"source":"matchButton","ast":{"kind":"id","name":"matchButton"},"dependencies":["matchButton"]}},{"kind":"attribute","name":"aria-disabled","expression":"{ true: 'true', false: null }[format('%s', loading or pending)]","expressionPlan":{"source":"{ true: 'true', false: null }[format('%s', loading or pending)]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"literal","value":"true"}},{"key":"false","value":{"kind":"literal","value":null}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}}]}},"dependencies":["loading","pending"]}},{"kind":"attribute","name":"aria-busy","expression":"loading or pending","expressionPlan":{"source":"loading or pending","ast":{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}},"dependencies":["loading","pending"]}}],"children":[{"kind":"element","name":"ui-spinner","attributes":[{"kind":"literal","name":"size","value":"sm"}],"children":[],"flow":{"kind":"if","test":"loading or pending","testPlan":{"source":"loading or pending","ast":{"kind":"binary","op":"or","left":{"kind":"id","name":"loading"},"right":{"kind":"id","name":"pending"}},"dependencies":["loading","pending"]}}},{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"class","value":"content"}],"children":[{"kind":"slot"}]}]},"declarations":[],"root":{"kind":"native","element":"button","choices":["button"]}},source:{file:import.meta.url},css:""};
7
7
 
8
8
  export function createUiIconButton(options = {}) {
9
9
  const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
@@ -20,6 +20,9 @@ export function createUiIconButton(options = {}) {
20
20
  const value1 = componentProps["label"] === undefined ? null : componentProps["label"];
21
21
  if (value1 === null || value1 === undefined) element.removeAttribute("aria-label");
22
22
  else element.setAttribute("aria-label", String(value1));
23
+ const value2 = componentProps["matchButton"] === undefined ? false : componentProps["matchButton"];
24
+ if (value2 === true) element.setAttribute("data-match-button", "");
25
+ else element.removeAttribute("data-match-button");
23
26
  element.setAttribute("data-component", "ui-icon-button");
24
27
  const element0 = document.createElement("ui-spinner");
25
28
  element0.setAttribute("size", "sm");
@@ -20,6 +20,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
20
20
  type: PropType<boolean | null>;
21
21
  default: boolean;
22
22
  };
23
+ matchButton: {
24
+ type: PropType<boolean | null>;
25
+ default: boolean;
26
+ };
23
27
  pending: {
24
28
  type: PropType<boolean | null>;
25
29
  default: boolean;
@@ -53,6 +57,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
53
57
  type: PropType<boolean | null>;
54
58
  default: boolean;
55
59
  };
60
+ matchButton: {
61
+ type: PropType<boolean | null>;
62
+ default: boolean;
63
+ };
56
64
  pending: {
57
65
  type: PropType<boolean | null>;
58
66
  default: boolean;
@@ -78,6 +86,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
78
86
  loading: boolean | null;
79
87
  pending: boolean | null;
80
88
  anticipatory: boolean | null;
89
+ matchButton: boolean | null;
81
90
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
82
91
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
83
92
  declare const _default: typeof __VLS_export;
@@ -40,6 +40,14 @@ const propValidityContract = {
40
40
  'Keeps the button focusable and named while work is in progress. It shows a spinner, states aria-disabled and aria-busy, and prevents activation until\n cleared.',
41
41
  default: false,
42
42
  },
43
+ matchButton: {
44
+ type: { kind: 'terminal', name: 'boolean' },
45
+ required: false,
46
+ target: { attribute: 'data-match-button' },
47
+ description:
48
+ 'Matches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row\'s height, including\n touch-sized controls. Leave it off for compact toolbar and inline icon buttons.',
49
+ default: false,
50
+ },
43
51
  pending: {
44
52
  type: { kind: 'terminal', name: 'boolean' },
45
53
  required: false,
@@ -79,6 +87,7 @@ const props = defineProps({
79
87
  disabled: { type: null as unknown as PropType<boolean | null>, default: false },
80
88
  label: { type: null as unknown as PropType<string | null>, default: null },
81
89
  loading: { type: null as unknown as PropType<boolean | null>, default: false },
90
+ matchButton: { type: null as unknown as PropType<boolean | null>, default: false },
82
91
  pending: { type: null as unknown as PropType<boolean | null>, default: false },
83
92
  round: { type: null as unknown as PropType<boolean | null>, default: false },
84
93
  size: { type: null as unknown as PropType<'sm' | 'md' | 'lg' | null>, default: 'md' },
@@ -92,6 +101,7 @@ const acceptedProps: Record<string, unknown> = {
92
101
  disabled: false,
93
102
  label: null,
94
103
  loading: false,
104
+ matchButton: false,
95
105
  pending: false,
96
106
  round: false,
97
107
  size: 'md',
@@ -126,6 +136,13 @@ const checkedProps = computed(() => ({
126
136
  'loading',
127
137
  acceptedProps,
128
138
  ) as boolean,
139
+ matchButton: checkedProp<boolean>(
140
+ props['matchButton'],
141
+ { kind: 'terminal', name: 'boolean' },
142
+ false,
143
+ 'matchButton',
144
+ acceptedProps,
145
+ ) as boolean,
129
146
  pending: checkedProp<boolean>(
130
147
  props['pending'],
131
148
  { kind: 'terminal', name: 'boolean' },
@@ -222,6 +239,7 @@ const hostState = computed(() =>
222
239
  checkedProps.value.pending && 'pending',
223
240
  checkedProps.value.size && 'size',
224
241
  checkedProps.value.size != null && `size=${encodeURIComponent(checkedProps.value.size)}`,
242
+ checkedProps.value.matchButton && 'matchButton',
225
243
  checkedProps.value.round && 'round',
226
244
  ].filter(Boolean).join(' ')
227
245
  )
@@ -248,6 +266,7 @@ useComponentHost(() => import('../components/ui-icon-button/ui-icon-button.js'),
248
266
  'disabled',
249
267
  'label',
250
268
  'loading',
269
+ 'matchButton',
251
270
  'pending',
252
271
  'round',
253
272
  'size',
@@ -297,6 +316,7 @@ function attribute(value: unknown): any {
297
316
  :data-disabled="reflectedProp('disabled', 'disabled', checkedProps.disabled, undefined, false)"
298
317
  :data-label="reflectedProp('label', 'label', checkedProps.label, undefined, false)"
299
318
  :data-loading="reflectedProp('loading', 'loading', checkedProps.loading, undefined, false)"
319
+ :data-match-button="reflectedProp('matchButton', 'match-button', checkedProps.matchButton, undefined, true)"
300
320
  :data-pending="reflectedProp('pending', 'pending', checkedProps.pending, undefined, false)"
301
321
  :data-round="reflectedProp('round', 'round', checkedProps.round, undefined, false)"
302
322
  :data-size="reflectedProp('size', 'size', checkedProps.size, undefined, false)"
@@ -527,6 +547,32 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"]::after {
527
547
  min-block-size: var(--ui-icon-button-size, var(--_size));
528
548
  }
529
549
 
550
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
551
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"] {
552
+ --_size: var(--ui-control-size-md);
553
+ block-size: auto;
554
+ align-self: stretch;
555
+ }
556
+
557
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=sm"] {
558
+ --_size: var(--ui-control-size-sm);
559
+ }
560
+
561
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=lg"] {
562
+ --_size: var(--ui-control-size-lg);
563
+ }
564
+
565
+ @media (pointer: coarse) {
566
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"] {
567
+ inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
568
+ min-inline-size: max(
569
+ var(--ui-icon-button-size, var(--_size)),
570
+ var(--ui-control-min-block-size)
571
+ );
572
+ min-block-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
573
+ }
574
+ }
575
+
530
576
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="round"] {
531
577
  border-radius: var(--ui-radius-round);
532
578
  }
@@ -13,6 +13,7 @@ var _hoisted_1 = [
13
13
  "data-disabled",
14
14
  "data-label",
15
15
  "data-loading",
16
+ "data-match-button",
16
17
  "data-pending",
17
18
  "data-round",
18
19
  "data-size",
@@ -42,6 +43,10 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
42
43
  type: null,
43
44
  default: false
44
45
  },
46
+ matchButton: {
47
+ type: null,
48
+ default: false
49
+ },
45
50
  pending: {
46
51
  type: null,
47
52
  default: false
@@ -100,6 +105,16 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
100
105
  description: "Keeps the button focusable and named while work is in progress. It shows a spinner, states aria-disabled and aria-busy, and prevents activation until\n cleared.",
101
106
  default: false
102
107
  },
108
+ matchButton: {
109
+ type: {
110
+ kind: "terminal",
111
+ name: "boolean"
112
+ },
113
+ required: false,
114
+ target: { attribute: "data-match-button" },
115
+ description: "Matches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row's height, including\n touch-sized controls. Leave it off for compact toolbar and inline icon buttons.",
116
+ default: false
117
+ },
103
118
  pending: {
104
119
  type: {
105
120
  kind: "terminal",
@@ -157,6 +172,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
157
172
  disabled: false,
158
173
  label: null,
159
174
  loading: false,
175
+ matchButton: false,
160
176
  pending: false,
161
177
  round: false,
162
178
  size: "md",
@@ -179,6 +195,10 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
179
195
  kind: "terminal",
180
196
  name: "boolean"
181
197
  }, false, "loading", acceptedProps),
198
+ matchButton: checkedProp(props["matchButton"], {
199
+ kind: "terminal",
200
+ name: "boolean"
201
+ }, false, "matchButton", acceptedProps),
182
202
  pending: checkedProp(props["pending"], {
183
203
  kind: "terminal",
184
204
  name: "boolean"
@@ -231,6 +251,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
231
251
  checkedProps.value.pending && "pending",
232
252
  checkedProps.value.size && "size",
233
253
  checkedProps.value.size != null && `size=${encodeURIComponent(checkedProps.value.size)}`,
254
+ checkedProps.value.matchButton && "matchButton",
234
255
  checkedProps.value.round && "round"
235
256
  ].filter(Boolean).join(" "));
236
257
  const dispatch = createDispatch(root);
@@ -252,6 +273,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
252
273
  "disabled",
253
274
  "label",
254
275
  "loading",
276
+ "matchButton",
255
277
  "pending",
256
278
  "round",
257
279
  "size",
@@ -292,6 +314,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
292
314
  "data-disabled": reflectedProp("disabled", "disabled", checkedProps.value.disabled, void 0, false),
293
315
  "data-label": reflectedProp("label", "label", checkedProps.value.label, void 0, false),
294
316
  "data-loading": reflectedProp("loading", "loading", checkedProps.value.loading, void 0, false),
317
+ "data-match-button": reflectedProp("matchButton", "match-button", checkedProps.value.matchButton, void 0, true),
295
318
  "data-pending": reflectedProp("pending", "pending", checkedProps.value.pending, void 0, false),
296
319
  "data-round": reflectedProp("round", "round", checkedProps.value.round, void 0, false),
297
320
  "data-size": reflectedProp("size", "size", checkedProps.value.size, void 0, false),
@@ -308,6 +331,6 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
308
331
  }]]);
309
332
  };
310
333
  }
311
- }), [["__scopeId", "data-v-7bb0fe2e"]]);
334
+ }), [["__scopeId", "data-v-1cd8b91b"]]);
312
335
  //#endregion
313
336
  export { UiIconButton_default as t };
@@ -4533,7 +4533,7 @@ svg[data-v-68ef93fb-s] {
4533
4533
  syntax: "*";
4534
4534
  inherits: false;
4535
4535
  }
4536
- [data-component~="ui-icon-button"][data-v-7bb0fe2e] {
4536
+ [data-component~="ui-icon-button"][data-v-1cd8b91b] {
4537
4537
  /* Hooks do not inherit, so the parts below read them from the root. */
4538
4538
  --_ui-icon-button-icon-size: var(--ui-icon-button-icon-size);
4539
4539
  --_ui-icon-button-icon-stroke-width: var(--ui-icon-button-icon-stroke-width);
@@ -4541,10 +4541,10 @@ svg[data-v-68ef93fb-s] {
4541
4541
  display: inline-flex;
4542
4542
  color: var(--ui-text-secondary);
4543
4543
  }
4544
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e] {
4544
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b] {
4545
4545
  position: relative;
4546
4546
  }
4547
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e]::before {
4547
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b]::before {
4548
4548
  content: "";
4549
4549
  position: absolute;
4550
4550
  inset: 50% auto auto 50%;
@@ -4558,13 +4558,13 @@ svg[data-v-68ef93fb-s] {
4558
4558
  transition: opacity var(--ui-affordance-motion, var(--ui-motion-fast)) var(--ui-motion-ease);
4559
4559
  pointer-events: none;
4560
4560
  }
4561
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e]:disabled::before {
4561
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b]:disabled::before {
4562
4562
  opacity: 0;
4563
4563
  }
4564
4564
 
4565
4565
  /* At rest an anticipatory button shows only its guide dot. The icon grows into place when
4566
4566
  proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
4567
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"] .content[data-v-7bb0fe2e] {
4567
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"] .content[data-v-1cd8b91b] {
4568
4568
  opacity: 1;
4569
4569
  transform: scale(1);
4570
4570
  transition:
@@ -4572,22 +4572,22 @@ svg[data-v-68ef93fb-s] {
4572
4572
  transform calc(var(--ui-motion-fast) * 2) cubic-bezier(0.2, 1.4, 0.35, 1);
4573
4573
  }
4574
4574
  @media (hover: hover) and (pointer: fine) {
4575
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e]:not([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"], :disabled, [data-ui-proximity="near"], :hover, :focus-visible) {
4575
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b]:not([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"], :disabled, [data-ui-proximity="near"], :hover, :focus-visible) {
4576
4576
  border-color: transparent;
4577
4577
  background-color: transparent;
4578
4578
  box-shadow: none;
4579
4579
  }
4580
4580
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"]:not([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"], :disabled, [data-ui-proximity="near"], :hover, :focus-visible)
4581
- .content[data-v-7bb0fe2e] {
4581
+ .content[data-v-1cd8b91b] {
4582
4582
  opacity: 0;
4583
4583
  transform: scale(0.65);
4584
4584
  transition-duration: var(--ui-motion-fast);
4585
4585
  }
4586
4586
  }
4587
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e]:is([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
4587
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b]:is([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
4588
4588
  opacity: 0;
4589
4589
  }
4590
- [data-component~="ui-icon-button"][data-v-7bb0fe2e] {
4590
+ [data-component~="ui-icon-button"][data-v-1cd8b91b] {
4591
4591
  /* The size prop resolves here; --ui-icon-button-size overrides it on an element. */
4592
4592
  --_size: 2rem;
4593
4593
  appearance: none;
@@ -4613,7 +4613,7 @@ svg[data-v-68ef93fb-s] {
4613
4613
  transform var(--ui-motion-fast) var(--ui-motion-ease);
4614
4614
  }
4615
4615
  @media (hover: none), (pointer: coarse) {
4616
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-7bb0fe2e]::before {
4616
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-v-1cd8b91b]::before {
4617
4617
  opacity: 0;
4618
4618
  }
4619
4619
  }
@@ -4621,10 +4621,10 @@ svg[data-v-68ef93fb-s] {
4621
4621
  /* A touch target without a bigger button: an invisible hit area, at least the control
4622
4622
  minimum, centred on the button (::before is the anticipatory guide). */
4623
4623
  @media (pointer: coarse) {
4624
- [data-component~="ui-icon-button"][data-v-7bb0fe2e] {
4624
+ [data-component~="ui-icon-button"][data-v-1cd8b91b] {
4625
4625
  position: relative;
4626
4626
  }
4627
- [data-component~="ui-icon-button"][data-v-7bb0fe2e]::after {
4627
+ [data-component~="ui-icon-button"][data-v-1cd8b91b]::after {
4628
4628
  content: "";
4629
4629
  position: absolute;
4630
4630
  inset: 50% auto auto 50%;
@@ -4633,10 +4633,10 @@ svg[data-v-68ef93fb-s] {
4633
4633
  transform: translate(-50%, -50%);
4634
4634
  }
4635
4635
  }
4636
- html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7bb0fe2e] {
4636
+ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-1cd8b91b] {
4637
4637
  position: relative;
4638
4638
  }
4639
- html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7bb0fe2e]::after {
4639
+ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-1cd8b91b]::after {
4640
4640
  content: "";
4641
4641
  position: absolute;
4642
4642
  inset: 50% auto auto 50%;
@@ -4644,31 +4644,54 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7
4644
4644
  block-size: max(100%, var(--ui-control-min-block-size));
4645
4645
  transform: translate(-50%, -50%);
4646
4646
  }
4647
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=sm"][data-v-7bb0fe2e] {
4647
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=sm"][data-v-1cd8b91b] {
4648
4648
  --_size: 1.75rem;
4649
4649
  inline-size: var(--ui-icon-button-size, var(--_size));
4650
4650
  block-size: var(--ui-icon-button-size, var(--_size));
4651
4651
  min-inline-size: var(--ui-icon-button-size, var(--_size));
4652
4652
  min-block-size: var(--ui-icon-button-size, var(--_size));
4653
4653
  }
4654
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=lg"][data-v-7bb0fe2e] {
4654
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=lg"][data-v-1cd8b91b] {
4655
4655
  --_size: 2.5rem;
4656
4656
  inline-size: var(--ui-icon-button-size, var(--_size));
4657
4657
  block-size: var(--ui-icon-button-size, var(--_size));
4658
4658
  min-inline-size: var(--ui-icon-button-size, var(--_size));
4659
4659
  min-block-size: var(--ui-icon-button-size, var(--_size));
4660
4660
  }
4661
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="round"][data-v-7bb0fe2e] {
4661
+
4662
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
4663
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-v-1cd8b91b] {
4664
+ --_size: var(--ui-control-size-md);
4665
+ block-size: auto;
4666
+ align-self: stretch;
4667
+ }
4668
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=sm"][data-v-1cd8b91b] {
4669
+ --_size: var(--ui-control-size-sm);
4670
+ }
4671
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=lg"][data-v-1cd8b91b] {
4672
+ --_size: var(--ui-control-size-lg);
4673
+ }
4674
+ @media (pointer: coarse) {
4675
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="matchButton"][data-v-1cd8b91b] {
4676
+ inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
4677
+ min-inline-size: max(
4678
+ var(--ui-icon-button-size, var(--_size)),
4679
+ var(--ui-control-min-block-size)
4680
+ );
4681
+ min-block-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
4682
+ }
4683
+ }
4684
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="round"][data-v-1cd8b91b] {
4662
4685
  border-radius: var(--ui-radius-round);
4663
4686
  }
4664
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"][data-v-7bb0fe2e] {
4687
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"][data-v-1cd8b91b] {
4665
4688
  border-color: var(--ui-icon-button-border, var(--ui-control-border, var(--ui-border-strong)));
4666
4689
  background-color: var(--ui-icon-button-outline-surface, var(--ui-surface-default));
4667
4690
  background-image: var(--ui-raised-highlight);
4668
4691
  color: var(--ui-icon-button-outline-text, var(--ui-text-primary));
4669
4692
  box-shadow: var(--ui-raised);
4670
4693
  }
4671
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"][data-v-7bb0fe2e] {
4694
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"][data-v-1cd8b91b] {
4672
4695
  background-color: var(--ui-icon-button-solid-surface, var(--ui-accent-solid));
4673
4696
  background-image: var(--ui-raised-highlight);
4674
4697
  color: var(--ui-icon-button-solid-text, var(--ui-text-on-accent));
@@ -4677,7 +4700,7 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7
4677
4700
  0 1px 2px color-mix(in srgb, var(--ui-accent-solid) 18%, transparent)
4678
4701
  );
4679
4702
  }
4680
- [data-component~="ui-icon-button"][data-v-7bb0fe2e]:hover:enabled:not([aria-disabled="true"]) {
4703
+ [data-component~="ui-icon-button"][data-v-1cd8b91b]:hover:enabled:not([aria-disabled="true"]) {
4681
4704
  /* Derived from the text colour so the ghost hover shows on any background. */
4682
4705
  background-color: var(
4683
4706
  --ui-icon-button-hover-surface,
@@ -4685,16 +4708,16 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7
4685
4708
  );
4686
4709
  color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
4687
4710
  }
4688
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"][data-v-7bb0fe2e]:hover:enabled:not([aria-disabled="true"]) {
4711
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"][data-v-1cd8b91b]:hover:enabled:not([aria-disabled="true"]) {
4689
4712
  border-color: var(
4690
4713
  --ui-icon-button-hover-border,
4691
4714
  var(--ui-control-border-hover, var(--ui-control-border))
4692
4715
  );
4693
4716
  }
4694
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"][data-v-7bb0fe2e]:hover:enabled:not([aria-disabled="true"]) {
4717
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"][data-v-1cd8b91b]:hover:enabled:not([aria-disabled="true"]) {
4695
4718
  background-color: var(--ui-icon-button-solid-hover-surface, var(--ui-accent-hover));
4696
4719
  }
4697
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=ghost"][aria-expanded="true"][data-v-7bb0fe2e]:enabled:not([aria-disabled="true"]) {
4720
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=ghost"][aria-expanded="true"][data-v-1cd8b91b]:enabled:not([aria-disabled="true"]) {
4698
4721
  background-color: var(
4699
4722
  --ui-icon-button-active-surface,
4700
4723
  color-mix(in srgb, currentColor 16%, transparent)
@@ -4702,33 +4725,33 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7
4702
4725
  color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
4703
4726
  box-shadow: var(--ui-pressed);
4704
4727
  }
4705
- [data-component~="ui-icon-button"][data-v-7bb0fe2e]:active:enabled:not([aria-disabled="true"]) {
4728
+ [data-component~="ui-icon-button"][data-v-1cd8b91b]:active:enabled:not([aria-disabled="true"]) {
4706
4729
  transform: scale(var(--ui-icon-button-active-scale, 0.96));
4707
4730
  }
4708
- :is([data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"][data-v-7bb0fe2e], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"][data-v-7bb0fe2e]) {
4731
+ :is([data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"][data-v-1cd8b91b], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"][data-v-1cd8b91b]) {
4709
4732
  cursor: progress;
4710
4733
  }
4711
- .content[data-v-7bb0fe2e] {
4734
+ .content[data-v-1cd8b91b] {
4712
4735
  display: inline-flex;
4713
4736
  align-items: center;
4714
4737
  justify-content: center;
4715
4738
  }
4716
4739
  :is([data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"])
4717
- .content[data-v-7bb0fe2e] {
4740
+ .content[data-v-1cd8b91b] {
4718
4741
  display: none;
4719
4742
  }
4720
4743
  @media (prefers-reduced-motion: reduce) {
4721
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"] .content[data-v-7bb0fe2e] {
4744
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"] .content[data-v-1cd8b91b] {
4722
4745
  transition: none;
4723
4746
  }
4724
4747
  }
4725
- [data-component~="ui-icon-button"][data-v-7bb0fe2e]:focus-visible {
4748
+ [data-component~="ui-icon-button"][data-v-1cd8b91b]:focus-visible {
4726
4749
  outline: none;
4727
4750
  box-shadow: var(--ui-focus-halo);
4728
4751
  }
4729
4752
 
4730
4753
  /* Disabled is a flat neutral control, independent of the active variant's tone. */
4731
- [data-component~="ui-icon-button"][data-v-7bb0fe2e]:disabled {
4754
+ [data-component~="ui-icon-button"][data-v-1cd8b91b]:disabled {
4732
4755
  border-color: var(--ui-disabled-border);
4733
4756
  background-color: var(--ui-disabled-surface);
4734
4757
  color: var(--ui-disabled-text);
@@ -4738,23 +4761,23 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"][data-v-7
4738
4761
  box-shadow: none;
4739
4762
  background-image: none;
4740
4763
  }
4741
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=ghost"][data-v-7bb0fe2e]:disabled {
4764
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=ghost"][data-v-1cd8b91b]:disabled {
4742
4765
  border-color: transparent;
4743
4766
  }
4744
- [data-component~="ui-icon-button"][data-v-7bb0fe2e] {
4767
+ [data-component~="ui-icon-button"][data-v-1cd8b91b] {
4745
4768
  --_icon-button-icon-default: var(--ui-icon-size-md);
4746
4769
  /* A slotted ui-icon is its own component, out of reach of the svg rule below; these are its
4747
4770
  defaults, which its own --ui-icon-* hooks still override. */
4748
4771
  --_ui-default-icon-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4749
4772
  --_ui-default-icon-stroke-width: var(--_ui-icon-button-icon-stroke-width, 1.75);
4750
4773
  }
4751
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=sm"][data-v-7bb0fe2e] {
4774
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=sm"][data-v-1cd8b91b] {
4752
4775
  --_icon-button-icon-default: var(--ui-icon-size-sm);
4753
4776
  }
4754
- [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=lg"][data-v-7bb0fe2e] {
4777
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="size=lg"][data-v-1cd8b91b] {
4755
4778
  --_icon-button-icon-default: var(--ui-icon-size-lg);
4756
4779
  }
4757
- svg[data-v-7bb0fe2e-s] {
4780
+ svg[data-v-1cd8b91b-s] {
4758
4781
  inline-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4759
4782
  block-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4760
4783
  flex-shrink: 0;
@@ -4762,7 +4785,7 @@ svg[data-v-7bb0fe2e-s] {
4762
4785
  }
4763
4786
 
4764
4787
  /* A component that sets its display still honours the hidden attribute on its root. */
4765
- [data-component~="ui-icon-button"][hidden][data-v-7bb0fe2e] {
4788
+ [data-component~="ui-icon-button"][hidden][data-v-1cd8b91b] {
4766
4789
  display: none;
4767
4790
  }
4768
4791