@nocoo/basalt 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -15
- package/ai/COMPATIBILITY.md +180 -0
- package/ai/INTEGRATION.md +1760 -0
- package/ai/RECIPES.md +161 -0
- package/ai/USAGE.md +99 -0
- package/ai/registry.json +38099 -0
- package/ai/sources.json +10 -0
- package/dist/assets/brand-mark.d.ts +1 -0
- package/dist/assets/brand-mark.js +7 -0
- package/dist/assets/brand-mark.js.map +1 -0
- package/dist/charts/area.d.ts +58 -5
- package/dist/charts/area.js +20 -12
- package/dist/charts/area.js.map +1 -1
- package/dist/charts/bar.d.ts +54 -5
- package/dist/charts/bar.js +16 -10
- package/dist/charts/bar.js.map +1 -1
- package/dist/charts/bullet.d.ts +18 -1
- package/dist/charts/bullet.js +6 -3
- package/dist/charts/bullet.js.map +1 -1
- package/dist/charts/charts.d.ts +58 -5
- package/dist/charts/charts.js +13 -2
- package/dist/charts/charts.js.map +1 -1
- package/dist/charts/config.d.ts +7 -0
- package/dist/charts/config.js +5 -1
- package/dist/charts/config.js.map +1 -1
- package/dist/charts/custom-chart.d.ts +58 -5
- package/dist/charts/custom-chart.js +13 -2
- package/dist/charts/custom-chart.js.map +1 -1
- package/dist/charts/donut.d.ts +18 -1
- package/dist/charts/donut.js +6 -3
- package/dist/charts/donut.js.map +1 -1
- package/dist/charts/frame.d.ts +40 -3
- package/dist/charts/frame.js +55 -28
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/funnel.d.ts +18 -1
- package/dist/charts/funnel.js +5 -1
- package/dist/charts/funnel.js.map +1 -1
- package/dist/charts/gauge.d.ts +18 -1
- package/dist/charts/gauge.js +38 -20
- package/dist/charts/gauge.js.map +1 -1
- package/dist/charts/grouped-bar.d.ts +54 -5
- package/dist/charts/grouped-bar.js +16 -10
- package/dist/charts/grouped-bar.js.map +1 -1
- package/dist/charts/heatmap-calendar.d.ts +61 -0
- package/dist/charts/heatmap-calendar.js +287 -96
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.d.ts +99 -0
- package/dist/charts/heatmap-matrix.js +249 -0
- package/dist/charts/heatmap-matrix.js.map +1 -0
- package/dist/charts/line.d.ts +66 -5
- package/dist/charts/line.js +37 -30
- package/dist/charts/line.js.map +1 -1
- package/dist/charts/palette.d.ts +1 -0
- package/dist/charts/palette.js +7 -1
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/radar.d.ts +18 -1
- package/dist/charts/radar.js +26 -19
- package/dist/charts/radar.js.map +1 -1
- package/dist/charts/sankey.d.ts +18 -1
- package/dist/charts/sankey.js +4 -1
- package/dist/charts/sankey.js.map +1 -1
- package/dist/charts/series.d.ts +5 -7
- package/dist/charts/series.js.map +1 -1
- package/dist/charts/slot-bar.d.ts +38 -6
- package/dist/charts/slot-bar.js +5 -2
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/sparkline.d.ts +35 -5
- package/dist/charts/sparkline.js +22 -18
- package/dist/charts/sparkline.js.map +1 -1
- package/dist/charts/stacked-bar.d.ts +58 -5
- package/dist/charts/stacked-bar.js +19 -12
- package/dist/charts/stacked-bar.js.map +1 -1
- package/dist/charts/stat-card.d.ts +51 -1
- package/dist/charts/stat-card.js +66 -39
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeline.d.ts +3 -0
- package/dist/charts/timeline.js +4 -3
- package/dist/charts/timeline.js.map +1 -1
- package/dist/charts/timeseries.d.ts +58 -5
- package/dist/charts/timeseries.js +13 -2
- package/dist/charts/timeseries.js.map +1 -1
- package/dist/charts/tooltip.d.ts +57 -0
- package/dist/charts/tooltip.js +119 -2
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/accordion.d.ts +117 -2
- package/dist/components/accordion.js +20 -13
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.d.ts +131 -13
- package/dist/components/alert-dialog.js +12 -9
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/app-header.js +18 -17
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +15 -14
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/autocomplete.d.ts +4 -0
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/avatar.d.ts +76 -3
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts +15 -1
- package/dist/components/badge.js +17 -16
- package/dist/components/badge.js.map +1 -1
- package/dist/components/banner.d.ts +88 -2
- package/dist/components/banner.js +41 -40
- package/dist/components/banner.js.map +1 -1
- package/dist/components/basalt-mark.js +14 -8
- package/dist/components/basalt-mark.js.map +1 -1
- package/dist/components/battery-meter.d.ts +10 -0
- package/dist/components/battery-meter.js +56 -0
- package/dist/components/battery-meter.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +27 -7
- package/dist/components/breadcrumbs.js +21 -20
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button.d.ts +48 -2
- package/dist/components/button.js +87 -36
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-bubble.d.ts +7 -0
- package/dist/components/chat-bubble.js +14 -13
- package/dist/components/chat-bubble.js.map +1 -1
- package/dist/components/chat-composer.d.ts +7 -3
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-header.d.ts +6 -1
- package/dist/components/chat-header.js +17 -16
- package/dist/components/chat-header.js.map +1 -1
- package/dist/components/chat-inbox.d.ts +7 -2
- package/dist/components/chat-inbox.js.map +1 -1
- package/dist/components/checkbox.js +84 -53
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/clipboard-text.d.ts +13 -2
- package/dist/components/clipboard-text.js +4 -4
- package/dist/components/clipboard-text.js.map +1 -1
- package/dist/components/collapsible.d.ts +58 -15
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/command-palette.d.ts +151 -61
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +1 -1
- package/dist/components/confirm-dialog.js +6 -4
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/context-menu.d.ts +210 -2
- package/dist/components/context-menu.js +7 -4
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.d.ts +40 -2
- package/dist/components/data-table.js +168 -120
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +53 -2
- package/dist/components/date-picker.js +387 -219
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.d.ts +7 -1
- package/dist/components/delete-resource.js +22 -18
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/description-list.js +16 -15
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog.d.ts +141 -12
- package/dist/components/dialog.js +42 -38
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dock.d.ts +1 -1
- package/dist/components/dock.js +39 -58
- package/dist/components/dock.js.map +1 -1
- package/dist/components/dropdown-menu.d.ts +229 -15
- package/dist/components/dropdown-menu.js +9 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.d.ts +33 -0
- package/dist/components/editable-nav-item.js +90 -0
- package/dist/components/editable-nav-item.js.map +1 -0
- package/dist/components/empty.d.ts +22 -2
- package/dist/components/empty.js +22 -13
- package/dist/components/empty.js.map +1 -1
- package/dist/components/field.js +31 -30
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +37 -0
- package/dist/components/file-dropzone.js +103 -0
- package/dist/components/file-dropzone.js.map +1 -0
- package/dist/components/filter-bar.d.ts +34 -0
- package/dist/components/filter-bar.js +52 -0
- package/dist/components/filter-bar.js.map +1 -0
- package/dist/components/flow.js +19 -18
- package/dist/components/flow.js.map +1 -1
- package/dist/components/grid.d.ts +3 -1
- package/dist/components/grid.js.map +1 -1
- package/dist/components/hover-card.d.ts +111 -1
- package/dist/components/hover-card.js +9 -6
- package/dist/components/hover-card.js.map +1 -1
- package/dist/components/icon-picker.d.ts +34 -0
- package/dist/components/icon-picker.js +77 -0
- package/dist/components/icon-picker.js.map +1 -0
- package/dist/components/inline-editable.d.ts +46 -0
- package/dist/components/inline-editable.js +124 -0
- package/dist/components/inline-editable.js.map +1 -0
- package/dist/components/input-area.js +3 -3
- package/dist/components/input-group.js +7 -7
- package/dist/components/input.js +3 -3
- package/dist/components/label.js +18 -17
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer-card.d.ts +10 -2
- package/dist/components/layer-card.js +71 -68
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/loader.d.ts +10 -2
- package/dist/components/loader.js.map +1 -1
- package/dist/components/menu-bar.d.ts +174 -6
- package/dist/components/menu-bar.js +33 -29
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/meter.d.ts +27 -2
- package/dist/components/meter.js.map +1 -1
- package/dist/components/multi-select.d.ts +64 -0
- package/dist/components/multi-select.js +218 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/navigation-menu.d.ts +88 -5
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/overlay.js +6 -5
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/page-header.js +23 -21
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.js +7 -7
- package/dist/components/popover.d.ts +136 -16
- package/dist/components/popover.js +32 -28
- package/dist/components/popover.js.map +1 -1
- package/dist/components/radio.js +38 -37
- package/dist/components/radio.js.map +1 -1
- package/dist/components/resource-list.d.ts +26 -1
- package/dist/components/resource-list.js +28 -15
- package/dist/components/resource-list.js.map +1 -1
- package/dist/components/responsive-master-detail.d.ts +27 -0
- package/dist/components/responsive-master-detail.js +85 -0
- package/dist/components/responsive-master-detail.js.map +1 -0
- package/dist/components/section-rule.js +23 -22
- package/dist/components/section-rule.js.map +1 -1
- package/dist/components/select.d.ts +27 -3
- package/dist/components/select.js +11 -11
- package/dist/components/select.js.map +1 -1
- package/dist/components/sheet.d.ts +115 -11
- package/dist/components/sheet.js +37 -30
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/sidebar.d.ts +109 -17
- package/dist/components/sidebar.js +109 -108
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +22 -2
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/slider.d.ts +61 -1
- package/dist/components/slider.js +31 -15
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-strip.js +16 -15
- package/dist/components/stat-strip.js.map +1 -1
- package/dist/components/switch.js +78 -47
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table-of-contents.js +18 -17
- package/dist/components/table-of-contents.js.map +1 -1
- package/dist/components/table-pager.js +20 -19
- package/dist/components/table-pager.js.map +1 -1
- package/dist/components/table.d.ts +9 -3
- package/dist/components/table.js +19 -18
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +29 -22
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-badge.d.ts +58 -0
- package/dist/components/tag-badge.js +72 -0
- package/dist/components/tag-badge.js.map +1 -0
- package/dist/components/tag-color-picker.d.ts +20 -0
- package/dist/components/tag-color-picker.js +42 -0
- package/dist/components/tag-color-picker.js.map +1 -0
- package/dist/components/text.js +17 -16
- package/dist/components/text.js.map +1 -1
- package/dist/components/toast.d.ts +173 -3
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.d.ts +88 -2
- package/dist/components/toggle-group.js +32 -31
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.d.ts +35 -2
- package/dist/components/toggle.js +12 -11
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tooltip.d.ts +144 -6
- package/dist/components/tooltip.js +9 -6
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/typeahead-field.js +193 -132
- package/dist/components/typeahead-field.js.map +1 -1
- package/dist/components/upload-queue.d.ts +51 -0
- package/dist/components/upload-queue.js +116 -0
- package/dist/components/upload-queue.js.map +1 -0
- package/dist/providers/accent.d.ts +46 -2
- package/dist/providers/accent.js +358 -172
- package/dist/providers/accent.js.map +1 -1
- package/dist/providers/link.d.ts +14 -4
- package/dist/providers/link.js.map +1 -1
- package/dist/providers/theme.d.ts +38 -2
- package/dist/providers/theme.js +160 -27
- package/dist/providers/theme.js.map +1 -1
- package/dist/styles/base.css +83 -0
- package/dist/styles/standalone.css +711 -120
- package/dist/styles/tailwind.css +21 -7
- package/dist/styles/tokens.css +145 -91
- package/dist/utils/control-surface.d.ts +2 -1
- package/dist/utils/control-surface.js +4 -4
- package/dist/utils/control-surface.js.map +1 -1
- package/dist/utils/selection-indicator.js +2 -2
- package/dist/utils/selection-indicator.js.map +1 -1
- package/package.json +8 -4
|
@@ -3,165 +3,226 @@ import { cn as e } from "../utils/cn.js";
|
|
|
3
3
|
import { overlayItemClass as t, overlayPanelClass as n } from "./overlay.js";
|
|
4
4
|
import { Input as r } from "./input.js";
|
|
5
5
|
import { useEffect as i, useId as a, useRef as o, useState as s } from "react";
|
|
6
|
-
import { jsx as c, jsxs as
|
|
6
|
+
import { jsx as c, jsxs as ee } from "react/jsx-runtime";
|
|
7
|
+
import * as l from "@radix-ui/react-popover";
|
|
7
8
|
//#region src/components/typeahead-field.tsx
|
|
8
|
-
function u({ items: u, value: p, defaultValue: m = "", onValueChange: h, name: g, placeholder: _ = "Select…", disabled: v = !1, loading: y = !1, size: b = "default", className: x, id: S, allowFreeform: C, "aria-label": w, "aria-describedby": T, "aria-invalid":
|
|
9
|
-
let [
|
|
10
|
-
p !==
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
function u({ items: u, value: p, defaultValue: m = "", onValueChange: h, name: g, placeholder: _ = "Select…", disabled: v = !1, loading: y = !1, size: b = "default", className: x, id: S, allowFreeform: C, "aria-label": w, "aria-describedby": T, "aria-invalid": te, onBlur: ne, ...E }) {
|
|
10
|
+
let [D, O] = s(m), k = p ?? D, [A, j] = s(d(u, k)), [M, N] = s(p), [P, F] = s(!1), [I, L] = s(null), R = a(), z = o(null), B = o(!1), V = o(null);
|
|
11
|
+
p !== M && (N(p), p === void 0 ? M !== void 0 && (O(M), j(d(u, M))) : j(d(u, p)));
|
|
12
|
+
let H = d(u, k), [U, W] = s(H);
|
|
13
|
+
H !== U && (W(H), (!P || A === U) && j(H));
|
|
14
|
+
let G = o({
|
|
15
|
+
defaultValue: m,
|
|
16
|
+
items: u,
|
|
17
|
+
value: p
|
|
18
|
+
});
|
|
19
|
+
i(() => {
|
|
20
|
+
G.current = {
|
|
21
|
+
defaultValue: m,
|
|
22
|
+
items: u,
|
|
23
|
+
value: p
|
|
24
|
+
};
|
|
25
|
+
}), i(() => {
|
|
26
|
+
let e = z.current?.form;
|
|
14
27
|
if (!e) return;
|
|
15
|
-
let t = (e) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
let t = !1, n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
29
|
+
let r = setTimeout(() => {
|
|
30
|
+
if (n.delete(r), t || e.defaultPrevented) return;
|
|
31
|
+
let i = G.current;
|
|
32
|
+
i.value === void 0 ? (O(i.defaultValue), j(d(i.items, i.defaultValue))) : j(d(i.items, i.value)), F(!1), L(null);
|
|
33
|
+
}, 0);
|
|
34
|
+
n.add(r);
|
|
19
35
|
};
|
|
20
|
-
return e.addEventListener("reset",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]);
|
|
26
|
-
let K = f(u,
|
|
36
|
+
return e.addEventListener("reset", r), () => {
|
|
37
|
+
t = !0;
|
|
38
|
+
for (let e of n) clearTimeout(e);
|
|
39
|
+
n.clear(), e.removeEventListener("reset", r);
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
let K = f(u, A, !C), q = I === null || K.length === 0 ? null : Math.min(I, K.length - 1), J = q === null ? void 0 : K[q], Y = P && K.length > 0, X = v || y;
|
|
27
43
|
i(() => {
|
|
28
|
-
if (!
|
|
29
|
-
let e =
|
|
30
|
-
|
|
44
|
+
if (!Y || q === null) return;
|
|
45
|
+
let e = document.getElementById(`${R}-opt-${q}`);
|
|
46
|
+
typeof e?.scrollIntoView == "function" && e.scrollIntoView({ block: "nearest" });
|
|
47
|
+
}, [
|
|
48
|
+
q,
|
|
49
|
+
R,
|
|
50
|
+
Y
|
|
51
|
+
]), i(() => {
|
|
52
|
+
if (!P) return;
|
|
53
|
+
let e = f(u, A, !C).length;
|
|
54
|
+
L((t) => t === null || e === 0 ? null : Math.min(t, e - 1));
|
|
31
55
|
}, [
|
|
32
56
|
C,
|
|
33
57
|
u,
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
P,
|
|
59
|
+
A
|
|
36
60
|
]);
|
|
37
|
-
function Z(e, t) {
|
|
38
|
-
p === void 0 ? (
|
|
61
|
+
function Z(e, t, n = !0) {
|
|
62
|
+
p === void 0 ? (O(e), j(t)) : j(d(u, p)), F(!1), L(null), h?.(e), n && z.current && document.activeElement !== z.current && (B.current = !0, z.current.focus());
|
|
39
63
|
}
|
|
40
|
-
function Q(e) {
|
|
41
|
-
e.disabled || Z(e.value, e.label);
|
|
64
|
+
function Q(e, t = !0) {
|
|
65
|
+
e.disabled || Z(e.value, e.label, t);
|
|
42
66
|
}
|
|
43
|
-
function $(e) {
|
|
44
|
-
let
|
|
45
|
-
if (
|
|
46
|
-
Q(
|
|
67
|
+
function $(e, t = !0) {
|
|
68
|
+
let n = e.trim(), r = u.find((e) => !e.disabled && (e.label.toLowerCase() === n.toLowerCase() || e.value === n));
|
|
69
|
+
if (r) {
|
|
70
|
+
Q(r, t);
|
|
47
71
|
return;
|
|
48
72
|
}
|
|
49
|
-
Z(
|
|
73
|
+
Z(n, n, t);
|
|
50
74
|
}
|
|
51
75
|
return i(() => {
|
|
52
|
-
if (!
|
|
76
|
+
if (!P) return;
|
|
53
77
|
let e = (e) => {
|
|
54
|
-
e.key !== "Escape" || e.isComposing || (e.preventDefault(), e.stopPropagation(), e.stopImmediatePropagation(),
|
|
78
|
+
e.key !== "Escape" || e.isComposing || (e.preventDefault(), e.stopPropagation(), e.stopImmediatePropagation(), F(!1), j(d(u, k)), L(null));
|
|
55
79
|
};
|
|
56
80
|
return window.addEventListener("keydown", e, !0), document.addEventListener("keydown", e, !0), () => {
|
|
57
81
|
window.removeEventListener("keydown", e, !0), document.removeEventListener("keydown", e, !0);
|
|
58
82
|
};
|
|
59
83
|
}, [
|
|
60
84
|
u,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
]), /* @__PURE__ */ l
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (D?.(e), !e.currentTarget.contains(e.relatedTarget)) {
|
|
68
|
-
if (C) {
|
|
69
|
-
if (M.trim() !== d(u, j)) {
|
|
70
|
-
$(M);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
} else N(d(u, j));
|
|
74
|
-
L(!1), z(null);
|
|
75
|
-
}
|
|
85
|
+
P,
|
|
86
|
+
k
|
|
87
|
+
]), /* @__PURE__ */ c(l.Root, {
|
|
88
|
+
open: Y,
|
|
89
|
+
onOpenChange: (e) => {
|
|
90
|
+
e || (F(!1), L(null), C || j(d(u, k)));
|
|
76
91
|
},
|
|
77
|
-
children:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
value: M,
|
|
88
|
-
disabled: X,
|
|
89
|
-
size: b,
|
|
90
|
-
"aria-busy": y || void 0,
|
|
91
|
-
"aria-invalid": E,
|
|
92
|
-
"aria-describedby": T,
|
|
93
|
-
onChange: (e) => {
|
|
94
|
-
N(e.target.value), L(!0), z(null);
|
|
95
|
-
},
|
|
96
|
-
onFocus: () => {
|
|
97
|
-
if (!X) {
|
|
98
|
-
if (H.current) {
|
|
99
|
-
H.current = !1;
|
|
92
|
+
children: /* @__PURE__ */ ee("div", {
|
|
93
|
+
...E,
|
|
94
|
+
className: e("relative w-full", x),
|
|
95
|
+
onBlur: (e) => {
|
|
96
|
+
ne?.(e);
|
|
97
|
+
let t = e.relatedTarget, n = document.getElementById(R);
|
|
98
|
+
if (!e.currentTarget.contains(t) && !n?.contains(t)) {
|
|
99
|
+
if (C) {
|
|
100
|
+
if (A.trim() !== d(u, k)) {
|
|
101
|
+
$(A, !1);
|
|
100
102
|
return;
|
|
101
103
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
} else j(d(u, k));
|
|
105
|
+
F(!1), L(null);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
children: [
|
|
109
|
+
g ? /* @__PURE__ */ c("input", {
|
|
110
|
+
type: "hidden",
|
|
111
|
+
name: g,
|
|
112
|
+
value: k,
|
|
113
|
+
disabled: X
|
|
114
|
+
}) : null,
|
|
115
|
+
/* @__PURE__ */ c(l.Anchor, {
|
|
116
|
+
asChild: !0,
|
|
117
|
+
children: /* @__PURE__ */ c(r, {
|
|
118
|
+
ref: z,
|
|
119
|
+
id: S,
|
|
120
|
+
value: A,
|
|
121
|
+
disabled: X,
|
|
122
|
+
size: b,
|
|
123
|
+
"aria-busy": y || void 0,
|
|
124
|
+
"aria-invalid": te,
|
|
125
|
+
"aria-describedby": T,
|
|
126
|
+
onChange: (e) => {
|
|
127
|
+
j(e.target.value), F(!0), L(null);
|
|
128
|
+
},
|
|
129
|
+
onFocus: () => {
|
|
130
|
+
if (!X) {
|
|
131
|
+
if (B.current) {
|
|
132
|
+
B.current = !1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
L(null), F(!0);
|
|
114
136
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
},
|
|
138
|
+
onClick: () => {
|
|
139
|
+
X || (P || L(null), F(!0));
|
|
140
|
+
},
|
|
141
|
+
onKeyDown: (e) => {
|
|
142
|
+
if (!(e.nativeEvent.isComposing || e.key === "Process")) {
|
|
143
|
+
if (e.key === "ArrowDown") {
|
|
144
|
+
if (e.preventDefault(), F(!0), K.length === 0) {
|
|
145
|
+
L(null);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
L((e) => e === null ? 0 : (e + 1) % K.length);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (e.key === "ArrowUp") {
|
|
152
|
+
if (e.preventDefault(), F(!0), K.length === 0) {
|
|
153
|
+
L(null);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
L((e) => e === null ? K.length - 1 : (e - 1 + K.length) % K.length);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (e.key === "Enter") {
|
|
160
|
+
if (P && J) {
|
|
161
|
+
e.preventDefault(), Q(J);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
C && A.trim() !== d(u, k) && (e.preventDefault(), $(A));
|
|
165
|
+
}
|
|
130
166
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
},
|
|
168
|
+
placeholder: _,
|
|
169
|
+
role: "combobox",
|
|
170
|
+
"aria-label": w ?? (S ? void 0 : _),
|
|
171
|
+
"aria-expanded": Y,
|
|
172
|
+
"aria-autocomplete": "list",
|
|
173
|
+
"aria-controls": Y ? R : void 0,
|
|
174
|
+
"aria-activedescendant": Y && J && q !== null ? `${R}-opt-${q}` : void 0
|
|
175
|
+
})
|
|
176
|
+
}),
|
|
177
|
+
Y ? /* @__PURE__ */ c(l.Portal, { children: /* @__PURE__ */ c(l.Content, {
|
|
178
|
+
side: "bottom",
|
|
179
|
+
sideOffset: 4,
|
|
180
|
+
align: "start",
|
|
181
|
+
avoidCollisions: !0,
|
|
182
|
+
collisionPadding: 8,
|
|
183
|
+
onPointerMove: (e) => {
|
|
184
|
+
V.current && V.current.x === e.clientX && V.current.y === e.clientY || (V.current = {
|
|
185
|
+
x: e.clientX,
|
|
186
|
+
y: e.clientY
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
onEscapeKeyDown: (e) => {
|
|
190
|
+
let t = e;
|
|
191
|
+
(t.isComposing || t.nativeEvent?.isComposing) && e.preventDefault();
|
|
192
|
+
},
|
|
193
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
194
|
+
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
195
|
+
onInteractOutside: (e) => {
|
|
196
|
+
let t = e.target;
|
|
197
|
+
z.current?.contains(t) && e.preventDefault();
|
|
158
198
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
199
|
+
id: R,
|
|
200
|
+
role: "listbox",
|
|
201
|
+
className: n("w-[var(--radix-popover-trigger-width)] max-h-[var(--radix-popover-content-available-height)] overflow-y-auto"),
|
|
202
|
+
children: K.map((n, r) => /* @__PURE__ */ c("button", {
|
|
203
|
+
type: "button",
|
|
204
|
+
id: `${R}-opt-${r}`,
|
|
205
|
+
role: "option",
|
|
206
|
+
tabIndex: -1,
|
|
207
|
+
disabled: n.disabled,
|
|
208
|
+
"aria-disabled": n.disabled || void 0,
|
|
209
|
+
"aria-selected": r === q,
|
|
210
|
+
className: e(t("hover:bg-basalt-accent"), r === q && "bg-basalt-accent", n.disabled && "opacity-50"),
|
|
211
|
+
onPointerMove: (e) => {
|
|
212
|
+
if (n.disabled) return;
|
|
213
|
+
let { clientX: t, clientY: i } = e;
|
|
214
|
+
V.current && V.current.x === t && V.current.y === i || (V.current = {
|
|
215
|
+
x: t,
|
|
216
|
+
y: i
|
|
217
|
+
}, L(r));
|
|
218
|
+
},
|
|
219
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
220
|
+
onClick: () => Q(n),
|
|
221
|
+
children: n.label
|
|
222
|
+
}, `${R}-opt-${r}`))
|
|
223
|
+
}) }) : null
|
|
224
|
+
]
|
|
225
|
+
})
|
|
165
226
|
});
|
|
166
227
|
}
|
|
167
228
|
function d(e, t) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typeahead-field.js","names":[],"sources":["../../src/components/typeahead-field.tsx"],"sourcesContent":["import { type ComponentPropsWithoutRef, useEffect, useId, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Input, type InputSize } from \"./input\";\nimport { overlayItemClass, overlayPanelClass } from \"./overlay\";\n\nexport type TypeaheadItem = {\n\tvalue: string;\n\tlabel: string;\n\tdisabled?: boolean;\n};\n\nexport function TypeaheadField({\n\titems,\n\tvalue,\n\tdefaultValue = \"\",\n\tonValueChange,\n\tname,\n\tplaceholder = \"Select…\",\n\tdisabled = false,\n\tloading = false,\n\tsize = \"default\",\n\tclassName,\n\tid,\n\tallowFreeform,\n\t\"aria-label\": ariaLabel,\n\t\"aria-describedby\": ariaDescribedBy,\n\t\"aria-invalid\": ariaInvalid,\n\tonBlur,\n\t...rest\n}: {\n\titems: TypeaheadItem[];\n\tvalue?: string;\n\tdefaultValue?: string;\n\tonValueChange?: (value: string) => void;\n\tname?: string;\n\tplaceholder?: string;\n\tdisabled?: boolean;\n\tloading?: boolean;\n\tsize?: InputSize;\n\tclassName?: string;\n\tid?: string;\n\tallowFreeform: boolean;\n\t\"aria-label\"?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\";\n} & Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"defaultValue\" | \"onChange\">) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultValue);\n\tconst selected = value ?? uncontrolled;\n\tconst [query, setQuery] = useState(displayOf(items, selected));\n\tconst [prevValue, setPrevValue] = useState(value);\n\tconst [open, setOpen] = useState(false);\n\tconst [active, setActive] = useState<number | null>(null);\n\tconst listId = useId();\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst skipFocusOpen = useRef(false);\n\tif (value !== prevValue) {\n\t\tsetPrevValue(value);\n\t\tif (value !== undefined) {\n\t\t\tsetQuery(displayOf(items, value));\n\t\t} else if (prevValue !== undefined) {\n\t\t\tsetUncontrolled(prevValue);\n\t\t\tsetQuery(displayOf(items, prevValue));\n\t\t}\n\t}\n\tconst selectedDisplay = displayOf(items, selected);\n\tconst [prevDisplay, setPrevDisplay] = useState(selectedDisplay);\n\tif (selectedDisplay !== prevDisplay) {\n\t\tsetPrevDisplay(selectedDisplay);\n\t\tif (!open || query === prevDisplay) {\n\t\t\tsetQuery(selectedDisplay);\n\t\t}\n\t}\n\tuseEffect(() => {\n\t\tconst node = inputRef.current;\n\t\tconst form = node?.form;\n\t\tif (!form) {\n\t\t\treturn;\n\t\t}\n\t\tconst onReset = (event: Event) => {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (event.defaultPrevented) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tsetUncontrolled(defaultValue);\n\t\t\t\t\tsetQuery(displayOf(items, defaultValue));\n\t\t\t\t} else {\n\t\t\t\t\tsetQuery(displayOf(items, value));\n\t\t\t\t}\n\t\t\t\tsetOpen(false);\n\t\t\t\tsetActive(null);\n\t\t\t});\n\t\t};\n\t\tform.addEventListener(\"reset\", onReset);\n\t\treturn () => form.removeEventListener(\"reset\", onReset);\n\t}, [defaultValue, items, value]);\n\tconst filtered = filterItems(items, query, !allowFreeform);\n\tconst activeIndex =\n\t\tactive === null || filtered.length === 0 ? null : Math.min(active, filtered.length - 1);\n\tconst activeItem = activeIndex === null ? undefined : filtered[activeIndex];\n\tconst listOpen = open && filtered.length > 0;\n\tconst busy = disabled || loading;\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\t\tconst nextLen = filterItems(items, query, !allowFreeform).length;\n\t\tsetActive((current) => {\n\t\t\tif (current === null || nextLen === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn Math.min(current, nextLen - 1);\n\t\t});\n\t}, [allowFreeform, items, open, query]);\n\n\tfunction commitValue(next: string, display: string) {\n\t\tif (value === undefined) {\n\t\t\tsetUncontrolled(next);\n\t\t\tsetQuery(display);\n\t\t} else {\n\t\t\tsetQuery(displayOf(items, value));\n\t\t}\n\t\tsetOpen(false);\n\t\tsetActive(null);\n\t\tonValueChange?.(next);\n\t\tif (inputRef.current && document.activeElement !== inputRef.current) {\n\t\t\tskipFocusOpen.current = true;\n\t\t\tinputRef.current.focus();\n\t\t}\n\t}\n\n\tfunction commitItem(item: TypeaheadItem) {\n\t\tif (item.disabled) {\n\t\t\treturn;\n\t\t}\n\t\tcommitValue(item.value, item.label);\n\t}\n\n\tfunction commitFreeform(text: string) {\n\t\tconst trimmed = text.trim();\n\t\tconst match = items.find(\n\t\t\t(item) =>\n\t\t\t\t!item.disabled &&\n\t\t\t\t(item.label.toLowerCase() === trimmed.toLowerCase() || item.value === trimmed),\n\t\t);\n\t\tif (match) {\n\t\t\tcommitItem(match);\n\t\t\treturn;\n\t\t}\n\t\tcommitValue(trimmed, trimmed);\n\t}\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.key !== \"Escape\" || event.isComposing) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\tevent.stopImmediatePropagation();\n\t\t\tsetOpen(false);\n\t\t\tsetQuery(displayOf(items, selected));\n\t\t\tsetActive(null);\n\t\t};\n\t\twindow.addEventListener(\"keydown\", onKey, true);\n\t\tdocument.addEventListener(\"keydown\", onKey, true);\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"keydown\", onKey, true);\n\t\t\tdocument.removeEventListener(\"keydown\", onKey, true);\n\t\t};\n\t}, [items, open, selected]);\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tclassName={cn(\"relative w-full\", className)}\n\t\t\tonBlur={(event) => {\n\t\t\t\tonBlur?.(event);\n\t\t\t\tif (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n\t\t\t\t\tif (allowFreeform) {\n\t\t\t\t\t\tif (query.trim() !== displayOf(items, selected)) {\n\t\t\t\t\t\t\tcommitFreeform(query);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetQuery(displayOf(items, selected));\n\t\t\t\t\t}\n\t\t\t\t\tsetOpen(false);\n\t\t\t\t\tsetActive(null);\n\t\t\t\t}\n\t\t\t}}\n\t\t>\n\t\t\t{name ? <input type=\"hidden\" name={name} value={selected} disabled={busy} /> : null}\n\t\t\t<Input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={id}\n\t\t\t\tvalue={query}\n\t\t\t\tdisabled={busy}\n\t\t\t\tsize={size}\n\t\t\t\taria-busy={loading || undefined}\n\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\taria-describedby={ariaDescribedBy}\n\t\t\t\tonChange={(event) => {\n\t\t\t\t\tsetQuery(event.target.value);\n\t\t\t\t\tsetOpen(true);\n\t\t\t\t\tsetActive(null);\n\t\t\t\t}}\n\t\t\t\tonFocus={() => {\n\t\t\t\t\tif (busy) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (skipFocusOpen.current) {\n\t\t\t\t\t\tskipFocusOpen.current = false;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsetActive(null);\n\t\t\t\t\tsetOpen(true);\n\t\t\t\t}}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tif (busy) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!open) {\n\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t}\n\t\t\t\t\tsetOpen(true);\n\t\t\t\t}}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tif (event.nativeEvent.isComposing || event.key === \"Process\") {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.key === \"ArrowDown\") {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\tif (filtered.length === 0) {\n\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsetActive((current) => (current === null ? 0 : (current + 1) % filtered.length));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.key === \"ArrowUp\") {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\tif (filtered.length === 0) {\n\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsetActive((current) =>\n\t\t\t\t\t\t\tcurrent === null\n\t\t\t\t\t\t\t\t? filtered.length - 1\n\t\t\t\t\t\t\t\t: (current - 1 + filtered.length) % filtered.length,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.key === \"Enter\") {\n\t\t\t\t\t\tif (open && activeItem) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tcommitItem(activeItem);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (allowFreeform && query.trim() !== displayOf(items, selected)) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tcommitFreeform(query);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tplaceholder={placeholder}\n\t\t\t\trole=\"combobox\"\n\t\t\t\taria-label={ariaLabel ?? (id ? undefined : placeholder)}\n\t\t\t\taria-expanded={listOpen}\n\t\t\t\taria-autocomplete=\"list\"\n\t\t\t\taria-controls={listOpen ? listId : undefined}\n\t\t\t\taria-activedescendant={\n\t\t\t\t\tlistOpen && activeItem && activeIndex !== null\n\t\t\t\t\t\t? `${listId}-opt-${activeIndex}`\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t/>\n\t\t\t{listOpen ? (\n\t\t\t\t<div\n\t\t\t\t\tid={listId}\n\t\t\t\t\trole=\"listbox\"\n\t\t\t\t\tclassName={overlayPanelClass(\"absolute top-full z-20 mt-1 w-full\")}\n\t\t\t\t>\n\t\t\t\t\t{filtered.map((item, index) => (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tkey={`${listId}-opt-${index}`}\n\t\t\t\t\t\t\tid={`${listId}-opt-${index}`}\n\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\tdisabled={item.disabled}\n\t\t\t\t\t\t\taria-disabled={item.disabled || undefined}\n\t\t\t\t\t\t\taria-selected={index === activeIndex}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\toverlayItemClass(\"hover:bg-basalt-accent\"),\n\t\t\t\t\t\t\t\tindex === activeIndex && \"bg-basalt-accent\",\n\t\t\t\t\t\t\t\titem.disabled && \"opacity-50\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tonMouseEnter={() => {\n\t\t\t\t\t\t\t\tif (!item.disabled) {\n\t\t\t\t\t\t\t\t\tsetActive(index);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonMouseDown={(event) => event.preventDefault()}\n\t\t\t\t\t\t\tonClick={() => commitItem(item)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n\nfunction displayOf(items: TypeaheadItem[], value: string) {\n\treturn items.find((item) => item.value === value)?.label ?? value;\n}\n\nfunction filterItems(items: TypeaheadItem[], query: string, showAllWhenEmpty: boolean) {\n\tconst needle = query.trim().toLowerCase();\n\tif (needle === \"\") {\n\t\treturn showAllWhenEmpty ? items : [];\n\t}\n\treturn items.filter((item) => item.label.toLowerCase().includes(needle));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"typeahead-field.js","names":[],"sources":["../../src/components/typeahead-field.tsx"],"sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport { type ComponentPropsWithoutRef, useEffect, useId, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Input, type InputSize } from \"./input\";\nimport { OVERLAY_GAP, overlayItemClass, overlayPanelClass } from \"./overlay\";\n\nexport type TypeaheadItem = {\n\tvalue: string;\n\tlabel: string;\n\tdisabled?: boolean;\n};\n\nexport function TypeaheadField({\n\titems,\n\tvalue,\n\tdefaultValue = \"\",\n\tonValueChange,\n\tname,\n\tplaceholder = \"Select…\",\n\tdisabled = false,\n\tloading = false,\n\tsize = \"default\",\n\tclassName,\n\tid,\n\tallowFreeform,\n\t\"aria-label\": ariaLabel,\n\t\"aria-describedby\": ariaDescribedBy,\n\t\"aria-invalid\": ariaInvalid,\n\tonBlur,\n\t...rest\n}: {\n\titems: TypeaheadItem[];\n\tvalue?: string;\n\tdefaultValue?: string;\n\tonValueChange?: (value: string) => void;\n\tname?: string;\n\tplaceholder?: string;\n\tdisabled?: boolean;\n\tloading?: boolean;\n\tsize?: InputSize;\n\tclassName?: string;\n\tid?: string;\n\tallowFreeform: boolean;\n\t\"aria-label\"?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\";\n} & Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"defaultValue\" | \"onChange\">) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultValue);\n\tconst selected = value ?? uncontrolled;\n\tconst [query, setQuery] = useState(displayOf(items, selected));\n\tconst [prevValue, setPrevValue] = useState(value);\n\tconst [open, setOpen] = useState(false);\n\tconst [active, setActive] = useState<number | null>(null);\n\tconst listId = useId();\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst skipFocusOpen = useRef(false);\n\tconst lastPointerPos = useRef<{ x: number; y: number } | null>(null);\n\tif (value !== prevValue) {\n\t\tsetPrevValue(value);\n\t\tif (value !== undefined) {\n\t\t\tsetQuery(displayOf(items, value));\n\t\t} else if (prevValue !== undefined) {\n\t\t\tsetUncontrolled(prevValue);\n\t\t\tsetQuery(displayOf(items, prevValue));\n\t\t}\n\t}\n\tconst selectedDisplay = displayOf(items, selected);\n\tconst [prevDisplay, setPrevDisplay] = useState(selectedDisplay);\n\tif (selectedDisplay !== prevDisplay) {\n\t\tsetPrevDisplay(selectedDisplay);\n\t\tif (!open || query === prevDisplay) {\n\t\t\tsetQuery(selectedDisplay);\n\t\t}\n\t}\n\tconst latestConfigRef = useRef({\n\t\tdefaultValue,\n\t\titems,\n\t\tvalue,\n\t});\n\tuseEffect(() => {\n\t\tlatestConfigRef.current = {\n\t\t\tdefaultValue,\n\t\t\titems,\n\t\t\tvalue,\n\t\t};\n\t});\n\n\tuseEffect(() => {\n\t\tconst node = inputRef.current;\n\t\tconst form = node?.form;\n\t\tif (!form) {\n\t\t\treturn;\n\t\t}\n\t\tlet disposed = false;\n\t\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\t\tconst onReset = (event: Event) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\ttimers.delete(timer);\n\t\t\t\tif (disposed || event.defaultPrevented) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst cfg = latestConfigRef.current;\n\t\t\t\tif (cfg.value === undefined) {\n\t\t\t\t\tsetUncontrolled(cfg.defaultValue);\n\t\t\t\t\tsetQuery(displayOf(cfg.items, cfg.defaultValue));\n\t\t\t\t} else {\n\t\t\t\t\tsetQuery(displayOf(cfg.items, cfg.value));\n\t\t\t\t}\n\t\t\t\tsetOpen(false);\n\t\t\t\tsetActive(null);\n\t\t\t}, 0);\n\t\t\ttimers.add(timer);\n\t\t};\n\t\tform.addEventListener(\"reset\", onReset);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tfor (const timer of timers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\ttimers.clear();\n\t\t\tform.removeEventListener(\"reset\", onReset);\n\t\t};\n\t}, []);\n\tconst filtered = filterItems(items, query, !allowFreeform);\n\tconst activeIndex =\n\t\tactive === null || filtered.length === 0 ? null : Math.min(active, filtered.length - 1);\n\tconst activeItem = activeIndex === null ? undefined : filtered[activeIndex];\n\tconst listOpen = open && filtered.length > 0;\n\tconst busy = disabled || loading;\n\n\tuseEffect(() => {\n\t\tif (!listOpen || activeIndex === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst optionElement = document.getElementById(`${listId}-opt-${activeIndex}`);\n\t\tif (typeof optionElement?.scrollIntoView === \"function\") {\n\t\t\toptionElement.scrollIntoView({ block: \"nearest\" });\n\t\t}\n\t}, [activeIndex, listId, listOpen]);\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\t\tconst nextLen = filterItems(items, query, !allowFreeform).length;\n\t\tsetActive((current) => {\n\t\t\tif (current === null || nextLen === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn Math.min(current, nextLen - 1);\n\t\t});\n\t}, [allowFreeform, items, open, query]);\n\n\tfunction commitValue(next: string, display: string, restoreFocus = true) {\n\t\tif (value === undefined) {\n\t\t\tsetUncontrolled(next);\n\t\t\tsetQuery(display);\n\t\t} else {\n\t\t\tsetQuery(displayOf(items, value));\n\t\t}\n\t\tsetOpen(false);\n\t\tsetActive(null);\n\t\tonValueChange?.(next);\n\t\tif (restoreFocus && inputRef.current && document.activeElement !== inputRef.current) {\n\t\t\tskipFocusOpen.current = true;\n\t\t\tinputRef.current.focus();\n\t\t}\n\t}\n\n\tfunction commitItem(item: TypeaheadItem, restoreFocus = true) {\n\t\tif (item.disabled) {\n\t\t\treturn;\n\t\t}\n\t\tcommitValue(item.value, item.label, restoreFocus);\n\t}\n\n\tfunction commitFreeform(text: string, restoreFocus = true) {\n\t\tconst trimmed = text.trim();\n\t\tconst match = items.find(\n\t\t\t(item) =>\n\t\t\t\t!item.disabled &&\n\t\t\t\t(item.label.toLowerCase() === trimmed.toLowerCase() || item.value === trimmed),\n\t\t);\n\t\tif (match) {\n\t\t\tcommitItem(match, restoreFocus);\n\t\t\treturn;\n\t\t}\n\t\tcommitValue(trimmed, trimmed, restoreFocus);\n\t}\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.key !== \"Escape\" || event.isComposing) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\tevent.stopImmediatePropagation();\n\t\t\tsetOpen(false);\n\t\t\tsetQuery(displayOf(items, selected));\n\t\t\tsetActive(null);\n\t\t};\n\t\twindow.addEventListener(\"keydown\", onKey, true);\n\t\tdocument.addEventListener(\"keydown\", onKey, true);\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"keydown\", onKey, true);\n\t\t\tdocument.removeEventListener(\"keydown\", onKey, true);\n\t\t};\n\t}, [items, open, selected]);\n\n\treturn (\n\t\t<PopoverPrimitive.Root\n\t\t\topen={listOpen}\n\t\t\tonOpenChange={(nextOpen) => {\n\t\t\t\tif (!nextOpen) {\n\t\t\t\t\tsetOpen(false);\n\t\t\t\t\tsetActive(null);\n\t\t\t\t\tif (!allowFreeform) {\n\t\t\t\t\t\tsetQuery(displayOf(items, selected));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\t{...rest}\n\t\t\t\tclassName={cn(\"relative w-full\", className)}\n\t\t\t\tonBlur={(event) => {\n\t\t\t\t\tonBlur?.(event);\n\t\t\t\t\tconst related = event.relatedTarget as Node | null;\n\t\t\t\t\tconst listbox = document.getElementById(listId);\n\t\t\t\t\tif (!event.currentTarget.contains(related) && !listbox?.contains(related)) {\n\t\t\t\t\t\tif (allowFreeform) {\n\t\t\t\t\t\t\tif (query.trim() !== displayOf(items, selected)) {\n\t\t\t\t\t\t\t\tcommitFreeform(query, false);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetQuery(displayOf(items, selected));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{name ? <input type=\"hidden\" name={name} value={selected} disabled={busy} /> : null}\n\t\t\t\t<PopoverPrimitive.Anchor asChild>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tref={inputRef}\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\tvalue={query}\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\taria-busy={loading || undefined}\n\t\t\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\t\t\taria-describedby={ariaDescribedBy}\n\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\tsetQuery(event.target.value);\n\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonFocus={() => {\n\t\t\t\t\t\t\tif (busy) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (skipFocusOpen.current) {\n\t\t\t\t\t\t\t\tskipFocusOpen.current = false;\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tif (busy) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!open) {\n\t\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\t\t\tif (event.nativeEvent.isComposing || event.key === \"Process\") {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.key === \"ArrowDown\") {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t\t\tif (filtered.length === 0) {\n\t\t\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tsetActive((current) => (current === null ? 0 : (current + 1) % filtered.length));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.key === \"ArrowUp\") {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t\t\tif (filtered.length === 0) {\n\t\t\t\t\t\t\t\t\tsetActive(null);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tsetActive((current) =>\n\t\t\t\t\t\t\t\t\tcurrent === null\n\t\t\t\t\t\t\t\t\t\t? filtered.length - 1\n\t\t\t\t\t\t\t\t\t\t: (current - 1 + filtered.length) % filtered.length,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.key === \"Enter\") {\n\t\t\t\t\t\t\t\tif (open && activeItem) {\n\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\tcommitItem(activeItem);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (allowFreeform && query.trim() !== displayOf(items, selected)) {\n\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\tcommitFreeform(query);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\t\trole=\"combobox\"\n\t\t\t\t\t\taria-label={ariaLabel ?? (id ? undefined : placeholder)}\n\t\t\t\t\t\taria-expanded={listOpen}\n\t\t\t\t\t\taria-autocomplete=\"list\"\n\t\t\t\t\t\taria-controls={listOpen ? listId : undefined}\n\t\t\t\t\t\taria-activedescendant={\n\t\t\t\t\t\t\tlistOpen && activeItem && activeIndex !== null\n\t\t\t\t\t\t\t\t? `${listId}-opt-${activeIndex}`\n\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t</PopoverPrimitive.Anchor>\n\t\t\t\t{listOpen ? (\n\t\t\t\t\t<PopoverPrimitive.Portal>\n\t\t\t\t\t\t<PopoverPrimitive.Content\n\t\t\t\t\t\t\tside=\"bottom\"\n\t\t\t\t\t\t\tsideOffset={OVERLAY_GAP}\n\t\t\t\t\t\t\talign=\"start\"\n\t\t\t\t\t\t\tavoidCollisions\n\t\t\t\t\t\t\tcollisionPadding={8}\n\t\t\t\t\t\t\tonPointerMove={(event) => {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tlastPointerPos.current &&\n\t\t\t\t\t\t\t\t\tlastPointerPos.current.x === event.clientX &&\n\t\t\t\t\t\t\t\t\tlastPointerPos.current.y === event.clientY\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlastPointerPos.current = { x: event.clientX, y: event.clientY };\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonEscapeKeyDown={(e) => {\n\t\t\t\t\t\t\t\tconst evt = e as unknown as {\n\t\t\t\t\t\t\t\t\tisComposing?: boolean;\n\t\t\t\t\t\t\t\t\tnativeEvent?: { isComposing?: boolean };\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tif (evt.isComposing || evt.nativeEvent?.isComposing) {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonOpenAutoFocus={(e) => e.preventDefault()}\n\t\t\t\t\t\t\tonCloseAutoFocus={(e) => e.preventDefault()}\n\t\t\t\t\t\t\tonInteractOutside={(e) => {\n\t\t\t\t\t\t\t\tconst target = e.target as Node | null;\n\t\t\t\t\t\t\t\tif (inputRef.current?.contains(target)) {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tid={listId}\n\t\t\t\t\t\t\trole=\"listbox\"\n\t\t\t\t\t\t\tclassName={overlayPanelClass(\n\t\t\t\t\t\t\t\t\"w-[var(--radix-popover-trigger-width)] max-h-[var(--radix-popover-content-available-height)] overflow-y-auto\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{filtered.map((item, index) => (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tkey={`${listId}-opt-${index}`}\n\t\t\t\t\t\t\t\t\tid={`${listId}-opt-${index}`}\n\t\t\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\t\t\tdisabled={item.disabled}\n\t\t\t\t\t\t\t\t\taria-disabled={item.disabled || undefined}\n\t\t\t\t\t\t\t\t\taria-selected={index === activeIndex}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\toverlayItemClass(\"hover:bg-basalt-accent\"),\n\t\t\t\t\t\t\t\t\t\tindex === activeIndex && \"bg-basalt-accent\",\n\t\t\t\t\t\t\t\t\t\titem.disabled && \"opacity-50\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tonPointerMove={(event) => {\n\t\t\t\t\t\t\t\t\t\tif (item.disabled) {\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tconst { clientX, clientY } = event;\n\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\tlastPointerPos.current &&\n\t\t\t\t\t\t\t\t\t\t\tlastPointerPos.current.x === clientX &&\n\t\t\t\t\t\t\t\t\t\t\tlastPointerPos.current.y === clientY\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tlastPointerPos.current = { x: clientX, y: clientY };\n\t\t\t\t\t\t\t\t\t\tsetActive(index);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonMouseDown={(event) => event.preventDefault()}\n\t\t\t\t\t\t\t\t\tonClick={() => commitItem(item)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</PopoverPrimitive.Content>\n\t\t\t\t\t</PopoverPrimitive.Portal>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</PopoverPrimitive.Root>\n\t);\n}\n\nfunction displayOf(items: TypeaheadItem[], value: string) {\n\treturn items.find((item) => item.value === value)?.label ?? value;\n}\n\nfunction filterItems(items: TypeaheadItem[], query: string, showAllWhenEmpty: boolean) {\n\tconst needle = query.trim().toLowerCase();\n\tif (needle === \"\") {\n\t\treturn showAllWhenEmpty ? items : [];\n\t}\n\treturn items.filter((item) => item.label.toLowerCase().includes(needle));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface UploadFile {
|
|
3
|
+
/** Stable queue identifier. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Display filename. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Optional size in bytes. */
|
|
8
|
+
size?: number;
|
|
9
|
+
/** Application-owned transport state. */
|
|
10
|
+
status: "queued" | "uploading" | "success" | "error" | "cancelled";
|
|
11
|
+
/** Progress percentage; omitted means indeterminate. */
|
|
12
|
+
progress?: number;
|
|
13
|
+
/** Application's error message. */
|
|
14
|
+
error?: string;
|
|
15
|
+
/** Optional image/icon. The caller creates and revokes any object URLs. */
|
|
16
|
+
preview?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export interface UploadLabels {
|
|
19
|
+
queued?: string;
|
|
20
|
+
uploading?: string;
|
|
21
|
+
success?: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
cancelled?: string;
|
|
24
|
+
cancel?: string;
|
|
25
|
+
retry?: string;
|
|
26
|
+
remove?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UploadItemProps {
|
|
29
|
+
/** Current queue entry. The component does not start a network request. */
|
|
30
|
+
file: UploadFile;
|
|
31
|
+
/** Cancel a queued or uploading entry. */
|
|
32
|
+
onCancel?: (id: string) => void;
|
|
33
|
+
/** Retry a failed or cancelled entry. */
|
|
34
|
+
onRetry?: (id: string) => void;
|
|
35
|
+
/** Remove an entry that is not currently uploading. */
|
|
36
|
+
onRemove?: (id: string) => void;
|
|
37
|
+
/** Localized statuses and action labels. */
|
|
38
|
+
labels?: UploadLabels;
|
|
39
|
+
/** Additional root classes. */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function UploadItem({ file, onCancel, onRetry, onRemove, labels, className, }: UploadItemProps): import("react").JSX.Element;
|
|
43
|
+
export interface UploadQueueProps extends Omit<UploadItemProps, "file"> {
|
|
44
|
+
/** Accessible queue name. */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Application-owned queue entries. */
|
|
47
|
+
files: readonly UploadFile[];
|
|
48
|
+
/** Empty queue text. @default "No files selected." */
|
|
49
|
+
emptyLabel?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare function UploadQueue({ label, files, emptyLabel, className, ...actions }: UploadQueueProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../utils/cn.js";
|
|
3
|
+
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
+
import { Button as n } from "./button.js";
|
|
5
|
+
import { Check as r, FileText as i, RotateCcw as a, Trash2 as o, X as s } from "lucide-react";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/upload-queue.tsx
|
|
8
|
+
var u = {
|
|
9
|
+
queued: "Queued",
|
|
10
|
+
uploading: "Uploading",
|
|
11
|
+
success: "Uploaded",
|
|
12
|
+
error: "Upload failed",
|
|
13
|
+
cancelled: "Cancelled",
|
|
14
|
+
cancel: "Cancel",
|
|
15
|
+
retry: "Retry",
|
|
16
|
+
remove: "Remove"
|
|
17
|
+
};
|
|
18
|
+
function d({ file: d, onCancel: f, onRetry: p, onRemove: m, labels: h, className: g }) {
|
|
19
|
+
let _ = {
|
|
20
|
+
...u,
|
|
21
|
+
...h
|
|
22
|
+
}, v = typeof d.progress == "number" && Number.isFinite(d.progress) ? Math.max(0, Math.min(100, d.progress)) : void 0, y = d.status === "queued" || d.status === "uploading";
|
|
23
|
+
return /* @__PURE__ */ l("div", {
|
|
24
|
+
className: e(t, "flex min-w-0 items-start gap-3 rounded-basalt-lg border border-basalt-border bg-basalt-card p-3", g),
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ c("span", {
|
|
27
|
+
className: "flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-basalt-md bg-basalt-accent",
|
|
28
|
+
children: d.preview ?? /* @__PURE__ */ c(i, {
|
|
29
|
+
className: "size-5 text-basalt-muted-foreground",
|
|
30
|
+
"aria-hidden": "true"
|
|
31
|
+
})
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ l("div", {
|
|
34
|
+
className: "min-w-0 flex-1 space-y-1",
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ c("p", {
|
|
37
|
+
className: "break-words text-sm font-medium",
|
|
38
|
+
children: d.name
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ l("p", {
|
|
41
|
+
className: "text-xs text-basalt-muted-foreground",
|
|
42
|
+
children: [d.size !== void 0 && `${Math.ceil(d.size / 1024).toLocaleString()} KB · `, _[d.status]]
|
|
43
|
+
}),
|
|
44
|
+
d.status === "uploading" && /* @__PURE__ */ c("div", {
|
|
45
|
+
role: "progressbar",
|
|
46
|
+
"aria-label": d.name,
|
|
47
|
+
"aria-valuemin": 0,
|
|
48
|
+
"aria-valuemax": 100,
|
|
49
|
+
"aria-valuenow": v,
|
|
50
|
+
className: "h-1.5 overflow-hidden rounded-full bg-basalt-accent",
|
|
51
|
+
children: /* @__PURE__ */ c("div", {
|
|
52
|
+
style: { width: v === void 0 ? "40%" : `${v}%` },
|
|
53
|
+
className: e("h-full rounded-full bg-basalt-primary", v === void 0 && "animate-pulse motion-reduce:animate-none")
|
|
54
|
+
})
|
|
55
|
+
}),
|
|
56
|
+
d.status === "error" && d.error && /* @__PURE__ */ c("p", {
|
|
57
|
+
role: "alert",
|
|
58
|
+
className: "break-words text-xs text-basalt-destructive",
|
|
59
|
+
children: d.error
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
}),
|
|
63
|
+
/* @__PURE__ */ l("div", {
|
|
64
|
+
className: "flex shrink-0 items-center gap-1",
|
|
65
|
+
children: [
|
|
66
|
+
d.status === "success" && /* @__PURE__ */ c(r, {
|
|
67
|
+
className: "size-4 text-basalt-success",
|
|
68
|
+
"aria-hidden": "true"
|
|
69
|
+
}),
|
|
70
|
+
y && f && /* @__PURE__ */ c(n, {
|
|
71
|
+
size: "icon",
|
|
72
|
+
variant: "ghost",
|
|
73
|
+
"aria-label": `${_.cancel} ${d.name}`,
|
|
74
|
+
onClick: () => f(d.id),
|
|
75
|
+
children: /* @__PURE__ */ c(s, {})
|
|
76
|
+
}),
|
|
77
|
+
(d.status === "error" || d.status === "cancelled") && p && /* @__PURE__ */ c(n, {
|
|
78
|
+
size: "icon",
|
|
79
|
+
variant: "ghost",
|
|
80
|
+
"aria-label": `${_.retry} ${d.name}`,
|
|
81
|
+
onClick: () => p(d.id),
|
|
82
|
+
children: /* @__PURE__ */ c(a, {})
|
|
83
|
+
}),
|
|
84
|
+
d.status !== "uploading" && m && /* @__PURE__ */ c(n, {
|
|
85
|
+
size: "icon",
|
|
86
|
+
variant: "ghost",
|
|
87
|
+
"aria-label": `${_.remove} ${d.name}`,
|
|
88
|
+
onClick: () => m(d.id),
|
|
89
|
+
children: /* @__PURE__ */ c(o, {})
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function f({ label: n, files: r, emptyLabel: i = "No files selected.", className: a, ...o }) {
|
|
97
|
+
return /* @__PURE__ */ c("div", {
|
|
98
|
+
className: e(t, "min-w-0 space-y-2", a),
|
|
99
|
+
children: r.length === 0 ? /* @__PURE__ */ c("p", {
|
|
100
|
+
role: "status",
|
|
101
|
+
className: "text-sm text-basalt-muted-foreground",
|
|
102
|
+
children: i
|
|
103
|
+
}) : /* @__PURE__ */ c("ul", {
|
|
104
|
+
"aria-label": n,
|
|
105
|
+
className: "m-0 list-none space-y-2 p-0",
|
|
106
|
+
children: r.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ c(d, {
|
|
107
|
+
file: e,
|
|
108
|
+
...o
|
|
109
|
+
}) }, e.id))
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { d as UploadItem, f as UploadQueue };
|
|
115
|
+
|
|
116
|
+
//# sourceMappingURL=upload-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-queue.js","names":[],"sources":["../../src/components/upload-queue.tsx"],"sourcesContent":["import { Check, FileText, RotateCcw, Trash2, X } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\n\nexport interface UploadFile {\n\t/** Stable queue identifier. */\n\tid: string;\n\t/** Display filename. */\n\tname: string;\n\t/** Optional size in bytes. */\n\tsize?: number;\n\t/** Application-owned transport state. */\n\tstatus: \"queued\" | \"uploading\" | \"success\" | \"error\" | \"cancelled\";\n\t/** Progress percentage; omitted means indeterminate. */\n\tprogress?: number;\n\t/** Application's error message. */\n\terror?: string;\n\t/** Optional image/icon. The caller creates and revokes any object URLs. */\n\tpreview?: ReactNode;\n}\nexport interface UploadLabels {\n\tqueued?: string;\n\tuploading?: string;\n\tsuccess?: string;\n\terror?: string;\n\tcancelled?: string;\n\tcancel?: string;\n\tretry?: string;\n\tremove?: string;\n}\nconst DEFAULT_LABELS = {\n\tqueued: \"Queued\",\n\tuploading: \"Uploading\",\n\tsuccess: \"Uploaded\",\n\terror: \"Upload failed\",\n\tcancelled: \"Cancelled\",\n\tcancel: \"Cancel\",\n\tretry: \"Retry\",\n\tremove: \"Remove\",\n};\n\nexport interface UploadItemProps {\n\t/** Current queue entry. The component does not start a network request. */\n\tfile: UploadFile;\n\t/** Cancel a queued or uploading entry. */\n\tonCancel?: (id: string) => void;\n\t/** Retry a failed or cancelled entry. */\n\tonRetry?: (id: string) => void;\n\t/** Remove an entry that is not currently uploading. */\n\tonRemove?: (id: string) => void;\n\t/** Localized statuses and action labels. */\n\tlabels?: UploadLabels;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nexport function UploadItem({\n\tfile,\n\tonCancel,\n\tonRetry,\n\tonRemove,\n\tlabels,\n\tclassName,\n}: UploadItemProps) {\n\tconst text = { ...DEFAULT_LABELS, ...labels };\n\tconst progress =\n\t\ttypeof file.progress === \"number\" && Number.isFinite(file.progress)\n\t\t\t? Math.max(0, Math.min(100, file.progress))\n\t\t\t: undefined;\n\tconst active = file.status === \"queued\" || file.status === \"uploading\";\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"flex min-w-0 items-start gap-3 rounded-basalt-lg border border-basalt-border bg-basalt-card p-3\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-basalt-md bg-basalt-accent\">\n\t\t\t\t{file.preview ?? (\n\t\t\t\t\t<FileText className=\"size-5 text-basalt-muted-foreground\" aria-hidden=\"true\" />\n\t\t\t\t)}\n\t\t\t</span>\n\t\t\t<div className=\"min-w-0 flex-1 space-y-1\">\n\t\t\t\t<p className=\"break-words text-sm font-medium\">{file.name}</p>\n\t\t\t\t<p className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t{file.size !== undefined && `${Math.ceil(file.size / 1024).toLocaleString()} KB · `}\n\t\t\t\t\t{text[file.status]}\n\t\t\t\t</p>\n\t\t\t\t{file.status === \"uploading\" && (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"progressbar\"\n\t\t\t\t\t\taria-label={file.name}\n\t\t\t\t\t\taria-valuemin={0}\n\t\t\t\t\t\taria-valuemax={100}\n\t\t\t\t\t\taria-valuenow={progress}\n\t\t\t\t\t\tclassName=\"h-1.5 overflow-hidden rounded-full bg-basalt-accent\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle={{ width: progress === undefined ? \"40%\" : `${progress}%` }}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"h-full rounded-full bg-basalt-primary\",\n\t\t\t\t\t\t\t\tprogress === undefined && \"animate-pulse motion-reduce:animate-none\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{file.status === \"error\" && file.error && (\n\t\t\t\t\t<p role=\"alert\" className=\"break-words text-xs text-basalt-destructive\">\n\t\t\t\t\t\t{file.error}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"flex shrink-0 items-center gap-1\">\n\t\t\t\t{file.status === \"success\" && (\n\t\t\t\t\t<Check className=\"size-4 text-basalt-success\" aria-hidden=\"true\" />\n\t\t\t\t)}\n\t\t\t\t{active && onCancel && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\taria-label={`${text.cancel} ${file.name}`}\n\t\t\t\t\t\tonClick={() => onCancel(file.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<X />\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t\t{(file.status === \"error\" || file.status === \"cancelled\") && onRetry && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\taria-label={`${text.retry} ${file.name}`}\n\t\t\t\t\t\tonClick={() => onRetry(file.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RotateCcw />\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t\t{file.status !== \"uploading\" && onRemove && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\taria-label={`${text.remove} ${file.name}`}\n\t\t\t\t\t\tonClick={() => onRemove(file.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport interface UploadQueueProps extends Omit<UploadItemProps, \"file\"> {\n\t/** Accessible queue name. */\n\tlabel: string;\n\t/** Application-owned queue entries. */\n\tfiles: readonly UploadFile[];\n\t/** Empty queue text. @default \"No files selected.\" */\n\temptyLabel?: string;\n}\n\nexport function UploadQueue({\n\tlabel,\n\tfiles,\n\temptyLabel = \"No files selected.\",\n\tclassName,\n\t...actions\n}: UploadQueueProps) {\n\treturn (\n\t\t<div className={cn(BASALT_UI_CLASS, \"min-w-0 space-y-2\", className)}>\n\t\t\t{files.length === 0 ? (\n\t\t\t\t<p role=\"status\" className=\"text-sm text-basalt-muted-foreground\">\n\t\t\t\t\t{emptyLabel}\n\t\t\t\t</p>\n\t\t\t) : (\n\t\t\t\t<ul aria-label={label} className=\"m-0 list-none space-y-2 p-0\">\n\t\t\t\t\t{files.map((file) => (\n\t\t\t\t\t\t<li key={file.id}>\n\t\t\t\t\t\t\t<UploadItem file={file} {...actions} />\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
|