@ansh-ui/vue 0.2.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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-2VSROZ2N.js +1281 -0
  3. package/dist/chunk-2VSROZ2N.js.map +1 -0
  4. package/dist/chunk-5BQEZYG6.cjs +1294 -0
  5. package/dist/chunk-5BQEZYG6.cjs.map +1 -0
  6. package/dist/chunk-6732H4BQ.cjs +28 -0
  7. package/dist/chunk-6732H4BQ.cjs.map +1 -0
  8. package/dist/chunk-6ABPGOJP.js +722 -0
  9. package/dist/chunk-6ABPGOJP.js.map +1 -0
  10. package/dist/chunk-6XJOB6LE.js +62 -0
  11. package/dist/chunk-6XJOB6LE.js.map +1 -0
  12. package/dist/chunk-774WBLDR.cjs +24 -0
  13. package/dist/chunk-774WBLDR.cjs.map +1 -0
  14. package/dist/chunk-B6OXKW5Q.js +567 -0
  15. package/dist/chunk-B6OXKW5Q.js.map +1 -0
  16. package/dist/chunk-DMPNT3MY.cjs +64 -0
  17. package/dist/chunk-DMPNT3MY.cjs.map +1 -0
  18. package/dist/chunk-EISHOEB6.cjs +158 -0
  19. package/dist/chunk-EISHOEB6.cjs.map +1 -0
  20. package/dist/chunk-EVO23GUS.js +223 -0
  21. package/dist/chunk-EVO23GUS.js.map +1 -0
  22. package/dist/chunk-FVKLCGA4.js +1035 -0
  23. package/dist/chunk-FVKLCGA4.js.map +1 -0
  24. package/dist/chunk-IOXGBPOV.cjs +3681 -0
  25. package/dist/chunk-IOXGBPOV.cjs.map +1 -0
  26. package/dist/chunk-J2LA4GRP.cjs +1051 -0
  27. package/dist/chunk-J2LA4GRP.cjs.map +1 -0
  28. package/dist/chunk-JQ4YLXXM.cjs +580 -0
  29. package/dist/chunk-JQ4YLXXM.cjs.map +1 -0
  30. package/dist/chunk-KCA7RNJ4.cjs +781 -0
  31. package/dist/chunk-KCA7RNJ4.cjs.map +1 -0
  32. package/dist/chunk-NJDDNO4C.js +23 -0
  33. package/dist/chunk-NJDDNO4C.js.map +1 -0
  34. package/dist/chunk-OAQ7MDYX.js +22 -0
  35. package/dist/chunk-OAQ7MDYX.js.map +1 -0
  36. package/dist/chunk-PP6OYURM.cjs +238 -0
  37. package/dist/chunk-PP6OYURM.cjs.map +1 -0
  38. package/dist/chunk-SHX2JGID.cjs +269 -0
  39. package/dist/chunk-SHX2JGID.cjs.map +1 -0
  40. package/dist/chunk-SOYRICHU.js +3645 -0
  41. package/dist/chunk-SOYRICHU.js.map +1 -0
  42. package/dist/chunk-T425FIC7.js +773 -0
  43. package/dist/chunk-T425FIC7.js.map +1 -0
  44. package/dist/chunk-TMG3M6TK.js +152 -0
  45. package/dist/chunk-TMG3M6TK.js.map +1 -0
  46. package/dist/chunk-XLLSS464.cjs +286 -0
  47. package/dist/chunk-XLLSS464.cjs.map +1 -0
  48. package/dist/chunk-XZ5ZFLZM.js +280 -0
  49. package/dist/chunk-XZ5ZFLZM.js.map +1 -0
  50. package/dist/chunk-Z7XOFKM4.cjs +733 -0
  51. package/dist/chunk-Z7XOFKM4.cjs.map +1 -0
  52. package/dist/chunk-ZGMXOMCB.js +266 -0
  53. package/dist/chunk-ZGMXOMCB.js.map +1 -0
  54. package/dist/data.cjs +70 -0
  55. package/dist/data.cjs.map +1 -0
  56. package/dist/data.d.cts +963 -0
  57. package/dist/data.d.ts +963 -0
  58. package/dist/data.js +5 -0
  59. package/dist/data.js.map +1 -0
  60. package/dist/form.cjs +151 -0
  61. package/dist/form.cjs.map +1 -0
  62. package/dist/form.d.cts +2639 -0
  63. package/dist/form.d.ts +2639 -0
  64. package/dist/form.js +6 -0
  65. package/dist/form.js.map +1 -0
  66. package/dist/index.cjs +1158 -0
  67. package/dist/index.cjs.map +1 -0
  68. package/dist/index.d.cts +439 -0
  69. package/dist/index.d.ts +439 -0
  70. package/dist/index.js +547 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/layout.cjs +67 -0
  73. package/dist/layout.cjs.map +1 -0
  74. package/dist/layout.d.cts +729 -0
  75. package/dist/layout.d.ts +729 -0
  76. package/dist/layout.js +6 -0
  77. package/dist/layout.js.map +1 -0
  78. package/dist/motion.cjs +50 -0
  79. package/dist/motion.cjs.map +1 -0
  80. package/dist/motion.d.cts +681 -0
  81. package/dist/motion.d.ts +681 -0
  82. package/dist/motion.js +5 -0
  83. package/dist/motion.js.map +1 -0
  84. package/dist/navigation.cjs +48 -0
  85. package/dist/navigation.cjs.map +1 -0
  86. package/dist/navigation.d.cts +515 -0
  87. package/dist/navigation.d.ts +515 -0
  88. package/dist/navigation.js +7 -0
  89. package/dist/navigation.js.map +1 -0
  90. package/dist/overlay.cjs +61 -0
  91. package/dist/overlay.cjs.map +1 -0
  92. package/dist/overlay.d.cts +772 -0
  93. package/dist/overlay.d.ts +772 -0
  94. package/dist/overlay.js +8 -0
  95. package/dist/overlay.js.map +1 -0
  96. package/dist/position-Cn7qP1pn.d.cts +50 -0
  97. package/dist/position-Cn7qP1pn.d.ts +50 -0
  98. package/dist/primitives.cjs +129 -0
  99. package/dist/primitives.cjs.map +1 -0
  100. package/dist/primitives.d.cts +300 -0
  101. package/dist/primitives.d.ts +300 -0
  102. package/dist/primitives.js +8 -0
  103. package/dist/primitives.js.map +1 -0
  104. package/dist/sidebar-CQqEmpid.d.cts +124 -0
  105. package/dist/sidebar-CTZ-Ckko.d.ts +124 -0
  106. package/dist/styles.css +5593 -0
  107. package/dist/utils-IKPG3zcC.d.cts +46 -0
  108. package/dist/utils-IKPG3zcC.d.ts +46 -0
  109. package/package.json +91 -0
