@threadlabs/looma 0.26.2 → 0.26.4

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/vue/UiBadge.vue CHANGED
@@ -13,7 +13,7 @@ const propValidityContract = {
13
13
  required: false,
14
14
  target: { attribute: 'shape' },
15
15
  description:
16
- 'Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it. circle frames a visible single glyph or icon in a fixed circle, centered in both directions.',
16
+ 'Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it. circle frames a visible glyph, icon or short bounded count in a fixed circle, centered in both\n directions.',
17
17
  values: ['pill', 'tag', 'dot', 'square', 'circle'],
18
18
  default: 'pill',
19
19
  },
@@ -22,8 +22,8 @@ const propValidityContract = {
22
22
  required: false,
23
23
  target: { attribute: 'size' },
24
24
  description:
25
- 'Scale. xs is a compact count beside small controls; md is the usual text badge. A square is 24px at xs and 32px at md with default spacing. A circle is\n 16px at xs and 24px at md.',
26
- values: ['xs', 'md'],
25
+ 'Scale. xs is compact; md is the usual text badge; lg adds room to fixed marks while retaining the usual text size. A square is 24px at xs, 32px at md and\n 40px at lg. A circle is 16px at xs, 24px at md and 32px at lg; use lg for short counts such as 30 or 99+.',
26
+ values: ['xs', 'md', 'lg'],
27
27
  default: 'md',
28
28
  },
29
29
  tone: {
@@ -40,8 +40,8 @@ const propValidityContract = {
40
40
  required: false,
41
41
  target: { attribute: 'variant' },
42
42
  description:
43
- 'Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.\n Neutral looks the same in solid and subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.',
44
- values: ['solid', 'subtle', 'outline'],
43
+ 'Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.\n inverse uses a translucent contrasting surface and toned ink for a count or label on a filled control of that tone. Neutral looks the same in solid and\n subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.',
44
+ values: ['solid', 'subtle', 'outline', 'inverse'],
45
45
  default: 'subtle',
46
46
  },
47
47
  },
