@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,773 @@
1
+ import { useRovingFocus } from './chunk-TMG3M6TK.js';
2
+ import { useControllableState } from './chunk-OAQ7MDYX.js';
3
+ import { useId, cx, resolveSlotContent } from './chunk-NJDDNO4C.js';
4
+ import { defineComponent, ref, computed, h, onBeforeUnmount, watch } from 'vue';
5
+
6
+ var Tabs = defineComponent({
7
+ name: "AnshTabs",
8
+ inheritAttrs: false,
9
+ props: {
10
+ items: { type: Array, required: true },
11
+ modelValue: { type: String, default: void 0 },
12
+ defaultValue: { type: String, default: void 0 },
13
+ variant: { type: String, default: "underline" },
14
+ orientation: { type: String, default: "horizontal" },
15
+ size: { type: String, default: "md" },
16
+ /** Stretch tabs to fill the available width. */
17
+ fitted: { type: Boolean, default: false },
18
+ /**
19
+ * Activate on arrow-key focus, rather than requiring Enter/Space.
20
+ *
21
+ * Automatic is the ARIA-preferred default for cheap panels. Set `false` when switching a tab
22
+ * triggers a fetch — arrowing past three tabs would fire three requests.
23
+ */
24
+ activateOnFocus: { type: Boolean, default: true },
25
+ /** Accessible name for the tab list. */
26
+ label: { type: String, required: true }
27
+ },
28
+ emits: ["update:modelValue"],
29
+ setup(props, { attrs, emit, slots }) {
30
+ const initialActive = props.defaultValue ?? props.items.find((item) => !item.disabled)?.id ?? "";
31
+ const [active, setActive] = useControllableState(
32
+ () => props.modelValue,
33
+ initialActive,
34
+ (next) => emit("update:modelValue", next)
35
+ );
36
+ const baseId = useId();
37
+ const tabRefs = ref([]);
38
+ const activeItem = computed(() => props.items.find((item) => item.id === active.value));
39
+ const enabledIds = computed(
40
+ () => props.items.filter((item) => !item.disabled).map((item) => item.id)
41
+ );
42
+ const onRovingActiveChange = (position) => {
43
+ const id = enabledIds.value[position];
44
+ if (id !== void 0 && props.activateOnFocus) setActive(id);
45
+ };
46
+ const onKeydown = useRovingFocus({
47
+ items: tabRefs,
48
+ active: () => enabledIds.value.indexOf(active.value),
49
+ onActiveChange: onRovingActiveChange,
50
+ orientation: props.orientation,
51
+ loop: true
52
+ });
53
+ return () => {
54
+ const { class: attrClass, ...restAttrs } = attrs;
55
+ const currentActive = active.value;
56
+ const currentActiveItem = activeItem.value;
57
+ const hasPanel = currentActiveItem?.content !== void 0 || Boolean(slots.default);
58
+ return h(
59
+ "div",
60
+ {
61
+ class: cx(
62
+ "ansh-tabs",
63
+ `ansh-tabs--${props.variant}`,
64
+ `ansh-tabs--${props.orientation}`,
65
+ `ansh-tabs--${props.size}`,
66
+ attrClass
67
+ ),
68
+ ...restAttrs
69
+ },
70
+ [
71
+ h(
72
+ "div",
73
+ {
74
+ role: "tablist",
75
+ "aria-label": props.label,
76
+ "aria-orientation": props.orientation,
77
+ class: cx("ansh-tabs__list", props.fitted && "ansh-tabs__list--fitted"),
78
+ onKeydown
79
+ },
80
+ props.items.map((item, index) => {
81
+ const selected = item.id === currentActive;
82
+ return h(
83
+ "button",
84
+ {
85
+ key: item.id,
86
+ ref: (node) => {
87
+ tabRefs.value[index] = item.disabled ? null : node;
88
+ },
89
+ type: "button",
90
+ role: "tab",
91
+ id: `${baseId}-tab-${item.id}`,
92
+ "aria-selected": selected,
93
+ "aria-controls": `${baseId}-panel-${item.id}`,
94
+ // Exactly one tab is in the tab order. Without this, a bar of eight tabs costs a
95
+ // keyboard user eight presses to pass.
96
+ tabindex: selected ? "0" : "-1",
97
+ disabled: item.disabled,
98
+ class: cx(
99
+ "ansh-tabs__tab",
100
+ selected && "ansh-tabs__tab--active",
101
+ "ansh-focusable"
102
+ ),
103
+ onClick: () => setActive(item.id)
104
+ },
105
+ [
106
+ item.icon !== void 0 ? h("span", { class: "ansh-tabs__icon" }, [resolveSlotContent(item.icon)]) : null,
107
+ h("span", {}, [resolveSlotContent(item.label)]),
108
+ item.badge !== void 0 ? h("span", { class: "ansh-tabs__badge" }, [resolveSlotContent(item.badge)]) : null
109
+ ]
110
+ );
111
+ })
112
+ ),
113
+ hasPanel ? h(
114
+ "div",
115
+ {
116
+ role: "tabpanel",
117
+ id: `${baseId}-panel-${currentActive}`,
118
+ "aria-labelledby": `${baseId}-tab-${currentActive}`,
119
+ // Focusable so a keyboard user can Tab from the tab into its panel and scroll it,
120
+ // which is required when the panel has no focusable content of its own.
121
+ tabindex: "0",
122
+ class: "ansh-tabs__panel ansh-focusable"
123
+ },
124
+ [
125
+ currentActiveItem?.content !== void 0 ? resolveSlotContent(currentActiveItem.content) : slots.default?.()
126
+ ]
127
+ ) : null
128
+ ]
129
+ );
130
+ };
131
+ }
132
+ });
133
+ var Breadcrumbs = defineComponent({
134
+ name: "AnshBreadcrumbs",
135
+ inheritAttrs: false,
136
+ props: {
137
+ items: { type: Array, required: true },
138
+ /** Collapse the middle when there are more than this many. Default `Infinity`. */
139
+ maxItems: { type: Number, default: Number.POSITIVE_INFINITY },
140
+ separator: { type: [String, Object, Function], default: void 0 }
141
+ },
142
+ setup(props, { attrs }) {
143
+ const expanded = ref(false);
144
+ const defaultChevron = () => h("svg", { viewBox: "0 0 12 12", width: "12", height: "12", "aria-hidden": "true" }, [
145
+ h("path", {
146
+ d: "M4.5 2.5L8 6l-3.5 3.5",
147
+ stroke: "currentColor",
148
+ "stroke-width": "1.5",
149
+ fill: "none",
150
+ "stroke-linecap": "round",
151
+ "stroke-linejoin": "round"
152
+ })
153
+ ]);
154
+ const renderChevron = () => props.separator !== void 0 ? resolveSlotContent(props.separator) : defaultChevron();
155
+ return () => {
156
+ const { class: attrClass, ...restAttrs } = attrs;
157
+ const items = props.items;
158
+ const collapsed = !expanded.value && items.length > props.maxItems && props.maxItems >= 2;
159
+ const shown = collapsed ? [items[0], ...items.slice(-2)] : items;
160
+ const gapAfter = collapsed ? 0 : -1;
161
+ return h(
162
+ "nav",
163
+ {
164
+ "aria-label": "Breadcrumb",
165
+ class: cx("ansh-breadcrumbs", attrClass),
166
+ ...restAttrs
167
+ },
168
+ [
169
+ h(
170
+ "ol",
171
+ { class: "ansh-breadcrumbs__list" },
172
+ shown.map((crumb, index) => {
173
+ const isLast = index === shown.length - 1;
174
+ return h("li", { key: index, class: "ansh-breadcrumbs__item" }, [
175
+ index > 0 ? h("span", { class: "ansh-breadcrumbs__separator", "aria-hidden": "true" }, [
176
+ renderChevron()
177
+ ]) : null,
178
+ isLast ? h("span", { class: "ansh-breadcrumbs__current", "aria-current": "page" }, [
179
+ crumb.icon !== void 0 ? resolveSlotContent(crumb.icon) : null,
180
+ resolveSlotContent(crumb.label)
181
+ ]) : h(
182
+ "a",
183
+ {
184
+ href: crumb.href ?? "#",
185
+ class: "ansh-breadcrumbs__link ansh-focusable",
186
+ onClick: crumb.onClick ? (event) => {
187
+ event.preventDefault();
188
+ crumb.onClick();
189
+ } : void 0
190
+ },
191
+ [
192
+ crumb.icon !== void 0 ? resolveSlotContent(crumb.icon) : null,
193
+ resolveSlotContent(crumb.label)
194
+ ]
195
+ ),
196
+ index === gapAfter ? [
197
+ h("span", { class: "ansh-breadcrumbs__separator", "aria-hidden": "true" }, [
198
+ renderChevron()
199
+ ]),
200
+ h(
201
+ "button",
202
+ {
203
+ type: "button",
204
+ class: "ansh-breadcrumbs__more ansh-focusable",
205
+ "aria-label": `Show ${items.length - 3} hidden breadcrumbs`,
206
+ "aria-expanded": false,
207
+ onClick: () => {
208
+ expanded.value = true;
209
+ }
210
+ },
211
+ "\u2026"
212
+ )
213
+ ] : null
214
+ ]);
215
+ })
216
+ )
217
+ ]
218
+ );
219
+ };
220
+ }
221
+ });
222
+ var Stepper = defineComponent({
223
+ name: "AnshStepper",
224
+ inheritAttrs: false,
225
+ props: {
226
+ steps: { type: Array, required: true },
227
+ /** Index of the current step. Steps before it are complete. */
228
+ current: { type: Number, required: true },
229
+ orientation: { type: String, default: "horizontal" }
230
+ },
231
+ emits: ["update:current"],
232
+ setup(props, { attrs, emit }) {
233
+ return () => {
234
+ const { class: attrClass, ...restAttrs } = attrs;
235
+ return h(
236
+ "nav",
237
+ {
238
+ class: cx("ansh-stepper", `ansh-stepper--${props.orientation}`, attrClass),
239
+ "aria-label": "Progress",
240
+ ...restAttrs
241
+ },
242
+ [
243
+ h(
244
+ "ol",
245
+ { class: "ansh-stepper__list" },
246
+ props.steps.map((step, index) => {
247
+ const complete = index < props.current;
248
+ const active = index === props.current;
249
+ const state = step.error ? "error" : complete ? "complete" : active ? "current" : "upcoming";
250
+ const interactive = step.clickable && index !== props.current;
251
+ const inner = [
252
+ h(
253
+ "span",
254
+ {
255
+ class: cx("ansh-stepper__marker", `ansh-stepper__marker--${state}`),
256
+ "aria-hidden": "true"
257
+ },
258
+ [
259
+ step.error ? "!" : complete ? h("svg", { viewBox: "0 0 14 14", width: "12", height: "12" }, [
260
+ h("path", {
261
+ d: "M2.5 7.5l3 3 6-6.5",
262
+ stroke: "currentColor",
263
+ "stroke-width": "2",
264
+ "stroke-linecap": "round",
265
+ "stroke-linejoin": "round",
266
+ fill: "none"
267
+ })
268
+ ]) : String(index + 1)
269
+ ]
270
+ ),
271
+ h("span", { class: "ansh-stepper__text" }, [
272
+ h("span", { class: "ansh-stepper__label" }, [resolveSlotContent(step.label)]),
273
+ step.description ? h("span", { class: "ansh-stepper__description" }, [
274
+ resolveSlotContent(step.description)
275
+ ]) : null,
276
+ h("span", { class: "ansh-visually-hidden" }, [
277
+ step.error ? " \u2014 has errors" : complete ? " \u2014 completed" : active ? " \u2014 current step" : " \u2014 not started"
278
+ ])
279
+ ])
280
+ ];
281
+ return h(
282
+ "li",
283
+ {
284
+ key: step.id,
285
+ class: cx("ansh-stepper__item", `ansh-stepper__item--${state}`),
286
+ "aria-current": active ? "step" : void 0
287
+ },
288
+ [
289
+ interactive ? h(
290
+ "button",
291
+ {
292
+ type: "button",
293
+ class: "ansh-stepper__button ansh-focusable",
294
+ onClick: () => emit("update:current", index)
295
+ },
296
+ inner
297
+ ) : h("span", { class: "ansh-stepper__button" }, inner)
298
+ ]
299
+ );
300
+ })
301
+ )
302
+ ]
303
+ );
304
+ };
305
+ }
306
+ });
307
+ var NavigationMenu = defineComponent({
308
+ name: "AnshNavigationMenu",
309
+ inheritAttrs: false,
310
+ props: {
311
+ items: { type: Array, required: true },
312
+ label: { type: String, default: "Main navigation" }
313
+ },
314
+ setup(props, { attrs }) {
315
+ const openId = ref(null);
316
+ const rootRef = ref(null);
317
+ const baseId = useId();
318
+ let timer;
319
+ const schedule = (next, delay) => {
320
+ clearTimeout(timer);
321
+ timer = setTimeout(() => {
322
+ openId.value = next;
323
+ }, delay);
324
+ };
325
+ onBeforeUnmount(() => clearTimeout(timer));
326
+ watch(openId, (id, _previous, onCleanup) => {
327
+ if (!id) return;
328
+ const root = rootRef.value;
329
+ if (!root) return;
330
+ const onFocusOut = (event) => {
331
+ const next = event.relatedTarget;
332
+ if (next && root.contains(next)) return;
333
+ openId.value = null;
334
+ };
335
+ const onKeyDown = (event) => {
336
+ if (event.key !== "Escape") return;
337
+ openId.value = null;
338
+ root.querySelector('[aria-expanded="true"]')?.focus();
339
+ };
340
+ root.addEventListener("focusout", onFocusOut);
341
+ document.addEventListener("keydown", onKeyDown);
342
+ onCleanup(() => {
343
+ root.removeEventListener("focusout", onFocusOut);
344
+ document.removeEventListener("keydown", onKeyDown);
345
+ });
346
+ });
347
+ return () => {
348
+ const { class: attrClass, ...restAttrs } = attrs;
349
+ return h(
350
+ "nav",
351
+ {
352
+ ref: rootRef,
353
+ class: cx("ansh-navmenu", attrClass),
354
+ "aria-label": props.label,
355
+ onMouseleave: () => schedule(null, 200),
356
+ ...restAttrs
357
+ },
358
+ [
359
+ h(
360
+ "ul",
361
+ { class: "ansh-navmenu__list" },
362
+ props.items.map((item) => {
363
+ const hasPanel = Boolean(item.columns?.length);
364
+ const open = openId.value === item.id;
365
+ const panelId = `${baseId}-${item.id}`;
366
+ if (!hasPanel) {
367
+ return h("li", { key: item.id, class: "ansh-navmenu__item" }, [
368
+ h(
369
+ "a",
370
+ { href: item.href ?? "#", class: "ansh-navmenu__link ansh-focusable" },
371
+ item.label
372
+ )
373
+ ]);
374
+ }
375
+ return h(
376
+ "li",
377
+ {
378
+ key: item.id,
379
+ class: cx("ansh-navmenu__item", open && "ansh-navmenu__item--open"),
380
+ onMouseenter: () => schedule(item.id, 80)
381
+ },
382
+ [
383
+ h(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ class: "ansh-navmenu__link ansh-navmenu__link--trigger ansh-focusable",
388
+ "aria-expanded": open,
389
+ "aria-controls": panelId,
390
+ onClick: () => {
391
+ openId.value = open ? null : item.id;
392
+ },
393
+ onKeydown: (event) => {
394
+ if (event.key !== "ArrowDown") return;
395
+ event.preventDefault();
396
+ openId.value = item.id;
397
+ requestAnimationFrame(() => {
398
+ document.getElementById(panelId)?.querySelector("a, button")?.focus();
399
+ });
400
+ }
401
+ },
402
+ [
403
+ item.label,
404
+ h(
405
+ "span",
406
+ {
407
+ class: cx("ansh-navmenu__chevron", open && "ansh-navmenu__chevron--open"),
408
+ "aria-hidden": "true"
409
+ },
410
+ [
411
+ h("svg", { viewBox: "0 0 12 12", width: "10", height: "10" }, [
412
+ h("path", {
413
+ d: "M3 4.5L6 7.5l3-3",
414
+ stroke: "currentColor",
415
+ "stroke-width": "1.5",
416
+ fill: "none",
417
+ "stroke-linecap": "round",
418
+ "stroke-linejoin": "round"
419
+ })
420
+ ])
421
+ ]
422
+ )
423
+ ]
424
+ ),
425
+ h(
426
+ "div",
427
+ {
428
+ id: panelId,
429
+ class: "ansh-navmenu__panel",
430
+ hidden: !open,
431
+ onMouseenter: () => clearTimeout(timer)
432
+ },
433
+ [
434
+ h("div", { class: "ansh-navmenu__grid" }, [
435
+ ...item.columns.map(
436
+ (column) => h("div", { class: "ansh-navmenu__column", key: column.id }, [
437
+ column.heading ? h("p", { class: "ansh-navmenu__heading" }, column.heading) : null,
438
+ h(
439
+ "ul",
440
+ { class: "ansh-navmenu__links" },
441
+ column.links.map(
442
+ (link) => h("li", { key: link.id }, [
443
+ h(
444
+ "a",
445
+ {
446
+ href: link.href ?? "#",
447
+ class: "ansh-navmenu__entry ansh-focusable",
448
+ onClick: link.onClick ? (event) => {
449
+ event.preventDefault();
450
+ link.onClick();
451
+ openId.value = null;
452
+ } : () => {
453
+ openId.value = null;
454
+ }
455
+ },
456
+ [
457
+ link.icon !== void 0 ? h(
458
+ "span",
459
+ { class: "ansh-navmenu__icon", "aria-hidden": "true" },
460
+ [resolveSlotContent(link.icon)]
461
+ ) : null,
462
+ h("span", { class: "ansh-navmenu__entry-text" }, [
463
+ h(
464
+ "span",
465
+ { class: "ansh-navmenu__entry-label" },
466
+ link.label
467
+ ),
468
+ link.description ? h(
469
+ "span",
470
+ { class: "ansh-navmenu__entry-description" },
471
+ link.description
472
+ ) : null
473
+ ])
474
+ ]
475
+ )
476
+ ])
477
+ )
478
+ )
479
+ ])
480
+ ),
481
+ item.feature !== void 0 ? h("div", { class: "ansh-navmenu__feature" }, [
482
+ resolveSlotContent(item.feature)
483
+ ]) : null
484
+ ])
485
+ ]
486
+ )
487
+ ]
488
+ );
489
+ })
490
+ )
491
+ ]
492
+ );
493
+ };
494
+ }
495
+ });
496
+ var Collapsible = defineComponent({
497
+ name: "AnshCollapsible",
498
+ inheritAttrs: false,
499
+ props: {
500
+ open: { type: Boolean, default: void 0 },
501
+ defaultOpen: { type: Boolean, default: false },
502
+ trigger: { type: [String, Object, Function], required: true },
503
+ bare: { type: Boolean, default: false }
504
+ },
505
+ emits: ["update:open"],
506
+ setup(props, { attrs, emit, slots }) {
507
+ const [isOpen, setOpen] = useControllableState(
508
+ () => props.open,
509
+ props.defaultOpen,
510
+ (next) => emit("update:open", next)
511
+ );
512
+ const id = useId();
513
+ return () => {
514
+ const { class: attrClass, ...restAttrs } = attrs;
515
+ return h(
516
+ "div",
517
+ {
518
+ class: cx("ansh-collapsible", attrClass),
519
+ "data-state": isOpen.value ? "open" : "closed",
520
+ ...restAttrs
521
+ },
522
+ [
523
+ h(
524
+ "button",
525
+ {
526
+ type: "button",
527
+ class: cx(
528
+ props.bare ? "ansh-collapsible__bare" : "ansh-collapsible__trigger",
529
+ "ansh-focusable"
530
+ ),
531
+ "aria-expanded": isOpen.value,
532
+ "aria-controls": id,
533
+ onClick: () => setOpen(!isOpen.value)
534
+ },
535
+ [
536
+ resolveSlotContent(props.trigger),
537
+ h(
538
+ "span",
539
+ {
540
+ class: cx(
541
+ "ansh-collapsible__chevron",
542
+ isOpen.value && "ansh-collapsible__chevron--open"
543
+ ),
544
+ "aria-hidden": "true"
545
+ },
546
+ [
547
+ h("svg", { viewBox: "0 0 12 12", width: "12", height: "12" }, [
548
+ h("path", {
549
+ d: "M3 4.5L6 7.5l3-3",
550
+ stroke: "currentColor",
551
+ "stroke-width": "1.5",
552
+ fill: "none",
553
+ "stroke-linecap": "round",
554
+ "stroke-linejoin": "round"
555
+ })
556
+ ])
557
+ ]
558
+ )
559
+ ]
560
+ ),
561
+ h(
562
+ "div",
563
+ {
564
+ class: "ansh-collapsible__region",
565
+ id,
566
+ role: "region",
567
+ "data-state": isOpen.value ? "open" : "closed"
568
+ },
569
+ [
570
+ // `inert` on the collapsed panel removes its contents from the tab order and the
571
+ // accessibility tree. Without it, a keyboard user tabs into links inside a section
572
+ // that is visually closed — invisible focus, and no way to tell where they are.
573
+ h(
574
+ "div",
575
+ { class: "ansh-collapsible__inner", ...isOpen.value ? null : { inert: true } },
576
+ slots.default?.()
577
+ )
578
+ ]
579
+ )
580
+ ]
581
+ );
582
+ };
583
+ }
584
+ });
585
+ var Accordion = defineComponent({
586
+ name: "AnshAccordion",
587
+ inheritAttrs: false,
588
+ props: {
589
+ items: { type: Array, required: true },
590
+ /** Allow several panels open at once. Default `false`. */
591
+ multiple: { type: Boolean, default: false },
592
+ modelValue: { type: Array, default: void 0 },
593
+ defaultValue: { type: Array, default: () => [] },
594
+ variant: { type: String, default: "bordered" }
595
+ },
596
+ emits: ["update:modelValue"],
597
+ setup(props, { attrs, emit }) {
598
+ const [openIds, setOpenIds] = useControllableState(
599
+ () => props.modelValue,
600
+ props.defaultValue,
601
+ (next) => emit("update:modelValue", next)
602
+ );
603
+ const baseId = useId();
604
+ const headerRefs = ref([]);
605
+ const toggle = (id) => {
606
+ if (openIds.value.includes(id)) {
607
+ setOpenIds(openIds.value.filter((entry) => entry !== id));
608
+ } else {
609
+ setOpenIds(props.multiple ? [...openIds.value, id] : [id]);
610
+ }
611
+ };
612
+ const onKeydown = useRovingFocus({
613
+ items: headerRefs,
614
+ // There is no single "active" header the way `Tabs` has a selected tab — arrow keys move
615
+ // relative to whichever header currently owns focus.
616
+ active: () => {
617
+ const enabled = headerRefs.value.filter((node) => node !== null);
618
+ return enabled.indexOf(document.activeElement);
619
+ },
620
+ // The hook already moves focus to the target header; there is no selection model to sync.
621
+ onActiveChange: () => {
622
+ },
623
+ orientation: "vertical",
624
+ loop: true
625
+ });
626
+ return () => {
627
+ const { class: attrClass, ...restAttrs } = attrs;
628
+ return h(
629
+ "div",
630
+ {
631
+ class: cx("ansh-accordion", `ansh-accordion--${props.variant}`, attrClass),
632
+ onKeydown,
633
+ ...restAttrs
634
+ },
635
+ props.items.map((item, index) => {
636
+ const open = openIds.value.includes(item.id);
637
+ const panelId = `${baseId}-panel-${item.id}`;
638
+ const headerId = `${baseId}-header-${item.id}`;
639
+ return h(
640
+ "div",
641
+ {
642
+ key: item.id,
643
+ class: cx("ansh-accordion__item", open && "ansh-accordion__item--open"),
644
+ "data-state": open ? "open" : "closed"
645
+ },
646
+ [
647
+ h("h3", { class: "ansh-accordion__heading" }, [
648
+ h(
649
+ "button",
650
+ {
651
+ ref: (node) => {
652
+ headerRefs.value[index] = item.disabled ? null : node;
653
+ },
654
+ type: "button",
655
+ id: headerId,
656
+ class: "ansh-accordion__trigger ansh-focusable",
657
+ "aria-expanded": open,
658
+ "aria-controls": panelId,
659
+ disabled: item.disabled,
660
+ onClick: () => toggle(item.id)
661
+ },
662
+ [
663
+ item.icon !== void 0 ? h("span", { class: "ansh-accordion__icon" }, [
664
+ resolveSlotContent(item.icon)
665
+ ]) : null,
666
+ h("span", { class: "ansh-accordion__text" }, [
667
+ h("span", { class: "ansh-accordion__title" }, [
668
+ resolveSlotContent(item.title)
669
+ ]),
670
+ item.subtitle ? h("span", { class: "ansh-accordion__subtitle" }, [
671
+ resolveSlotContent(item.subtitle)
672
+ ]) : null
673
+ ]),
674
+ h(
675
+ "span",
676
+ {
677
+ class: cx(
678
+ "ansh-accordion__chevron",
679
+ open && "ansh-accordion__chevron--open"
680
+ ),
681
+ "aria-hidden": "true"
682
+ },
683
+ [
684
+ h("svg", { viewBox: "0 0 12 12", width: "12", height: "12" }, [
685
+ h("path", {
686
+ d: "M3 4.5L6 7.5l3-3",
687
+ stroke: "currentColor",
688
+ "stroke-width": "1.5",
689
+ fill: "none",
690
+ "stroke-linecap": "round",
691
+ "stroke-linejoin": "round"
692
+ })
693
+ ])
694
+ ]
695
+ )
696
+ ]
697
+ )
698
+ ]),
699
+ h(
700
+ "div",
701
+ {
702
+ class: "ansh-accordion__region",
703
+ id: panelId,
704
+ role: "region",
705
+ "aria-labelledby": headerId,
706
+ "data-state": open ? "open" : "closed"
707
+ },
708
+ [
709
+ h("div", { class: "ansh-accordion__panel", ...open ? null : { inert: true } }, [
710
+ resolveSlotContent(item.content)
711
+ ])
712
+ ]
713
+ )
714
+ ]
715
+ );
716
+ })
717
+ );
718
+ };
719
+ }
720
+ });
721
+ var DisclosureList = defineComponent({
722
+ name: "AnshDisclosureList",
723
+ inheritAttrs: false,
724
+ props: {
725
+ items: { type: Array, required: true },
726
+ initial: { type: Number, default: 3 },
727
+ moreLabel: {
728
+ type: Function,
729
+ default: (hidden) => `Show ${hidden} more`
730
+ },
731
+ lessLabel: { type: String, default: "Show less" }
732
+ },
733
+ setup(props, { attrs }) {
734
+ const expanded = ref(false);
735
+ const id = useId();
736
+ return () => {
737
+ const { class: attrClass, ...restAttrs } = attrs;
738
+ const hidden = props.items.length - props.initial;
739
+ if (hidden <= 0) {
740
+ return h(
741
+ "ul",
742
+ { class: cx("ansh-disclosure-list", attrClass), ...restAttrs },
743
+ props.items.map((item, index) => h("li", { key: index }, [resolveSlotContent(item)]))
744
+ );
745
+ }
746
+ const shown = expanded.value ? props.items : props.items.slice(0, props.initial);
747
+ return h("div", { class: attrClass, ...restAttrs }, [
748
+ h(
749
+ "ul",
750
+ { class: "ansh-disclosure-list", id },
751
+ shown.map((item, index) => h("li", { key: index }, [resolveSlotContent(item)]))
752
+ ),
753
+ h(
754
+ "button",
755
+ {
756
+ type: "button",
757
+ class: "ansh-disclosure-list__toggle ansh-focusable",
758
+ "aria-expanded": expanded.value,
759
+ "aria-controls": id,
760
+ onClick: () => {
761
+ expanded.value = !expanded.value;
762
+ }
763
+ },
764
+ expanded.value ? props.lessLabel : props.moreLabel(hidden)
765
+ )
766
+ ]);
767
+ };
768
+ }
769
+ });
770
+
771
+ export { Accordion, Breadcrumbs, Collapsible, DisclosureList, NavigationMenu, Stepper, Tabs };
772
+ //# sourceMappingURL=chunk-T425FIC7.js.map
773
+ //# sourceMappingURL=chunk-T425FIC7.js.map