@threadlabs/looma 0.26.3 → 0.26.5

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 (39) hide show
  1. package/components/ui-badge/ui-badge.html +41 -4
  2. package/components/ui-button/ui-button.html +50 -5
  3. package/components/ui-callout/ui-callout.html +2 -1
  4. package/components/ui-icon-button/ui-icon-button.html +35 -7
  5. package/components/ui-input-group/ui-input-group.html +9 -0
  6. package/components/ui-toast/ui-toast.html +13 -7
  7. package/components/ui-toast-region/ui-toast-region.html +18 -7
  8. package/dist/index.js +1 -1
  9. package/package.json +1 -1
  10. package/styles/ui-badge.css +40 -1
  11. package/styles/ui-button.css +53 -5
  12. package/styles/ui-callout.css +2 -1
  13. package/styles/ui-icon-button.css +35 -7
  14. package/styles/ui-input-group.css +6 -0
  15. package/styles/ui-toast-region.css +18 -7
  16. package/styles/ui-toast.css +13 -7
  17. package/vanilla/UiBadge.d.ts +1 -1
  18. package/vanilla/UiBadge.js +1 -1
  19. package/vanilla/UiButton.js +47 -21
  20. package/vanilla/UiInputGroup.d.ts +1 -0
  21. package/vanilla/UiInputGroup.js +4 -4
  22. package/vue/UiBadge.d.ts +3 -3
  23. package/vue/UiBadge.vue +79 -6
  24. package/vue/UiButton.d.ts +6 -2
  25. package/vue/UiButton.vue +56 -6
  26. package/vue/UiCallout.vue +4 -2
  27. package/vue/UiIconButton.vue +40 -7
  28. package/vue/UiInputGroup.d.ts +9 -0
  29. package/vue/UiInputGroup.vue +29 -1
  30. package/vue/UiToast.vue +16 -8
  31. package/vue/UiToastRegion.vue +18 -7
  32. package/vue/chunks/UiBadge.js +3 -2
  33. package/vue/chunks/UiButton.js +15 -5
  34. package/vue/chunks/UiCallout.js +1 -1
  35. package/vue/chunks/UiIconButton.js +1 -1
  36. package/vue/chunks/UiInputGroup.js +29 -4
  37. package/vue/chunks/UiToast.js +1 -1
  38. package/vue/chunks/UiToastRegion.js +1 -1
  39. package/vue/components.css +435 -263
package/vue/UiBadge.vue CHANGED
@@ -22,8 +22,8 @@ const propValidityContract = {
22
22
  required: false,
23
23
  target: { attribute: 'size' },
24
24
  description:
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'],
25
+ 'Scale. xs is compact; sm keeps the usual badge geometry with compact text, fitting short counts such as 99+ inside a 24px circle. md is the usual text\n badge; lg adds room to fixed marks while retaining the usual text size. A square is 24px at xs, 32px at sm and md, and 40px at lg. A circle is 16px at xs,\n 24px at sm and md, and 32px at lg.',
26
+ values: ['xs', 'sm', 'md', 'lg'],
27
27
  default: 'md',
28
28
  },