@@ -51,7 +51,7 @@ const props = defineProps({
51
51
  type: null as unknown as PropType<'pill' | 'tag' | 'dot' | 'square' | 'circle' | null>,
52
52
  default: 'pill',
53
53
  },
54
- size: { type: null as unknown as PropType<'xs' | 'md' | null>, default: 'md' },
54
+ size: { type: null as unknown as PropType<'xs' | 'md' | 'lg' | null>, default: 'md' },
55
55
  tone: {
56
56
  type: null as unknown as PropType<
57
57
  'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger' | null
@@ -59,7 +59,7 @@ const props = defineProps({
59
59
  default: 'neutral',
60
60
  },
61
61
  variant: {
62
- type: null as unknown as PropType<'solid' | 'subtle' | 'outline' | null>,
62
+ type: null as unknown as PropType<'solid' | 'subtle' | 'outline' | 'inverse' | null>,
63
63
  default: 'subtle',
64
64
  },
65
65
  })
@@ -77,13 +77,13 @@ const checkedProps = computed(() => ({
77
77
  'shape',
78
78
  acceptedProps,
79
79
  ) as 'pill' | 'tag' | 'dot' | 'square' | 'circle',
80
- size: checkedProp<'xs' | 'md'>(
80
+ size: checkedProp<'xs' | 'md' | 'lg'>(
81
81
  props['size'],
82
82
  { kind: 'terminal', name: 'keyword' },
83
83
  false,
84
84
  'size',
85
85
  acceptedProps,
86
- ) as 'xs' | 'md',
86
+ ) as 'xs' | 'md' | 'lg',
87
87
  tone: checkedProp<'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger'>(
88
88
  props['tone'],
89
89
  { kind: 'terminal', name: 'keyword' },
@@ -91,13 +91,13 @@ const checkedProps = computed(() => ({
91
91
  'tone',
92
92
  acceptedProps,
93
93
  ) as 'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger',
94
- variant: checkedProp<'solid' | 'subtle' | 'outline'>(
94
+ variant: checkedProp<'solid' | 'subtle' | 'outline' | 'inverse'>(
95
95
  props['variant'],
96
96
  { kind: 'terminal', name: 'keyword' },
97
97
  false,
98
98
  'variant',
99
99
  acceptedProps,
100
- ) as 'solid' | 'subtle' | 'outline',
100
+ ) as 'solid' | 'subtle' | 'outline' | 'inverse',
101
101
  }))
102
102
  void checkedProps.value
103
103
  watchSyncEffect(() => {
@@ -328,25 +328,26 @@ const hostState = computed(() =>
328
328
  text-box-trim: none;
329
329
  }
330
330
 
331
- /* Text-only badges retain their trimmed inline baseline. Icon content needs a flex row;
332
- trimming its label separately keeps the glyph centered without changing adjacent lines. */
331
+ /* Center the capital/baseline text box, while clipping only inline overflow for ellipsis.
332
+ Vertical ink remains visible so trimming never cuts off ascenders or descenders. */
333
333
  @supports (text-box-trim: trim-both) {
334
334
  [data-component~="ui-badge"] {
335
335
  display: inline-block;
336
336
  min-block-size: var(--ui-badge-min-block-size, 1.5rem);
337
337
  text-align: center;
338
338
  align-content: center;
339
- text-box-trim: trim-both;
340
- text-box-edge: text;
339
+ text-box-trim: none;
341
340
  }
342
341
  [data-component~="ui-badge"]:has(.icon:not(:empty)),
343
342
  [data-component~="ui-badge"]:has(.label svg) {
344
343
  display: inline-flex;
345
344
  text-box-trim: none;
346
345
  }
347
- [data-component~="ui-badge"]:has(.icon:not(:empty)) .label {
346
+ .label:not(:has(svg)) {
348
347
  text-box-trim: trim-both;
349
- text-box-edge: text;
348
+ text-box-edge: cap alphabetic;
349
+ overflow-x: clip;
350
+ overflow-y: visible;
350
351
  }
351
352
  }
352
353
 
@@ -427,6 +428,42 @@ const hostState = computed(() =>
427
428
  --_badge-color-text: color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default));
428
429
  }
429
430
 
431
+ /* A translucent inverse surface picks up its filled control's tone. Deepen the tone ink
432
+ toward the theme text to retain contrast against that composed surface. */
433
+ [data-component~="ui-badge"][data-ui-badge-state~="variant=inverse"] {
434
+ --_badge-color-surface: color-mix(
435
+ in srgb,
436
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) 88%,
437
+ transparent
438
+ );
439
+ --_badge-color-border: var(--_badge-color-surface);
440
+ --_badge-color-text: color-mix(in srgb, var(--_badge-color-ink) 85%, var(--ui-text-primary));
441
+ --_badge-outline-surface: var(
442
+ --ui-badge-surface,
443
+ var(--_badge-color-surface, color-mix(in srgb, var(--_badge-text) 88%, transparent))
444
+ );
445
+ border-color: var(
446
+ --ui-badge-border,
447
+ var(--_badge-color-border, color-mix(in srgb, var(--_badge-text) 88%, transparent))
448
+ );
449
+ color: var(
450
+ --ui-badge-text,
451
+ var(--_badge-color-text, color-mix(in srgb, var(--_badge-surface) 85%, var(--ui-text-primary)))
452
+ );
453
+ /* Paint each translucent layer once, including the border, without a bright double-painted ring. */
454
+ background-clip: padding-box;
455
+ }
456
+
457
+ [data-component~="ui-badge"][data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="shape=circle"] {
458
+ box-shadow: var(--ui-shadow-sm);
459
+ }
460
+
461
+ /* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
462
+ surface ink: moving it toward dark-theme primary text would reduce overlay contrast. */
463
+ [data-component~="ui-badge"][data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"] {
464
+ color: var(--ui-badge-text, var(--_badge-color-text, var(--_badge-surface)));
465
+ }
466
+
430
467
  [data-component~="ui-badge"][data-ui-badge-state~="variant=outline"] {
431
468
  --_badge-surface: var(--ui-surface-default);
432
469
  --_badge-border: var(--ui-border-strong);
@@ -480,6 +517,13 @@ const hostState = computed(() =>
480
517
  --_badge-square-size: var(--ui-badge-square-size, calc(var(--ui-space-3) * 2));
481
518
  }
482
519
 
520
+ [data-component~="ui-badge"][data-ui-badge-state~="shape=square"][data-ui-badge-state~="size=lg"] {
521
+ --_badge-square-size: var(
522
+ --ui-badge-square-size,
523
+ calc(var(--ui-space-4) * 2 + var(--ui-space-2))
524
+ );
525
+ }
526
+
483
527
  [data-component~="ui-badge"][data-ui-badge-state~="shape=square"] .label {
484
528
  display: inline-flex;
485
529
  align-items: center;
@@ -512,6 +556,10 @@ const hostState = computed(() =>
512
556
  --_badge-circle-size: var(--ui-badge-circle-size, var(--ui-space-4));
513
557
  }
514
558
 
559
+ [data-component~="ui-badge"][data-ui-badge-state~="shape=circle"][data-ui-badge-state~="size=lg"] {
560
+ --_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-4) * 2));
561
+ }
562
+
515
563
  [data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] .label {
516
564
  display: inline-flex;
517
565
  align-items: center;
@@ -528,6 +576,18 @@ const hostState = computed(() =>
528
576
  display: none;
529
577
  }
530
578
 
579
+ /* Center capital and numeral ink, rather than the font's ascent/descent line box.
580
+ Icon labels retain flex geometry; untrimmed browsers keep that fallback too. */
581
+ @supports (text-box-trim: trim-both) {
582
+ [data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] .label:not(:has(svg)),
583
+ [data-component~="ui-badge"][data-ui-badge-state~="shape=square"] .label:not(:has(svg)) {
584
+ display: block;
585
+ text-box-trim: trim-both;
586
+ text-box-edge: cap alphabetic;
587
+ overflow: visible;
588
+ }
589
+ }
590
+
531
591
  /* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
532
592
  [data-component~="ui-badge"][data-ui-badge-state~="shape=dot"] {
533
593
  position: relative;
@@ -587,6 +647,10 @@ const hostState = computed(() =>
587
647
  pointer-events: none;
588
648
  }
589
649
 
650
+ [data-component~="ui-badge"][data-ui-badge-state~="shape=tag"][data-ui-badge-state~="variant=inverse"] {
651
+ background: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-text)));
652
+ }
653
+
590
654
  [data-component~="ui-badge"][data-ui-badge-state~="shape=tag"]:dir(rtl) {
591
655
  padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2));
592
656
  padding-inline-start: calc(
package/vue/UiCallout.vue CHANGED
@@ -245,8 +245,10 @@ const hostState = computed(() =>
245
245
  padding-inline-end: var(--ui-callout-padding-inline, var(--ui-space-3));
246
246
  border: var(--ui-callout-border-width, var(--ui-border-width)) solid
247
247
  color-mix(in srgb, var(--ui-callout-border, var(--_callout-border)) 35%, transparent);
248
- border-inline-start: var(--ui-callout-leading-border-width, var(--ui-accent-line-width)) solid
249
- var(--ui-callout-border, var(--_callout-border));
248
+ border-inline-start: var(
249
+ --ui-callout-leading-border-width,
250
+ var(--ui-callout-border-width, var(--ui-border-width))
251
+ ) solid color-mix(in srgb, var(--ui-callout-border, var(--_callout-border)) 35%, transparent);
250
252
  border-radius: var(--ui-radius-md);
251
253
  background: var(--ui-callout-surface, var(--_callout-surface));
252
254
  color: var(--ui-callout-text, var(--ui-text-primary));
package/vue/UiCard.d.ts CHANGED
@@ -52,7 +52,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
52
52
  default: string;
53
53
  };
54
54
  }>> & Readonly<{}>, {
55
- size: "sm" | "md" | "content" | "lg" | null;
55
+ size: "sm" | "md" | "lg" | "content" | null;
56
56
  tone: "info" | "neutral" | "accent" | "success" | "warning" | "danger" | null;
57
57
  variant: "subtle" | "outlined" | "elevated" | null;
58
58
  as: "div" | "article" | "aside" | "section" | null;
@@ -10,6 +10,10 @@ type __VLS_Slots = {} & {
10
10
  trailing?: (props: typeof __VLS_7) => any;
11
11
  };
12
12
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
13
+ align: {
14
+ type: PropType<"center" | "title" | null>;
15
+ default: string;
16
+ };
13
17
  current: {
14
18
  type: PropType<boolean | null>;
15
19
  default: boolean;
@@ -31,6 +35,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
31
35
  default: boolean;
32
36
  };
33
37
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
38
+ align: {
39
+ type: PropType<"center" | "title" | null>;
40
+ default: string;
41
+ };
34
42
  current: {
35
43
  type: PropType<boolean | null>;
36
44
  default: boolean;
@@ -54,6 +62,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
54
62
  }>> & Readonly<{}>, {
55
63
  variant: "card" | "row" | null;
56
64
  current: boolean | null;
65
+ align: "title" | "center" | null;
57
66
  wrap: boolean | null;
58
67
  highlighted: boolean | null;
59
68
  leadingInteractive: boolean | null;
@@ -8,6 +8,15 @@ defineOptions({ inheritAttrs: false })
8
8
 
9
9
  const propValidityContract = {
10
10
  props: {
11
+ align: {
12
+ type: { kind: 'terminal', name: 'keyword' },
13
+ required: false,
14
+ target: { attribute: 'align' },
15
+ description:
16
+ 'Where the leading and trailing regions sit vertically. center aligns them with the whole row. title aligns them with the first title line, keeping an\n identifying icon beside its name when the title or description wraps. Taller controls retain their natural height.',
17
+ values: ['center', 'title'],
18
+ default: 'center',
19
+ },
11
20
  current: {
12
21
  type: { kind: 'terminal', name: 'boolean' },
13
22
  required: false,
@@ -52,6 +61,7 @@ const propValidityContract = {
52
61
  },
53
62
  } as const
54
63
  const props = defineProps({
64
+ align: { type: null as unknown as PropType<'center' | 'title' | null>, default: 'center' },
55
65
  current: { type: null as unknown as PropType<boolean | null>, default: false },
56
66
  highlighted: { type: null as unknown as PropType<boolean | null>, default: false },
57
67
  leadingInteractive: { type: null as unknown as PropType<boolean | null>, default: false },
@@ -59,6 +69,7 @@ const props = defineProps({
59
69
  wrap: { type: null as unknown as PropType<boolean | null>, default: false },
60
70
  })
61
71
  const acceptedProps: Record<string, unknown> = {
72
+ align: 'center',
62
73
  current: false,
63
74
  highlighted: false,
64
75
  leadingInteractive: false,
@@ -66,6 +77,13 @@ const acceptedProps: Record<string, unknown> = {
66
77
  wrap: false,
67
78
  }
68
79
  const checkedProps = computed(() => ({
80
+ align: checkedProp<'center' | 'title'>(
81
+ props['align'],
82
+ { kind: 'terminal', name: 'keyword' },
83
+ false,
84
+ 'align',
85
+ acceptedProps,
86
+ ) as 'center' | 'title',
69
87
  current: checkedProp<boolean>(
70
88
  props['current'],
71
89
  { kind: 'terminal', name: 'boolean' },
@@ -167,6 +185,8 @@ const hostState = computed(() =>
167
185
  checkedProps.value.current && 'current',
168
186
  checkedProps.value.leadingInteractive && 'leadingInteractive',
169
187
  checkedProps.value.wrap && 'wrap',
188
+ checkedProps.value.align && 'align',
189
+ checkedProps.value.align != null && `align=${encodeURIComponent(checkedProps.value.align)}`,
170
190
  ].filter(Boolean).join(' ')
171
191
  )
172
192
  </script>
@@ -177,6 +197,7 @@ const hostState = computed(() =>
177
197
  v-bind="nativeAttrs($attrs)"
178
198
  :aria-current="checkedProps.current ?? undefined"
179
199
  v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
200
+ :data-align="reflectedProp('align', 'align', checkedProps.align, undefined, false)"
180
201
  :data-current="reflectedProp('current', 'current', checkedProps.current, undefined, false)"
181
202
  :data-highlighted="reflectedProp('highlighted', 'highlighted', checkedProps.highlighted, undefined, false)"
182
203
  :data-leading-interactive="reflectedProp(
@@ -341,6 +362,16 @@ const hostState = computed(() =>
341
362
  line-height: var(--ui-line-height-tight);
342
363
  }
343
364
 
365
+ /* Keep identity and disclosure marks beside the first line, even with a long description. */
366
+ [data-component~="ui-list-item"][data-ui-list-item-state~="align=title"] {
367
+ align-items: flex-start;
368
+ }
369
+
370
+ [data-component~="ui-list-item"][data-ui-list-item-state~="align=title"] .leading,
371
+ [data-component~="ui-list-item"][data-ui-list-item-state~="align=title"] .trailing {
372
+ min-block-size: calc(var(--ui-font-size-md) * var(--ui-line-height-tight));
373
+ }
374
+
344
375
  .description {
345
376
  color: var(--ui-text-muted);
346
377
  font-size: var(--ui-font-size-sm);
@@ -63,7 +63,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
63
63
  }>) => any) | undefined;
64
64
  }>, {
65
65
  open: boolean | null;
66
- size: "sm" | "md" | "content" | "lg" | null;
66
+ size: "sm" | "md" | "lg" | "content" | null;
67
67
  for: string | null;
68
68
  placement: "left" | "right" | "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left-start" | "left-end" | "right-start" | "right-end" | null;
69
69
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -39,7 +39,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
39
39
  };
