@threadlabs/looma 0.26.25 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/components/shared/editor.js +4 -5
  2. package/components/shared/overlay.js +231 -55
  3. package/components/ui-affordance-scope/ui-affordance-scope.js +4 -8
  4. package/components/ui-card/ui-card.html +3 -0
  5. package/components/ui-dialog/ui-dialog.html +7 -5
  6. package/components/ui-dialog/ui-dialog.js +67 -7
  7. package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +6 -0
  8. package/components/ui-editor-mention-menu/ui-editor-mention-menu.js +5 -9
  9. package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +6 -0
  10. package/components/ui-editor-slash-menu/ui-editor-slash-menu.js +5 -9
  11. package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +21 -4
  12. package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.js +50 -22
  13. package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +4 -6
  14. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +3 -11
  15. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +33 -44
  16. package/components/ui-icon-button/ui-icon-button.html +12 -2
  17. package/components/ui-listbox/ui-listbox.html +22 -17
  18. package/components/ui-menu/ui-menu.js +5 -3
  19. package/components/ui-popover/ui-popover.js +3 -2
  20. package/components/ui-scroll-area/ui-scroll-area.html +16 -0
  21. package/components/ui-search-shell/ui-search-shell.html +1 -1
  22. package/components/ui-search-shell/ui-search-shell.js +3 -5
  23. package/components/ui-section/ui-section.html +3 -0
  24. package/components/ui-toast/ui-toast.html +2 -1
  25. package/components/ui-toast/ui-toast.js +18 -2
  26. package/components/ui-toast-region/ui-toast-region.js +11 -3
  27. package/components/ui-tooltip/ui-tooltip.html +2 -1
  28. package/components/ui-tooltip/ui-tooltip.js +20 -0
  29. package/dist/index.js +1 -1
  30. package/editor/chunks/extensions.js +2 -0
  31. package/editor/extensions/slash-command.d.ts +2 -0
  32. package/editor/mention-contract.d.ts +2 -0
  33. package/package.json +1 -1
  34. package/styles/ui-card.css +3 -0
  35. package/styles/ui-dialog.css +4 -2
  36. package/styles/ui-editor-mention-menu.css +7 -1
  37. package/styles/ui-editor-slash-menu.css +7 -1
  38. package/styles/ui-editor-table-context-menu.css +29 -5
  39. package/styles/ui-editor-table-toolbar.css +3 -11
  40. package/styles/ui-icon-button.css +9 -2
  41. package/styles/ui-listbox.css +6 -0
  42. package/styles/ui-scroll-area.css +13 -0
  43. package/styles/ui-search-shell.css +1 -1
  44. package/styles/ui-section.css +3 -0
  45. package/vanilla/UiDialog.js +10 -6
  46. package/vanilla/UiIconButton.d.ts +1 -0
  47. package/vanilla/UiIconButton.js +14 -14
  48. package/vanilla/UiListbox.js +10 -9
  49. package/vanilla/UiScrollArea.d.ts +1 -0
  50. package/vanilla/UiScrollArea.js +4 -4
  51. package/vue/UiCard.vue +3 -0
  52. package/vue/UiDialog.vue +12 -6
  53. package/vue/UiEditorMentionMenu.vue +6 -0
  54. package/vue/UiEditorSlashMenu.vue +6 -0
  55. package/vue/UiEditorTableContextMenu.vue +21 -4
  56. package/vue/UiEditorTableToolbar.vue +3 -11
  57. package/vue/UiIconButton.d.ts +9 -0
  58. package/vue/UiIconButton.vue +31 -2
  59. package/vue/UiListbox.vue +20 -15
  60. package/vue/UiScrollArea.d.ts +9 -0
  61. package/vue/UiScrollArea.vue +39 -1
  62. package/vue/UiSearchShell.vue +1 -1
  63. package/vue/UiSection.vue +3 -0
  64. package/vue/UiToast.vue +1 -1
  65. package/vue/UiTooltip.vue +1 -1
  66. package/vue/chunks/UiCard.js +1 -1
  67. package/vue/chunks/UiDialog.js +25 -8
  68. package/vue/chunks/UiEditorMentionMenu.js +1 -1
  69. package/vue/chunks/UiEditorSlashMenu.js +1 -1
  70. package/vue/chunks/UiEditorTableContextMenu.js +1 -1
  71. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  72. package/vue/chunks/UiIconButton.js +26 -1
  73. package/vue/chunks/UiListbox.js +12 -12
  74. package/vue/chunks/UiScrollArea.js +33 -2
  75. package/vue/chunks/UiSearchShell.js +1 -1
  76. package/vue/chunks/UiSection.js +1 -1
  77. package/vue/chunks/UiToast.js +2 -2
  78. package/vue/chunks/UiTooltip.js +2 -2
  79. package/vue/components.css +340 -289
  80. package/vue/editor/index.js +225 -40