29
29
  tone: {
@@ -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' | 'lg' | null>, default: 'md' },
54
+ size: { type: null as unknown as PropType<'xs' | 'sm' | '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
@@ -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' | 'lg'>(
80
+ size: checkedProp<'xs' | 'sm' | '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' | 'lg',
86
+ ) as 'xs' | 'sm' | 'md' | 'lg',
87
87
  tone: checkedProp<'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger'>(
88
88
  props['tone'],
89
89
  { kind: 'terminal', name: 'keyword' },
@@ -195,6 +195,10 @@ const hostState = computed(() =>
195
195
  syntax: "*";
196
196
  inherits: false;
197
197
  }
198
+ @property --ui-badge-circle-opacity {
199
+ syntax: "*";
200
+ inherits: false;
201
+ }
198
202
  @property --ui-badge-dot-size {
199
203
  syntax: "*";
200
204
  inherits: false;
@@ -360,6 +364,11 @@ const hostState = computed(() =>
360
364
  line-height: var(--ui-badge-line-height, 1);
361
365
  }
362
366
 
367
+ [data-component~="ui-badge"][data-ui-badge-state~="size=sm"] {
368
+ font-size: var(--ui-badge-font-size, var(--ui-font-size-2xs));
369
+ line-height: var(--ui-badge-line-height, 1);
370
+ }
371
+
363
372
  [data-component~="ui-badge"][data-ui-badge-state~="tone=accent"] {
364
373
  --_badge-surface: var(--ui-accent-strong-surface, var(--ui-accent-solid));
365
374
  --_badge-border: var(--ui-accent-strong-surface, var(--ui-accent-solid));
@@ -454,8 +463,72 @@ const hostState = computed(() =>
454
463
  background-clip: padding-box;
455
464
  }
456
465
 
466
+ /* A circular count has a tone-tinted surface, a separate lighter rim and readable tone ink.
467
+ Dark controls retain a shaded surface and theme ink with a quieter rim. */
457
468
  [data-component~="ui-badge"][data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="shape=circle"] {
458
- box-shadow: var(--ui-shadow-sm);
469
+ --_badge-color-surface: light-dark(
470
+ color-mix(
471
+ in srgb,
472
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) var(
473
+ --ui-badge-circle-opacity,
474
+ 66%
475
+ ),
476
+ transparent
477
+ ),
478
+ color-mix(
479
+ in srgb,
480
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) var(
481
+ --ui-badge-circle-opacity,
482
+ 56%
483
+ ),
484
+ transparent
485
+ )
486
+ );
487
+ --_badge-color-border: light-dark(
488
+ color-mix(
489
+ in srgb,
490
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) 88%,
491
+ transparent
492
+ ),
493
+ color-mix(
494
+ in srgb,
495
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) 44%,
496
+ transparent
497
+ )
498
+ );
499
+ --_badge-color-text: light-dark(
500
+ color-mix(in srgb, var(--_badge-color-ink) 65%, var(--ui-text-primary)),
501
+ color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-text-primary))
502
+ );
503
+ --_badge-count-surface: light-dark(
504
+ color-mix(in srgb, var(--_badge-text) var(--ui-badge-circle-opacity, 66%), transparent),
505
+ color-mix(in srgb, var(--_badge-text) var(--ui-badge-circle-opacity, 56%), transparent)
506
+ );
507
+ --_badge-outline-surface: var(
508
+ --ui-badge-surface,
509
+ var(--_badge-color-surface, var(--_badge-count-surface))
510
+ );
511
+ border-color: var(
512
+ --ui-badge-border,
513
+ var(
514
+ --_badge-color-border,
515
+ light-dark(
516
+ color-mix(in srgb, var(--_badge-text) 88%, transparent),
517
+ color-mix(in srgb, var(--_badge-text) 44%, transparent)
518
+ )
519
+ )
520
+ );
521
+ color: var(
522
+ --ui-badge-text,
523
+ var(
524
+ --_badge-color-text,
525
+ light-dark(
526
+ color-mix(in srgb, var(--_badge-surface) 65%, var(--ui-text-primary)),
527
+ var(--ui-text-primary)
528
+ )
529
+ )
530
+ );
531
+ box-shadow: 0 1px 1px light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.12));
459
532
  }
460
533
 