40
40
  }>> & Readonly<{}>, {
41
41
  fill: boolean | null;
42
- size: "sm" | "md" | "content" | "lg" | null;
42
+ size: "sm" | "md" | "lg" | "content" | null;
43
43
  trim: boolean | null;
44
44
  orientation: "vertical" | "horizontal" | null;
45
45
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
package/vue/UiToast.vue CHANGED
@@ -234,6 +234,7 @@ function attribute(value: unknown): any {
234
234
 
235
235
  [data-component~="ui-toast"] {
236
236
  --_ui-toast-accent: var(--ui-border-strong);
237
+ --_ui-toast-surface: var(--ui-surface-muted);
237
238
 
238
239
  display: flex;
239
240
  align-items: center;
@@ -242,13 +243,20 @@ function attribute(value: unknown): any {
242
243
  inline-size: 100%;
243
244
  margin: 0;
244
245
  padding: var(--ui-space-3) var(--ui-space-4);
246
+ /* The close button's internal space supplies the rest of the trailing inset. */
247
+ padding-inline-end: var(--ui-space-2);
245
248
  border: var(--ui-border-width) solid
246
- var(--ui-toast-border, var(--ui-overlay-border, var(--ui-border-strong)));
247
- border-inline-start: var(--ui-accent-line-width) solid
248
- var(--ui-toast-accent, var(--_ui-toast-accent));
249
+ var(
250
+ --ui-toast-border,
251
+ var(--ui-overlay-border, var(--ui-toast-accent, var(--_ui-toast-accent)))
252
+ );
249
253
  border-radius: var(--ui-toast-radius, var(--ui-overlay-radius, var(--ui-radius-lg)));
250
- background: var(--ui-toast-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
254
+ background: var(--ui-toast-surface, var(--ui-overlay-surface, var(--_ui-toast-surface)));
251
255
  color: var(--ui-text-primary);
256
+ font-family: var(--ui-font-family-sans);
257
+ font-size: var(--ui-font-size-sm);
258
+ font-weight: var(--ui-font-normal);
259
+ line-height: var(--ui-line-height-md);
252
260
  box-shadow: var(
253
261
  --ui-toast-shadow,
254
262
  var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg)))
@@ -258,15 +266,19 @@ function attribute(value: unknown): any {
258
266
 
259
267
  [data-component~="ui-toast"][data-ui-toast-state~="tone=info"] {
260
268
  --_ui-toast-accent: var(--ui-info-solid);
269
+ --_ui-toast-surface: var(--ui-info-soft);
261
270
  }
262
271
  [data-component~="ui-toast"][data-ui-toast-state~="tone=success"] {
263
272
  --_ui-toast-accent: var(--ui-success-solid);
273
+ --_ui-toast-surface: var(--ui-success-soft);
264
274
  }
265
275
  [data-component~="ui-toast"][data-ui-toast-state~="tone=warning"] {
266
276
  --_ui-toast-accent: var(--ui-warning-solid);
277
+ --_ui-toast-surface: var(--ui-warning-soft);
267
278
  }
268
279
  [data-component~="ui-toast"][data-ui-toast-state~="tone=danger"] {
269
280
  --_ui-toast-accent: var(--ui-danger-solid);
281
+ --_ui-toast-surface: var(--ui-danger-soft);
270
282
  }
271
283
 
272
284
  .message {
@@ -276,10 +288,6 @@ function attribute(value: unknown): any {
276
288
  .action:not(:has(> *)) {
277
289
  display: none;
278
290
  }
279
- .dismiss {
280
- margin-inline-end: calc(var(--ui-space-2) * -1);
281
- }
282
-
283
291
  [data-component~="ui-toast"][hidden] {
284
292
  display: none;
285
293
  }
@@ -460,19 +460,27 @@ function uniqueKeys<T>(
460
460
  }
461
461
 
462
462
  .toast {
463
+ --_ui-toast-region-accent: var(--ui-border-strong);
464
+ --_ui-toast-region-tone-surface: var(--ui-surface-muted);
463
465
  display: grid;
464
466
  grid-template-columns: 1fr auto;
465
467
  gap: var(--ui-space-2);
466
468
  align-items: start;
467
469
  border: var(--ui-border-width) solid
468
- var(--_ui-toast-region-border, var(--ui-overlay-border, var(--ui-border-strong)));
470
+ var(--_ui-toast-region-border, var(--ui-overlay-border, var(--_ui-toast-region-accent)));
469
471
  border-radius: var(--_ui-toast-region-radius, var(--ui-overlay-radius, var(--ui-radius-lg)));
470
472
  padding: var(--ui-space-3) var(--ui-space-4);
473
+ /* The close button's internal space supplies the rest of the trailing inset. */
474
+ padding-inline-end: var(--ui-space-2);
471
475
  background: var(
472
476
  --_ui-toast-region-surface,
473
- var(--ui-overlay-surface, var(--ui-surface-elevated))
477
+ var(--ui-overlay-surface, var(--_ui-toast-region-tone-surface))
474
478
  );
475
479
  color: var(--ui-text-primary);
480
+ font-family: var(--ui-font-family-sans);
481
+ font-size: var(--ui-font-size-sm);
482
+ font-weight: var(--ui-font-normal);
483
+ line-height: var(--ui-line-height-md);
476
484
  box-shadow: var(
477
485
  --_ui-toast-region-shadow,
478
486
  var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg)))
@@ -482,16 +490,20 @@ function uniqueKeys<T>(
482
490
  }
483
491
 
484
492
  .toast[data-tone="info"] {
485
- border-inline-start: var(--ui-accent-line-width) solid var(--ui-info-solid);
493
+ --_ui-toast-region-accent: var(--ui-info-solid);
494
+ --_ui-toast-region-tone-surface: var(--ui-info-soft);
486
495
  }
487
496
  .toast[data-tone="success"] {
488
- border-inline-start: var(--ui-accent-line-width) solid var(--ui-success-solid);
497
+ --_ui-toast-region-accent: var(--ui-success-solid);
498
+ --_ui-toast-region-tone-surface: var(--ui-success-soft);
489
499
  }
490
500
  .toast[data-tone="warning"] {
491
- border-inline-start: var(--ui-accent-line-width) solid var(--ui-warning-solid);
501
+ --_ui-toast-region-accent: var(--ui-warning-solid);
502
+ --_ui-toast-region-tone-surface: var(--ui-warning-soft);
492
503
  }
493
504
  .toast[data-tone="danger"] {
494
- border-inline-start: var(--ui-accent-line-width) solid var(--ui-danger-solid);
505
+ --_ui-toast-region-accent: var(--ui-danger-solid);
506
+ --_ui-toast-region-tone-surface: var(--ui-danger-soft);
495
507
  }
496
508
 
497
509
  /* Leaving slides on down and fades; the controller removes the toast when this ends. */
@@ -567,7 +579,6 @@ function uniqueKeys<T>(
567
579
 
568
580
  .dismiss {
569
581
  align-self: center;
570
- margin-inline-end: calc(var(--ui-space-2) * -1);
571
582
  }
572
583
 
573
584
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -87,10 +87,10 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
87
87
  }>) => any) | undefined;
88
88
  }>, {
89
89
  open: boolean | null;
90
+ inverse: boolean | null;
90
91
  trigger: "hover" | "click" | "focus" | null;
91
92
  for: string | null;
92
93
  hideDelay: number | null;
93
- inverse: boolean | null;
94
94
  placement: "left" | "right" | "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left-start" | "left-end" | "right-start" | "right-end" | null;
95
95
  showDelay: number | null;
96
96
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>, {
@@ -125,7 +125,7 @@ var UiAvatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
125
125
  },
126
126
  required: false,
127
127
  target: { attribute: "shape" },
128
- description: "Circle by default; square uses the theme's medium radius.",
128
+ description: "Circle by default, with a shallow shadow; square uses the theme's medium radius.",
129
129
  values: ["circle", "square"],
130
130
  default: "circle"
131
131
  },
@@ -362,6 +362,6 @@ var UiAvatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
362
362
  }]]);
