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