461
534
  /* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
package/vue/UiButton.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { PropType } from 'vue';
2
- declare var __VLS_6: {}, __VLS_8: {}, __VLS_10: {}, __VLS_22: {}, __VLS_24: {}, __VLS_26: {}, __VLS_38: {}, __VLS_45: {};
2
+ declare var __VLS_6: {}, __VLS_8: {}, __VLS_10: {}, __VLS_22: {}, __VLS_24: {}, __VLS_26: {}, __VLS_38: {}, __VLS_40: {}, __VLS_47: {}, __VLS_49: {};
3
3
  type __VLS_Slots = {} & {
4
4
  icon?: (props: typeof __VLS_6) => any;
5
5
  } & {
@@ -15,7 +15,11 @@ type __VLS_Slots = {} & {
15
15
  } & {
16
16
  default?: (props: typeof __VLS_38) => any;
17
17
  } & {
18
- default?: (props: typeof __VLS_45) => any;
18
+ badge?: (props: typeof __VLS_40) => any;
19
+ } & {
20
+ default?: (props: typeof __VLS_47) => any;
21
+ } & {
22
+ badge?: (props: typeof __VLS_49) => any;
19
23
  };
20
24
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
21
25
  align: {
package/vue/UiButton.vue CHANGED
@@ -808,7 +808,8 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
808
808
  ><span v-if="checkedProps.loading || checkedProps.pending" class="spinner-wrap"><UiSpinner
809
809
  size="sm"
810
810
  /></span>
811
- <slot /></a>
811
+ <slot />
812
+ <span class="badge"><slot name="badge" /></span></a>
812
813
  <button
813
814
  v-else
814
815
  data-component="ui-button"
@@ -839,6 +840,7 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
839
840
  size="sm"
840
841
  /></span>
841
842
  <slot />
843
+ <span class="badge"><slot name="badge" /></span>
842
844
  </button>
843
845
  </template>
844
846
 
@@ -918,6 +920,21 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
918
920
  }
919
921
 
920
922
  [data-component~="ui-button"] {
923
+ /* Optional inherited action-group values keep text and icon actions under the same light.
924
+ One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
925
+ A single ambient lift avoids stacking a face gradient or another inset bevel. */
926
+ --_ui-action-start: 1px;
927
+ --_ui-action-edge: var(
928
+ --ui-action-edge,
929
+ inset var(--_ui-action-start) 1px 0 light-dark(
930
+ rgb(255 255 255 / 0.08),
931
+ rgb(255 255 255 / 0.06)
932
+ ),
933
+ inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.08))
934
+ );
935
+ --_ui-action-shadow:
936
+ var(--_ui-action-edge),
937
+ 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20));
921
938
  --_hue: var(--ui-accent);
922
939
  --_hue-hover: var(--ui-accent-hover);
923
940
  --_hue-active: var(--ui-accent-active);
@@ -938,6 +955,10 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
938
955
  color: var(--_tone-text);
939
956
  }
940
957
 
958
+ [data-component~="ui-button"]:dir(rtl) {
959
+ --_ui-action-start: -1px;
960
+ }
961
+
941
962
  [data-component~="ui-button"][data-ui-button-state~="align=start"] {
942
963
  justify-content: flex-start;
943
964
  text-align: start;
@@ -964,8 +985,8 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
964
985
  white-space: var(--ui-button-white-space, inherit);
965
986
  line-height: var(--ui-line-height-tight);
966
987
  padding: var(--ui-space-2) var(--ui-space-3);
967
- background-image: var(--ui-raised-highlight);
968
- box-shadow: var(--ui-button-shadow, var(--ui-raised));
988
+ background-image: none;
989
+ box-shadow: var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
969
990
  cursor: pointer;
970
991
  transition:
971
992
  background-color var(--ui-motion-fast) var(--ui-motion-ease),
@@ -986,6 +1007,22 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
986
1007
  vertical-align: middle;
987
1008
  }
988
1009
 