363
363
  };
364
364
  }
365
- }), [["__scopeId", "data-v-8b3c5fb3"]]);
365
+ }), [["__scopeId", "data-v-03720dc1"]]);
366
366
  //#endregion
367
367
  export { UiAvatar_default as t };
@@ -46,7 +46,7 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
46
46
  },
47
47
  required: false,
48
48
  target: { attribute: "shape" },
49
- description: "Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it. circle frames a visible single glyph or icon in a fixed circle, centered in both directions.",
49
+ description: "Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it. circle frames a visible glyph, icon or short bounded count in a fixed circle, centered in both\n directions.",
50
50
  values: [
51
51
  "pill",
52
52
  "tag",
@@ -63,8 +63,12 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
63
63
  },
64
64
  required: false,
65
65
  target: { attribute: "size" },
66
- description: "Scale. xs is a compact count beside small controls; md is the usual text badge. A square is 24px at xs and 32px at md with default spacing. A circle is\n 16px at xs and 24px at md.",
67
- values: ["xs", "md"],
66
+ description: "Scale. xs is compact; md is the usual text badge; lg adds room to fixed marks while retaining the usual text size. A square is 24px at xs, 32px at md and\n 40px at lg. A circle is 16px at xs, 24px at md and 32px at lg; use lg for short counts such as 30 or 99+.",
67
+ values: [
68
+ "xs",
69
+ "md",
70
+ "lg"
71
+ ],
68
72
  default: "md"
