@nuykon/basecoat-vue 0.0.0-stage → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2655 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Accordion: () => Accordion,
24
+ AccordionRoot: () => AccordionRoot,
25
+ Alert: () => Alert,
26
+ AlertDescription: () => AlertDescription,
27
+ AlertDialog: () => AlertDialog,
28
+ AlertDialogRoot: () => AlertDialogRoot,
29
+ AlertTitle: () => AlertTitle,
30
+ Avatar: () => Avatar,
31
+ AvatarFallback: () => AvatarFallback,
32
+ AvatarImage: () => AvatarImage,
33
+ Badge: () => Badge,
34
+ Breadcrumb: () => Breadcrumb,
35
+ BreadcrumbItem: () => BreadcrumbItem,
36
+ BreadcrumbLink: () => BreadcrumbLink,
37
+ BreadcrumbList: () => BreadcrumbList,
38
+ BreadcrumbSeparator: () => BreadcrumbSeparator,
39
+ Button: () => Button,
40
+ ButtonGroup: () => ButtonGroup,
41
+ Card: () => Card,
42
+ CardAction: () => CardAction,
43
+ CardContent: () => CardContent,
44
+ CardDescription: () => CardDescription,
45
+ CardFooter: () => CardFooter,
46
+ CardHeader: () => CardHeader,
47
+ CardTitle: () => CardTitle,
48
+ Chart: () => Chart,
49
+ ChartRoot: () => ChartRoot,
50
+ Checkbox: () => Checkbox,
51
+ Collapsible: () => Collapsible,
52
+ Combobox: () => Combobox,
53
+ ComboboxRoot: () => ComboboxRoot,
54
+ Command: () => Command,
55
+ CommandRoot: () => CommandRoot,
56
+ Dialog: () => Dialog,
57
+ DialogContent: () => DialogContent,
58
+ DialogDescription: () => DialogDescription,
59
+ DialogFooter: () => DialogFooter,
60
+ DialogHeader: () => DialogHeader,
61
+ DialogRoot: () => DialogRoot,
62
+ DialogTitle: () => DialogTitle,
63
+ Drawer: () => Drawer,
64
+ DrawerRoot: () => DrawerRoot,
65
+ DropdownMenu: () => DropdownMenu,
66
+ DropdownMenuRoot: () => DropdownMenuRoot,
67
+ Empty: () => Empty,
68
+ EmptyContent: () => EmptyContent,
69
+ EmptyDescription: () => EmptyDescription,
70
+ EmptyHeader: () => EmptyHeader,
71
+ EmptyTitle: () => EmptyTitle,
72
+ Field: () => Field,
73
+ FieldDescription: () => FieldDescription,
74
+ FieldError: () => FieldError,
75
+ FieldLabel: () => FieldLabel,
76
+ Input: () => Input,
77
+ InputGroup: () => InputGroup,
78
+ InputGroupAddon: () => InputGroupAddon,
79
+ Item: () => Item,
80
+ ItemActions: () => ItemActions,
81
+ ItemContent: () => ItemContent,
82
+ ItemDescription: () => ItemDescription,
83
+ ItemTitle: () => ItemTitle,
84
+ Kbd: () => Kbd,
85
+ Label: () => Label,
86
+ NativeSelect: () => NativeSelect,
87
+ Pagination: () => Pagination,
88
+ Popover: () => Popover,
89
+ PopoverRoot: () => PopoverRoot,
90
+ Progress: () => Progress,
91
+ RadioGroup: () => RadioGroup,
92
+ ScrollArea: () => ScrollArea,
93
+ Select: () => Select,
94
+ SelectRoot: () => SelectRoot,
95
+ Separator: () => Separator,
96
+ Sidebar: () => Sidebar,
97
+ SidebarContent: () => SidebarContent,
98
+ SidebarFooter: () => SidebarFooter,
99
+ SidebarGroup: () => SidebarGroup,
100
+ SidebarHeader: () => SidebarHeader,
101
+ SidebarItem: () => SidebarItem,
102
+ SidebarRoot: () => SidebarRoot,
103
+ Skeleton: () => Skeleton,
104
+ Slider: () => Slider,
105
+ Spinner: () => Spinner,
106
+ Switch: () => Switch,
107
+ Table: () => Table,
108
+ TableBody: () => TableBody,
109
+ TableCaption: () => TableCaption,
110
+ TableCell: () => TableCell,
111
+ TableFooter: () => TableFooter,
112
+ TableHead: () => TableHead,
113
+ TableHeader: () => TableHeader,
114
+ TableRow: () => TableRow,
115
+ Tabs: () => Tabs,
116
+ TabsRoot: () => TabsRoot,
117
+ Textarea: () => Textarea,
118
+ ThemeSwitcher: () => ThemeSwitcher,
119
+ Toaster: () => Toaster,
120
+ Tooltip: () => Tooltip
121
+ });
122
+ module.exports = __toCommonJS(index_exports);
123
+
124
+ // src/primitives.ts
125
+ var import_vue = require("vue");
126
+
127
+ // ../core/src/chart.ts
128
+ function attachCanvasChart(canvas, config) {
129
+ const doc = canvas.ownerDocument, win = doc.defaultView, ctx = canvas.getContext("2d");
130
+ if (!ctx) return () => {
131
+ };
132
+ const data = config.data ?? [], series = Object.entries(config.series ?? {}), labelKey = config.labelKey ?? "label";
133
+ const color = (value) => value.startsWith("var(") ? win.getComputedStyle(canvas).getPropertyValue(value.slice(4, -1)).trim() || "#888" : value;
134
+ const legend = doc.createElement("ul");
135
+ legend.className = "chart-legend";
136
+ if (config.legend) {
137
+ for (const [index, [key, options]] of series.entries()) {
138
+ const item = doc.createElement("li"), content = doc.createElement("span"), indicator = doc.createElement("span");
139
+ content.className = "chart-legend-item";
140
+ indicator.className = "chart-legend-indicator";
141
+ indicator.style.setProperty(
142
+ "--chart-indicator-color",
143
+ options.color ?? `var(--chart-${index + 1})`
144
+ );
145
+ content.append(indicator, doc.createTextNode(options.label ?? key));
146
+ item.append(content);
147
+ legend.append(item);
148
+ }
149
+ canvas.after(legend);
150
+ }
151
+ canvas.style.width = "100%";
152
+ canvas.style.aspectRatio = "16 / 9";
153
+ canvas.style.display = "block";
154
+ const draw = () => {
155
+ const width = Math.max(200, canvas.parentElement?.clientWidth ?? 400), height = width * 9 / 16, ratio = win.devicePixelRatio || 1;
156
+ canvas.width = Math.round(width * ratio);
157
+ canvas.height = Math.round(height * ratio);
158
+ canvas.style.height = `${height}px`;
159
+ ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
160
+ ctx.clearRect(0, 0, width, height);
161
+ const padding = { left: 30, top: 10, right: 10, bottom: 30 }, w = width - padding.left - padding.right, h25 = height - padding.top - padding.bottom;
162
+ const max = Math.max(
163
+ 1,
164
+ ...data.map(
165
+ (row) => config.options?.scales?.y?.stacked ? series.reduce((sum, [key]) => sum + Number(row[key] ?? 0), 0) : Math.max(...series.map(([key]) => Number(row[key] ?? 0)))
166
+ )
167
+ );
168
+ const x = (index) => padding.left + index / Math.max(1, data.length - 1) * w, y = (value) => padding.top + h25 - value / max * h25;
169
+ ctx.font = '12px "Geist Sans",system-ui';
170
+ ctx.fillStyle = color("var(--muted-foreground)");
171
+ ctx.strokeStyle = color("var(--border)");
172
+ ctx.lineWidth = 0.5;
173
+ if (config.type !== "doughnut" && config.type !== "radar") {
174
+ for (let index = 0; index <= 4; index++) {
175
+ const top = padding.top + index * h25 / 4;
176
+ ctx.beginPath();
177
+ ctx.moveTo(padding.left, top);
178
+ ctx.lineTo(width - padding.right, top);
179
+ ctx.stroke();
180
+ ctx.fillText(String(Math.round(max * (4 - index) / 4)), 0, top + 4);
181
+ }
182
+ for (let index = 0; index < data.length; index++)
183
+ if (index % Math.max(1, Math.ceil(data.length / 6)) === 0)
184
+ ctx.fillText(String(data[index][labelKey] ?? ""), x(index) - 10, height - 8);
185
+ }
186
+ if (config.type === "doughnut") {
187
+ const key = series[0]?.[0] ?? "value", values = data.map((row) => Number(row[key] ?? 0)), total = values.reduce((a, b) => a + b, 0) || 1, radius = Math.min(w, h25) * 0.45, cx3 = width / 2, cy = height / 2;
188
+ let start = -Math.PI / 2;
189
+ values.forEach((value, index) => {
190
+ const end = start + value / total * Math.PI * 2;
191
+ ctx.beginPath();
192
+ ctx.arc(cx3, cy, radius, start, end);
193
+ ctx.arc(cx3, cy, radius * 0.62, end, start, true);
194
+ ctx.closePath();
195
+ ctx.fillStyle = color(`var(--chart-${index % 5 + 1})`);
196
+ ctx.fill();
197
+ start = end;
198
+ });
199
+ } else if (config.type === "radar") {
200
+ const radius = Math.min(w, h25) * 0.4, cx3 = width / 2, cy = height / 2;
201
+ const point = (index, scale) => {
202
+ const angle = index / Math.max(1, data.length) * Math.PI * 2 - Math.PI / 2;
203
+ return [
204
+ cx3 + Math.cos(angle) * radius * scale,
205
+ cy + Math.sin(angle) * radius * scale
206
+ ];
207
+ };
208
+ for (let ring = 1; ring <= 4; ring++) {
209
+ ctx.beginPath();
210
+ data.forEach((_, i) => {
211
+ const [x2, y2] = point(i, ring / 4);
212
+ if (i === 0) ctx.moveTo(x2, y2);
213
+ else ctx.lineTo(x2, y2);
214
+ });
215
+ ctx.closePath();
216
+ ctx.stroke();
217
+ }
218
+ series.forEach(([key, options], index) => {
219
+ ctx.beginPath();
220
+ data.forEach((row, i) => {
221
+ const [x2, y2] = point(i, Number(row[key] ?? 0) / max);
222
+ if (i === 0) ctx.moveTo(x2, y2);
223
+ else ctx.lineTo(x2, y2);
224
+ });
225
+ ctx.closePath();
226
+ ctx.strokeStyle = color(options.color ?? `var(--chart-${index + 1})`);
227
+ ctx.stroke();
228
+ ctx.globalAlpha = 0.2;
229
+ ctx.fillStyle = ctx.strokeStyle;
230
+ ctx.fill();
231
+ ctx.globalAlpha = 1;
232
+ });
233
+ ctx.fillStyle = color("var(--muted-foreground)");
234
+ data.forEach((row, i) => {
235
+ const [x2, y2] = point(i, 1.15);
236
+ ctx.fillText(String(row[labelKey] ?? ""), x2 - 15, y2);
237
+ });
238
+ } else {
239
+ const stacks2 = data.map(() => 0);
240
+ series.forEach(([key, options], seriesIndex) => {
241
+ const fill = color(options.color ?? `var(--chart-${seriesIndex + 1})`);
242
+ ctx.strokeStyle = fill;
243
+ ctx.fillStyle = fill;
244
+ ctx.lineWidth = 1.5;
245
+ if (config.type === "bar")
246
+ data.forEach((row, index) => {
247
+ const value = Number(row[key] ?? 0), stacked = config.options?.scales?.y?.stacked, group = w / Math.max(1, data.length), barWidth = group * 0.65 / (stacked ? 1 : series.length), left = padding.left + index * group + group * 0.15 + (stacked ? 0 : seriesIndex * barWidth), base = stacks2[index];
248
+ ctx.beginPath();
249
+ ctx.roundRect(
250
+ left,
251
+ y(value + base),
252
+ Math.max(1, barWidth - 2),
253
+ Math.max(0, y(base) - y(value + base)),
254
+ 3
255
+ );
256
+ ctx.fill();
257
+ if (stacked) stacks2[index] += value;
258
+ });
259
+ else {
260
+ ctx.beginPath();
261
+ data.forEach((row, index) => {
262
+ const top = y(Number(row[key] ?? 0));
263
+ if (index === 0) ctx.moveTo(x(index), top);
264
+ else if (options.dataset?.stepped) {
265
+ ctx.lineTo(x(index), y(Number(data[index - 1][key] ?? 0)));
266
+ ctx.lineTo(x(index), top);
267
+ } else ctx.lineTo(x(index), top);
268
+ });
269
+ ctx.stroke();
270
+ if (options.dataset?.fill || options.surface === "gradient") {
271
+ ctx.lineTo(x(data.length - 1), y(0));
272
+ ctx.lineTo(x(0), y(0));
273
+ ctx.closePath();
274
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
275
+ gradient.addColorStop(0, fill);
276
+ gradient.addColorStop(1, "transparent");
277
+ ctx.globalAlpha = 0.3;
278
+ ctx.fillStyle = gradient;
279
+ ctx.fill();
280
+ ctx.globalAlpha = 1;
281
+ }
282
+ }
283
+ });
284
+ }
285
+ };
286
+ const resize = new win.ResizeObserver(draw), themes = new win.MutationObserver(draw);
287
+ resize.observe(canvas.parentElement ?? canvas);
288
+ themes.observe(doc.documentElement, {
289
+ attributes: true,
290
+ attributeFilter: ["class", "data-style-variant"]
291
+ });
292
+ doc.addEventListener("basecoat:stylechange", draw);
293
+ draw();
294
+ return () => {
295
+ resize.disconnect();
296
+ themes.disconnect();
297
+ legend.remove();
298
+ doc.removeEventListener("basecoat:stylechange", draw);
299
+ };
300
+ }
301
+
302
+ // ../core/src/widgets.ts
303
+ function attachWidget(root) {
304
+ const abort = new AbortController(), signal = abort.signal, cleanups = [];
305
+ const on = (element, name, fn) => element?.addEventListener(name, fn, { signal });
306
+ const emit = (detail) => root.dispatchEvent(new CustomEvent("basecoat:change", { bubbles: true, detail }));
307
+ if (root instanceof HTMLCanvasElement && root.dataset.chartConfig)
308
+ cleanups.push(attachCanvasChart(root, JSON.parse(root.dataset.chartConfig)));
309
+ if (root.classList.contains("sidebar")) {
310
+ const media = root.ownerDocument.defaultView.matchMedia("(min-width: 768px)");
311
+ root.dataset.sidebarInitialized = "true";
312
+ const set = (open) => root.setAttribute("aria-hidden", String(!open));
313
+ const toggle = () => set(root.getAttribute("aria-hidden") === "true");
314
+ const sidebar = root;
315
+ sidebar.toggle = toggle;
316
+ set(media.matches);
317
+ on(media, "change", () => set(media.matches));
318
+ on(root, "click", (event) => {
319
+ if (event.target === root && !media.matches) set(false);
320
+ });
321
+ on(root.ownerDocument, "keydown", (event) => {
322
+ if (event.key === "Escape" && !media.matches) set(false);
323
+ });
324
+ cleanups.push(() => {
325
+ delete sidebar.toggle;
326
+ delete root.dataset.sidebarInitialized;
327
+ });
328
+ }
329
+ if (root.classList.contains("toaster")) {
330
+ const timers = /* @__PURE__ */ new Set();
331
+ const toast = (message) => {
332
+ const item = root.ownerDocument.createElement("div");
333
+ item.className = "toast";
334
+ item.setAttribute("role", "status");
335
+ const content = root.ownerDocument.createElement("div");
336
+ content.className = "toast-content";
337
+ const section = root.ownerDocument.createElement("section"), heading = root.ownerDocument.createElement("h2");
338
+ heading.textContent = message.title ?? "";
339
+ section.append(heading);
340
+ if (message.description) {
341
+ const description = root.ownerDocument.createElement("p");
342
+ description.textContent = message.description;
343
+ section.append(description);
344
+ }
345
+ const footer = root.ownerDocument.createElement("footer"), close = root.ownerDocument.createElement("button");
346
+ close.type = "button";
347
+ close.className = "btn";
348
+ close.dataset.variant = "outline";
349
+ close.dataset.toastCancel = "";
350
+ close.textContent = message.cancel?.label ?? "Dismiss";
351
+ close.addEventListener("click", () => item.remove(), { signal });
352
+ footer.append(close);
353
+ if (message.action) {
354
+ const action = root.ownerDocument.createElement("button");
355
+ action.type = "button";
356
+ action.className = "btn";
357
+ action.textContent = message.action.label ?? "Action";
358
+ action.addEventListener(
359
+ "click",
360
+ () => {
361
+ message.action?.onclick?.();
362
+ item.remove();
363
+ },
364
+ { signal }
365
+ );
366
+ footer.append(action);
367
+ }
368
+ content.append(section, footer);
369
+ item.append(content);
370
+ root.append(item);
371
+ if ((message.duration ?? 5e3) > 0) {
372
+ const timer = setTimeout(() => {
373
+ item.remove();
374
+ timers.delete(timer);
375
+ }, message.duration ?? 5e3);
376
+ timers.add(timer);
377
+ }
378
+ return item;
379
+ };
380
+ root.toast = toast;
381
+ on(root, "click", (event) => {
382
+ const button = event.target.closest("[data-toast-cancel]");
383
+ button?.closest(".toast")?.remove();
384
+ });
385
+ cleanups.push(() => {
386
+ timers.forEach(clearTimeout);
387
+ delete root.toast;
388
+ });
389
+ }
390
+ if (root.classList.contains("tabs")) {
391
+ const tabs = [...root.querySelectorAll("[role=tab]")].filter(
392
+ (tab) => tab.closest(".tabs") === root
393
+ );
394
+ const set = (target) => {
395
+ if (target.disabled || target.getAttribute("aria-disabled") === "true") return;
396
+ for (const tab of tabs) {
397
+ const active = tab === target;
398
+ tab.setAttribute("aria-selected", String(active));
399
+ tab.tabIndex = active ? 0 : -1;
400
+ const panel = root.ownerDocument.getElementById(tab.getAttribute("aria-controls") ?? "");
401
+ if (panel) {
402
+ panel.hidden = !active;
403
+ panel.setAttribute("aria-selected", String(active));
404
+ }
405
+ }
406
+ emit(target.id);
407
+ };
408
+ for (const [index, tab] of tabs.entries()) {
409
+ on(tab, "click", () => set(tab));
410
+ on(tab, "keydown", (event) => {
411
+ const key = event.key, vertical = tab.parentElement?.getAttribute("aria-orientation") === "vertical";
412
+ if (!(vertical ? ["ArrowUp", "ArrowDown"] : ["ArrowLeft", "ArrowRight"]).includes(key) && !["Home", "End"].includes(key))
413
+ return;
414
+ event.preventDefault();
415
+ const target = tabs[nextIndex(
416
+ tabs.map((item) => ({
417
+ disabled: item.disabled || item.getAttribute("aria-disabled") === "true"
418
+ })),
419
+ index,
420
+ key
421
+ )];
422
+ target?.focus();
423
+ if (target) set(target);
424
+ });
425
+ }
426
+ }
427
+ if (root.classList.contains("accordion")) {
428
+ const summaries = [...root.querySelectorAll("summary")];
429
+ on(root, "keydown", (event) => {
430
+ const index = summaries.indexOf(event.target), key = event.key;
431
+ if (index >= 0 && ["ArrowUp", "ArrowDown", "Home", "End"].includes(key)) {
432
+ event.preventDefault();
433
+ summaries[nextIndex(
434
+ summaries.map((el) => ({ disabled: el.getAttribute("aria-disabled") === "true" })),
435
+ index,
436
+ key
437
+ )]?.focus();
438
+ }
439
+ });
440
+ on(root, "click", (event) => {
441
+ const summary = event.target.closest("summary");
442
+ if (summary?.getAttribute("aria-disabled") === "true" || summary?.parentElement?.getAttribute("aria-disabled") === "true")
443
+ event.preventDefault();
444
+ });
445
+ }
446
+ const kind = ["select", "combobox", "dropdown-menu", "popover"].find(
447
+ (kind2) => root.classList.contains(kind2)
448
+ );
449
+ if (kind) {
450
+ const trigger = root.querySelector(
451
+ ":scope > button, :scope > input[role=combobox], :scope > .input-group input[role=combobox]"
452
+ ), popup = root.querySelector(":scope > [data-popover]");
453
+ const search = root.querySelector(
454
+ "[data-popover] input, input[role=combobox]"
455
+ );
456
+ if (trigger && popup) {
457
+ let open = false, active = -1, disposePosition, disposeLayer;
458
+ const selector = kind === "dropdown-menu" ? "[role=menuitem], [role=menuitemcheckbox], [role=menuitemradio]" : "[role=option]";
459
+ const items = () => [...popup.querySelectorAll(selector)].filter(
460
+ (item) => !item.hidden && item.getAttribute("aria-hidden") !== "true"
461
+ );
462
+ const disabled = (item) => item.matches(":disabled") || item.getAttribute("aria-disabled") === "true";
463
+ const cursor = () => items().map((item) => ({
464
+ value: item.dataset.value ?? item.id,
465
+ label: item.textContent?.trim() ?? "",
466
+ disabled: disabled(item)
467
+ }));
468
+ const typeahead = createTypeahead();
469
+ const highlight = (index) => {
470
+ active = index;
471
+ const all = items();
472
+ for (const [i, item2] of all.entries()) {
473
+ item2.classList.toggle("active", i === index);
474
+ if (kind === "dropdown-menu") item2.tabIndex = i === index ? 0 : -1;
475
+ }
476
+ const item = all[index];
477
+ if (item) {
478
+ if (kind === "dropdown-menu") item.focus();
479
+ else {
480
+ const list = popup.querySelector("[role=listbox]");
481
+ if (list) {
482
+ list.setAttribute("aria-activedescendant", item.id);
483
+ scrollWithin(list, item);
484
+ }
485
+ search?.setAttribute("aria-activedescendant", item.id);
486
+ }
487
+ }
488
+ };
489
+ const close = (restore = false) => {
490
+ if (!open) return;
491
+ open = false;
492
+ disposeLayer?.();
493
+ disposePosition?.();
494
+ trigger.setAttribute("aria-expanded", "false");
495
+ popup.setAttribute("aria-hidden", "true");
496
+ popup.hidden = true;
497
+ if (restore) trigger.focus();
498
+ };
499
+ const show = (last = false) => {
500
+ if (open || disabled(trigger)) return;
501
+ open = true;
502
+ popup.hidden = false;
503
+ popup.setAttribute("aria-hidden", "false");
504
+ popup.setAttribute("popover", "manual");
505
+ popup.classList.add("bc-floating");
506
+ trigger.setAttribute("aria-expanded", "true");
507
+ disposePosition = attachFloating(trigger, popup, {
508
+ side: popup.dataset.side,
509
+ align: popup.dataset.align,
510
+ matchWidth: kind === "select" || kind === "combobox"
511
+ });
512
+ disposeLayer = dismissableLayer(root.ownerDocument, {
513
+ elements: () => [trigger, popup],
514
+ dismiss: (reason) => close(reason === "escape")
515
+ });
516
+ const list = popup.querySelector("[role=listbox],[role=menu]");
517
+ if (list) {
518
+ list.tabIndex = -1;
519
+ (search ?? list).focus();
520
+ }
521
+ if (kind === "popover") focusFirst(popup);
522
+ else highlight(nextIndex(cursor(), -1, last ? "End" : "Home"));
523
+ };
524
+ const choose = (item) => {
525
+ if (disabled(item)) return;
526
+ if (kind === "select" || kind === "combobox") {
527
+ const multiple = popup.querySelector("[aria-multiselectable=true]") !== null;
528
+ if (!multiple)
529
+ items().forEach(
530
+ (option) => option.setAttribute("aria-selected", String(option === item))
531
+ );
532
+ else
533
+ item.setAttribute(
534
+ "aria-selected",
535
+ String(item.getAttribute("aria-selected") !== "true")
536
+ );
537
+ const selected = items().filter(
538
+ (option) => option.getAttribute("aria-selected") === "true"
539
+ ), values = selected.map(
540
+ (option) => option.dataset.value ?? option.textContent?.trim() ?? ""
541
+ );
542
+ if (trigger instanceof HTMLInputElement) trigger.value = item.textContent?.trim() ?? "";
543
+ else {
544
+ const label = trigger.querySelector("span");
545
+ if (label)
546
+ label.textContent = selected.map((option) => option.textContent?.trim()).join(", ");
547
+ }
548
+ const hidden = root.querySelector("input[type=hidden]");
549
+ if (hidden) {
550
+ hidden.value = multiple ? JSON.stringify(values) : values[0] ?? "";
551
+ hidden.dispatchEvent(new Event("change", { bubbles: true }));
552
+ }
553
+ emit(multiple ? values : values[0]);
554
+ if (!multiple) close(true);
555
+ } else if (kind === "dropdown-menu") {
556
+ if (item.getAttribute("role") === "menuitemcheckbox") {
557
+ item.setAttribute("aria-checked", String(item.getAttribute("aria-checked") !== "true"));
558
+ emit(item.id);
559
+ } else close(true);
560
+ }
561
+ };
562
+ popup.hidden = popup.getAttribute("aria-hidden") !== "false";
563
+ on(trigger, "click", () => open ? close() : show());
564
+ on(trigger, "keydown", (event) => {
565
+ const key = event.key;
566
+ if (!open && ["ArrowDown", "ArrowUp", "Enter", " "].includes(key)) {
567
+ event.preventDefault();
568
+ show(key === "ArrowUp");
569
+ }
570
+ });
571
+ on(popup, "keydown", (event) => {
572
+ const keyboard = event;
573
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(keyboard.key)) {
574
+ event.preventDefault();
575
+ highlight(nextIndex(cursor(), active, keyboard.key));
576
+ } else if (keyboard.key === "Enter" || !search && keyboard.key === " ") {
577
+ event.preventDefault();
578
+ const item = items()[active];
579
+ if (item) {
580
+ choose(item);
581
+ if (item instanceof HTMLAnchorElement) item.click();
582
+ }
583
+ } else if (keyboard.key === "Tab") close();
584
+ else if (!search && keyboard.key.length === 1 && !keyboard.ctrlKey && !keyboard.metaKey) {
585
+ event.preventDefault();
586
+ highlight(typeahead(keyboard.key, cursor(), active));
587
+ }
588
+ });
589
+ on(popup, "click", (event) => {
590
+ const item = event.target.closest(selector);
591
+ if (item) {
592
+ if (disabled(item)) event.preventDefault();
593
+ else choose(item);
594
+ }
595
+ });
596
+ on(popup, "pointermove", (event) => {
597
+ const pointer = event, item = event.target.closest(selector);
598
+ if (item && !disabled(item) && (pointer.movementX || pointer.movementY))
599
+ highlight(items().indexOf(item));
600
+ });
601
+ on(search, "input", () => {
602
+ for (const item of popup.querySelectorAll(selector)) {
603
+ const hidden = !item.textContent?.toLocaleLowerCase().includes(search.value.toLocaleLowerCase());
604
+ item.hidden = hidden;
605
+ item.setAttribute("aria-hidden", String(hidden));
606
+ }
607
+ if (!open) show();
608
+ highlight(nextIndex(cursor(), -1, "Home"));
609
+ });
610
+ cleanups.push(() => close());
611
+ }
612
+ }
613
+ if (root.classList.contains("command")) {
614
+ const input = root.querySelector("input"), list = root.querySelector("[role=menu],[role=listbox]");
615
+ let active = 0;
616
+ const items = () => [...list?.querySelectorAll("[role=menuitem],[role=option]") ?? []].filter(
617
+ (item) => !item.hidden
618
+ );
619
+ const refresh = () => {
620
+ const all = items();
621
+ all.forEach((item, index) => item.classList.toggle("active", index === active));
622
+ const current = all[active];
623
+ if (current) input?.setAttribute("aria-activedescendant", current.id);
624
+ };
625
+ on(input, "input", () => {
626
+ list?.querySelectorAll("[role=menuitem],[role=option]").forEach((item) => {
627
+ item.hidden = !item.textContent?.toLocaleLowerCase().includes(input.value.toLocaleLowerCase());
628
+ item.setAttribute("aria-hidden", String(item.hidden));
629
+ });
630
+ active = 0;
631
+ refresh();
632
+ });
633
+ on(input, "keydown", (event) => {
634
+ const key = event.key;
635
+ if (["ArrowUp", "ArrowDown", "Home", "End"].includes(key)) {
636
+ event.preventDefault();
637
+ active = nextIndex(
638
+ items().map((item) => ({ disabled: item.getAttribute("aria-disabled") === "true" })),
639
+ active,
640
+ key
641
+ );
642
+ refresh();
643
+ } else if (key === "Enter") {
644
+ event.preventDefault();
645
+ items()[active]?.click();
646
+ }
647
+ });
648
+ root.refresh = refresh;
649
+ }
650
+ if (root.matches("input[type=range]")) {
651
+ const range = root, update = () => range.style.setProperty(
652
+ "--slider-value",
653
+ `${percentage(range.valueAsNumber, Number(range.min || 0), Number(range.max || 100))}%`
654
+ );
655
+ on(range, "input", update);
656
+ update();
657
+ }
658
+ return () => {
659
+ abort.abort();
660
+ cleanups.forEach((cleanup) => cleanup());
661
+ };
662
+ }
663
+
664
+ // ../core/src/index.ts
665
+ function cx(...values) {
666
+ return values.filter(Boolean).join(" ");
667
+ }
668
+ function percentage(value, min = 0, max = 100) {
669
+ return Number.isFinite(value) && max > min ? Math.min(100, Math.max(0, (value - min) / (max - min) * 100)) : 0;
670
+ }
671
+ function nextIndex(items, current, key, loop = true) {
672
+ const enabled = items.map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0);
673
+ if (!enabled.length) return -1;
674
+ if (key === "Home") return enabled[0];
675
+ if (key === "End") return enabled[enabled.length - 1];
676
+ const direction = key === "ArrowUp" || key === "ArrowLeft" ? -1 : 1;
677
+ const position = enabled.indexOf(current);
678
+ if (position < 0) return direction < 0 ? enabled[enabled.length - 1] : enabled[0];
679
+ const next = position + direction;
680
+ return enabled[loop ? (next + enabled.length) % enabled.length : Math.min(enabled.length - 1, Math.max(0, next))];
681
+ }
682
+ function createTypeahead() {
683
+ let buffer = "", last = 0;
684
+ return (key, items, current) => {
685
+ const now = Date.now();
686
+ buffer = now - last > 700 ? key : buffer + key;
687
+ last = now;
688
+ const query = [...buffer].every((char) => char === buffer[0]) ? buffer[0] : buffer;
689
+ for (let offset = 1; offset <= items.length; offset++) {
690
+ const index = (current + offset + items.length) % items.length;
691
+ if (!items[index].disabled && items[index].label.toLocaleLowerCase().startsWith(query.toLocaleLowerCase()))
692
+ return index;
693
+ }
694
+ return current;
695
+ };
696
+ }
697
+ var stacks = /* @__PURE__ */ new WeakMap();
698
+ function dismissableLayer(doc, layer) {
699
+ let stack = stacks.get(doc);
700
+ if (!stack) {
701
+ const layers = [];
702
+ const pointer = (event) => {
703
+ const top = layers.at(-1);
704
+ if (top && !top.elements().some((el) => el && event.composedPath().includes(el)))
705
+ top.dismiss("outside");
706
+ };
707
+ const keyboard = (event) => {
708
+ if (event.key === "Escape" && !event.defaultPrevented && layers.length) {
709
+ event.preventDefault();
710
+ event.stopPropagation();
711
+ layers.at(-1)?.dismiss("escape");
712
+ }
713
+ };
714
+ doc.addEventListener("pointerdown", pointer, true);
715
+ doc.addEventListener("keydown", keyboard);
716
+ stack = {
717
+ layers,
718
+ dispose: () => {
719
+ doc.removeEventListener("pointerdown", pointer, true);
720
+ doc.removeEventListener("keydown", keyboard);
721
+ }
722
+ };
723
+ stacks.set(doc, stack);
724
+ }
725
+ stack.layers.push(layer);
726
+ return () => {
727
+ const index = stack.layers.indexOf(layer);
728
+ if (index >= 0) stack.layers.splice(index, 1);
729
+ if (!stack.layers.length) {
730
+ stack.dispose();
731
+ stacks.delete(doc);
732
+ }
733
+ };
734
+ }
735
+ function floatingPosition(anchor, popup, width, height, options = {}) {
736
+ let side = options.side ?? "bottom";
737
+ const align = options.align ?? "start", offset = options.offset ?? 6, padding = 8;
738
+ const available = {
739
+ bottom: height - anchor.bottom,
740
+ top: anchor.top,
741
+ right: width - anchor.right,
742
+ left: anchor.left
743
+ };
744
+ const opposite = {
745
+ top: "bottom",
746
+ bottom: "top",
747
+ left: "right",
748
+ right: "left"
749
+ };
750
+ const required = (side === "top" || side === "bottom" ? popup.height : popup.width) + offset + padding;
751
+ if (available[side] < required && available[opposite[side]] > available[side])
752
+ side = opposite[side];
753
+ const vertical = side === "top" || side === "bottom";
754
+ let x = vertical ? anchor.left : side === "left" ? anchor.left - popup.width - offset : anchor.right + offset;
755
+ let y = vertical ? side === "top" ? anchor.top - popup.height - offset : anchor.bottom + offset : anchor.top;
756
+ if (vertical)
757
+ x += align === "end" ? anchor.width - popup.width : align === "center" ? (anchor.width - popup.width) / 2 : 0;
758
+ else
759
+ y += align === "end" ? anchor.height - popup.height : align === "center" ? (anchor.height - popup.height) / 2 : 0;
760
+ return {
761
+ x: Math.max(padding, Math.min(x, width - popup.width - padding)),
762
+ y: Math.max(padding, Math.min(y, height - popup.height - padding)),
763
+ side,
764
+ maxHeight: Math.max(40, available[side] - offset - padding)
765
+ };
766
+ }
767
+ function attachFloating(anchor, popup, options = {}) {
768
+ const win = anchor.ownerDocument.defaultView;
769
+ if (typeof popup.showPopover === "function") popup.showPopover();
770
+ const update = () => {
771
+ const rect = anchor.getBoundingClientRect();
772
+ if (options.matchWidth) popup.style.minWidth = `${rect.width}px`;
773
+ const viewport = win.visualViewport;
774
+ const result = floatingPosition(
775
+ rect,
776
+ popup.getBoundingClientRect(),
777
+ viewport?.width ?? win.innerWidth,
778
+ viewport?.height ?? win.innerHeight,
779
+ options
780
+ );
781
+ Object.assign(popup.style, {
782
+ left: `${result.x + (viewport?.offsetLeft ?? 0)}px`,
783
+ top: `${result.y + (viewport?.offsetTop ?? 0)}px`,
784
+ maxHeight: `${result.maxHeight}px`
785
+ });
786
+ popup.dataset.side = result.side;
787
+ };
788
+ let frame = 0;
789
+ const schedule = () => {
790
+ win.cancelAnimationFrame(frame);
791
+ frame = win.requestAnimationFrame(update);
792
+ };
793
+ const observer = typeof win.ResizeObserver === "function" ? new win.ResizeObserver(schedule) : null;
794
+ observer?.observe(anchor);
795
+ observer?.observe(popup);
796
+ win.addEventListener("resize", schedule);
797
+ win.addEventListener("scroll", schedule, true);
798
+ win.visualViewport?.addEventListener("resize", schedule);
799
+ win.visualViewport?.addEventListener("scroll", schedule);
800
+ update();
801
+ return () => {
802
+ win.cancelAnimationFrame(frame);
803
+ observer?.disconnect();
804
+ win.removeEventListener("resize", schedule);
805
+ win.removeEventListener("scroll", schedule, true);
806
+ win.visualViewport?.removeEventListener("resize", schedule);
807
+ win.visualViewport?.removeEventListener("scroll", schedule);
808
+ if (typeof popup.hidePopover === "function" && popup.matches(":popover-open"))
809
+ popup.hidePopover();
810
+ };
811
+ }
812
+ var scrollLocks = /* @__PURE__ */ new WeakMap();
813
+ function lockScroll(doc) {
814
+ const record = scrollLocks.get(doc) ?? { count: 0, overflow: doc.documentElement.style.overflow };
815
+ record.count++;
816
+ scrollLocks.set(doc, record);
817
+ doc.documentElement.style.overflow = "hidden";
818
+ let disposed = false;
819
+ return () => {
820
+ if (disposed) return;
821
+ disposed = true;
822
+ if (--record.count === 0) {
823
+ doc.documentElement.style.overflow = record.overflow;
824
+ scrollLocks.delete(doc);
825
+ }
826
+ };
827
+ }
828
+ function focusFirst(root) {
829
+ const target = root.querySelector(
830
+ '[autofocus],button:not(:disabled),[href],input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex="0"]'
831
+ );
832
+ (target ?? root).focus({ preventScroll: true });
833
+ }
834
+ function scrollWithin(container, item) {
835
+ const parent = container.scrollHeight > container.clientHeight ? container : container.parentElement ?? container;
836
+ const outer = parent.getBoundingClientRect(), inner = item.getBoundingClientRect();
837
+ if (inner.top < outer.top) parent.scrollTop -= outer.top - inner.top;
838
+ else if (inner.bottom > outer.bottom) parent.scrollTop += inner.bottom - outer.bottom;
839
+ }
840
+ function formReset(element, reset) {
841
+ const form = element.closest("form");
842
+ let timer;
843
+ const listener = (event) => {
844
+ clearTimeout(timer);
845
+ timer = setTimeout(() => {
846
+ if (!event.defaultPrevented) reset();
847
+ }, 0);
848
+ };
849
+ form?.addEventListener("reset", listener);
850
+ return () => {
851
+ clearTimeout(timer);
852
+ form?.removeEventListener("reset", listener);
853
+ };
854
+ }
855
+ var primitiveDefinitions = {
856
+ ChartRoot: ["canvas", "chart-canvas"],
857
+ SelectRoot: ["div", "select"],
858
+ ComboboxRoot: ["div", "combobox"],
859
+ DropdownMenuRoot: ["div", "dropdown-menu"],
860
+ PopoverRoot: ["div", "popover"],
861
+ TabsRoot: ["div", "tabs"],
862
+ AccordionRoot: ["div", "accordion"],
863
+ CommandRoot: ["div", "command"],
864
+ SidebarRoot: ["div", "sidebar"],
865
+ DialogRoot: ["dialog", "dialog"],
866
+ DrawerRoot: ["dialog", "drawer"],
867
+ AlertDialogRoot: ["dialog", "alert-dialog"],
868
+ Button: ["button", "btn"],
869
+ Badge: ["span", "badge"],
870
+ Card: ["article", "card"],
871
+ CardHeader: ["header", ""],
872
+ CardTitle: ["h3", "card-title"],
873
+ CardDescription: ["p", ""],
874
+ CardContent: ["section", ""],
875
+ CardFooter: ["footer", ""],
876
+ CardAction: ["div", "card-action"],
877
+ Alert: ["div", "alert"],
878
+ AlertTitle: ["h2", ""],
879
+ AlertDescription: ["section", ""],
880
+ Avatar: ["span", "avatar"],
881
+ AvatarImage: ["img", ""],
882
+ AvatarFallback: ["span", ""],
883
+ Breadcrumb: ["nav", "breadcrumb"],
884
+ BreadcrumbList: ["ol", ""],
885
+ BreadcrumbItem: ["li", ""],
886
+ BreadcrumbLink: ["a", ""],
887
+ BreadcrumbSeparator: ["li", ""],
888
+ ButtonGroup: ["div", "button-group"],
889
+ Field: ["div", "field"],
890
+ FieldLabel: ["label", "label"],
891
+ FieldDescription: ["p", ""],
892
+ FieldError: ["p", ""],
893
+ Label: ["label", "label"],
894
+ Input: ["input", "input"],
895
+ Textarea: ["textarea", "textarea"],
896
+ NativeSelect: ["select", "select"],
897
+ InputGroup: ["div", "input-group"],
898
+ InputGroupAddon: ["div", ""],
899
+ Empty: ["div", "empty"],
900
+ EmptyHeader: ["header", ""],
901
+ EmptyTitle: ["h3", ""],
902
+ EmptyDescription: ["p", ""],
903
+ EmptyContent: ["section", ""],
904
+ Item: ["div", "item"],
905
+ ItemContent: ["section", ""],
906
+ ItemTitle: ["h3", ""],
907
+ ItemDescription: ["p", ""],
908
+ ItemActions: ["div", ""],
909
+ Kbd: ["kbd", "kbd"],
910
+ ScrollArea: ["div", "scrollbar"],
911
+ Skeleton: ["div", "skeleton"],
912
+ Spinner: ["span", "bc-spinner"],
913
+ Separator: ["hr", ""],
914
+ Table: ["table", "table"],
915
+ TableHeader: ["thead", ""],
916
+ TableBody: ["tbody", ""],
917
+ TableFooter: ["tfoot", ""],
918
+ TableRow: ["tr", ""],
919
+ TableHead: ["th", ""],
920
+ TableCell: ["td", ""],
921
+ TableCaption: ["caption", ""],
922
+ DialogHeader: ["header", ""],
923
+ DialogTitle: ["h2", ""],
924
+ DialogDescription: ["p", ""],
925
+ DialogContent: ["section", ""],
926
+ DialogFooter: ["footer", ""],
927
+ SidebarHeader: ["header", ""],
928
+ SidebarContent: ["section", ""],
929
+ SidebarFooter: ["footer", ""],
930
+ SidebarGroup: ["section", ""],
931
+ SidebarItem: ["a", ""]
932
+ };
933
+
934
+ // src/primitives.ts
935
+ function primitive(name, tag) {
936
+ return (0, import_vue.defineComponent)({
937
+ name,
938
+ inheritAttrs: false,
939
+ props: {
940
+ as: String,
941
+ asChild: Boolean,
942
+ variant: String,
943
+ size: String
944
+ },
945
+ setup(props, { attrs, slots, expose }) {
946
+ let element = null;
947
+ let dispose;
948
+ (0, import_vue.onMounted)(() => {
949
+ if (name.endsWith("Root") && element) dispose = attachWidget(element);
950
+ });
951
+ (0, import_vue.onUnmounted)(() => dispose?.());
952
+ expose({
953
+ get el() {
954
+ return element;
955
+ },
956
+ focus: () => element?.focus()
957
+ });
958
+ const renderElement = () => {
959
+ const base = {
960
+ class: primitiveDefinitions[name][1],
961
+ "data-variant": props.variant,
962
+ "data-size": props.size
963
+ };
964
+ if (tag === "button") base.type = "button";
965
+ if (name === "Alert") base.role = "alert";
966
+ if (name === "Breadcrumb") base["aria-label"] = "Breadcrumb";
967
+ if (name === "BreadcrumbSeparator") {
968
+ base["aria-hidden"] = true;
969
+ base.role = "presentation";
970
+ }
971
+ if (name === "Skeleton") base["aria-hidden"] = true;
972
+ if (name === "Spinner") {
973
+ base.role = "status";
974
+ base["aria-label"] = "Loading";
975
+ }
976
+ if (name === "FieldError") base.role = "alert";
977
+ if (name === "ScrollArea") base.style = { overflow: "auto" };
978
+ const attributes = (0, import_vue.mergeProps)(base, attrs, {
979
+ ref: (el) => {
980
+ element = el;
981
+ }
982
+ });
983
+ if (props.asChild) {
984
+ const children = slots.default?.() ?? [];
985
+ if (children.length !== 1)
986
+ throw new Error(`${name} with asChild expects a single element.`);
987
+ return (0, import_vue.cloneVNode)(children[0], attributes, true);
988
+ }
989
+ return (0, import_vue.h)(props.as ?? tag, attributes, slots.default?.());
990
+ };
991
+ return { renderElement, focus: () => element?.focus() };
992
+ },
993
+ render() {
994
+ return this.renderElement();
995
+ }
996
+ });
997
+ }
998
+
999
+ // src/components/ChartRoot.ts
1000
+ var ChartRoot = /* @__PURE__ */ primitive("ChartRoot", "canvas");
1001
+
1002
+ // src/components/SelectRoot.ts
1003
+ var SelectRoot = /* @__PURE__ */ primitive("SelectRoot", "div");
1004
+
1005
+ // src/components/ComboboxRoot.ts
1006
+ var ComboboxRoot = /* @__PURE__ */ primitive("ComboboxRoot", "div");
1007
+
1008
+ // src/components/DropdownMenuRoot.ts
1009
+ var DropdownMenuRoot = /* @__PURE__ */ primitive("DropdownMenuRoot", "div");
1010
+
1011
+ // src/components/PopoverRoot.ts
1012
+ var PopoverRoot = /* @__PURE__ */ primitive("PopoverRoot", "div");
1013
+
1014
+ // src/components/TabsRoot.ts
1015
+ var TabsRoot = /* @__PURE__ */ primitive("TabsRoot", "div");
1016
+
1017
+ // src/components/AccordionRoot.ts
1018
+ var AccordionRoot = /* @__PURE__ */ primitive("AccordionRoot", "div");
1019
+
1020
+ // src/components/CommandRoot.ts
1021
+ var CommandRoot = /* @__PURE__ */ primitive("CommandRoot", "div");
1022
+
1023
+ // src/components/SidebarRoot.ts
1024
+ var SidebarRoot = /* @__PURE__ */ primitive("SidebarRoot", "div");
1025
+
1026
+ // src/components/DialogRoot.ts
1027
+ var DialogRoot = /* @__PURE__ */ primitive("DialogRoot", "dialog");
1028
+
1029
+ // src/components/DrawerRoot.ts
1030
+ var DrawerRoot = /* @__PURE__ */ primitive("DrawerRoot", "dialog");
1031
+
1032
+ // src/components/AlertDialogRoot.ts
1033
+ var AlertDialogRoot = /* @__PURE__ */ primitive("AlertDialogRoot", "dialog");
1034
+
1035
+ // src/components/Button.ts
1036
+ var Button = /* @__PURE__ */ primitive("Button", "button");
1037
+
1038
+ // src/components/Badge.ts
1039
+ var Badge = /* @__PURE__ */ primitive("Badge", "span");
1040
+
1041
+ // src/components/Card.ts
1042
+ var Card = /* @__PURE__ */ primitive("Card", "article");
1043
+
1044
+ // src/components/CardHeader.ts
1045
+ var CardHeader = /* @__PURE__ */ primitive("CardHeader", "header");
1046
+
1047
+ // src/components/CardTitle.ts
1048
+ var CardTitle = /* @__PURE__ */ primitive("CardTitle", "h3");
1049
+
1050
+ // src/components/CardDescription.ts
1051
+ var CardDescription = /* @__PURE__ */ primitive("CardDescription", "p");
1052
+
1053
+ // src/components/CardContent.ts
1054
+ var CardContent = /* @__PURE__ */ primitive("CardContent", "section");
1055
+
1056
+ // src/components/CardFooter.ts
1057
+ var CardFooter = /* @__PURE__ */ primitive("CardFooter", "footer");
1058
+
1059
+ // src/components/CardAction.ts
1060
+ var CardAction = /* @__PURE__ */ primitive("CardAction", "div");
1061
+
1062
+ // src/components/Alert.ts
1063
+ var Alert = /* @__PURE__ */ primitive("Alert", "div");
1064
+
1065
+ // src/components/AlertTitle.ts
1066
+ var AlertTitle = /* @__PURE__ */ primitive("AlertTitle", "h2");
1067
+
1068
+ // src/components/AlertDescription.ts
1069
+ var AlertDescription = /* @__PURE__ */ primitive("AlertDescription", "section");
1070
+
1071
+ // src/components/Avatar.ts
1072
+ var Avatar = /* @__PURE__ */ primitive("Avatar", "span");
1073
+
1074
+ // src/components/AvatarImage.ts
1075
+ var AvatarImage = /* @__PURE__ */ primitive("AvatarImage", "img");
1076
+
1077
+ // src/components/AvatarFallback.ts
1078
+ var AvatarFallback = /* @__PURE__ */ primitive("AvatarFallback", "span");
1079
+
1080
+ // src/components/Breadcrumb.ts
1081
+ var Breadcrumb = /* @__PURE__ */ primitive("Breadcrumb", "nav");
1082
+
1083
+ // src/components/BreadcrumbList.ts
1084
+ var BreadcrumbList = /* @__PURE__ */ primitive("BreadcrumbList", "ol");
1085
+
1086
+ // src/components/BreadcrumbItem.ts
1087
+ var BreadcrumbItem = /* @__PURE__ */ primitive("BreadcrumbItem", "li");
1088
+
1089
+ // src/components/BreadcrumbLink.ts
1090
+ var BreadcrumbLink = /* @__PURE__ */ primitive("BreadcrumbLink", "a");
1091
+
1092
+ // src/components/BreadcrumbSeparator.ts
1093
+ var BreadcrumbSeparator = /* @__PURE__ */ primitive("BreadcrumbSeparator", "li");
1094
+
1095
+ // src/components/ButtonGroup.ts
1096
+ var ButtonGroup = /* @__PURE__ */ primitive("ButtonGroup", "div");
1097
+
1098
+ // src/components/Field.ts
1099
+ var Field = /* @__PURE__ */ primitive("Field", "div");
1100
+
1101
+ // src/components/FieldLabel.ts
1102
+ var FieldLabel = /* @__PURE__ */ primitive("FieldLabel", "label");
1103
+
1104
+ // src/components/FieldDescription.ts
1105
+ var FieldDescription = /* @__PURE__ */ primitive("FieldDescription", "p");
1106
+
1107
+ // src/components/FieldError.ts
1108
+ var FieldError = /* @__PURE__ */ primitive("FieldError", "p");
1109
+
1110
+ // src/components/Label.ts
1111
+ var Label = /* @__PURE__ */ primitive("Label", "label");
1112
+
1113
+ // src/components/Input.ts
1114
+ var Input = /* @__PURE__ */ primitive("Input", "input");
1115
+
1116
+ // src/components/Textarea.ts
1117
+ var Textarea = /* @__PURE__ */ primitive("Textarea", "textarea");
1118
+
1119
+ // src/components/NativeSelect.ts
1120
+ var NativeSelect = /* @__PURE__ */ primitive("NativeSelect", "select");
1121
+
1122
+ // src/components/InputGroup.ts
1123
+ var InputGroup = /* @__PURE__ */ primitive("InputGroup", "div");
1124
+
1125
+ // src/components/InputGroupAddon.ts
1126
+ var InputGroupAddon = /* @__PURE__ */ primitive("InputGroupAddon", "div");
1127
+
1128
+ // src/components/Empty.ts
1129
+ var Empty = /* @__PURE__ */ primitive("Empty", "div");
1130
+
1131
+ // src/components/EmptyHeader.ts
1132
+ var EmptyHeader = /* @__PURE__ */ primitive("EmptyHeader", "header");
1133
+
1134
+ // src/components/EmptyTitle.ts
1135
+ var EmptyTitle = /* @__PURE__ */ primitive("EmptyTitle", "h3");
1136
+
1137
+ // src/components/EmptyDescription.ts
1138
+ var EmptyDescription = /* @__PURE__ */ primitive("EmptyDescription", "p");
1139
+
1140
+ // src/components/EmptyContent.ts
1141
+ var EmptyContent = /* @__PURE__ */ primitive("EmptyContent", "section");
1142
+
1143
+ // src/components/Item.ts
1144
+ var Item = /* @__PURE__ */ primitive("Item", "div");
1145
+
1146
+ // src/components/ItemContent.ts
1147
+ var ItemContent = /* @__PURE__ */ primitive("ItemContent", "section");
1148
+
1149
+ // src/components/ItemTitle.ts
1150
+ var ItemTitle = /* @__PURE__ */ primitive("ItemTitle", "h3");
1151
+
1152
+ // src/components/ItemDescription.ts
1153
+ var ItemDescription = /* @__PURE__ */ primitive("ItemDescription", "p");
1154
+
1155
+ // src/components/ItemActions.ts
1156
+ var ItemActions = /* @__PURE__ */ primitive("ItemActions", "div");
1157
+
1158
+ // src/components/Kbd.ts
1159
+ var Kbd = /* @__PURE__ */ primitive("Kbd", "kbd");
1160
+
1161
+ // src/components/ScrollArea.ts
1162
+ var ScrollArea = /* @__PURE__ */ primitive("ScrollArea", "div");
1163
+
1164
+ // src/components/Skeleton.ts
1165
+ var Skeleton = /* @__PURE__ */ primitive("Skeleton", "div");
1166
+
1167
+ // src/components/Spinner.ts
1168
+ var Spinner = /* @__PURE__ */ primitive("Spinner", "span");
1169
+
1170
+ // src/components/Separator.ts
1171
+ var Separator = /* @__PURE__ */ primitive("Separator", "hr");
1172
+
1173
+ // src/components/Table.ts
1174
+ var Table = /* @__PURE__ */ primitive("Table", "table");
1175
+
1176
+ // src/components/TableHeader.ts
1177
+ var TableHeader = /* @__PURE__ */ primitive("TableHeader", "thead");
1178
+
1179
+ // src/components/TableBody.ts
1180
+ var TableBody = /* @__PURE__ */ primitive("TableBody", "tbody");
1181
+
1182
+ // src/components/TableFooter.ts
1183
+ var TableFooter = /* @__PURE__ */ primitive("TableFooter", "tfoot");
1184
+
1185
+ // src/components/TableRow.ts
1186
+ var TableRow = /* @__PURE__ */ primitive("TableRow", "tr");
1187
+
1188
+ // src/components/TableHead.ts
1189
+ var TableHead = /* @__PURE__ */ primitive("TableHead", "th");
1190
+
1191
+ // src/components/TableCell.ts
1192
+ var TableCell = /* @__PURE__ */ primitive("TableCell", "td");
1193
+
1194
+ // src/components/TableCaption.ts
1195
+ var TableCaption = /* @__PURE__ */ primitive("TableCaption", "caption");
1196
+
1197
+ // src/components/DialogHeader.ts
1198
+ var DialogHeader = /* @__PURE__ */ primitive("DialogHeader", "header");
1199
+
1200
+ // src/components/DialogTitle.ts
1201
+ var DialogTitle = /* @__PURE__ */ primitive("DialogTitle", "h2");
1202
+
1203
+ // src/components/DialogDescription.ts
1204
+ var DialogDescription = /* @__PURE__ */ primitive("DialogDescription", "p");
1205
+
1206
+ // src/components/DialogContent.ts
1207
+ var DialogContent = /* @__PURE__ */ primitive("DialogContent", "section");
1208
+
1209
+ // src/components/DialogFooter.ts
1210
+ var DialogFooter = /* @__PURE__ */ primitive("DialogFooter", "footer");
1211
+
1212
+ // src/components/SidebarHeader.ts
1213
+ var SidebarHeader = /* @__PURE__ */ primitive("SidebarHeader", "header");
1214
+
1215
+ // src/components/SidebarContent.ts
1216
+ var SidebarContent = /* @__PURE__ */ primitive("SidebarContent", "section");
1217
+
1218
+ // src/components/SidebarFooter.ts
1219
+ var SidebarFooter = /* @__PURE__ */ primitive("SidebarFooter", "footer");
1220
+
1221
+ // src/components/SidebarGroup.ts
1222
+ var SidebarGroup = /* @__PURE__ */ primitive("SidebarGroup", "section");
1223
+
1224
+ // src/components/SidebarItem.ts
1225
+ var SidebarItem = /* @__PURE__ */ primitive("SidebarItem", "a");
1226
+
1227
+ // src/components/Checkbox.ts
1228
+ var import_vue3 = require("vue");
1229
+
1230
+ // src/hooks.ts
1231
+ var import_vue2 = require("vue");
1232
+ function useValue(getValue, getDefault, change) {
1233
+ const internal = (0, import_vue2.shallowRef)(getDefault());
1234
+ return (0, import_vue2.computed)({
1235
+ get: () => getValue() === void 0 ? internal.value : getValue(),
1236
+ set: (value) => {
1237
+ if (Object.is(value, getValue() === void 0 ? internal.value : getValue())) return;
1238
+ if (getValue() === void 0) internal.value = value;
1239
+ change(value);
1240
+ }
1241
+ });
1242
+ }
1243
+ function useFloating(open, anchor, popup, close, options = () => ({})) {
1244
+ (0, import_vue2.watchEffect)(
1245
+ (cleanup) => {
1246
+ if (!open.value || !anchor.value || !popup.value) return;
1247
+ const trigger = anchor.value, content = popup.value;
1248
+ const position = attachFloating(trigger, content, options());
1249
+ const layer = dismissableLayer(trigger.ownerDocument, {
1250
+ elements: () => [trigger, content],
1251
+ dismiss: (reason) => close(reason === "escape")
1252
+ });
1253
+ cleanup(() => {
1254
+ layer();
1255
+ position();
1256
+ });
1257
+ },
1258
+ { flush: "post" }
1259
+ );
1260
+ }
1261
+
1262
+ // src/components/Checkbox.ts
1263
+ var Checkbox = (0, import_vue3.defineComponent)({
1264
+ name: "Checkbox",
1265
+ inheritAttrs: false,
1266
+ props: {
1267
+ modelValue: { type: Boolean, default: void 0 },
1268
+ defaultValue: { type: Boolean, default: false },
1269
+ indeterminate: Boolean,
1270
+ disabled: Boolean,
1271
+ name: String,
1272
+ required: Boolean
1273
+ },
1274
+ emits: { "update:modelValue": (_value) => true },
1275
+ setup(props, { emit, attrs, expose }) {
1276
+ const element = (0, import_vue3.ref)(null), value = useValue(
1277
+ () => props.modelValue,
1278
+ () => props.defaultValue,
1279
+ (value2) => emit("update:modelValue", value2)
1280
+ );
1281
+ (0, import_vue3.watchEffect)(() => {
1282
+ if (element.value) element.value.indeterminate = props.indeterminate;
1283
+ });
1284
+ let cleanup;
1285
+ (0, import_vue3.onMounted)(() => {
1286
+ cleanup = formReset(element.value, () => {
1287
+ value.value = props.defaultValue;
1288
+ });
1289
+ });
1290
+ (0, import_vue3.onUnmounted)(() => cleanup?.());
1291
+ expose({
1292
+ focus: () => element.value?.focus(),
1293
+ get el() {
1294
+ return element.value;
1295
+ }
1296
+ });
1297
+ return () => (0, import_vue3.h)("input", {
1298
+ ...attrs,
1299
+ ref: element,
1300
+ class: cx("input", attrs.class),
1301
+ type: "checkbox",
1302
+ checked: value.value,
1303
+ disabled: props.disabled,
1304
+ name: props.name,
1305
+ required: props.required,
1306
+ onChange: (event) => {
1307
+ value.value = event.target.checked;
1308
+ attrs.onChange?.(event);
1309
+ }
1310
+ });
1311
+ }
1312
+ });
1313
+
1314
+ // src/components/Switch.ts
1315
+ var import_vue4 = require("vue");
1316
+ var Switch = (0, import_vue4.defineComponent)({
1317
+ name: "Switch",
1318
+ inheritAttrs: false,
1319
+ setup: (_, { attrs, slots }) => () => (0, import_vue4.h)(Checkbox, { ...attrs, role: "switch" }, slots)
1320
+ });
1321
+
1322
+ // src/components/Slider.ts
1323
+ var import_vue5 = require("vue");
1324
+ var Slider = (0, import_vue5.defineComponent)({
1325
+ name: "Slider",
1326
+ inheritAttrs: false,
1327
+ props: {
1328
+ modelValue: Number,
1329
+ defaultValue: { type: Number, default: 0 },
1330
+ min: { type: Number, default: 0 },
1331
+ max: { type: Number, default: 100 },
1332
+ step: { type: Number, default: 1 },
1333
+ disabled: Boolean,
1334
+ name: String
1335
+ },
1336
+ emits: { "update:modelValue": (_value) => true },
1337
+ setup(props, { emit, attrs }) {
1338
+ const value = useValue(
1339
+ () => props.modelValue,
1340
+ () => props.defaultValue,
1341
+ (value2) => emit("update:modelValue", value2)
1342
+ ), element = (0, import_vue5.ref)(null);
1343
+ let cleanup;
1344
+ (0, import_vue5.onMounted)(() => {
1345
+ cleanup = formReset(element.value, () => {
1346
+ value.value = props.defaultValue;
1347
+ });
1348
+ });
1349
+ (0, import_vue5.onUnmounted)(() => cleanup?.());
1350
+ return () => (0, import_vue5.h)("input", {
1351
+ ...attrs,
1352
+ ref: element,
1353
+ class: cx("input", attrs.class),
1354
+ type: "range",
1355
+ value: value.value,
1356
+ min: props.min,
1357
+ max: props.max,
1358
+ step: props.step,
1359
+ disabled: props.disabled,
1360
+ name: props.name,
1361
+ style: [
1362
+ attrs.style,
1363
+ { "--slider-value": `${percentage(value.value, props.min, props.max)}%` }
1364
+ ],
1365
+ onInput: (event) => {
1366
+ value.value = event.target.valueAsNumber;
1367
+ }
1368
+ });
1369
+ }
1370
+ });
1371
+
1372
+ // src/components/RadioGroup.ts
1373
+ var import_vue6 = require("vue");
1374
+
1375
+ // src/shared/optionProps.ts
1376
+ var optionsProp = {
1377
+ type: Array,
1378
+ required: true
1379
+ };
1380
+
1381
+ // src/components/RadioGroup.ts
1382
+ var RadioGroup = (0, import_vue6.defineComponent)({
1383
+ name: "RadioGroup",
1384
+ inheritAttrs: false,
1385
+ props: {
1386
+ options: optionsProp,
1387
+ modelValue: String,
1388
+ defaultValue: { type: String, default: "" },
1389
+ name: String,
1390
+ disabled: Boolean,
1391
+ required: Boolean
1392
+ },
1393
+ emits: { "update:modelValue": (_value) => true },
1394
+ setup(props, { emit, attrs }) {
1395
+ const value = useValue(
1396
+ () => props.modelValue,
1397
+ () => props.defaultValue,
1398
+ (value2) => emit("update:modelValue", value2)
1399
+ ), id = (0, import_vue6.useId)(), root = (0, import_vue6.ref)(null);
1400
+ let cleanup;
1401
+ (0, import_vue6.onMounted)(() => {
1402
+ cleanup = formReset(root.value, () => {
1403
+ value.value = props.defaultValue;
1404
+ });
1405
+ });
1406
+ (0, import_vue6.onUnmounted)(() => cleanup?.());
1407
+ return () => (0, import_vue6.h)(
1408
+ "div",
1409
+ {
1410
+ ...attrs,
1411
+ ref: root,
1412
+ role: "radiogroup",
1413
+ class: cx("bc-radio-group", attrs.class)
1414
+ },
1415
+ props.options.map(
1416
+ (option) => (0, import_vue6.h)("label", { key: option.value }, [
1417
+ (0, import_vue6.h)("input", {
1418
+ type: "radio",
1419
+ class: "input",
1420
+ name: props.name ?? id,
1421
+ value: option.value,
1422
+ checked: value.value === option.value,
1423
+ disabled: props.disabled || option.disabled,
1424
+ required: props.required,
1425
+ onChange: () => {
1426
+ value.value = option.value;
1427
+ }
1428
+ }),
1429
+ ` ${option.label}`
1430
+ ])
1431
+ )
1432
+ );
1433
+ }
1434
+ });
1435
+
1436
+ // src/components/Progress.ts
1437
+ var import_vue7 = require("vue");
1438
+ var Progress = (0, import_vue7.defineComponent)({
1439
+ name: "Progress",
1440
+ props: { value: Number, max: { type: Number, default: 100 } },
1441
+ setup: (props) => () => (0, import_vue7.h)(
1442
+ "div",
1443
+ {
1444
+ class: "progress",
1445
+ role: "progressbar",
1446
+ "aria-valuemin": 0,
1447
+ "aria-valuemax": props.max,
1448
+ "aria-valuenow": props.value,
1449
+ "aria-busy": props.value === void 0
1450
+ },
1451
+ (0, import_vue7.h)("span", {
1452
+ style: {
1453
+ width: `${props.value === void 0 ? 100 : percentage(props.value, 0, props.max)}%`
1454
+ }
1455
+ })
1456
+ )
1457
+ });
1458
+
1459
+ // src/components/Tabs.ts
1460
+ var import_vue8 = require("vue");
1461
+ var Tabs = (0, import_vue8.defineComponent)({
1462
+ name: "Tabs",
1463
+ props: {
1464
+ items: optionsProp,
1465
+ modelValue: String,
1466
+ defaultValue: String,
1467
+ orientation: { type: String, default: "horizontal" },
1468
+ activation: { type: String, default: "automatic" },
1469
+ variant: String,
1470
+ keepMounted: Boolean
1471
+ },
1472
+ emits: { "update:modelValue": (_value) => true },
1473
+ setup(props, { emit, slots }) {
1474
+ const id = (0, import_vue8.useId)(), elements = [], value = useValue(
1475
+ () => props.modelValue,
1476
+ () => props.defaultValue ?? props.items.find((item) => !item.disabled)?.value ?? "",
1477
+ (value2) => emit("update:modelValue", value2)
1478
+ );
1479
+ const selected = (0, import_vue8.computed)(() => {
1480
+ const index = props.items.findIndex((item) => item.value === value.value && !item.disabled);
1481
+ return index >= 0 ? index : props.items.findIndex((item) => !item.disabled);
1482
+ });
1483
+ return () => (0, import_vue8.h)("div", { class: "tabs" }, [
1484
+ (0, import_vue8.h)(
1485
+ "div",
1486
+ { role: "tablist", "aria-orientation": props.orientation, "data-variant": props.variant },
1487
+ props.items.map(
1488
+ (item, index) => (0, import_vue8.h)(
1489
+ "button",
1490
+ {
1491
+ key: item.value,
1492
+ ref: (el) => {
1493
+ elements[index] = el;
1494
+ },
1495
+ type: "button",
1496
+ role: "tab",
1497
+ id: `${id}-tab-${index}`,
1498
+ "aria-controls": `${id}-panel-${index}`,
1499
+ "aria-selected": selected.value === index,
1500
+ disabled: item.disabled,
1501
+ tabindex: selected.value === index ? 0 : -1,
1502
+ onClick: () => {
1503
+ value.value = item.value;
1504
+ },
1505
+ onKeydown: (event) => {
1506
+ const arrows = props.orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : ["ArrowLeft", "ArrowRight"];
1507
+ if (!arrows.includes(event.key) && !["Home", "End"].includes(event.key)) return;
1508
+ event.preventDefault();
1509
+ let key = event.key;
1510
+ if (props.orientation === "horizontal" && event.target.closest('[dir="rtl"]'))
1511
+ key = key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
1512
+ const next = nextIndex(props.items, index, key);
1513
+ elements[next]?.focus();
1514
+ if (props.activation === "automatic" && next >= 0)
1515
+ value.value = props.items[next].value;
1516
+ }
1517
+ },
1518
+ item.label
1519
+ )
1520
+ )
1521
+ ),
1522
+ ...props.items.map(
1523
+ (item, index) => (0, import_vue8.h)(
1524
+ "div",
1525
+ {
1526
+ key: item.value,
1527
+ id: `${id}-panel-${index}`,
1528
+ role: "tabpanel",
1529
+ "aria-labelledby": `${id}-tab-${index}`,
1530
+ tabindex: 0,
1531
+ hidden: selected.value !== index
1532
+ },
1533
+ props.keepMounted || selected.value === index ? slots.panel?.({ item }) : void 0
1534
+ )
1535
+ )
1536
+ ]);
1537
+ }
1538
+ });
1539
+
1540
+ // src/components/Accordion.ts
1541
+ var import_vue9 = require("vue");
1542
+ var Accordion = (0, import_vue9.defineComponent)({
1543
+ name: "Accordion",
1544
+ props: {
1545
+ items: optionsProp,
1546
+ modelValue: Array,
1547
+ defaultValue: { type: Array, default: () => [] },
1548
+ multiple: Boolean
1549
+ },
1550
+ emits: { "update:modelValue": (_value) => true },
1551
+ setup(props, { emit, slots }) {
1552
+ const value = useValue(
1553
+ () => props.modelValue,
1554
+ () => props.defaultValue,
1555
+ (value2) => emit("update:modelValue", value2)
1556
+ ), elements = [];
1557
+ return () => (0, import_vue9.h)(
1558
+ "div",
1559
+ { class: "accordion" },
1560
+ props.items.map(
1561
+ (item, index) => (0, import_vue9.h)(
1562
+ "details",
1563
+ {
1564
+ key: item.value,
1565
+ open: value.value.includes(item.value),
1566
+ "aria-disabled": item.disabled || void 0
1567
+ },
1568
+ [
1569
+ (0, import_vue9.h)(
1570
+ "summary",
1571
+ {
1572
+ ref: (el) => {
1573
+ elements[index] = el;
1574
+ },
1575
+ tabindex: item.disabled ? -1 : 0,
1576
+ "aria-disabled": item.disabled || void 0,
1577
+ onClick: (event) => {
1578
+ event.preventDefault();
1579
+ if (!item.disabled)
1580
+ value.value = value.value.includes(item.value) ? value.value.filter((key) => key !== item.value) : props.multiple ? [...value.value, item.value] : [item.value];
1581
+ },
1582
+ onKeydown: (event) => {
1583
+ if (["ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
1584
+ event.preventDefault();
1585
+ elements[nextIndex(props.items, index, event.key)]?.focus();
1586
+ }
1587
+ }
1588
+ },
1589
+ [item.label, (0, import_vue9.h)("span", { "aria-hidden": true }, "\u2304")]
1590
+ ),
1591
+ (0, import_vue9.h)("section", slots.panel?.({ item }))
1592
+ ]
1593
+ )
1594
+ )
1595
+ );
1596
+ }
1597
+ });
1598
+
1599
+ // src/components/Collapsible.ts
1600
+ var import_vue10 = require("vue");
1601
+ var Collapsible = (0, import_vue10.defineComponent)({
1602
+ name: "Collapsible",
1603
+ props: {
1604
+ open: { type: Boolean, default: void 0 },
1605
+ defaultOpen: Boolean,
1606
+ trigger: { type: String, default: "Toggle" }
1607
+ },
1608
+ emits: { "update:open": (_value) => true },
1609
+ setup(props, { emit, slots }) {
1610
+ const id = (0, import_vue10.useId)(), value = useValue(
1611
+ () => props.open,
1612
+ () => props.defaultOpen,
1613
+ (value2) => emit("update:open", value2)
1614
+ );
1615
+ return () => (0, import_vue10.h)("div", { class: "collapsible" }, [
1616
+ (0, import_vue10.h)(
1617
+ "button",
1618
+ {
1619
+ type: "button",
1620
+ class: "btn",
1621
+ "data-variant": "ghost",
1622
+ "aria-expanded": value.value,
1623
+ "aria-controls": id,
1624
+ onClick: () => {
1625
+ value.value = !value.value;
1626
+ }
1627
+ },
1628
+ slots.trigger?.() ?? props.trigger
1629
+ ),
1630
+ (0, import_vue10.h)("div", { id, hidden: !value.value }, slots.default?.())
1631
+ ]);
1632
+ }
1633
+ });
1634
+
1635
+ // src/components/Dialog.ts
1636
+ var import_vue11 = require("vue");
1637
+ var Dialog = (0, import_vue11.defineComponent)({
1638
+ name: "Dialog",
1639
+ props: {
1640
+ open: { type: Boolean, default: void 0 },
1641
+ defaultOpen: Boolean,
1642
+ trigger: String,
1643
+ title: { type: String, required: true },
1644
+ description: String,
1645
+ closeOnOutside: { type: Boolean, default: true },
1646
+ closeOnEscape: { type: Boolean, default: true },
1647
+ closeLabel: { type: String, default: "Close" },
1648
+ kind: { type: String, default: "dialog" },
1649
+ side: { type: String, default: "right" }
1650
+ },
1651
+ emits: { "update:open": (_value) => true },
1652
+ setup(props, { emit, slots }) {
1653
+ const element = (0, import_vue11.ref)(null), id = (0, import_vue11.useId)(), open = useValue(
1654
+ () => props.open,
1655
+ () => props.defaultOpen,
1656
+ (value) => emit("update:open", value)
1657
+ );
1658
+ (0, import_vue11.watchEffect)(
1659
+ (cleanup) => {
1660
+ const dialog = element.value;
1661
+ if (!dialog) return;
1662
+ if (!open.value) {
1663
+ if (dialog.open) dialog.close();
1664
+ return;
1665
+ }
1666
+ if (!dialog.open) dialog.showModal();
1667
+ const unlock = lockScroll(dialog.ownerDocument);
1668
+ cleanup(() => {
1669
+ unlock();
1670
+ if (dialog.open) dialog.close();
1671
+ });
1672
+ },
1673
+ { flush: "post" }
1674
+ );
1675
+ return () => [
1676
+ props.trigger !== void 0 || slots.trigger ? (0, import_vue11.h)(
1677
+ "button",
1678
+ {
1679
+ class: "btn",
1680
+ type: "button",
1681
+ "data-variant": "outline",
1682
+ onClick: () => {
1683
+ open.value = true;
1684
+ }
1685
+ },
1686
+ slots.trigger?.() ?? props.trigger
1687
+ ) : null,
1688
+ (0, import_vue11.h)(
1689
+ "dialog",
1690
+ {
1691
+ ref: element,
1692
+ class: props.kind,
1693
+ role: props.kind === "alert-dialog" ? "alertdialog" : void 0,
1694
+ "data-side": props.kind === "drawer" ? props.side : void 0,
1695
+ "aria-labelledby": `${id}-title`,
1696
+ "aria-describedby": props.description ? `${id}-description` : void 0,
1697
+ onCancel: (event) => {
1698
+ event.preventDefault();
1699
+ if (props.closeOnEscape) open.value = false;
1700
+ },
1701
+ onClose: () => {
1702
+ if (open.value) {
1703
+ open.value = false;
1704
+ void (0, import_vue11.nextTick)(() => {
1705
+ if (open.value && element.value?.isConnected && !element.value.open)
1706
+ element.value.showModal();
1707
+ });
1708
+ }
1709
+ },
1710
+ onClick: (event) => {
1711
+ if (props.closeOnOutside && props.kind !== "alert-dialog" && event.target === event.currentTarget)
1712
+ open.value = false;
1713
+ }
1714
+ },
1715
+ (0, import_vue11.h)("div", { class: props.kind === "drawer" ? "bc-drawer-surface" : "bc-dialog-surface" }, [
1716
+ (0, import_vue11.h)("header", [
1717
+ (0, import_vue11.h)("h2", { id: `${id}-title` }, props.title),
1718
+ props.description ? (0, import_vue11.h)("p", { id: `${id}-description` }, props.description) : null
1719
+ ]),
1720
+ (0, import_vue11.h)("section", slots.default?.()),
1721
+ slots.footer ? (0, import_vue11.h)("footer", slots.footer()) : null,
1722
+ props.kind !== "alert-dialog" ? (0, import_vue11.h)(
1723
+ "button",
1724
+ {
1725
+ type: "button",
1726
+ class: "btn",
1727
+ "data-variant": "ghost",
1728
+ "data-size": "icon-sm",
1729
+ "aria-label": props.closeLabel,
1730
+ onClick: () => {
1731
+ open.value = false;
1732
+ }
1733
+ },
1734
+ "\xD7"
1735
+ ) : null
1736
+ ])
1737
+ )
1738
+ ];
1739
+ }
1740
+ });
1741
+
1742
+ // src/components/AlertDialog.ts
1743
+ var import_vue12 = require("vue");
1744
+ var AlertDialog = (0, import_vue12.defineComponent)({
1745
+ name: "AlertDialog",
1746
+ inheritAttrs: false,
1747
+ setup: (_, { attrs, slots }) => () => (0, import_vue12.h)(
1748
+ Dialog,
1749
+ { ...attrs, title: attrs.title, kind: "alert-dialog", closeOnOutside: false },
1750
+ slots
1751
+ )
1752
+ });
1753
+
1754
+ // src/components/Drawer.ts
1755
+ var import_vue13 = require("vue");
1756
+ var Drawer = (0, import_vue13.defineComponent)({
1757
+ name: "Drawer",
1758
+ inheritAttrs: false,
1759
+ setup: (_, { attrs, slots }) => () => (0, import_vue13.h)(Dialog, { ...attrs, title: attrs.title, kind: "drawer" }, slots)
1760
+ });
1761
+
1762
+ // src/components/Popover.ts
1763
+ var import_vue14 = require("vue");
1764
+ var Popover = (0, import_vue14.defineComponent)({
1765
+ name: "Popover",
1766
+ props: {
1767
+ open: { type: Boolean, default: void 0 },
1768
+ defaultOpen: Boolean,
1769
+ trigger: { type: String, default: "Open" },
1770
+ label: { type: String, default: "Popover" },
1771
+ side: String,
1772
+ align: String
1773
+ },
1774
+ emits: { "update:open": (_value) => true },
1775
+ setup(props, { emit, slots }) {
1776
+ const id = (0, import_vue14.useId)(), anchor = (0, import_vue14.ref)(null), popup = (0, import_vue14.ref)(null), open = useValue(
1777
+ () => props.open,
1778
+ () => props.defaultOpen,
1779
+ (value) => emit("update:open", value)
1780
+ );
1781
+ useFloating(
1782
+ open,
1783
+ anchor,
1784
+ popup,
1785
+ (restore) => {
1786
+ open.value = false;
1787
+ if (restore) anchor.value?.focus();
1788
+ },
1789
+ () => ({ side: props.side, align: props.align })
1790
+ );
1791
+ (0, import_vue14.watch)(open, (value) => {
1792
+ if (value)
1793
+ void (0, import_vue14.nextTick)(() => {
1794
+ if (popup.value) focusFirst(popup.value);
1795
+ });
1796
+ });
1797
+ return () => (0, import_vue14.h)("div", { class: "popover" }, [
1798
+ (0, import_vue14.h)(
1799
+ "button",
1800
+ {
1801
+ type: "button",
1802
+ class: "btn",
1803
+ "data-variant": "outline",
1804
+ ref: anchor,
1805
+ "aria-haspopup": "dialog",
1806
+ "aria-expanded": open.value,
1807
+ "aria-controls": id,
1808
+ onClick: () => {
1809
+ open.value = !open.value;
1810
+ }
1811
+ },
1812
+ slots.trigger?.() ?? props.trigger
1813
+ ),
1814
+ open.value ? (0, import_vue14.h)(
1815
+ "div",
1816
+ {
1817
+ ref: popup,
1818
+ id,
1819
+ "data-popover": "",
1820
+ popover: "manual",
1821
+ class: "bc-floating",
1822
+ role: "dialog",
1823
+ "aria-label": props.label,
1824
+ tabindex: -1
1825
+ },
1826
+ slots.default?.()
1827
+ ) : null
1828
+ ]);
1829
+ }
1830
+ });
1831
+
1832
+ // src/components/Tooltip.ts
1833
+ var import_vue15 = require("vue");
1834
+ var Tooltip = (0, import_vue15.defineComponent)({
1835
+ name: "Tooltip",
1836
+ props: {
1837
+ content: { type: String, required: true },
1838
+ delay: { type: Number, default: 300 },
1839
+ side: { type: String, default: "top" }
1840
+ },
1841
+ setup(props, { slots }) {
1842
+ const open = (0, import_vue15.ref)(false), anchor = (0, import_vue15.ref)(null), popup = (0, import_vue15.ref)(null), id = (0, import_vue15.useId)();
1843
+ let timer;
1844
+ useFloating(
1845
+ open,
1846
+ anchor,
1847
+ popup,
1848
+ () => {
1849
+ open.value = false;
1850
+ },
1851
+ () => ({ side: props.side, align: "center" })
1852
+ );
1853
+ const close = () => {
1854
+ clearTimeout(timer);
1855
+ open.value = false;
1856
+ };
1857
+ (0, import_vue15.onUnmounted)(close);
1858
+ return () => (0, import_vue15.h)(
1859
+ "span",
1860
+ {
1861
+ ref: anchor,
1862
+ tabindex: 0,
1863
+ "aria-describedby": open.value ? id : void 0,
1864
+ onPointerenter: () => {
1865
+ timer = setTimeout(() => {
1866
+ open.value = true;
1867
+ }, props.delay);
1868
+ },
1869
+ onPointerleave: close,
1870
+ onFocusin: () => {
1871
+ open.value = true;
1872
+ },
1873
+ onFocusout: close
1874
+ },
1875
+ [
1876
+ slots.default?.(),
1877
+ open.value ? (0, import_vue15.h)(
1878
+ "div",
1879
+ {
1880
+ ref: popup,
1881
+ id,
1882
+ role: "tooltip",
1883
+ popover: "manual",
1884
+ class: "bc-floating tooltip"
1885
+ },
1886
+ props.content
1887
+ ) : null
1888
+ ]
1889
+ );
1890
+ }
1891
+ });
1892
+
1893
+ // src/components/Select.ts
1894
+ var import_vue16 = require("vue");
1895
+ var Select = (0, import_vue16.defineComponent)({
1896
+ name: "Select",
1897
+ props: {
1898
+ options: { type: Array, required: true },
1899
+ modelValue: [String, Array],
1900
+ defaultValue: [String, Array],
1901
+ multiple: Boolean,
1902
+ disabled: Boolean,
1903
+ required: Boolean,
1904
+ name: String,
1905
+ label: { type: String, required: true },
1906
+ placeholder: { type: String, default: "Select\u2026" },
1907
+ searchable: Boolean,
1908
+ searchPlaceholder: { type: String, default: "Search\u2026" },
1909
+ emptyLabel: { type: String, default: "No results" }
1910
+ },
1911
+ emits: { "update:modelValue": (_value) => true },
1912
+ setup(props, { emit }) {
1913
+ const current = useValue(
1914
+ () => props.modelValue,
1915
+ () => props.defaultValue ?? (props.multiple ? [] : ""),
1916
+ (value) => emit("update:modelValue", value)
1917
+ );
1918
+ const open = (0, import_vue16.ref)(false), query = (0, import_vue16.ref)(""), active = (0, import_vue16.ref)(-1), id = (0, import_vue16.useId)(), anchor = (0, import_vue16.ref)(null), popup = (0, import_vue16.ref)(null), list = (0, import_vue16.ref)(null), search = (0, import_vue16.ref)(null), native = (0, import_vue16.ref)(null), typeahead = createTypeahead();
1919
+ const visible = (0, import_vue16.computed)(
1920
+ () => props.options.filter(
1921
+ (option) => !props.searchable || option.label.toLocaleLowerCase().includes(query.value.toLocaleLowerCase())
1922
+ )
1923
+ ), selected = (0, import_vue16.computed)(() => Array.isArray(current.value) ? current.value : [current.value]);
1924
+ const close = (restore) => {
1925
+ open.value = false;
1926
+ query.value = "";
1927
+ if (restore) anchor.value?.focus();
1928
+ };
1929
+ useFloating(open, anchor, popup, close, () => ({ matchWidth: true }));
1930
+ (0, import_vue16.watch)(
1931
+ () => props.disabled,
1932
+ (disabled) => {
1933
+ if (disabled) close(false);
1934
+ }
1935
+ );
1936
+ (0, import_vue16.watch)([open, query], () => {
1937
+ if (open.value) {
1938
+ active.value = nextIndex(visible.value, -1, "Home");
1939
+ void (0, import_vue16.nextTick)(() => (search.value ?? list.value)?.focus());
1940
+ }
1941
+ });
1942
+ (0, import_vue16.watch)(
1943
+ active,
1944
+ () => void (0, import_vue16.nextTick)(() => {
1945
+ const item = list.value?.querySelector(`[data-index="${active.value}"]`);
1946
+ if (list.value && item) scrollWithin(list.value, item);
1947
+ })
1948
+ );
1949
+ let cleanup;
1950
+ (0, import_vue16.onMounted)(() => {
1951
+ cleanup = formReset(native.value, () => {
1952
+ current.value = props.defaultValue ?? (props.multiple ? [] : "");
1953
+ });
1954
+ });
1955
+ (0, import_vue16.onUnmounted)(() => cleanup?.());
1956
+ const choose = (index) => {
1957
+ const option = visible.value[index];
1958
+ if (!option || option.disabled) return;
1959
+ current.value = props.multiple ? selected.value.includes(option.value) ? selected.value.filter((value) => value !== option.value) : [...selected.value.filter(Boolean), option.value] : option.value;
1960
+ if (!props.multiple) close(true);
1961
+ };
1962
+ const keyboard = (event) => {
1963
+ if (["ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
1964
+ event.preventDefault();
1965
+ active.value = nextIndex(visible.value, active.value, event.key);
1966
+ } else if (event.key === "Enter" || !props.searchable && event.key === " ") {
1967
+ event.preventDefault();
1968
+ choose(active.value);
1969
+ } else if (event.key === "Tab") close(false);
1970
+ else if (!props.searchable && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
1971
+ event.preventDefault();
1972
+ active.value = typeahead(event.key, visible.value, active.value);
1973
+ }
1974
+ };
1975
+ return () => (0, import_vue16.h)("div", { class: props.searchable ? "combobox" : "select" }, [
1976
+ (0, import_vue16.h)(
1977
+ "button",
1978
+ {
1979
+ ref: anchor,
1980
+ type: "button",
1981
+ class: "btn",
1982
+ "data-variant": "outline",
1983
+ disabled: props.disabled,
1984
+ role: "combobox",
1985
+ "aria-label": props.label,
1986
+ "aria-haspopup": "listbox",
1987
+ "aria-expanded": open.value,
1988
+ "aria-controls": `${id}-list`,
1989
+ "aria-required": props.required,
1990
+ onClick: () => {
1991
+ open.value = !open.value;
1992
+ },
1993
+ onKeydown: (event) => {
1994
+ if (["ArrowDown", "ArrowUp"].includes(event.key)) {
1995
+ event.preventDefault();
1996
+ open.value = true;
1997
+ }
1998
+ }
1999
+ },
2000
+ [
2001
+ (0, import_vue16.h)(
2002
+ "span",
2003
+ props.options.filter((option) => selected.value.includes(option.value)).map((option) => option.label).join(", ") || props.placeholder
2004
+ ),
2005
+ (0, import_vue16.h)("span", { "aria-hidden": true }, "\u2304")
2006
+ ]
2007
+ ),
2008
+ open.value ? (0, import_vue16.h)("div", { ref: popup, "data-popover": "", popover: "manual", class: "bc-floating" }, [
2009
+ props.searchable ? (0, import_vue16.h)("input", {
2010
+ ref: search,
2011
+ class: "input bc-search",
2012
+ value: query.value,
2013
+ role: "combobox",
2014
+ "aria-label": props.searchPlaceholder,
2015
+ "aria-autocomplete": "list",
2016
+ "aria-expanded": true,
2017
+ "aria-controls": `${id}-list`,
2018
+ "aria-activedescendant": active.value >= 0 ? `${id}-option-${active.value}` : void 0,
2019
+ placeholder: props.searchPlaceholder,
2020
+ onInput: (event) => {
2021
+ query.value = event.target.value;
2022
+ },
2023
+ onKeydown: keyboard
2024
+ }) : null,
2025
+ (0, import_vue16.h)(
2026
+ "div",
2027
+ {
2028
+ ref: list,
2029
+ id: `${id}-list`,
2030
+ role: "listbox",
2031
+ tabindex: -1,
2032
+ "aria-label": props.label,
2033
+ "aria-multiselectable": props.multiple || void 0,
2034
+ "aria-activedescendant": active.value >= 0 ? `${id}-option-${active.value}` : void 0,
2035
+ "data-empty": props.emptyLabel,
2036
+ onKeydown: props.searchable ? void 0 : keyboard
2037
+ },
2038
+ visible.value.map(
2039
+ (option, index) => (0, import_vue16.h)(
2040
+ "div",
2041
+ {
2042
+ key: option.value,
2043
+ id: `${id}-option-${index}`,
2044
+ "data-index": index,
2045
+ "data-value": option.value,
2046
+ role: "option",
2047
+ "aria-selected": selected.value.includes(option.value),
2048
+ "aria-disabled": option.disabled || void 0,
2049
+ class: active.value === index ? "active" : void 0,
2050
+ onPointermove: (event) => {
2051
+ if ((event.movementX || event.movementY) && !option.disabled)
2052
+ active.value = index;
2053
+ },
2054
+ onPointerdown: (event) => event.preventDefault(),
2055
+ onClick: () => choose(index)
2056
+ },
2057
+ option.label
2058
+ )
2059
+ )
2060
+ )
2061
+ ]) : null,
2062
+ (0, import_vue16.h)(
2063
+ "select",
2064
+ {
2065
+ ref: native,
2066
+ class: "bc-form-control",
2067
+ tabindex: -1,
2068
+ "aria-hidden": true,
2069
+ name: props.name,
2070
+ disabled: props.disabled,
2071
+ required: props.required,
2072
+ multiple: props.multiple,
2073
+ onChange: (event) => {
2074
+ const el = event.target;
2075
+ current.value = props.multiple ? [...el.selectedOptions].map((option) => option.value) : el.value;
2076
+ },
2077
+ onInvalid: (event) => {
2078
+ event.preventDefault();
2079
+ anchor.value?.focus();
2080
+ anchor.value?.setAttribute("aria-invalid", "true");
2081
+ }
2082
+ },
2083
+ [
2084
+ !props.multiple ? (0, import_vue16.h)("option", { value: "", selected: current.value === "" }, props.placeholder) : null,
2085
+ ...props.options.map(
2086
+ (option) => (0, import_vue16.h)(
2087
+ "option",
2088
+ {
2089
+ key: option.value,
2090
+ value: option.value,
2091
+ selected: selected.value.includes(option.value),
2092
+ disabled: option.disabled
2093
+ },
2094
+ option.label
2095
+ )
2096
+ )
2097
+ ]
2098
+ )
2099
+ ]);
2100
+ }
2101
+ });
2102
+
2103
+ // src/components/Combobox.ts
2104
+ var import_vue17 = require("vue");
2105
+ var Combobox = (0, import_vue17.defineComponent)({
2106
+ name: "Combobox",
2107
+ inheritAttrs: false,
2108
+ setup: (_, { attrs }) => () => (0, import_vue17.h)(Select, {
2109
+ ...attrs,
2110
+ options: attrs.options,
2111
+ label: attrs.label,
2112
+ searchable: true
2113
+ })
2114
+ });
2115
+
2116
+ // src/components/DropdownMenu.ts
2117
+ var import_vue18 = require("vue");
2118
+ var DropdownMenu = (0, import_vue18.defineComponent)({
2119
+ name: "DropdownMenu",
2120
+ props: {
2121
+ items: { type: Array, required: true },
2122
+ trigger: { type: String, default: "Menu" },
2123
+ label: { type: String, default: "Menu" },
2124
+ open: { type: Boolean, default: void 0 },
2125
+ defaultOpen: Boolean,
2126
+ side: String,
2127
+ align: String
2128
+ },
2129
+ emits: { "update:open": (_value) => true, select: (_value) => true },
2130
+ setup(props, { emit, slots }) {
2131
+ const id = (0, import_vue18.useId)(), anchor = (0, import_vue18.ref)(null), popup = (0, import_vue18.ref)(null), open = useValue(
2132
+ () => props.open,
2133
+ () => props.defaultOpen,
2134
+ (value) => emit("update:open", value)
2135
+ ), elements = [], typeahead = createTypeahead();
2136
+ let initial = "Home";
2137
+ const enabled = (0, import_vue18.computed)(
2138
+ () => props.items.map((item) => ({ ...item, disabled: item.disabled || item.separator }))
2139
+ );
2140
+ useFloating(
2141
+ open,
2142
+ anchor,
2143
+ popup,
2144
+ (restore) => {
2145
+ open.value = false;
2146
+ if (restore) anchor.value?.focus();
2147
+ },
2148
+ () => ({ side: props.side, align: props.align })
2149
+ );
2150
+ (0, import_vue18.watch)(open, (value) => {
2151
+ if (value) void (0, import_vue18.nextTick)(() => elements[nextIndex(enabled.value, -1, initial)]?.focus());
2152
+ });
2153
+ return () => (0, import_vue18.h)("div", { class: "dropdown-menu" }, [
2154
+ (0, import_vue18.h)(
2155
+ "button",
2156
+ {
2157
+ ref: anchor,
2158
+ type: "button",
2159
+ class: "btn",
2160
+ "data-variant": "outline",
2161
+ "aria-haspopup": "menu",
2162
+ "aria-controls": id,
2163
+ "aria-expanded": open.value,
2164
+ onClick: () => {
2165
+ initial = "Home";
2166
+ open.value = !open.value;
2167
+ },
2168
+ onKeydown: (event) => {
2169
+ if (["ArrowDown", "ArrowUp"].includes(event.key)) {
2170
+ event.preventDefault();
2171
+ initial = event.key === "ArrowUp" ? "End" : "Home";
2172
+ open.value = true;
2173
+ }
2174
+ }
2175
+ },
2176
+ slots.trigger?.() ?? props.trigger
2177
+ ),
2178
+ open.value ? (0, import_vue18.h)(
2179
+ "div",
2180
+ { ref: popup, "data-popover": "", popover: "manual", class: "bc-floating" },
2181
+ (0, import_vue18.h)(
2182
+ "div",
2183
+ { id, role: "menu", "aria-label": props.label },
2184
+ props.items.map(
2185
+ (item, index) => item.separator ? (0, import_vue18.h)("hr", { key: item.value, role: "separator" }) : (0, import_vue18.h)(
2186
+ item.href ? "a" : "button",
2187
+ {
2188
+ key: item.value,
2189
+ ref: (el) => {
2190
+ elements[index] = el;
2191
+ },
2192
+ href: item.href,
2193
+ type: item.href ? void 0 : "button",
2194
+ class: "btn",
2195
+ "data-variant": "ghost",
2196
+ role: "menuitem",
2197
+ tabindex: -1,
2198
+ "aria-disabled": item.disabled || void 0,
2199
+ disabled: !item.href && item.disabled,
2200
+ onClick: (event) => {
2201
+ if (item.disabled) {
2202
+ event.preventDefault();
2203
+ return;
2204
+ }
2205
+ item.onSelect?.();
2206
+ emit("select", item.value);
2207
+ open.value = false;
2208
+ anchor.value?.focus();
2209
+ },
2210
+ onKeydown: (event) => {
2211
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
2212
+ event.preventDefault();
2213
+ elements[nextIndex(enabled.value, index, event.key)]?.focus();
2214
+ } else if (event.key === "Tab") open.value = false;
2215
+ else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey)
2216
+ elements[typeahead(event.key, enabled.value, index)]?.focus();
2217
+ }
2218
+ },
2219
+ [
2220
+ item.label,
2221
+ item.shortcut ? (0, import_vue18.h)("kbd", { "data-shortcut": "" }, item.shortcut) : null
2222
+ ]
2223
+ )
2224
+ )
2225
+ )
2226
+ ) : null
2227
+ ]);
2228
+ }
2229
+ });
2230
+
2231
+ // src/components/Command.ts
2232
+ var import_vue19 = require("vue");
2233
+ var Command = (0, import_vue19.defineComponent)({
2234
+ name: "Command",
2235
+ props: {
2236
+ items: { type: Array, required: true },
2237
+ label: { type: String, default: "Commands" },
2238
+ placeholder: { type: String, default: "Search commands\u2026" },
2239
+ emptyLabel: { type: String, default: "No results" }
2240
+ },
2241
+ emits: { select: (_value) => true },
2242
+ setup(props, { emit }) {
2243
+ const query = (0, import_vue19.ref)(""), active = (0, import_vue19.ref)(0), id = (0, import_vue19.useId)(), visible = (0, import_vue19.computed)(
2244
+ () => props.items.filter(
2245
+ (item) => !item.separator && item.label.toLocaleLowerCase().includes(query.value.toLocaleLowerCase())
2246
+ )
2247
+ );
2248
+ const choose = (index) => {
2249
+ const item = visible.value[index];
2250
+ if (item && !item.disabled) {
2251
+ item.onSelect?.();
2252
+ emit("select", item.value);
2253
+ }
2254
+ };
2255
+ return () => (0, import_vue19.h)("div", { class: "command" }, [
2256
+ (0, import_vue19.h)(
2257
+ "header",
2258
+ (0, import_vue19.h)("input", {
2259
+ class: "input",
2260
+ value: query.value,
2261
+ role: "combobox",
2262
+ "aria-label": props.label,
2263
+ "aria-autocomplete": "list",
2264
+ "aria-expanded": true,
2265
+ "aria-controls": id,
2266
+ "aria-activedescendant": visible.value[active.value] ? `${id}-${active.value}` : void 0,
2267
+ placeholder: props.placeholder,
2268
+ onInput: (event) => {
2269
+ query.value = event.target.value;
2270
+ active.value = 0;
2271
+ },
2272
+ onKeydown: (event) => {
2273
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
2274
+ event.preventDefault();
2275
+ active.value = nextIndex(visible.value, active.value, event.key);
2276
+ } else if (event.key === "Enter") {
2277
+ event.preventDefault();
2278
+ choose(active.value);
2279
+ }
2280
+ }
2281
+ })
2282
+ ),
2283
+ (0, import_vue19.h)(
2284
+ "div",
2285
+ { id, role: "listbox", "aria-label": props.label },
2286
+ visible.value.length ? visible.value.map(
2287
+ (item, index) => (0, import_vue19.h)(
2288
+ "div",
2289
+ {
2290
+ key: item.value,
2291
+ id: `${id}-${index}`,
2292
+ role: "option",
2293
+ "aria-selected": active.value === index,
2294
+ "aria-disabled": item.disabled || void 0,
2295
+ class: active.value === index ? "active" : void 0,
2296
+ onPointermove: (event) => {
2297
+ if ((event.movementX || event.movementY) && !item.disabled)
2298
+ active.value = index;
2299
+ },
2300
+ onClick: () => choose(index)
2301
+ },
2302
+ item.label
2303
+ )
2304
+ ) : (0, import_vue19.h)("p", { role: "status" }, props.emptyLabel)
2305
+ )
2306
+ ]);
2307
+ }
2308
+ });
2309
+
2310
+ // src/components/Pagination.ts
2311
+ var import_vue20 = require("vue");
2312
+ var Pagination = (0, import_vue20.defineComponent)({
2313
+ name: "Pagination",
2314
+ props: {
2315
+ page: { type: Number, required: true },
2316
+ count: { type: Number, required: true },
2317
+ label: { type: String, default: "Pagination" }
2318
+ },
2319
+ emits: { "update:page": (_value) => true },
2320
+ setup: (props, { emit }) => () => {
2321
+ const total = Math.max(1, Math.floor(props.count)), current = Math.max(1, Math.min(props.page, total));
2322
+ return (0, import_vue20.h)("nav", { class: "bc-pagination", "aria-label": props.label }, [
2323
+ (0, import_vue20.h)(
2324
+ "button",
2325
+ {
2326
+ type: "button",
2327
+ class: "btn",
2328
+ "data-variant": "outline",
2329
+ disabled: current === 1,
2330
+ "aria-label": "Previous page",
2331
+ onClick: () => emit("update:page", current - 1)
2332
+ },
2333
+ "\u2039"
2334
+ ),
2335
+ (0, import_vue20.h)("span", { "aria-live": "polite" }, `${current} / ${total}`),
2336
+ (0, import_vue20.h)(
2337
+ "button",
2338
+ {
2339
+ type: "button",
2340
+ class: "btn",
2341
+ "data-variant": "outline",
2342
+ disabled: current === total,
2343
+ "aria-label": "Next page",
2344
+ onClick: () => emit("update:page", current + 1)
2345
+ },
2346
+ "\u203A"
2347
+ )
2348
+ ]);
2349
+ }
2350
+ });
2351
+
2352
+ // src/components/Sidebar.ts
2353
+ var import_vue21 = require("vue");
2354
+ var Sidebar = (0, import_vue21.defineComponent)({
2355
+ name: "Sidebar",
2356
+ props: {
2357
+ collapsed: { type: Boolean, default: void 0 },
2358
+ defaultCollapsed: Boolean,
2359
+ label: { type: String, default: "Navigation" }
2360
+ },
2361
+ emits: { "update:collapsed": (_value) => true },
2362
+ setup(props, { emit, slots }) {
2363
+ const collapsed = useValue(
2364
+ () => props.collapsed,
2365
+ () => props.defaultCollapsed,
2366
+ (value) => emit("update:collapsed", value)
2367
+ );
2368
+ return () => (0, import_vue21.h)("aside", { class: "bc-sidebar", "data-collapsed": collapsed.value }, [
2369
+ (0, import_vue21.h)(
2370
+ "button",
2371
+ {
2372
+ type: "button",
2373
+ class: "btn",
2374
+ "data-variant": "ghost",
2375
+ "aria-label": collapsed.value ? "Expand sidebar" : "Collapse sidebar",
2376
+ "aria-expanded": !collapsed.value,
2377
+ onClick: () => {
2378
+ collapsed.value = !collapsed.value;
2379
+ }
2380
+ },
2381
+ "\u2630"
2382
+ ),
2383
+ (0, import_vue21.h)("nav", { "aria-label": props.label }, slots.default?.())
2384
+ ]);
2385
+ }
2386
+ });
2387
+
2388
+ // src/components/ThemeSwitcher.ts
2389
+ var import_vue22 = require("vue");
2390
+ var ThemeSwitcher = (0, import_vue22.defineComponent)({
2391
+ name: "ThemeSwitcher",
2392
+ props: {
2393
+ modelValue: String,
2394
+ defaultValue: { type: String, default: "light" },
2395
+ label: { type: String, default: "Dark mode" }
2396
+ },
2397
+ emits: { "update:modelValue": (_value) => true },
2398
+ setup(props, { emit }) {
2399
+ const value = useValue(
2400
+ () => props.modelValue,
2401
+ () => props.defaultValue,
2402
+ (value2) => emit("update:modelValue", value2)
2403
+ );
2404
+ return () => (0, import_vue22.h)(
2405
+ "button",
2406
+ {
2407
+ type: "button",
2408
+ class: "btn",
2409
+ "data-variant": "outline",
2410
+ role: "switch",
2411
+ "aria-label": props.label,
2412
+ "aria-checked": value.value === "dark",
2413
+ onClick: () => {
2414
+ value.value = value.value === "dark" ? "light" : "dark";
2415
+ }
2416
+ },
2417
+ value.value === "dark" ? "\u263E" : "\u2600"
2418
+ );
2419
+ }
2420
+ });
2421
+
2422
+ // src/components/Toaster.ts
2423
+ var import_vue24 = require("vue");
2424
+
2425
+ // src/components/Toast.ts
2426
+ var import_vue23 = require("vue");
2427
+ var Toast = (0, import_vue23.defineComponent)({
2428
+ name: "Toast",
2429
+ props: { message: { type: Object, required: true } },
2430
+ emits: ["dismiss"],
2431
+ setup(props, { emit }) {
2432
+ let timer, remaining = props.message.duration ?? 5e3, started = 0;
2433
+ const pause = () => {
2434
+ clearTimeout(timer);
2435
+ if (started) remaining = Math.max(0, remaining - (Date.now() - started));
2436
+ started = 0;
2437
+ };
2438
+ const resume = () => {
2439
+ if ((props.message.duration ?? 5e3) <= 0 || started) return;
2440
+ started = Date.now();
2441
+ timer = setTimeout(() => emit("dismiss"), remaining);
2442
+ };
2443
+ (0, import_vue23.onMounted)(resume);
2444
+ (0, import_vue23.onUnmounted)(pause);
2445
+ return () => (0, import_vue23.h)(
2446
+ "div",
2447
+ {
2448
+ class: "toast",
2449
+ "data-variant": props.message.variant,
2450
+ onPointerenter: pause,
2451
+ onPointerleave: resume,
2452
+ onFocusin: pause,
2453
+ onFocusout: (event) => {
2454
+ if (!event.currentTarget.contains(event.relatedTarget))
2455
+ resume();
2456
+ }
2457
+ },
2458
+ (0, import_vue23.h)("div", { class: "toast-content" }, [
2459
+ (0, import_vue23.h)("section", [
2460
+ (0, import_vue23.h)("h2", props.message.title),
2461
+ props.message.description ? (0, import_vue23.h)("p", props.message.description) : null
2462
+ ]),
2463
+ (0, import_vue23.h)(
2464
+ "footer",
2465
+ (0, import_vue23.h)(
2466
+ "button",
2467
+ {
2468
+ type: "button",
2469
+ class: "btn",
2470
+ "data-variant": "ghost",
2471
+ "data-size": "icon-sm",
2472
+ "aria-label": "Dismiss notification",
2473
+ onClick: () => emit("dismiss")
2474
+ },
2475
+ "\xD7"
2476
+ )
2477
+ )
2478
+ ])
2479
+ );
2480
+ }
2481
+ });
2482
+
2483
+ // src/components/Toaster.ts
2484
+ var Toaster = (0, import_vue24.defineComponent)({
2485
+ name: "Toaster",
2486
+ props: {
2487
+ messages: { type: Array, required: true },
2488
+ label: { type: String, default: "Notifications" }
2489
+ },
2490
+ emits: { dismiss: (_id) => true },
2491
+ setup: (props, { emit }) => () => (0, import_vue24.h)("section", { class: "toaster", "aria-label": props.label }, [
2492
+ (0, import_vue24.h)(
2493
+ "div",
2494
+ { class: "bc-live", role: "status", "aria-live": "polite", "aria-atomic": true },
2495
+ props.messages.at(-1)?.title
2496
+ ),
2497
+ ...props.messages.map(
2498
+ (message) => (0, import_vue24.h)(Toast, { key: message.id, message, onDismiss: () => emit("dismiss", message.id) })
2499
+ )
2500
+ ])
2501
+ });
2502
+
2503
+ // src/components/Chart.ts
2504
+ var import_vue25 = require("vue");
2505
+ var Chart = (0, import_vue25.defineComponent)({
2506
+ name: "Chart",
2507
+ props: {
2508
+ data: { type: Array, required: true },
2509
+ label: { type: String, required: true },
2510
+ kind: { type: String, default: "line" }
2511
+ },
2512
+ setup(props) {
2513
+ const id = (0, import_vue25.useId)();
2514
+ return () => {
2515
+ const finite = props.data.map((point) => Number.isFinite(point.value) ? point.value : 0), min = Math.min(0, ...finite), max = Math.max(1, ...finite), y = (value) => 180 - (value - min) / (max - min) * 160;
2516
+ return (0, import_vue25.h)("figure", { class: "chart" }, [
2517
+ (0, import_vue25.h)(
2518
+ "svg",
2519
+ { class: "bc-chart", viewBox: "0 0 400 200", role: "img", "aria-labelledby": id },
2520
+ [
2521
+ (0, import_vue25.h)("title", { id }, props.label),
2522
+ props.kind === "line" ? (0, import_vue25.h)("polyline", {
2523
+ fill: "none",
2524
+ stroke: "currentColor",
2525
+ "stroke-width": 3,
2526
+ points: finite.map(
2527
+ (value, index) => `${20 + index / Math.max(1, finite.length - 1) * 360},${y(value)}`
2528
+ ).join(" ")
2529
+ }) : finite.map(
2530
+ (value, index) => (0, import_vue25.h)("rect", {
2531
+ x: 20 + index / Math.max(1, finite.length) * 360,
2532
+ y: Math.min(y(0), y(value)),
2533
+ width: Math.max(1, 360 / Math.max(1, finite.length) - 8),
2534
+ height: Math.abs(y(value) - y(0)),
2535
+ fill: "currentColor"
2536
+ })
2537
+ )
2538
+ ]
2539
+ ),
2540
+ (0, import_vue25.h)("figcaption", props.label),
2541
+ (0, import_vue25.h)("table", { class: "bc-live" }, [
2542
+ (0, import_vue25.h)("caption", props.label),
2543
+ (0, import_vue25.h)(
2544
+ "tbody",
2545
+ props.data.map(
2546
+ (point) => (0, import_vue25.h)("tr", [(0, import_vue25.h)("th", { scope: "row" }, point.label), (0, import_vue25.h)("td", point.value)])
2547
+ )
2548
+ )
2549
+ ])
2550
+ ]);
2551
+ };
2552
+ }
2553
+ });
2554
+ // Annotate the CommonJS export names for ESM import in node:
2555
+ 0 && (module.exports = {
2556
+ Accordion,
2557
+ AccordionRoot,
2558
+ Alert,
2559
+ AlertDescription,
2560
+ AlertDialog,
2561
+ AlertDialogRoot,
2562
+ AlertTitle,
2563
+ Avatar,
2564
+ AvatarFallback,
2565
+ AvatarImage,
2566
+ Badge,
2567
+ Breadcrumb,
2568
+ BreadcrumbItem,
2569
+ BreadcrumbLink,
2570
+ BreadcrumbList,
2571
+ BreadcrumbSeparator,
2572
+ Button,
2573
+ ButtonGroup,
2574
+ Card,
2575
+ CardAction,
2576
+ CardContent,
2577
+ CardDescription,
2578
+ CardFooter,
2579
+ CardHeader,
2580
+ CardTitle,
2581
+ Chart,
2582
+ ChartRoot,
2583
+ Checkbox,
2584
+ Collapsible,
2585
+ Combobox,
2586
+ ComboboxRoot,
2587
+ Command,
2588
+ CommandRoot,
2589
+ Dialog,
2590
+ DialogContent,
2591
+ DialogDescription,
2592
+ DialogFooter,
2593
+ DialogHeader,
2594
+ DialogRoot,
2595
+ DialogTitle,
2596
+ Drawer,
2597
+ DrawerRoot,
2598
+ DropdownMenu,
2599
+ DropdownMenuRoot,
2600
+ Empty,
2601
+ EmptyContent,
2602
+ EmptyDescription,
2603
+ EmptyHeader,
2604
+ EmptyTitle,
2605
+ Field,
2606
+ FieldDescription,
2607
+ FieldError,
2608
+ FieldLabel,
2609
+ Input,
2610
+ InputGroup,
2611
+ InputGroupAddon,
2612
+ Item,
2613
+ ItemActions,
2614
+ ItemContent,
2615
+ ItemDescription,
2616
+ ItemTitle,
2617
+ Kbd,
2618
+ Label,
2619
+ NativeSelect,
2620
+ Pagination,
2621
+ Popover,
2622
+ PopoverRoot,
2623
+ Progress,
2624
+ RadioGroup,
2625
+ ScrollArea,
2626
+ Select,
2627
+ SelectRoot,
2628
+ Separator,
2629
+ Sidebar,
2630
+ SidebarContent,
2631
+ SidebarFooter,
2632
+ SidebarGroup,
2633
+ SidebarHeader,
2634
+ SidebarItem,
2635
+ SidebarRoot,
2636
+ Skeleton,
2637
+ Slider,
2638
+ Spinner,
2639
+ Switch,
2640
+ Table,
2641
+ TableBody,
2642
+ TableCaption,
2643
+ TableCell,
2644
+ TableFooter,
2645
+ TableHead,
2646
+ TableHeader,
2647
+ TableRow,
2648
+ Tabs,
2649
+ TabsRoot,
2650
+ Textarea,
2651
+ ThemeSwitcher,
2652
+ Toaster,
2653
+ Tooltip
2654
+ });
2655
+ //# sourceMappingURL=index.cjs.map