1010
+ /* A count is an adornment, not another line of label text. Keep the standard control height
1011
+ with enough inset for a 24px mark; large content can still grow the button naturally. */
1012
+ [data-component~="ui-button"]:not([variant="link"]):has(.badge:not(:empty)) {
1013
+ padding-block: var(--ui-space-0-5);
1014
+ }
1015
+
1016
+ .badge {
1017
+ display: inline-flex;
1018
+ align-items: center;
1019
+ flex: none;
1020
+ }
1021
+
1022
+ .badge:empty {
1023
+ display: none;
1024
+ }
1025
+
989
1026
  @supports (text-box-trim: trim-both) {
990
1027
  [data-component~="ui-button"] {
991
1028
  text-box-trim: trim-both;
@@ -1059,6 +1096,15 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
1059
1096
  background-color: var(--ui-button-hover-surface, oklch(from var(--_tone) l c h / 12%));
1060
1097
  }
1061
1098
 
1099
+ /* A neutral card encloses content quietly; ordinary outlines keep their action-tone edge. */
1100
+ [data-component~="ui-button"][data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"] {
1101
+ border-color: var(--ui-button-border, var(--ui-border));
1102
+ }
1103
+
1104
+ [data-component~="ui-button"][data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"]:hover:not(:disabled, [aria-disabled="true"]) {
1105
+ border-color: var(--ui-button-hover-border, var(--ui-border-strong));
1106
+ }
1107
+
1062
1108
  /* Pressed reads as pressed in: the highlight goes, and the shadow moves inside. */
1063
1109
  [data-component~="ui-button"]:active:not(:disabled, [aria-disabled="true"]) {
1064
1110
  background-color: var(--ui-button-active-surface, oklch(from var(--_tone) l c h / 18%));
@@ -1071,7 +1117,7 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
1071
1117
  border-color: var(--_tone);
1072
1118
  background-color: var(--_tone);
1073
1119
  color: var(--_on-tone);
1074
- box-shadow: var(--ui-button-solid-shadow, var(--ui-raised));
1120
+ box-shadow: var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
1075
1121
  }
1076
1122
 
1077
1123
  :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"], [data-component~="ui-button"][data-ui-button-state~="variant=danger"]):hover:not(:disabled, [aria-disabled="true"]) {
@@ -1159,16 +1205,20 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
1159
1205
  [data-component~="ui-button"]:focus-visible {
1160
1206
  outline: none;
1161
1207
  box-shadow:
1162
- var(--ui-button-shadow, var(--ui-raised)),
1208
+ var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
1163
1209
  var(--ui-focus-halo);
1164
1210
  }
1165
1211
 
1166
1212
  [data-component~="ui-button"][data-ui-button-state~="variant=solid"]:focus-visible {
1167
1213
  box-shadow:
1168
- var(--ui-button-solid-shadow, var(--ui-raised)),
1214
+ var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
1169
1215
  var(--ui-focus-halo);
1170
1216
  }
1171
1217
 
1218
+ :is([data-component~="ui-button"][data-ui-button-state~="variant=ghost"], [data-component~="ui-button"][data-ui-button-state~="variant=link"], [data-component~="ui-button"][data-ui-button-state~="variant=card"]):focus-visible {
1219
+ box-shadow: var(--ui-focus-halo);
1220
+ }
1221
+
1172
1222
  /* A loading action stays visually active; only an explicitly disabled action takes the
1173
1223
  neutral disabled palette. Its flat surface and muted ink make the state unambiguous. */
1174
1224
  [data-component~="ui-button"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
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));
@@ -474,6 +474,21 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
474
474
  }
475
475
 
476
476
  [data-component~="ui-icon-button"] {
477
+ /* Optional inherited action-group values keep text and icon actions under the same light.
478
+ One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
479
+ A single ambient lift avoids stacking a face gradient or another inset bevel. */
480
+ --_ui-action-start: 1px;
481
+ --_ui-action-edge: var(
482
+ --ui-action-edge,
483
+ inset var(--_ui-action-start) 1px 0 light-dark(
484
+ rgb(255 255 255 / 0.08),
485
+ rgb(255 255 255 / 0.06)
486
+ ),
487
+ inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.08))
488
+ );
489
+ --_ui-action-shadow:
490
+ var(--_ui-action-edge),
491
+ 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20));
477
492
  /* Hooks do not inherit, so the parts below read them from the root. */
478
493
  --_ui-icon-button-icon-size: var(--ui-icon-button-icon-size);
479
494
  --_ui-icon-button-icon-stroke-width: var(--ui-icon-button-icon-stroke-width);
@@ -482,6 +497,10 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
482
497
  color: var(--ui-text-secondary);
483
498
  }
484
499
 
500
+ [data-component~="ui-icon-button"]:dir(rtl) {
501
+ --_ui-action-start: -1px;
502
+ }
503
+
485
504
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="tone=accent"] {
486
505
  --_icon-button-border: var(--ui-accent-solid);
487
506
  --_icon-button-hover-border: var(--ui-accent-hover);
@@ -670,9 +689,9 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"]::after {
670
689
  --ui-icon-button-outline-surface,
671
690
  var(--_icon-button-outline-surface, var(--ui-surface-default))
672
691
  );