@@ -654,10 +654,16 @@ function uniqueKeys<T>(
654
654
  </template>
655
655
 
656
656
  <style scoped>
657
+ [data-component~="ui-editor-table-context-menu"][popover] {
658
+ position: fixed;
659
+ inset: auto;
660
+ margin: 0;
661
+ }
662
+
657
663
  [data-component~="ui-editor-table-context-menu"] {
658
664
  /* The max-width is a promise about the menu's footprint, so it counts padding and border. */
659
665
  box-sizing: border-box;
660
- min-width: 14rem;
666
+ min-width: min(14rem, calc(100vw - 24px));
661
667
  max-width: min(17rem, calc(100vw - 24px));
662
668
  max-height: min(28rem, calc(100vh - 24px));
663
669
  padding: var(--ui-space-2);
@@ -712,16 +718,22 @@ function uniqueKeys<T>(
712
718
  color: var(--ui-danger);
713
719
  }
714
720
 
721
+ /* Swatches wrap like words: the row asks for the menu's full width, and a narrower menu fits fewer. */
715
722
  .swatches {
716
- display: grid;
717
- grid-template-columns: repeat(3, minmax(0, 1fr));
723
+ display: flex;
724
+ flex-wrap: wrap;
718
725
  gap: 3px;
719
726
  }
720
727
 
721
- .swatch-button {
728
+ /* Three to a row at the menu's full width; 5rem keeps the longest label, "Default", whole. */
729
+ [data-component~="ui-editor-table-context-menu"] .swatch-button {
722
730
  display: inline-flex;
723
731
  align-items: center;
724
732
  gap: var(--ui-space-2);
733
+ flex: 1 0 5rem;
734
+ min-width: 5rem;
735
+ max-width: calc((100% - 6px) / 3);
736
+ padding-inline-end: var(--ui-space-1);
725
737
  }
726
738
 
727
739
  .swatch {
@@ -768,6 +780,11 @@ function uniqueKeys<T>(
768
780
  margin: var(--ui-space-1) 0;
769
781
  }
770
782
 
783
+ /* Separators divide sections, so none sits above the first. */
784
+ .sep:first-child {
785
+ display: none;
786
+ }
787
+
771
788
  [data-component~="ui-editor-table-context-menu"][hidden] {
772
789
  display: none;
773
790
  }
@@ -796,14 +796,6 @@ function uniqueKeys<T>(
796
796
  background: var(--ui-accent-soft, var(--ui-accent-subtle));
797
797
  }
798
798
 
799
- .looma-editor__mobile-toolbar-shell [data-component~="ui-editor-table-toolbar"] .menu {
800
- top: auto;
801
- right: 0;
802
- bottom: calc(100% + var(--ui-space-2));
803
- max-height: min(50dvh, 22rem);
804
- overflow-y: auto;
805
- overscroll-behavior: contain;
806
- }
807
799
  [data-component~="ui-editor-table-toolbar"] {
808
800
  display: inline-flex;
809
801
  align-items: center;
@@ -894,9 +886,9 @@ function uniqueKeys<T>(
894
886
 
895
887
  .menu {
896
888
  box-sizing: border-box;
897
- position: absolute;
898
- top: calc(100% + var(--ui-space-2));
899
- right: 0;
889
+ position: fixed;
890
+ inset: auto;
891
+ margin: 0;
900
892
  min-width: 12rem;
901
893
  max-width: min(17rem, calc(100vw - 24px));
902
894
  padding: var(--ui-space-1);
@@ -12,6 +12,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
12
12
  type: PropType<boolean | null>;
13
13
  default: boolean;
14
14
  };
15
+ guide: {
16
+ type: PropType<"dot" | "bar" | null>;
17
+ default: string;
18
+ };
15
19
  label: {
16
20
  type: PropType<string | null>;
17
21
  default: null;
@@ -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
+ guide: {
61
+ type: PropType<"dot" | "bar" | null>;
62
+ default: string;
63
+ };
56
64
  label: {
57
65
  type: PropType<string | null>;
58
66
  default: null;
@@ -87,6 +95,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
87
95
  };
88
96
  }>> & Readonly<{}>, {
89
97
  label: string | null;
98
+ guide: "bar" | "dot" | null;
90
99
  round: boolean | null;
91
100
  size: "sm" | "md" | "lg" | null;
92
101
  tone: "neutral" | "accent" | null;
@@ -26,6 +26,15 @@ const propValidityContract = {
26
26
  'Disables the button, so it cannot be pressed or focused, and gives it a flat neutral surface and muted icon.',
27
27
  default: false,
28
28
  },
29
+ guide: {
30
+ type: { kind: 'terminal', name: 'keyword' },
31
+ required: false,
32
+ target: { attribute: 'guide' },
33
+ description:
34
+ 'The idle marker of an anticipatory button: dot for contextual actions, or a slim neutral rounded bar for a panel-edge control. The icon appears on hover or\n keyboard focus; touch always shows the icon.',
35
+ values: ['dot', 'bar'],
36
+ default: 'dot',
37
+ },
29
38
  label: {
30
39
  type: { kind: 'terminal', name: 'string' },
31
40
  required: false,
@@ -93,6 +102,7 @@ const propValidityContract = {
93
102
  const props = defineProps({
94
103
  anticipatory: { type: null as unknown as PropType<boolean | null>, default: false },
95
104
  disabled: { type: null as unknown as PropType<boolean | null>, default: false },
105
+ guide: { type: null as unknown as PropType<'dot' | 'bar' | null>, default: 'dot' },
96
106
  label: { type: null as unknown as PropType<string | null>, default: null },
97
107
  loading: { type: null as unknown as PropType<boolean | null>, default: false },
98
108
  matchButton: { type: null as unknown as PropType<boolean | null>, default: false },
@@ -108,6 +118,7 @@ const props = defineProps({
108
118
  const acceptedProps: Record<string, unknown> = {
109
119
  anticipatory: false,
110
120
  disabled: false,
121
+ guide: 'dot',
111
122
  label: null,
112
123
  loading: false,
113
124
  matchButton: false,
@@ -132,6 +143,13 @@ const checkedProps = computed(() => ({
132
143
  'disabled',
133
144
  acceptedProps,
134
145
  ) as boolean,
146
+ guide: checkedProp<'dot' | 'bar'>(
147
+ props['guide'],
148
+ { kind: 'terminal', name: 'keyword' },
149
+ false,
150
+ 'guide',
151
+ acceptedProps,
152
+ ) as 'dot' | 'bar',
135
153
  label: checkedProp<string>(
136
154
  props['label'],
137
155
  { kind: 'terminal', name: 'string' },
@@ -289,6 +307,8 @@ const hostState = computed(() =>
289
307
  checkedProps.value.tone && 'tone',
290
308
  checkedProps.value.tone != null && `tone=${encodeURIComponent(checkedProps.value.tone)}`,
291
309
  checkedProps.value.anticipatory && 'anticipatory',
310
+ checkedProps.value.guide && 'guide',
311
+ checkedProps.value.guide != null && `guide=${encodeURIComponent(checkedProps.value.guide)}`,
292
312
  checkedProps.value.variant && 'variant',
293
313
  checkedProps.value.variant != null
294
314
  && `variant=${encodeURIComponent(checkedProps.value.variant)}`,
@@ -321,6 +341,7 @@ useComponentHost(() => import('../components/ui-icon-button/ui-icon-button.js'),
321
341
  propNames: [
322
342
  'anticipatory',
323
343
  'disabled',
344
+ 'guide',
324
345
  'label',
325
346
  'loading',
326
347
  'matchButton',
@@ -378,6 +399,7 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
378
399
  v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
379
400
  :data-anticipatory="reflectedProp('anticipatory', 'anticipatory', checkedProps.anticipatory, undefined, false)"
380
401
  :data-disabled="reflectedProp('disabled', 'disabled', checkedProps.disabled, undefined, false)"
402
+ :data-guide="reflectedProp('guide', 'guide', checkedProps.guide, undefined, false)"
381
403
  :data-label="reflectedProp('label', 'label', checkedProps.label, undefined, false)"
382
404
  :data-loading="reflectedProp('loading', 'loading', checkedProps.loading, undefined, false)"
383
405
  :data-match-button="reflectedProp('matchButton', 'match-button', checkedProps.matchButton, undefined, true)"
@@ -539,6 +561,13 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
539
561
  pointer-events: none;
540
562
  }
541
563
 
564
+ [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"][data-ui-icon-button-state~="guide=bar"]::before {
565
+ inline-size: 2px;
566
+ block-size: 20px;
567
+ background: var(--ui-border-strong);
568
+ opacity: 1;
569
+ }
570
+
542
571
  [data-component~="ui-icon-button"][data-ui-icon-button-state~="anticipatory"]:disabled::before {
543
572
  opacity: 0;
544
573
  }
@@ -595,7 +624,7 @@ function concat<T extends unknown[]>(...values: T): ConcatResult<T> {
595
624
  border-color var(--ui-motion-fast) var(--ui-motion-ease),
596
625
  color var(--ui-motion-fast) var(--ui-motion-ease),
597
626
  box-shadow var(--ui-motion-base) var(--ui-motion-ease),
598
- transform var(--ui-motion-fast) var(--ui-motion-ease);
627
+ scale var(--ui-motion-fast) var(--ui-motion-ease);
599
628
  }
600
629
 
601
630
  @media (hover: none), (pointer: coarse) {
@@ -752,7 +781,7 @@ html[data-ui-input-modality="touch"] [data-component~="ui-icon-button"]::after {
752
781
  }
753
782
 
754
783
  [data-component~="ui-icon-button"]:active:enabled:not([aria-disabled="true"]) {
755
- transform: scale(var(--ui-icon-button-active-scale, 0.96));
784
+ scale: var(--ui-icon-button-active-scale, 0.96);
756
785
  }
757
786
 
758
787
  :is([data-component~="ui-icon-button"][data-ui-icon-button-state~="loading"], [data-component~="ui-icon-button"][data-ui-icon-button-state~="pending"]) {
package/vue/UiListbox.vue CHANGED
@@ -479,21 +479,23 @@ function uniqueKeys<T>(
479
479
  :data-values="reflectedProp('values', 'values', checkedProps.values, undefined, false)"
480
480
  ref="root"
481
481
  >
482
- <UiScrollArea class="choices" ref="choicesElement"><KeyedBoundary><div
483
- v-for="choice in uniqueKeys(choices, (choice, index, loop) => choice.index)"
484
- :key="choice.index"
485
- class="option"
486
- role="option"
487
- data-ui-choice-option=""
488
- :data-multiple="checkedProps.multiple ? '' : undefined"
489
- :id="concat(uid, '-option-', choice.index)"
490
- :data-index="choice.index"
491
- :aria-selected="choice.selected"
492
- :aria-disabled="choice.disabled"
493
- :class="{ active: choice.index === active }"
494
- >
495
- <span>{{ choice.label }}</span>
496
- </div></KeyedBoundary></UiScrollArea>
482
+ <div class="choices">
483
+ <UiScrollArea ref="choicesElement"><KeyedBoundary><div
484
+ v-for="choice in uniqueKeys(choices, (choice, index, loop) => choice.index)"
485
+ :key="choice.index"
486
+ class="option"
487
+ role="option"
488
+ data-ui-choice-option=""
489
+ :data-multiple="checkedProps.multiple ? '' : undefined"
490
+ :id="concat(uid, '-option-', choice.index)"
491
+ :data-index="choice.index"
492
+ :aria-selected="choice.selected"
493
+ :aria-disabled="choice.disabled"
494
+ :class="{ active: choice.index === active }"
495
+ >
496
+ <span>{{ choice.label }}</span>
497
+ </div></KeyedBoundary></UiScrollArea>
498
+ </div>
497
499
  <select
498
500
  class="fallback"
499
501
  aria-label="Choices"
@@ -566,7 +568,10 @@ function uniqueKeys<T>(
566
568
  outline: none;
567
569
  }
568
570
 
571
+ /* Its own box around the nested Scroll Area, which it shrinks into so the choices scroll. */
569
572
  .choices {
573
+ display: flex;
574
+ flex-direction: column;
570
575
  max-block-size: calc(max(2, var(--_rows, 5)) * var(--ui-control-size-md));
571
576
  }
572
577
 
@@ -12,6 +12,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
12
12
  type: PropType<"vertical" | "horizontal" | null>;
13
13
  default: string;
14
14
  };
15
+ padding: {
16
+ type: PropType<"none" | "xs" | "sm" | "md" | "lg" | null>;
17
+ default: string;
18
+ };
15
19
  size: {
16
20
  type: PropType<"content" | "sm" | "md" | "lg" | null>;
17
21
  default: string;
@@ -29,6 +33,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
29
33
  type: PropType<"vertical" | "horizontal" | null>;
30
34
  default: string;
31
35
  };
36
+ padding: {
37
+ type: PropType<"none" | "xs" | "sm" | "md" | "lg" | null>;
38
+ default: string;
39
+ };
32
40
  size: {
33
41
  type: PropType<"content" | "sm" | "md" | "lg" | null>;
34
42
  default: string;
@@ -40,6 +48,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
40
48
  }>> & Readonly<{}>, {
41
49
  fill: boolean | null;
42
50
  size: "sm" | "md" | "lg" | "content" | null;
51
+ padding: "none" | "xs" | "sm" | "md" | "lg" | null;
43
52
  trim: boolean | null;
44
53
  orientation: "vertical" | "horizontal" | null;
45
54
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -26,6 +26,15 @@ const propValidityContract = {
26
26
  values: ['vertical', 'horizontal'],
27
27
  default: 'vertical',
28
28
  },
29
+ padding: {
30
+ type: { kind: 'terminal', name: 'keyword' },
31
+ required: false,
32
+ target: { attribute: 'padding' },
33
+ description:
34
+ 'The space inside the scrolling region, on Card\'s scale: xs is 0.5rem, sm 0.75rem, md 1.5rem, and lg 2rem. It scrolls with the content, so the scrollbar and\n fades stay at the edges.',
35
+ values: ['none', 'xs', 'sm', 'md', 'lg'],
36
+ default: 'none',
37
+ },
29
38
  size: {
30
39
  type: { kind: 'terminal', name: 'keyword' },
31
40
  required: false,
@@ -51,6 +60,10 @@ const props = defineProps({
51
60
  type: null as unknown as PropType<'vertical' | 'horizontal' | null>,
52
61
  default: 'vertical',
53
62
  },
63
+ padding: {
64
+ type: null as unknown as PropType<'none' | 'xs' | 'sm' | 'md' | 'lg' | null>,
65
+ default: 'none',
66
+ },
54
67
  size: {
55
68
  type: null as unknown as PropType<'content' | 'sm' | 'md' | 'lg' | null>,
56
69
  default: 'content',
@@ -60,6 +73,7 @@ const props = defineProps({
60
73
  const acceptedProps: Record<string, unknown> = {
61
74
  fill: false,
62
75
  orientation: 'vertical',
76
+ padding: 'none',
63
77
  size: 'content',
64
78
  trim: false,
65
79
  }
@@ -78,6 +92,13 @@ const checkedProps = computed(() => ({
78
92
  'orientation',
79
93
  acceptedProps,
80
94
  ) as 'vertical' | 'horizontal',
95
+ padding: checkedProp<'none' | 'xs' | 'sm' | 'md' | 'lg'>(
96
+ props['padding'],
97
+ { kind: 'terminal', name: 'keyword' },
98
+ false,
99
+ 'padding',
100
+ acceptedProps,
101
+ ) as 'none' | 'xs' | 'sm' | 'md' | 'lg',
81
102
  size: checkedProp<'content' | 'sm' | 'md' | 'lg'>(
82
103
  props['size'],
83
104
  { kind: 'terminal', name: 'keyword' },
@@ -160,6 +181,9 @@ const hostState = computed(() =>
160
181
  && `orientation=${encodeURIComponent(checkedProps.value.orientation)}`,
161
182
  checkedProps.value.size && 'size',
162
183
  checkedProps.value.size != null && `size=${encodeURIComponent(checkedProps.value.size)}`,
184
+ checkedProps.value.padding && 'padding',
185
+ checkedProps.value.padding != null
186
+ && `padding=${encodeURIComponent(checkedProps.value.padding)}`,
163
187
  ].filter(Boolean).join(' ')
164
188
  )
165
189
 
@@ -180,7 +204,7 @@ useComponentHost(() => import('../components/ui-scroll-area/ui-scroll-area.js'),
180
204
  ? (incoming[name] ?? incoming[kebab] ?? null)
181
205
  : null
182
206
  },
183
- propNames: ['fill', 'orientation', 'size', 'trim'],
207
+ propNames: ['fill', 'orientation', 'padding', 'size', 'trim'],
184
208
  propValidity: (name: string) =>
185
209
  propValidityState({ contract: propValidityContract, values: { ...props } }, name),
186
210
  refs: { content: contentElement },
@@ -194,6 +218,7 @@ useComponentHost(() => import('../components/ui-scroll-area/ui-scroll-area.js'),
194
218
  v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
195
219
  :data-fill="reflectedProp('fill', 'fill', checkedProps.fill, undefined, false)"
196
220
  :data-orientation="reflectedProp('orientation', 'orientation', checkedProps.orientation, undefined, false)"
221
+ :data-padding="reflectedProp('padding', 'padding', checkedProps.padding, undefined, false)"
197
222
  :data-size="reflectedProp('size', 'size', checkedProps.size, undefined, false)"
198
223
  :data-trim="reflectedProp('trim', 'trim', checkedProps.trim, undefined, false)"
199
224
  :data-ui-scroll-area-state="hostState || undefined"
@@ -268,6 +293,19 @@ useComponentHost(() => import('../components/ui-scroll-area/ui-scroll-area.js'),
268
293
  max-block-size: 30rem;
269
294
  }
270
295
 
296
+ [data-component~="ui-scroll-area"][data-ui-scroll-area-state~="padding=xs"] {
297
+ padding: var(--ui-space-2);
298
+ }
299
+ [data-component~="ui-scroll-area"][data-ui-scroll-area-state~="padding=sm"] {
300
+ padding: var(--ui-space-3);
301
+ }
302
+ [data-component~="ui-scroll-area"][data-ui-scroll-area-state~="padding=md"] {
303
+ padding: var(--ui-space-5);
304
+ }
305
+ [data-component~="ui-scroll-area"][data-ui-scroll-area-state~="padding=lg"] {
306
+ padding: var(--ui-space-6);
307
+ }
308
+
271
309
  /* A component that sets its display still honours the hidden attribute on its root. */
272
310
  [data-component~="ui-scroll-area"][hidden] {
273
311
  display: none;
@@ -302,7 +302,7 @@ dialog {
302
302
  color: var(--ui-text-primary);
303
303
  }
304
304
 
305
- dialog::backdrop {
305
+ dialog:modal::backdrop {
306
306
  background: var(--ui-overlay-backdrop);
307
307
  }
308
308
 
package/vue/UiSection.vue CHANGED
@@ -191,6 +191,9 @@ const hostState = computed(() =>
191
191
  --_ui-selection-context-text: var(--ui-text-primary);
192
192
  border-color: color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border-default));
193
193
  border-inline-start: var(--ui-accent-line-width) solid var(--ui-danger);
194
+ /* An accent edge keeps the corners on its side straight. */
195
+ border-start-start-radius: 0;
196
+ border-end-start-radius: 0;
194
197
  background: var(--ui-danger-soft);
195
198
  }
196
199
 
package/vue/UiToast.vue CHANGED
@@ -16,7 +16,7 @@ const propValidityContract = {
16
16
  required: false,
17
17
  target: { attribute: 'duration' },
18
18
  description:
19
- 'Milliseconds before requesting dismissal; 0 keeps the toast until an action dismisses it. The timer pauses on hover or focus.',
19
+ 'Milliseconds the toast is shown before it dismisses itself; 0 keeps it until an action dismisses it. The timer starts when the toast is shown, starts again\n each time it is shown, and pauses on hover or focus.',
20
20
  default: 0,
21
21
  },
22
22
  tone: {
package/vue/UiTooltip.vue CHANGED
@@ -84,7 +84,7 @@ const propValidityContract = {
84
84
  required: false,
85
85
  target: { attribute: 'trigger' },
86
86
  description:
87
- 'How the trigger opens it. hover also opens on keyboard focus; click toggles it and suits a help button, where hovering a question mark says nothing; focus\n opens only while the trigger holds focus.',
87
+ 'How the trigger opens it. hover also opens on keyboard focus; click toggles it and suits a help button, where hovering a question mark says nothing; focus\n opens only on keyboard-visible focus. Action activation dismisses hover/focus hints without removing focus; a fresh hover or keyboard focus can open them\n again.',
88
88
  values: ['hover', 'click', 'focus'],
89
89
  default: 'hover',
90
90
  },
@@ -274,6 +274,6 @@ var UiCard_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
274
274
  }]]);
275
275
  };
276
276
  }
277
- }), [["__scopeId", "data-v-150bfc3d"]]);
277
+ }), [["__scopeId", "data-v-b5f8424c"]]);
278
278
  //#endregion
279
279
  export { UiCard_default as t };
@@ -20,7 +20,6 @@ var _hoisted_2 = {
20
20
  key: 0,
21
21
  class: "title"
22
22
  };
23
- var _hoisted_3 = { class: "body" };
24
23
  var htmlNextAuthoredCheck2Reported = /* @__PURE__ */ new Set();
25
24
  function htmlNextAuthoredCheck2(accepted, location, message) {
26
25
  if (!accepted && !htmlNextAuthoredCheck2Reported.has(location)) {
@@ -229,7 +228,10 @@ var UiDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
229
228
  const hydrationInstance = getCurrentInstance();
230
229
  const emit = __emit;
231
230
  const root = ref(null);
231
+ const headerElement = useTemplateRef("headerElement");
232
232
  const closeElement = useTemplateRef("closeElement");
233
+ const bodyElement = useTemplateRef("bodyElement");
234
+ const footerElement = useTemplateRef("footerElement");
233
235
  const internalOpen = ref(false);
234
236
  const accessibleLabel = ref("Dialog");
235
237
  let guardedPrevious;
@@ -307,7 +309,12 @@ var UiDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
307
309
  contract: propValidityContract,
308
310
  values: { ...props }
309
311
  }, name),
310
- refs: { close: closeElement },
312
+ refs: {
313
+ header: headerElement,
314
+ close: closeElement,
315
+ body: bodyElement,
316
+ footer: footerElement
317
+ },
311
318
  state: {
312
319
  internalOpen,
313
320
  accessibleLabel
@@ -328,24 +335,34 @@ var UiDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
328
335
  ref_key: "root",
329
336
  ref: root
330
337
  }), [
331
- createElementVNode("header", null, [checkedProps.value.label ? (openBlock(), createElementBlock("h2", _hoisted_2, toDisplayString(checkedProps.value.label), 1)) : createCommentVNode("v-if", true), createElementVNode("button", {
338
+ createElementVNode("header", {
339
+ ref_key: "headerElement",
340
+ ref: headerElement
341
+ }, [checkedProps.value.label ? (openBlock(), createElementBlock("h2", _hoisted_2, toDisplayString(checkedProps.value.label), 1)) : createCommentVNode("v-if", true), createElementVNode("button", {
332
342
  class: "close",
333
343
  type: "button",
334
344
  "aria-label": "Close",
335
345
  ref_key: "closeElement",
336
346
  ref: closeElement
337
- }, null, 512)]),
338
- createElementVNode("div", _hoisted_3, [createVNode(UiScrollArea_default, { trim: true }, {
347
+ }, null, 512)], 512),
348
+ createElementVNode("div", {
349
+ class: "body",
350
+ ref_key: "bodyElement",
351
+ ref: bodyElement
352
+ }, [createVNode(UiScrollArea_default, { trim: true }, {
339
353
  default: withCtx(() => [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
340
354
  _: 3
341
- })]),
342
- createElementVNode("footer", null, [renderSlot(_ctx.$slots, "actions", {}, void 0, true)])
355
+ })], 512),
356
+ createElementVNode("footer", {
357
+ ref_key: "footerElement",
358
+ ref: footerElement
359
+ }, [renderSlot(_ctx.$slots, "actions", {}, void 0, true)], 512)
343
360
  ], 16, _hoisted_1)), [[unref(vPropValidity), {
344
361
  contract: propValidityContract,
345
362
  values: { ...props }
346
363
  }]]);
347
364
  };
348
365
  }
349
- }), [["__scopeId", "data-v-6d90ae32"]]);
366
+ }), [["__scopeId", "data-v-1ec9644b"]]);
350
367
  //#endregion
351
368
  export { UiDialog_default as t };
@@ -613,6 +613,6 @@ var UiEditorMentionMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_defaul
613
613
  }]]);
614
614
  };
615
615
  }
616
- }), [["__scopeId", "data-v-ba581126"]]);
616
+ }), [["__scopeId", "data-v-f27cd779"]]);
617
617
  //#endregion