69
73
  },
70
74
  tone: {
@@ -92,11 +96,12 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
92
96
  },
93
97
  required: false,
94
98
  target: { attribute: "variant" },
95
- description: "Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.\n Neutral looks the same in solid and subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.",
99
+ description: "Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.\n inverse uses a translucent contrasting surface and toned ink for a count or label on a filled control of that tone. Neutral looks the same in solid and\n subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.",
96
100
  values: [
97
101
  "solid",
98
102
  "subtle",
99
- "outline"
103
+ "outline",
104
+ "inverse"
100
105
  ],
101
106
  default: "subtle"
102
107
  }
@@ -174,6 +179,6 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
174
179
  }]]);
175
180
  };
176
181
  }
177
- }), [["__scopeId", "data-v-c96818e7"]]);
182
+ }), [["__scopeId", "data-v-4d2f1396"]]);
178
183
  //#endregion
179
184
  export { UiBadge_default as t };
@@ -160,6 +160,6 @@ var UiCallout_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
160
160
  }]]);
161
161
  };
162
162
  }
163
- }), [["__scopeId", "data-v-948263db"]]);
163
+ }), [["__scopeId", "data-v-ca7a11cb"]]);
164
164
  //#endregion
165
165
  export { UiCallout_default as t };
@@ -4,6 +4,7 @@ import { computed, createElementBlock, createElementVNode, defineComponent, getC
4
4
  //#region .build/vue/UiListItem.vue?vue&type=script&setup=true&lang.ts
5
5
  var _hoisted_1 = [
6
6
  "aria-current",
7
+ "data-align",
7
8
  "data-current",
8
9
  "data-highlighted",
9
10
  "data-leading-interactive",
@@ -22,6 +23,10 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
22
23
  inheritAttrs: false,
23
24
  __name: "UiListItem",
24
25
  props: {
26
+ align: {
27
+ type: null,
28
+ default: "center"
29
+ },
25
30
  current: {
26
31
  type: null,
27
32
  default: false
@@ -45,6 +50,17 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
45
50
  },
46
51
  setup(__props) {
47
52
  const propValidityContract = { props: {
53
+ align: {
54
+ type: {
55
+ kind: "terminal",
56
+ name: "keyword"
57
+ },
58
+ required: false,
59
+ target: { attribute: "align" },
60
+ description: "Where the leading and trailing regions sit vertically. center aligns them with the whole row. title aligns them with the first title line, keeping an\n identifying icon beside its name when the title or description wraps. Taller controls retain their natural height.",
61
+ values: ["center", "title"],
62
+ default: "center"
63
+ },
48
64
  current: {
49
65
  type: {
50
66
  kind: "terminal",
@@ -99,6 +115,7 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
99
115
  } };
100
116
  const props = __props;
101
117
  const acceptedProps = {
118
+ align: "center",
102
119
  current: false,
103
120
  highlighted: false,
104
121
  leadingInteractive: false,
@@ -106,6 +123,10 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
106
123
  wrap: false
107
124
  };
108
125
  const checkedProps = computed(() => ({
126
+ align: checkedProp(props["align"], {
127
+ kind: "terminal",
128
+ name: "keyword"
129
+ }, false, "align", acceptedProps),
109
130
  current: checkedProp(props["current"], {
110
131
  kind: "terminal",
111
132
  name: "boolean"
@@ -158,11 +179,14 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
158
179
  checkedProps.value.highlighted && "highlighted",
159
180
  checkedProps.value.current && "current",
160
181
  checkedProps.value.leadingInteractive && "leadingInteractive",
161
- checkedProps.value.wrap && "wrap"
182
+ checkedProps.value.wrap && "wrap",
183
+ checkedProps.value.align && "align",
184
+ checkedProps.value.align != null && `align=${encodeURIComponent(checkedProps.value.align)}`
162
185
  ].filter(Boolean).join(" "));
163
186
  return (_ctx, _cache) => {
164
187
  return withDirectives((openBlock(), createElementBlock("li", mergeProps({ "data-component": "ui-list-item" }, nativeAttrs(_ctx.$attrs), {
165
188
  "aria-current": checkedProps.value.current ?? void 0,
189
+ "data-align": reflectedProp("align", "align", checkedProps.value.align, void 0, false),
166
190
  "data-current": reflectedProp("current", "current", checkedProps.value.current, void 0, false),
167
191
  "data-highlighted": reflectedProp("highlighted", "highlighted", checkedProps.value.highlighted, void 0, false),
168
192
  "data-leading-interactive": reflectedProp("leadingInteractive", "leading-interactive", checkedProps.value.leadingInteractive, void 0, false),
@@ -179,6 +203,6 @@ var UiListItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
179
203
  }]]);
180
204
  };
181
205
  }
182
- }), [["__scopeId", "data-v-bb9ba09d"]]);
206
+ }), [["__scopeId", "data-v-6c3bc8f3"]]);
183
207
  //#endregion
184
208
  export { UiListItem_default as t };