673
- background-image: var(--ui-raised-highlight);
692
+ background-image: none;
674
693
  color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
675
- box-shadow: var(--ui-raised);
694
+ box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow));
676
695
  }
677
696
 
678
697
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"] {
@@ -680,12 +699,9 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"]::after {
680
699
  --ui-icon-button-solid-surface,
681
700
  var(--_icon-button-solid-surface, var(--ui-accent-solid))
682
701
  );
683
- background-image: var(--ui-raised-highlight);
702
+ background-image: none;
684
703
  color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
685
- box-shadow: var(
686
- --ui-icon-button-solid-shadow,
687
- 0 1px 2px color-mix(in srgb, var(--ui-accent-solid) 18%, transparent)
688
- );
704
+ box-shadow: var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
689
705
  }
690
706
 
691
707
  [data-component~="ui-icon-button"]:hover:enabled:not([aria-disabled="true"]) {
@@ -765,6 +781,23 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"]::after {
765
781
  box-shadow: var(--ui-focus-halo);
766
782
  }
767
783
 
784
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"]:focus-visible {
785
+ box-shadow:
786
+ var(--ui-action-shadow, var(--_ui-action-shadow)),
787
+ var(--ui-focus-halo);
788
+ }
789
+
790
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"]:focus-visible {
791
+ box-shadow:
792
+ var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
793
+ var(--ui-focus-halo);
794
+ }
795
+
796
+ [data-component~="ui-icon-button"]:is([data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=solid"]):active:enabled:not([aria-disabled="true"]) {
797
+ background-image: none;
798
+ box-shadow: var(--ui-pressed);
799
+ }
800
+
768
801
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible {
769
802
  box-shadow:
770
803
  var(--ui-pressed),
@@ -26,6 +26,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
26
26
  type: PropType<"text" | "icon" | null>;
27
27
  default: string;
28
28
  };
29
+ variant: {
30
+ type: PropType<"outline" | "subtle" | null>;
31
+ default: string;
32
+ };
29
33
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
30
34
  actionPosition: {
31
35
  type: PropType<"below" | "top-end" | null>;
@@ -43,7 +47,12 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
43
47
  type: PropType<"text" | "icon" | null>;
44
48
  default: string;
45
49
  };
50
+ variant: {
51
+ type: PropType<"outline" | "subtle" | null>;
52
+ default: string;
53
+ };
46
54
  }>> & Readonly<{}>, {
55
+ variant: "subtle" | "outline" | null;
47
56
  disabled: boolean | null;
48
57
  multiline: boolean | null;
49
58
  actionPosition: "top-end" | "below" | null;
@@ -42,6 +42,15 @@ const propValidityContract = {
42
42
  values: ['text', 'icon'],
43
43
  default: 'text',
44
44
  },
45
+ variant: {
46
+ type: { kind: 'terminal', name: 'keyword' },
47
+ required: false,
48
+ target: { attribute: 'variant' },
49
+ description:
50
+ 'outline uses the standard field edge and surface. subtle uses a quiet decorative edge and muted surface for a multiline composer. Both retain the same\n focus, invalid and disabled states, and the field inside shares the group\'s one frame.',
51
+ values: ['outline', 'subtle'],
52
+ default: 'outline',
53
+ },
45
54
  },
46
55
  } as const