618
618
  export { UiEditorMentionMenu_default as t };
@@ -538,6 +538,6 @@ var UiEditorSlashMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_default(
538
538
  }]]);
539
539
  };
540
540
  }
541
- }), [["__scopeId", "data-v-cedd7cd4"]]);
541
+ }), [["__scopeId", "data-v-a85c3b18"]]);
542
542
  //#endregion
543
543
  export { UiEditorSlashMenu_default as t };
@@ -547,6 +547,6 @@ var UiEditorTableContextMenu_default = /*#__PURE__*/ _plugin_vue_export_helper_d
547
547
  }]]);
548
548
  };
549
549
  }
550
- }), [["__scopeId", "data-v-d311fe5d"]]);
550
+ }), [["__scopeId", "data-v-f2ebbbc8"]]);
551
551
  //#endregion
552
552
  export { UiEditorTableContextMenu_default as t };
@@ -737,6 +737,6 @@ var UiEditorTableToolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_defau
737
737
  }]]);
738
738
  };
739
739
  }
740
- }), [["__scopeId", "data-v-b9979342"]]);
740
+ }), [["__scopeId", "data-v-8c2d4497"]]);
741
741
  //#endregion
742
742
  export { UiEditorTableToolbar_default as t };
@@ -11,6 +11,7 @@ var _hoisted_1 = [
11
11
  "aria-busy",
12
12
  "data-anticipatory",
13
13
  "data-disabled",
14
+ "data-guide",
14
15
  "data-label",
15
16
  "data-loading",
16
17
  "data-match-button",
@@ -36,6 +37,10 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
36
37
  type: null,
37
38
  default: false
38
39
  },