@@ -0,0 +1,1294 @@
1
+ 'use strict';
2
+
3
+ var chunkDMPNT3MY_cjs = require('./chunk-DMPNT3MY.cjs');
4
+ var chunkXLLSS464_cjs = require('./chunk-XLLSS464.cjs');
5
+ var chunkEISHOEB6_cjs = require('./chunk-EISHOEB6.cjs');
6
+ var chunk774WBLDR_cjs = require('./chunk-774WBLDR.cjs');
7
+ var chunk6732H4BQ_cjs = require('./chunk-6732H4BQ.cjs');
8
+ var vue = require('vue');
9
+
10
+ var PopoverKey = /* @__PURE__ */ Symbol("ansh-popover");
11
+ function usePopoverContext(component) {
12
+ const context = vue.inject(PopoverKey, null);
13
+ if (!context) throw new Error(`<${component}> must be rendered inside <Popover>.`);
14
+ return context;
15
+ }
16
+ var Popover = vue.defineComponent({
17
+ name: "AnshPopover",
18
+ props: {
19
+ open: { type: Boolean, default: void 0 },
20
+ defaultOpen: { type: Boolean, default: false },
21
+ placement: { type: String, default: "bottom" },
22
+ /** Gap from the trigger, in px. Default `8`. */
23
+ offset: { type: Number, default: 8 },
24
+ /** Trap focus and block interaction behind. Default `false` — most popovers are non-modal. */
25
+ modal: { type: Boolean, default: false }
26
+ },
27
+ emits: ["update:open"],
28
+ setup(props, { slots, emit }) {
29
+ const [isOpen, setOpen] = chunk774WBLDR_cjs.useControllableState(
30
+ () => props.open,
31
+ props.defaultOpen,
32
+ (next) => emit("update:open", next)
33
+ );
34
+ const triggerRef = vue.ref(null);
35
+ const contentId = chunk6732H4BQ_cjs.useId("popover");
36
+ vue.provide(PopoverKey, {
37
+ open: isOpen,
38
+ setOpen,
39
+ triggerRef,
40
+ contentId,
41
+ get placement() {
42
+ return props.placement;
43
+ },
44
+ get offset() {
45
+ return props.offset;
46
+ },
47
+ get modal() {
48
+ return props.modal;
49
+ }
50
+ });
51
+ return () => slots.default?.();
52
+ }
53
+ });
54
+ var PopoverTrigger = vue.defineComponent({
55
+ name: "AnshPopoverTrigger",
56
+ inheritAttrs: false,
57
+ props: {
58
+ /** Tag to render. Default `'button'`. */
59
+ as: { type: String, default: "button" }
60
+ },
61
+ setup(props, { slots, attrs }) {
62
+ const ctx = usePopoverContext("PopoverTrigger");
63
+ return () => {
64
+ const { onClick, ...restAttrs } = attrs;
65
+ return vue.h(
66
+ props.as,
67
+ {
68
+ ref: ctx.triggerRef,
69
+ ...props.as === "button" ? { type: "button" } : null,
70
+ "aria-haspopup": "dialog",
71
+ "aria-expanded": ctx.open.value,
72
+ "aria-controls": ctx.open.value ? ctx.contentId : void 0,
73
+ ...restAttrs,
74
+ onClick: (event) => {
75
+ onClick?.(event);
76
+ if (event.defaultPrevented) return;
77
+ ctx.setOpen(!ctx.open.value);
78
+ }
79
+ },
80
+ slots.default?.()
81
+ );
82
+ };
83
+ }
84
+ });
85
+ var PopoverContent = vue.defineComponent({
86
+ name: "AnshPopoverContent",
87
+ inheritAttrs: false,
88
+ props: {
89
+ /** Draw an arrow pointing at the trigger. Default `false`. */
90
+ arrow: { type: Boolean, default: false },
91
+ /** Match the trigger's width — for a popover acting as a dropdown panel. */
92
+ matchWidth: { type: Boolean, default: false },
93
+ /** Accessible name. Required unless the content contains its own heading. */
94
+ label: { type: String, default: void 0 }
95
+ },
96
+ setup(props, { slots, attrs }) {
97
+ const ctx = usePopoverContext("PopoverContent");
98
+ const contentRef = vue.ref(null);
99
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(ctx.open, contentRef);
100
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(ctx.triggerRef, contentRef, mounted, {
101
+ placement: ctx.placement,
102
+ offset: ctx.offset,
103
+ matchWidth: props.matchWidth,
104
+ arrowSize: props.arrow ? 10 : 0
105
+ });
106
+ chunkXLLSS464_cjs.useDismiss(contentRef, ctx.open, () => ctx.setOpen(false), { ignore: [ctx.triggerRef] });
107
+ const trapActive = vue.computed(() => ctx.open.value && ctx.modal);
108
+ chunkEISHOEB6_cjs.useFocusTrap(contentRef, trapActive);
109
+ chunkEISHOEB6_cjs.useAutoFocus(contentRef, ctx.open);
110
+ chunkEISHOEB6_cjs.useFocusRestore(ctx.open);
111
+ return () => {
112
+ if (!mounted.value) return null;
113
+ const { class: attrClass, style: attrStyle, ...restAttrs } = attrs;
114
+ return vue.h(vue.Teleport, { to: "body" }, [
115
+ vue.h(
116
+ "div",
117
+ {
118
+ ref: contentRef,
119
+ id: ctx.contentId,
120
+ role: "dialog",
121
+ "aria-modal": ctx.modal || void 0,
122
+ ...props.label ? { "aria-label": props.label } : null,
123
+ tabindex: "-1",
124
+ "data-state": state.value,
125
+ "data-side": position.value.side,
126
+ class: chunk6732H4BQ_cjs.cx("ansh-popover", attrClass),
127
+ style: [position.value.style, attrStyle],
128
+ ...restAttrs
129
+ },
130
+ [
131
+ slots.default?.(),
132
+ props.arrow && position.value.arrowStyle ? vue.h("span", {
133
+ class: "ansh-popover__arrow",
134
+ style: position.value.arrowStyle,
135
+ "aria-hidden": "true"
136
+ }) : null
137
+ ]
138
+ )
139
+ ]);
140
+ };
141
+ }
142
+ });
143
+ var HoverCard = vue.defineComponent({
144
+ name: "AnshHoverCard",
145
+ props: {
146
+ /** Delay before opening, in ms. Default `500`. */
147
+ openDelay: { type: Number, default: 500 },
148
+ /** Delay before closing, in ms. Default `200`. */
149
+ closeDelay: { type: Number, default: 200 },
150
+ placement: { type: String, default: "bottom" }
151
+ },
152
+ setup(props, { slots, attrs }) {
153
+ const open = vue.ref(false);
154
+ const triggerRef = vue.ref(null);
155
+ const cardRef = vue.ref(null);
156
+ const id = chunk6732H4BQ_cjs.useId("hovercard");
157
+ let timer;
158
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(open, cardRef);
159
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(triggerRef, cardRef, mounted, {
160
+ placement: props.placement,
161
+ offset: 8
162
+ });
163
+ const schedule = (next) => {
164
+ clearTimeout(timer);
165
+ timer = setTimeout(
166
+ () => {
167
+ open.value = next;
168
+ },
169
+ next ? props.openDelay : props.closeDelay
170
+ );
171
+ };
172
+ vue.onBeforeUnmount(() => clearTimeout(timer));
173
+ return () => vue.h("span", { style: { display: "contents" } }, [
174
+ vue.h(
175
+ "span",
176
+ {
177
+ ref: triggerRef,
178
+ class: "ansh-hovercard__trigger",
179
+ // `aria-describedby` rather than `aria-details`: support for details is still patchy,
180
+ // and a description is the honest relationship for supplementary content.
181
+ "aria-describedby": open.value ? id : void 0,
182
+ onMouseenter: () => schedule(true),
183
+ onMouseleave: () => schedule(false),
184
+ onFocus: () => {
185
+ open.value = true;
186
+ },
187
+ onBlur: () => {
188
+ open.value = false;
189
+ }
190
+ },
191
+ slots.default?.()
192
+ ),
193
+ mounted.value ? vue.h(vue.Teleport, { to: "body" }, [
194
+ vue.h(
195
+ "div",
196
+ {
197
+ ref: cardRef,
198
+ id,
199
+ role: "tooltip",
200
+ "data-state": state.value,
201
+ class: chunk6732H4BQ_cjs.cx("ansh-hovercard", attrs.class),
202
+ style: position.value.style,
203
+ // Keeping the card open while the pointer is over it is what makes its contents
204
+ // clickable at all.
205
+ onMouseenter: () => schedule(true),
206
+ onMouseleave: () => schedule(false)
207
+ },
208
+ slots.content?.()
209
+ )
210
+ ]) : null
211
+ ]);
212
+ }
213
+ });
214
+ var TooltipGroupKey = /* @__PURE__ */ Symbol("ansh-tooltip-group");
215
+ var TooltipProvider = vue.defineComponent({
216
+ name: "AnshTooltipProvider",
217
+ props: {
218
+ /** Delay before the first tooltip in a group opens, in ms. Default `600`. */
219
+ delay: { type: Number, default: 600 }
220
+ },
221
+ setup(props, { slots }) {
222
+ const active = vue.ref(false);
223
+ vue.provide(TooltipGroupKey, {
224
+ active,
225
+ setActive: (next) => {
226
+ active.value = next;
227
+ },
228
+ get delay() {
229
+ return props.delay;
230
+ }
231
+ });
232
+ return () => slots.default?.();
233
+ }
234
+ });
235
+ var Tooltip = vue.defineComponent({
236
+ name: "AnshTooltip",
237
+ inheritAttrs: false,
238
+ props: {
239
+ /** The tooltip text. Keep it short — it is read as one description. */
240
+ content: { type: [String, Object, Function], required: true },
241
+ placement: { type: String, default: "top" },
242
+ /** Override the group delay, in ms. */
243
+ delay: { type: Number, default: void 0 },
244
+ /** Draw an arrow. Default `true`. */
245
+ arrow: { type: Boolean, default: true },
246
+ disabled: { type: Boolean, default: false }
247
+ },
248
+ setup(props, { slots, attrs }) {
249
+ const group = vue.inject(TooltipGroupKey, null);
250
+ const open = vue.ref(false);
251
+ const triggerRef = vue.ref(null);
252
+ const tipRef = vue.ref(null);
253
+ let timer;
254
+ const id = chunk6732H4BQ_cjs.useId("tooltip");
255
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(open, tipRef);
256
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(triggerRef, tipRef, mounted, {
257
+ placement: props.placement,
258
+ offset: 6,
259
+ arrowSize: props.arrow ? 8 : 0
260
+ });
261
+ const effectiveDelay = () => props.delay ?? group?.delay ?? 600;
262
+ const show = (immediate = false) => {
263
+ if (props.disabled) return;
264
+ clearTimeout(timer);
265
+ if (immediate || group?.active.value) {
266
+ open.value = true;
267
+ group?.setActive(true);
268
+ return;
269
+ }
270
+ timer = setTimeout(() => {
271
+ open.value = true;
272
+ group?.setActive(true);
273
+ }, effectiveDelay());
274
+ };
275
+ const hide = () => {
276
+ clearTimeout(timer);
277
+ open.value = false;
278
+ timer = setTimeout(() => group?.setActive(false), 200);
279
+ };
280
+ vue.onBeforeUnmount(() => clearTimeout(timer));
281
+ chunkXLLSS464_cjs.useDismiss(
282
+ tipRef,
283
+ open,
284
+ () => {
285
+ open.value = false;
286
+ group?.setActive(false);
287
+ },
288
+ { outsidePress: false, escapeKey: true }
289
+ );
290
+ return () => {
291
+ const { class: attrClass, ...restAttrs } = attrs;
292
+ return vue.h(
293
+ "span",
294
+ {
295
+ // No box of its own — see the module comment on why this wrapper exists at all.
296
+ style: { display: "contents" }
297
+ },
298
+ [
299
+ vue.h(
300
+ "span",
301
+ {
302
+ ...restAttrs,
303
+ ref: triggerRef,
304
+ class: chunk6732H4BQ_cjs.cx("ansh-tooltip-trigger", attrClass),
305
+ "aria-describedby": open.value ? id : void 0,
306
+ onMouseenter: () => show(),
307
+ onMouseleave: hide,
308
+ onFocusin: () => show(true),
309
+ onFocusout: hide
310
+ },
311
+ slots.default?.()
312
+ ),
313
+ mounted.value && !props.disabled ? vue.h(vue.Teleport, { to: "body" }, [
314
+ vue.h(
315
+ "div",
316
+ {
317
+ ref: tipRef,
318
+ id,
319
+ role: "tooltip",
320
+ "data-state": state.value,
321
+ "data-side": position.value.side,
322
+ class: "ansh-tooltip",
323
+ style: position.value.style
324
+ },
325
+ [
326
+ chunk6732H4BQ_cjs.resolveSlotContent(props.content),
327
+ props.arrow && position.value.arrowStyle ? vue.h("span", {
328
+ class: "ansh-tooltip__arrow",
329
+ style: position.value.arrowStyle,
330
+ "aria-hidden": "true"
331
+ }) : null
332
+ ]
333
+ )
334
+ ]) : null
335
+ ]
336
+ );
337
+ };
338
+ }
339
+ });
340
+ var Dialog = vue.defineComponent({
341
+ name: "AnshDialog",
342
+ inheritAttrs: false,
343
+ props: {
344
+ open: { type: Boolean, default: void 0 },
345
+ defaultOpen: { type: Boolean, default: false },
346
+ /** The dialog's accessible name. Required — a dialog announced as just "dialog" is useless. */
347
+ title: { type: [String, Object, Function], required: true },
348
+ /** Supporting text, wired to `aria-describedby`. */
349
+ description: { type: [String, Object, Function], default: void 0 },
350
+ size: { type: String, default: "md" },
351
+ /** Show the close button. Default `true`. */
352
+ showClose: { type: Boolean, default: true },
353
+ /** Allow closing via scrim click and Escape. Default `true`. */
354
+ dismissable: { type: Boolean, default: true },
355
+ /** Element to focus on open. Defaults to the first tabbable one. */
356
+ initialFocus: { type: Object, default: void 0 }
357
+ },
358
+ emits: ["update:open"],
359
+ setup(props, { slots, attrs, emit }) {
360
+ const [isOpen, setOpen] = chunk774WBLDR_cjs.useControllableState(
361
+ () => props.open,
362
+ props.defaultOpen,
363
+ (next) => emit("update:open", next)
364
+ );
365
+ const panelRef = vue.ref(null);
366
+ const id = chunk6732H4BQ_cjs.useId("dialog");
367
+ const titleId = `${id}-title`;
368
+ const descriptionId = `${id}-description`;
369
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(isOpen, panelRef);
370
+ const close = () => {
371
+ if (props.dismissable) setOpen(false);
372
+ };
373
+ chunkXLLSS464_cjs.useDismiss(panelRef, isOpen, close, {
374
+ outsidePress: props.dismissable,
375
+ escapeKey: props.dismissable
376
+ });
377
+ chunkEISHOEB6_cjs.useFocusTrap(panelRef, isOpen);
378
+ chunkEISHOEB6_cjs.useAutoFocus(panelRef, isOpen, props.initialFocus);
379
+ chunkEISHOEB6_cjs.useFocusRestore(isOpen);
380
+ chunkXLLSS464_cjs.useScrollLock(isOpen);
381
+ return () => {
382
+ if (!mounted.value) return null;
383
+ const { class: attrClass, ...restAttrs } = attrs;
384
+ return vue.h(vue.Teleport, { to: "body" }, [
385
+ vue.h("div", { class: "ansh-dialog__layer", "data-state": state.value }, [
386
+ // The scrim is not a button and takes no focus — it's decorative. Dismissal is handled
387
+ // by `useDismiss` on a pointerdown outside the panel, which also covers the gap around
388
+ // the panel that isn't the scrim element itself.
389
+ vue.h("div", {
390
+ class: "ansh-dialog__scrim",
391
+ "data-state": state.value,
392
+ "aria-hidden": "true"
393
+ }),
394
+ vue.h(
395
+ "div",
396
+ {
397
+ ref: panelRef,
398
+ role: "dialog",
399
+ "aria-modal": "true",
400
+ "aria-labelledby": titleId,
401
+ ...props.description ? { "aria-describedby": descriptionId } : null,
402
+ tabindex: "-1",
403
+ "data-state": state.value,
404
+ class: chunk6732H4BQ_cjs.cx("ansh-dialog", `ansh-dialog--${props.size}`, attrClass),
405
+ ...restAttrs
406
+ },
407
+ [
408
+ vue.h("header", { class: "ansh-dialog__header" }, [
409
+ vue.h("div", { class: "ansh-dialog__heading" }, [
410
+ vue.h("h2", { class: "ansh-dialog__title", id: titleId }, [
411
+ chunk6732H4BQ_cjs.resolveSlotContent(props.title)
412
+ ]),
413
+ props.description ? vue.h("p", { class: "ansh-dialog__description", id: descriptionId }, [
414
+ chunk6732H4BQ_cjs.resolveSlotContent(props.description)
415
+ ]) : null
416
+ ]),
417
+ props.showClose ? vue.h(
418
+ "button",
419
+ {
420
+ type: "button",
421
+ class: "ansh-dialog__close ansh-focusable",
422
+ "aria-label": "Close dialog",
423
+ onClick: () => setOpen(false)
424
+ },
425
+ [
426
+ vue.h(
427
+ "svg",
428
+ {
429
+ viewBox: "0 0 16 16",
430
+ width: "14",
431
+ height: "14",
432
+ "aria-hidden": "true"
433
+ },
434
+ [
435
+ vue.h("path", {
436
+ d: "M4 4l8 8M12 4l-8 8",
437
+ stroke: "currentColor",
438
+ "stroke-width": "1.75",
439
+ "stroke-linecap": "round",
440
+ fill: "none"
441
+ })
442
+ ]
443
+ )
444
+ ]
445
+ ) : null
446
+ ]),
447
+ slots.default ? vue.h("div", { class: "ansh-dialog__body" }, slots.default()) : null,
448
+ slots.footer ? vue.h("footer", { class: "ansh-dialog__footer" }, slots.footer()) : null
449
+ ]
450
+ )
451
+ ])
452
+ ]);
453
+ };
454
+ }
455
+ });
456
+ var AlertDialog = vue.defineComponent({
457
+ name: "AnshAlertDialog",
458
+ inheritAttrs: false,
459
+ props: {
460
+ open: { type: Boolean, default: void 0 },
461
+ defaultOpen: { type: Boolean, default: false },
462
+ title: { type: [String, Object, Function], required: true },
463
+ description: { type: [String, Object, Function], required: true },
464
+ /** Confirm button text. Default `'Confirm'`. */
465
+ confirmLabel: { type: String, default: "Confirm" },
466
+ cancelLabel: { type: String, default: "Cancel" },
467
+ /** Style the confirm action as destructive. */
468
+ destructive: { type: Boolean, default: false },
469
+ /** Disable the buttons while an async confirm runs. */
470
+ busy: { type: Boolean, default: false }
471
+ },
472
+ emits: ["update:open", "confirm", "cancel"],
473
+ setup(props, { attrs, emit }) {
474
+ const [isOpen, setOpen] = chunk774WBLDR_cjs.useControllableState(
475
+ () => props.open,
476
+ props.defaultOpen,
477
+ (next) => emit("update:open", next)
478
+ );
479
+ const panelRef = vue.ref(null);
480
+ const cancelRef = vue.ref(null);
481
+ const id = chunk6732H4BQ_cjs.useId("alertdialog");
482
+ const titleId = `${id}-title`;
483
+ const descriptionId = `${id}-description`;
484
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(isOpen, panelRef);
485
+ const cancel = () => {
486
+ emit("cancel");
487
+ setOpen(false);
488
+ };
489
+ chunkXLLSS464_cjs.useDismiss(panelRef, isOpen, cancel, { outsidePress: false, escapeKey: true });
490
+ chunkEISHOEB6_cjs.useFocusTrap(panelRef, isOpen);
491
+ chunkEISHOEB6_cjs.useAutoFocus(panelRef, isOpen, cancelRef);
492
+ chunkEISHOEB6_cjs.useFocusRestore(isOpen);
493
+ chunkXLLSS464_cjs.useScrollLock(isOpen);
494
+ return () => {
495
+ if (!mounted.value) return null;
496
+ const { class: attrClass, ...restAttrs } = attrs;
497
+ return vue.h(vue.Teleport, { to: "body" }, [
498
+ vue.h("div", { class: "ansh-dialog__layer", "data-state": state.value }, [
499
+ vue.h("div", {
500
+ class: "ansh-dialog__scrim",
501
+ "data-state": state.value,
502
+ "aria-hidden": "true"
503
+ }),
504
+ vue.h(
505
+ "div",
506
+ {
507
+ ref: panelRef,
508
+ role: "alertdialog",
509
+ "aria-modal": "true",
510
+ "aria-labelledby": titleId,
511
+ "aria-describedby": descriptionId,
512
+ tabindex: "-1",
513
+ "data-state": state.value,
514
+ class: chunk6732H4BQ_cjs.cx(
515
+ "ansh-dialog",
516
+ "ansh-dialog--sm",
517
+ "ansh-dialog--alert",
518
+ attrClass
519
+ ),
520
+ ...restAttrs
521
+ },
522
+ [
523
+ vue.h("div", { class: "ansh-dialog__body" }, [
524
+ props.destructive ? vue.h(
525
+ "span",
526
+ {
527
+ class: "ansh-dialog__alert-icon ansh-dialog__alert-icon--danger",
528
+ "aria-hidden": "true"
529
+ },
530
+ [
531
+ vue.h(
532
+ "svg",
533
+ {
534
+ viewBox: "0 0 24 24",
535
+ width: "20",
536
+ height: "20",
537
+ fill: "none",
538
+ stroke: "currentColor",
539
+ "stroke-width": "1.75"
540
+ },
541
+ [
542
+ vue.h("path", { d: "M12 8v5", "stroke-linecap": "round" }),
543
+ vue.h("circle", {
544
+ cx: "12",
545
+ cy: "16.5",
546
+ r: "1",
547
+ fill: "currentColor",
548
+ stroke: "none"
549
+ }),
550
+ vue.h("path", {
551
+ d: "M10.3 3.9L2.6 17.4A2 2 0 004.3 20.4h15.4a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z",
552
+ "stroke-linejoin": "round"
553
+ })
554
+ ]
555
+ )
556
+ ]
557
+ ) : null,
558
+ vue.h("h2", { class: "ansh-dialog__title", id: titleId }, [
559
+ chunk6732H4BQ_cjs.resolveSlotContent(props.title)
560
+ ]),
561
+ vue.h("p", { class: "ansh-dialog__description", id: descriptionId }, [
562
+ chunk6732H4BQ_cjs.resolveSlotContent(props.description)
563
+ ])
564
+ ]),
565
+ vue.h("footer", { class: "ansh-dialog__footer" }, [
566
+ vue.h(
567
+ "button",
568
+ {
569
+ ref: cancelRef,
570
+ type: "button",
571
+ class: "ansh-btn ansh-btn--ghost ansh-btn--sm ansh-focusable",
572
+ disabled: props.busy,
573
+ onClick: cancel
574
+ },
575
+ [props.cancelLabel]
576
+ ),
577
+ vue.h(
578
+ "button",
579
+ {
580
+ type: "button",
581
+ class: chunk6732H4BQ_cjs.cx(
582
+ "ansh-btn",
583
+ "ansh-btn--sm",
584
+ props.destructive ? "ansh-btn--danger" : "ansh-btn--solid",
585
+ "ansh-focusable"
586
+ ),
587
+ disabled: props.busy,
588
+ onClick: () => emit("confirm")
589
+ },
590
+ [
591
+ props.busy ? vue.h("span", { class: "ansh-spinner ansh-spinner--sm", "aria-hidden": "true" }) : null,
592
+ props.confirmLabel
593
+ ]
594
+ )
595
+ ])
596
+ ]
597
+ )
598
+ ])
599
+ ]);
600
+ };
601
+ }
602
+ });
603
+ var DialogFooter = vue.defineComponent({
604
+ name: "AnshDialogFooter",
605
+ setup(_props, { slots, attrs }) {
606
+ return () => vue.h("div", { class: chunk6732H4BQ_cjs.cx("ansh-dialog__actions", attrs.class) }, slots.default?.());
607
+ }
608
+ });
609
+ var Drawer = vue.defineComponent({
610
+ name: "AnshDrawer",
611
+ inheritAttrs: false,
612
+ props: {
613
+ open: { type: Boolean, default: void 0 },
614
+ defaultOpen: { type: Boolean, default: false },
615
+ /** Which edge it slides from. Default `'right'`. */
616
+ side: { type: String, default: "right" },
617
+ title: { type: [String, Object, Function], required: true },
618
+ description: { type: [String, Object, Function], default: void 0 },
619
+ /** Width for left/right, height for top/bottom. Default `'22rem'`. */
620
+ size: { type: String, default: "22rem" },
621
+ showClose: { type: Boolean, default: true },
622
+ /** Block interaction behind and lock scroll. Default `true`. */
623
+ modal: { type: Boolean, default: true },
624
+ dismissable: { type: Boolean, default: true }
625
+ },
626
+ emits: ["update:open"],
627
+ setup(props, { slots, attrs, emit }) {
628
+ const [isOpen, setOpen] = chunk774WBLDR_cjs.useControllableState(
629
+ () => props.open,
630
+ props.defaultOpen,
631
+ (next) => emit("update:open", next)
632
+ );
633
+ const panelRef = vue.ref(null);
634
+ const id = chunk6732H4BQ_cjs.useId("drawer");
635
+ const titleId = `${id}-title`;
636
+ const descriptionId = `${id}-description`;
637
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(isOpen, panelRef);
638
+ const close = () => {
639
+ if (props.dismissable) setOpen(false);
640
+ };
641
+ chunkXLLSS464_cjs.useDismiss(panelRef, isOpen, close, {
642
+ outsidePress: props.dismissable && props.modal,
643
+ escapeKey: props.dismissable
644
+ });
645
+ const trapActive = vue.computed(() => isOpen.value && props.modal);
646
+ chunkEISHOEB6_cjs.useFocusTrap(panelRef, trapActive);
647
+ chunkEISHOEB6_cjs.useAutoFocus(panelRef, isOpen);
648
+ chunkEISHOEB6_cjs.useFocusRestore(isOpen);
649
+ const scrollLockActive = vue.computed(() => isOpen.value && props.modal);
650
+ chunkXLLSS464_cjs.useScrollLock(scrollLockActive);
651
+ return () => {
652
+ if (!mounted.value) return null;
653
+ const { class: attrClass, ...restAttrs } = attrs;
654
+ const horizontal = props.side === "left" || props.side === "right";
655
+ return vue.h(vue.Teleport, { to: "body" }, [
656
+ vue.h(
657
+ "div",
658
+ {
659
+ class: chunk6732H4BQ_cjs.cx("ansh-drawer__layer", !props.modal && "ansh-drawer__layer--inline"),
660
+ "data-state": state.value
661
+ },
662
+ [
663
+ props.modal ? vue.h("div", {
664
+ class: "ansh-dialog__scrim",
665
+ "data-state": state.value,
666
+ "aria-hidden": "true"
667
+ }) : null,
668
+ vue.h(
669
+ "div",
670
+ {
671
+ ref: panelRef,
672
+ role: "dialog",
673
+ "aria-modal": props.modal || void 0,
674
+ "aria-labelledby": titleId,
675
+ ...props.description ? { "aria-describedby": descriptionId } : null,
676
+ tabindex: "-1",
677
+ "data-state": state.value,
678
+ "data-side": props.side,
679
+ class: chunk6732H4BQ_cjs.cx("ansh-drawer", `ansh-drawer--${props.side}`, attrClass),
680
+ // The size travels as a custom property so the closed-state transform can be
681
+ // written in terms of it — `translateX(100%)` alone breaks when the panel has a
682
+ // max-width.
683
+ style: {
684
+ [horizontal ? "width" : "height"]: props.size,
685
+ "--ansh-drawer-size": props.size
686
+ },
687
+ ...restAttrs
688
+ },
689
+ [
690
+ vue.h("header", { class: "ansh-drawer__header" }, [
691
+ vue.h("div", { class: "ansh-dialog__heading" }, [
692
+ vue.h("h2", { class: "ansh-dialog__title", id: titleId }, [
693
+ chunk6732H4BQ_cjs.resolveSlotContent(props.title)
694
+ ]),
695
+ props.description ? vue.h("p", { class: "ansh-dialog__description", id: descriptionId }, [
696
+ chunk6732H4BQ_cjs.resolveSlotContent(props.description)
697
+ ]) : null
698
+ ]),
699
+ props.showClose ? vue.h(
700
+ "button",
701
+ {
702
+ type: "button",
703
+ class: "ansh-dialog__close ansh-focusable",
704
+ "aria-label": "Close panel",
705
+ onClick: () => setOpen(false)
706
+ },
707
+ [
708
+ vue.h(
709
+ "svg",
710
+ {
711
+ viewBox: "0 0 16 16",
712
+ width: "14",
713
+ height: "14",
714
+ "aria-hidden": "true"
715
+ },
716
+ [
717
+ vue.h("path", {
718
+ d: "M4 4l8 8M12 4l-8 8",
719
+ stroke: "currentColor",
720
+ "stroke-width": "1.75",
721
+ "stroke-linecap": "round",
722
+ fill: "none"
723
+ })
724
+ ]
725
+ )
726
+ ]
727
+ ) : null
728
+ ]),
729
+ vue.h("div", { class: "ansh-drawer__body" }, slots.default?.()),
730
+ slots.footer ? vue.h("footer", { class: "ansh-drawer__footer" }, slots.footer()) : null
731
+ ]
732
+ )
733
+ ]
734
+ )
735
+ ]);
736
+ };
737
+ }
738
+ });
739
+ function flatten(items) {
740
+ const rows = [];
741
+ for (const entry of items) {
742
+ if ("type" in entry && (entry.type === "separator" || entry.type === "label")) continue;
743
+ if ("type" in entry && entry.type === "radio") {
744
+ entry.options.forEach((option, optionIndex) => {
745
+ rows.push({ entry, optionIndex, disabled: option.disabled ?? false });
746
+ });
747
+ continue;
748
+ }
749
+ rows.push({ entry, disabled: entry.disabled ?? false });
750
+ }
751
+ return rows;
752
+ }
753
+ var DropdownMenu = vue.defineComponent({
754
+ name: "AnshDropdownMenu",
755
+ inheritAttrs: false,
756
+ props: {
757
+ items: { type: Array, required: true },
758
+ placement: { type: String, default: "bottom-start" },
759
+ /** Accessible name for the menu itself. */
760
+ label: { type: String, default: "Menu" },
761
+ open: { type: Boolean, default: void 0 },
762
+ defaultOpen: { type: Boolean, default: false }
763
+ },
764
+ emits: ["update:open"],
765
+ setup(props, { slots, attrs, emit }) {
766
+ const [isOpen, setOpen] = chunk774WBLDR_cjs.useControllableState(
767
+ () => props.open,
768
+ props.defaultOpen,
769
+ (next) => emit("update:open", next)
770
+ );
771
+ const triggerRef = vue.ref(null);
772
+ const menuRef = vue.ref(null);
773
+ const menuId = chunk6732H4BQ_cjs.useId("menu");
774
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(isOpen, menuRef);
775
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(triggerRef, menuRef, mounted, {
776
+ placement: props.placement,
777
+ offset: 6
778
+ });
779
+ chunkXLLSS464_cjs.useDismiss(menuRef, isOpen, () => setOpen(false), { ignore: [triggerRef] });
780
+ return () => {
781
+ const panelClass = attrs.class;
782
+ return vue.h("span", { style: { display: "contents" } }, [
783
+ vue.h(
784
+ "span",
785
+ {
786
+ ref: triggerRef,
787
+ class: "ansh-menu-trigger",
788
+ "aria-haspopup": "menu",
789
+ "aria-expanded": isOpen.value,
790
+ "aria-controls": isOpen.value ? menuId : void 0,
791
+ onClick: () => setOpen(!isOpen.value),
792
+ onKeydown: (event) => {
793
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
794
+ event.preventDefault();
795
+ setOpen(true);
796
+ }
797
+ }
798
+ },
799
+ slots.default?.()
800
+ ),
801
+ mounted.value ? vue.h(vue.Teleport, { to: "body" }, [
802
+ vue.h(MenuSurface, {
803
+ panelRef: menuRef,
804
+ id: menuId,
805
+ items: props.items,
806
+ label: props.label,
807
+ state: state.value,
808
+ positionStyle: position.value.style,
809
+ panelClass,
810
+ onClose: () => {
811
+ setOpen(false);
812
+ triggerRef.value?.focus?.();
813
+ }
814
+ })
815
+ ]) : null
816
+ ]);
817
+ };
818
+ }
819
+ });
820
+ var ContextMenu = vue.defineComponent({
821
+ name: "AnshContextMenu",
822
+ inheritAttrs: false,
823
+ props: {
824
+ items: { type: Array, required: true },
825
+ label: { type: String, default: "Context menu" }
826
+ },
827
+ setup(props, { slots, attrs }) {
828
+ const point = vue.ref(null);
829
+ const menuRef = vue.ref(null);
830
+ const anchorRef = vue.ref(null);
831
+ const menuId = chunk6732H4BQ_cjs.useId("contextmenu");
832
+ const open = vue.computed(() => point.value !== null);
833
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(open, menuRef);
834
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(anchorRef, menuRef, mounted, {
835
+ placement: "bottom-start",
836
+ offset: 2
837
+ });
838
+ chunkXLLSS464_cjs.useDismiss(menuRef, open, () => {
839
+ point.value = null;
840
+ });
841
+ return () => {
842
+ const panelClass = attrs.class;
843
+ return vue.h("span", { style: { display: "contents" } }, [
844
+ vue.h(
845
+ "span",
846
+ {
847
+ class: "ansh-contextmenu__area",
848
+ onContextmenu: (event) => {
849
+ event.preventDefault();
850
+ point.value = { x: event.clientX, y: event.clientY };
851
+ },
852
+ onKeydown: (event) => {
853
+ if (event.key === "ContextMenu" || event.shiftKey && event.key === "F10") {
854
+ event.preventDefault();
855
+ const rect = event.currentTarget.getBoundingClientRect();
856
+ point.value = { x: rect.left + 8, y: rect.top + 8 };
857
+ }
858
+ }
859
+ },
860
+ slots.default?.()
861
+ ),
862
+ // A zero-size anchor placed at the pointer. Cheaper than teaching the positioner about
863
+ // virtual elements, and it inherits flip/shift behaviour for free.
864
+ point.value ? vue.h("span", {
865
+ ref: anchorRef,
866
+ "aria-hidden": "true",
867
+ style: {
868
+ position: "fixed",
869
+ left: `${point.value.x}px`,
870
+ top: `${point.value.y}px`,
871
+ width: "0px",
872
+ height: "0px"
873
+ }
874
+ }) : null,
875
+ mounted.value ? vue.h(vue.Teleport, { to: "body" }, [
876
+ vue.h(MenuSurface, {
877
+ panelRef: menuRef,
878
+ id: menuId,
879
+ items: props.items,
880
+ label: props.label,
881
+ state: state.value,
882
+ positionStyle: position.value.style,
883
+ panelClass,
884
+ onClose: () => {
885
+ point.value = null;
886
+ }
887
+ })
888
+ ]) : null
889
+ ]);
890
+ };
891
+ }
892
+ });
893
+ var MenuSurface = vue.defineComponent({
894
+ name: "AnshMenuSurface",
895
+ props: {
896
+ panelRef: { type: Object, required: true },
897
+ id: { type: String, required: true },
898
+ items: { type: Array, required: true },
899
+ label: { type: String, required: true },
900
+ state: { type: String, required: true },
901
+ // Named `positionStyle`/`panelClass` rather than `style`/`class` — Vue merges those two
902
+ // particular prop names onto a component's root element automatically regardless of whether
903
+ // they're declared, which would double up the class list.
904
+ positionStyle: { type: Object, required: true },
905
+ panelClass: { type: String, default: void 0 },
906
+ onClose: { type: Function, required: true }
907
+ },
908
+ setup(props) {
909
+ const rows = vue.computed(() => flatten(props.items));
910
+ const itemRefs = vue.ref([]);
911
+ const active = vue.ref(rows.value.findIndex((row) => !row.disabled));
912
+ const openSubmenu = vue.ref(null);
913
+ let typeaheadBuffer = "";
914
+ let typeaheadTimer;
915
+ vue.onMounted(() => {
916
+ itemRefs.value[active.value]?.focus();
917
+ });
918
+ vue.onBeforeUnmount(() => clearTimeout(typeaheadTimer));
919
+ const move = (delta) => {
920
+ const list = rows.value;
921
+ if (list.length === 0) return;
922
+ let next = active.value;
923
+ for (let attempts = 0; attempts < list.length; attempts++) {
924
+ next = (next + delta + list.length) % list.length;
925
+ if (!list[next]?.disabled) break;
926
+ }
927
+ active.value = next;
928
+ itemRefs.value[next]?.focus();
929
+ };
930
+ const activate = (index) => {
931
+ const row = rows.value[index];
932
+ if (!row || row.disabled) return;
933
+ const { entry } = row;
934
+ if ("type" in entry && entry.type === "submenu") {
935
+ openSubmenu.value = index;
936
+ return;
937
+ }
938
+ if ("type" in entry && entry.type === "checkbox") {
939
+ entry.onChange(!entry.checked);
940
+ return;
941
+ }
942
+ if ("type" in entry && entry.type === "radio") {
943
+ entry.onChange(entry.options[row.optionIndex].value);
944
+ props.onClose();
945
+ return;
946
+ }
947
+ entry.onSelect?.();
948
+ props.onClose();
949
+ };
950
+ const onKeydown = (event) => {
951
+ switch (event.key) {
952
+ case "ArrowDown":
953
+ event.preventDefault();
954
+ move(1);
955
+ break;
956
+ case "ArrowUp":
957
+ event.preventDefault();
958
+ move(-1);
959
+ break;
960
+ case "Home":
961
+ event.preventDefault();
962
+ active.value = 0;
963
+ itemRefs.value[0]?.focus();
964
+ break;
965
+ case "End":
966
+ event.preventDefault();
967
+ active.value = rows.value.length - 1;
968
+ itemRefs.value[rows.value.length - 1]?.focus();
969
+ break;
970
+ case "Enter":
971
+ case " ":
972
+ event.preventDefault();
973
+ activate(active.value);
974
+ break;
975
+ case "ArrowRight": {
976
+ const row = rows.value[active.value];
977
+ if (row && "type" in row.entry && row.entry.type === "submenu") {
978
+ event.preventDefault();
979
+ openSubmenu.value = active.value;
980
+ }
981
+ break;
982
+ }
983
+ case "Escape":
984
+ event.preventDefault();
985
+ props.onClose();
986
+ break;
987
+ case "Tab":
988
+ event.preventDefault();
989
+ props.onClose();
990
+ break;
991
+ default: {
992
+ if (event.key.length !== 1) return;
993
+ clearTimeout(typeaheadTimer);
994
+ typeaheadBuffer += event.key.toLowerCase();
995
+ typeaheadTimer = setTimeout(() => {
996
+ typeaheadBuffer = "";
997
+ }, 600);
998
+ const match = rows.value.findIndex((row, index) => {
999
+ if (row.disabled || index === active.value) return false;
1000
+ const text = typeof row.entry.label === "string" ? row.entry.label : "";
1001
+ return text.toLowerCase().startsWith(typeaheadBuffer);
1002
+ });
1003
+ if (match >= 0) {
1004
+ active.value = match;
1005
+ itemRefs.value[match]?.focus();
1006
+ }
1007
+ }
1008
+ }
1009
+ };
1010
+ return () => {
1011
+ let rowIndex = -1;
1012
+ return vue.h(
1013
+ "div",
1014
+ {
1015
+ ref: props.panelRef,
1016
+ id: props.id,
1017
+ role: "menu",
1018
+ "aria-label": props.label,
1019
+ "data-state": props.state,
1020
+ class: chunk6732H4BQ_cjs.cx("ansh-menu", props.panelClass),
1021
+ style: props.positionStyle,
1022
+ onKeydown
1023
+ },
1024
+ props.items.map((entry, entryIndex) => {
1025
+ if ("type" in entry && entry.type === "separator") {
1026
+ return vue.h("div", {
1027
+ key: `sep-${entryIndex}`,
1028
+ role: "separator",
1029
+ class: "ansh-menu__separator"
1030
+ });
1031
+ }
1032
+ if ("type" in entry && entry.type === "label") {
1033
+ return vue.h(
1034
+ "div",
1035
+ { key: `label-${entryIndex}`, role: "presentation", class: "ansh-menu__label" },
1036
+ [chunk6732H4BQ_cjs.resolveSlotContent(entry.label)]
1037
+ );
1038
+ }
1039
+ if ("type" in entry && entry.type === "radio") {
1040
+ return vue.h(
1041
+ "div",
1042
+ { key: `radio-${entryIndex}`, role: "group", class: "ansh-menu__group" },
1043
+ entry.options.map((option) => {
1044
+ rowIndex++;
1045
+ const index2 = rowIndex;
1046
+ return vue.h(
1047
+ "div",
1048
+ {
1049
+ key: option.value,
1050
+ ref: (node) => {
1051
+ itemRefs.value[index2] = node;
1052
+ },
1053
+ role: "menuitemradio",
1054
+ "aria-checked": entry.value === option.value,
1055
+ "aria-disabled": option.disabled || void 0,
1056
+ tabindex: index2 === active.value ? "0" : "-1",
1057
+ class: chunk6732H4BQ_cjs.cx("ansh-menu__item", option.disabled && "ansh-menu__item--disabled"),
1058
+ onClick: () => activate(index2),
1059
+ onMouseenter: () => {
1060
+ if (!option.disabled) active.value = index2;
1061
+ }
1062
+ },
1063
+ [
1064
+ vue.h("span", {
1065
+ class: chunk6732H4BQ_cjs.cx(
1066
+ "ansh-menu__indicator",
1067
+ entry.value === option.value && "ansh-menu__indicator--on"
1068
+ ),
1069
+ "aria-hidden": "true"
1070
+ }),
1071
+ vue.h("span", { class: "ansh-menu__text" }, [chunk6732H4BQ_cjs.resolveSlotContent(option.label)])
1072
+ ]
1073
+ );
1074
+ })
1075
+ );
1076
+ }
1077
+ rowIndex++;
1078
+ const index = rowIndex;
1079
+ if ("type" in entry && entry.type === "checkbox") {
1080
+ return vue.h(
1081
+ "div",
1082
+ {
1083
+ key: entry.id ?? `check-${entryIndex}`,
1084
+ ref: (node) => {
1085
+ itemRefs.value[index] = node;
1086
+ },
1087
+ role: "menuitemcheckbox",
1088
+ "aria-checked": entry.checked,
1089
+ "aria-disabled": entry.disabled || void 0,
1090
+ tabindex: index === active.value ? "0" : "-1",
1091
+ class: chunk6732H4BQ_cjs.cx("ansh-menu__item", entry.disabled && "ansh-menu__item--disabled"),
1092
+ onClick: () => activate(index),
1093
+ onMouseenter: () => {
1094
+ if (!entry.disabled) active.value = index;
1095
+ }
1096
+ },
1097
+ [
1098
+ vue.h(
1099
+ "span",
1100
+ {
1101
+ class: chunk6732H4BQ_cjs.cx(
1102
+ "ansh-menu__indicator",
1103
+ "ansh-menu__indicator--check",
1104
+ entry.checked && "ansh-menu__indicator--on"
1105
+ ),
1106
+ "aria-hidden": "true"
1107
+ },
1108
+ [
1109
+ vue.h("svg", { viewBox: "0 0 14 14", width: "10", height: "10" }, [
1110
+ vue.h("path", {
1111
+ d: "M2.5 7.5l3 3 6-6.5",
1112
+ stroke: "currentColor",
1113
+ "stroke-width": "2",
1114
+ "stroke-linecap": "round",
1115
+ "stroke-linejoin": "round",
1116
+ fill: "none"
1117
+ })
1118
+ ])
1119
+ ]
1120
+ ),
1121
+ vue.h("span", { class: "ansh-menu__text" }, [chunk6732H4BQ_cjs.resolveSlotContent(entry.label)]),
1122
+ entry.shortcut ? vue.h("kbd", { class: "ansh-menu__shortcut" }, entry.shortcut) : null
1123
+ ]
1124
+ );
1125
+ }
1126
+ if ("type" in entry && entry.type === "submenu") {
1127
+ return vue.h(Submenu, {
1128
+ key: entry.id ?? `sub-${entryIndex}`,
1129
+ entry,
1130
+ active: index === active.value,
1131
+ open: openSubmenu.value === index,
1132
+ onOpenChange: (next) => {
1133
+ openSubmenu.value = next ? index : null;
1134
+ },
1135
+ onHover: () => {
1136
+ active.value = index;
1137
+ },
1138
+ onCloseAll: () => props.onClose(),
1139
+ onItemRef: (node) => {
1140
+ itemRefs.value[index] = node;
1141
+ }
1142
+ });
1143
+ }
1144
+ const action = entry;
1145
+ return vue.h(
1146
+ "div",
1147
+ {
1148
+ key: action.id ?? `item-${entryIndex}`,
1149
+ ref: (node) => {
1150
+ itemRefs.value[index] = node;
1151
+ },
1152
+ role: "menuitem",
1153
+ "aria-disabled": action.disabled || void 0,
1154
+ tabindex: index === active.value ? "0" : "-1",
1155
+ class: chunk6732H4BQ_cjs.cx(
1156
+ "ansh-menu__item",
1157
+ action.danger && "ansh-menu__item--danger",
1158
+ action.disabled && "ansh-menu__item--disabled"
1159
+ ),
1160
+ onClick: () => activate(index),
1161
+ onMouseenter: () => {
1162
+ if (!action.disabled) active.value = index;
1163
+ }
1164
+ },
1165
+ [
1166
+ action.icon ? vue.h("span", { class: "ansh-menu__icon" }, [chunk6732H4BQ_cjs.resolveSlotContent(action.icon)]) : null,
1167
+ vue.h("span", { class: "ansh-menu__text" }, [chunk6732H4BQ_cjs.resolveSlotContent(action.label)]),
1168
+ action.shortcut ? vue.h("kbd", { class: "ansh-menu__shortcut" }, action.shortcut) : null
1169
+ ]
1170
+ );
1171
+ })
1172
+ );
1173
+ };
1174
+ }
1175
+ });
1176
+ var Submenu = vue.defineComponent({
1177
+ name: "AnshMenuSubmenu",
1178
+ props: {
1179
+ entry: { type: Object, required: true },
1180
+ active: { type: Boolean, required: true },
1181
+ open: { type: Boolean, required: true },
1182
+ onOpenChange: { type: Function, required: true },
1183
+ onHover: { type: Function, required: true },
1184
+ onCloseAll: { type: Function, required: true },
1185
+ /** Reports this submenu's trigger element up so the parent's roving-focus array includes it. */
1186
+ onItemRef: { type: Function, required: true }
1187
+ },
1188
+ setup(props) {
1189
+ const triggerRef = vue.ref(null);
1190
+ const panelRef = vue.ref(null);
1191
+ let timer;
1192
+ const id = chunk6732H4BQ_cjs.useId("submenu");
1193
+ const openRef = vue.computed(() => props.open);
1194
+ const { mounted, state } = chunkDMPNT3MY_cjs.usePresence(openRef, panelRef);
1195
+ const { position } = chunkXLLSS464_cjs.useAnchoredPosition(triggerRef, panelRef, mounted, {
1196
+ placement: "right-start",
1197
+ offset: 2
1198
+ });
1199
+ vue.onBeforeUnmount(() => clearTimeout(timer));
1200
+ return () => vue.h("span", { style: { display: "contents" } }, [
1201
+ vue.h(
1202
+ "div",
1203
+ {
1204
+ ref: (node) => {
1205
+ triggerRef.value = node;
1206
+ props.onItemRef(node);
1207
+ },
1208
+ role: "menuitem",
1209
+ "aria-haspopup": "menu",
1210
+ "aria-expanded": props.open,
1211
+ "aria-controls": props.open ? id : void 0,
1212
+ "aria-disabled": props.entry.disabled || void 0,
1213
+ tabindex: props.active ? "0" : "-1",
1214
+ class: chunk6732H4BQ_cjs.cx(
1215
+ "ansh-menu__item",
1216
+ "ansh-menu__item--submenu",
1217
+ props.entry.disabled && "ansh-menu__item--disabled"
1218
+ ),
1219
+ onMouseenter: () => {
1220
+ props.onHover();
1221
+ clearTimeout(timer);
1222
+ timer = setTimeout(() => props.onOpenChange(true), 120);
1223
+ },
1224
+ onMouseleave: () => {
1225
+ clearTimeout(timer);
1226
+ timer = setTimeout(() => props.onOpenChange(false), 200);
1227
+ },
1228
+ onClick: () => props.onOpenChange(!props.open)
1229
+ },
1230
+ [
1231
+ props.entry.icon ? vue.h("span", { class: "ansh-menu__icon" }, [chunk6732H4BQ_cjs.resolveSlotContent(props.entry.icon)]) : null,
1232
+ vue.h("span", { class: "ansh-menu__text" }, [chunk6732H4BQ_cjs.resolveSlotContent(props.entry.label)]),
1233
+ vue.h("span", { class: "ansh-menu__chevron", "aria-hidden": "true" }, [
1234
+ vue.h("svg", { viewBox: "0 0 12 12", width: "12", height: "12" }, [
1235
+ vue.h("path", {
1236
+ d: "M4.5 2.5L8 6l-3.5 3.5",
1237
+ stroke: "currentColor",
1238
+ "stroke-width": "1.5",
1239
+ fill: "none",
1240
+ "stroke-linecap": "round",
1241
+ "stroke-linejoin": "round"
1242
+ })
1243
+ ])
1244
+ ])
1245
+ ]
1246
+ ),
1247
+ mounted.value ? vue.h(vue.Teleport, { to: "body" }, [
1248
+ vue.h(
1249
+ "div",
1250
+ {
1251
+ onMouseenter: () => clearTimeout(timer),
1252
+ onMouseleave: () => {
1253
+ timer = setTimeout(() => props.onOpenChange(false), 200);
1254
+ },
1255
+ onKeydown: (event) => {
1256
+ if (event.key === "ArrowLeft") {
1257
+ event.preventDefault();
1258
+ event.stopPropagation();
1259
+ props.onOpenChange(false);
1260
+ triggerRef.value?.focus();
1261
+ }
1262
+ }
1263
+ },
1264
+ [
1265
+ vue.h(MenuSurface, {
1266
+ panelRef,
1267
+ id,
1268
+ items: props.entry.items,
1269
+ label: typeof props.entry.label === "string" ? props.entry.label : "Submenu",
1270
+ state: state.value,
1271
+ positionStyle: position.value.style,
1272
+ onClose: props.onCloseAll
1273
+ })
1274
+ ]
1275
+ )
1276
+ ]) : null
1277
+ ]);
1278
+ }
1279
+ });
1280
+
1281
+ exports.AlertDialog = AlertDialog;
1282
+ exports.ContextMenu = ContextMenu;
1283
+ exports.Dialog = Dialog;
1284
+ exports.DialogFooter = DialogFooter;
1285
+ exports.Drawer = Drawer;
1286
+ exports.DropdownMenu = DropdownMenu;
1287
+ exports.HoverCard = HoverCard;
1288
+ exports.Popover = Popover;
1289
+ exports.PopoverContent = PopoverContent;
1290
+ exports.PopoverTrigger = PopoverTrigger;
1291
+ exports.Tooltip = Tooltip;
1292
+ exports.TooltipProvider = TooltipProvider;
1293
+ //# sourceMappingURL=chunk-5BQEZYG6.cjs.map
1294
+ //# sourceMappingURL=chunk-5BQEZYG6.cjs.map