47
56
  const props = defineProps({
@@ -52,12 +61,14 @@ const props = defineProps({
52
61
  disabled: { type: null as unknown as PropType<boolean | null>, default: false },
53
62
  multiline: { type: null as unknown as PropType<boolean | null>, default: false },
54
63
  prefixKind: { type: null as unknown as PropType<'text' | 'icon' | null>, default: 'text' },
64
+ variant: { type: null as unknown as PropType<'outline' | 'subtle' | null>, default: 'outline' },
55
65
  })
56
66
  const acceptedProps: Record<string, unknown> = {
57
67
  actionPosition: 'below',
58
68
  disabled: false,
59
69
  multiline: false,
60
70
  prefixKind: 'text',
71
+ variant: 'outline',
61
72
  }
62
73
  const checkedProps = computed(() => ({
63
74
  actionPosition: checkedProp<'below' | 'top-end'>(
@@ -88,6 +99,13 @@ const checkedProps = computed(() => ({
88
99
  'prefixKind',
89
100
  acceptedProps,
90
101
  ) as 'text' | 'icon',
102
+ variant: checkedProp<'outline' | 'subtle'>(
103
+ props['variant'],
104
+ { kind: 'terminal', name: 'keyword' },
105
+ false,
106
+ 'variant',
107
+ acceptedProps,
108
+ ) as 'outline' | 'subtle',
91
109
  }))
92
110
  void checkedProps.value
93
111
  watchSyncEffect(() => {
@@ -148,6 +166,9 @@ if (
148
166
  /** The values the styles' :host-state() rules test. */
149
167
  const hostState = computed(() =>
150
168
  [
169
+ checkedProps.value.variant && 'variant',
170
+ checkedProps.value.variant != null
171
+ && `variant=${encodeURIComponent(checkedProps.value.variant)}`,
151
172
  checkedProps.value.disabled && 'disabled',
152
173
  checkedProps.value.prefixKind && 'prefixKind',
153
174
  checkedProps.value.prefixKind != null
@@ -176,7 +197,7 @@ useComponentHost(() => import('../components/ui-input-group/ui-input-group.js'),
176
197
  ? (incoming[name] ?? incoming[kebab] ?? null)
177
198
  : null
178
199
  },
179
- propNames: ['actionPosition', 'disabled', 'multiline', 'prefixKind'],
200
+ propNames: ['actionPosition', 'disabled', 'multiline', 'prefixKind', 'variant'],
180
201
  propValidity: (name: string) =>
181
202
  propValidityState({ contract: propValidityContract, values: { ...props } }, name),
182
203
  })
@@ -191,6 +212,7 @@ useComponentHost(() => import('../components/ui-input-group/ui-input-group.js'),
191
212
  :data-disabled="reflectedProp('disabled', 'disabled', checkedProps.disabled, undefined, false)"
192
213
  :data-multiline="reflectedProp('multiline', 'multiline', checkedProps.multiline, undefined, false)"
193
214
  :data-prefix-kind="reflectedProp('prefixKind', 'prefix-kind', checkedProps.prefixKind, undefined, false)"
215
+ :data-variant="reflectedProp('variant', 'variant', checkedProps.variant, undefined, false)"
194
216
  :data-ui-input-group-state="hostState || undefined"
195
217
  ref="root"
196
218
  >
@@ -268,6 +290,12 @@ useComponentHost(() => import('../components/ui-input-group/ui-input-group.js'),
268
290
  box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
269
291
  }
270
292
 
293
+ [data-component~="ui-input-group"][data-ui-input-group-state~="variant=subtle"] {
294
+ border-color: var(--ui-border);
295
+ background: var(--ui-surface-muted);
296
+ box-shadow: none;
297
+ }
298
+
271
299
  /* The frame takes its input's size, so a small group lines up with small buttons and fields. */
272
300
  [data-component~="ui-input-group"]:has(.field [data-ui-input-state~="size=sm"]) {
273
301
  min-block-size: var(--ui-control-size-sm);
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. */
@@ -63,9 +63,10 @@ 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 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+.",
66
+ description: "Scale. xs is compact; sm keeps the usual badge geometry with compact text, fitting short counts such as 99+ inside a 24px circle. md is the usual text\n badge; lg adds room to fixed marks while retaining the usual text size. A square is 24px at xs, 32px at sm and md, and 40px at lg. A circle is 16px at xs,\n 24px at sm and md, and 32px at lg.",
67
67
  values: [
68
68
  "xs",
69
+ "sm",
69
70
  "md",
70
71
  "lg"
71
72
  ],
@@ -179,6 +180,6 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
179
180
  }]]);
180
181
  };
181
182
  }
182
- }), [["__scopeId", "data-v-4d2f1396"]]);
183
+ }), [["__scopeId", "data-v-57826cf9"]]);
183
184
  //#endregion
184
185
  export { UiBadge_default as t };