40
+ guide: {
41
+ type: null,
42
+ default: "dot"
43
+ },
39
44
  label: {
40
45
  type: null,
41
46
  default: null
@@ -91,6 +96,17 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
91
96
  description: "Disables the button, so it cannot be pressed or focused, and gives it a flat neutral surface and muted icon.",
92
97
  default: false
93
98
  },
99
+ guide: {
100
+ type: {
101
+ kind: "terminal",
102
+ name: "keyword"
103
+ },
104
+ required: false,
105
+ target: { attribute: "guide" },
106
+ description: "The idle marker of an anticipatory button: dot for contextual actions, or a slim neutral rounded bar for a panel-edge control. The icon appears on hover or\n keyboard focus; touch always shows the icon.",
107
+ values: ["dot", "bar"],
108
+ default: "dot"
109
+ },
94
110
  label: {
95
111
  type: {
96
112
  kind: "terminal",
@@ -185,6 +201,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
185
201
  const acceptedProps = {
186
202
  anticipatory: false,
187
203
  disabled: false,
204
+ guide: "dot",
188
205
  label: null,
189
206
  loading: false,
190
207
  matchButton: false,
@@ -203,6 +220,10 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
203
220
  kind: "terminal",
204
221
  name: "boolean"
205
222
  }, false, "disabled", acceptedProps),
223
+ guide: checkedProp(props["guide"], {
224
+ kind: "terminal",
225
+ name: "keyword"
226
+ }, false, "guide", acceptedProps),
206
227
  label: checkedProp(props["label"], {
207
228
  kind: "terminal",
208
229
  name: "string"
@@ -284,6 +305,8 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
284
305
  checkedProps.value.tone && "tone",
285
306
  checkedProps.value.tone != null && `tone=${encodeURIComponent(checkedProps.value.tone)}`,
286
307
  checkedProps.value.anticipatory && "anticipatory",
308
+ checkedProps.value.guide && "guide",
309
+ checkedProps.value.guide != null && `guide=${encodeURIComponent(checkedProps.value.guide)}`,
287
310
  checkedProps.value.variant && "variant",
288
311
  checkedProps.value.variant != null && `variant=${encodeURIComponent(checkedProps.value.variant)}`,
289
312
  checkedProps.value.loading && "loading",
@@ -310,6 +333,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
310
333
  propNames: [
311
334
  "anticipatory",
312
335
  "disabled",
336
+ "guide",
313
337
  "label",
314
338
  "loading",
315
339
  "matchButton",
@@ -349,6 +373,7 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
349
373
  "aria-busy": checkedProps.value.loading || checkedProps.value.pending,
350
374
  "data-anticipatory": reflectedProp("anticipatory", "anticipatory", checkedProps.value.anticipatory, void 0, false),
351
375
  "data-disabled": reflectedProp("disabled", "disabled", checkedProps.value.disabled, void 0, false),
376
+ "data-guide": reflectedProp("guide", "guide", checkedProps.value.guide, void 0, false),
352
377
  "data-label": reflectedProp("label", "label", checkedProps.value.label, void 0, false),
353
378
  "data-loading": reflectedProp("loading", "loading", checkedProps.value.loading, void 0, false),
354
379
  "data-match-button": reflectedProp("matchButton", "match-button", checkedProps.value.matchButton, void 0, true),
@@ -369,6 +394,6 @@ var UiIconButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @_
369
394
  }]]);
370
395
  };
371
396
  }
372
- }), [["__scopeId", "data-v-219fa683"]]);
397
+ }), [["__scopeId", "data-v-ea2a5496"]]);
373
398
  //#endregion
374
399
  export { UiIconButton_default as t };