@fabio.caffarello/react-design-system 3.13.0 → 4.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/dist/granular/ui/components/Autocomplete/Autocomplete.js +116 -88
- package/dist/granular/ui/components/Autocomplete/Autocomplete.js.map +1 -1
- package/dist/granular/ui/components/Autocomplete/AutocompleteList.js +57 -47
- package/dist/granular/ui/components/Autocomplete/AutocompleteList.js.map +1 -1
- package/dist/granular/ui/components/Autocomplete/AutocompleteOption.js +21 -20
- package/dist/granular/ui/components/Autocomplete/AutocompleteOption.js.map +1 -1
- package/dist/granular/ui/components/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/granular/ui/components/ColorPicker/ColorPicker.js.map +1 -1
- package/dist/granular/ui/components/CommandPalette/CommandPalette.js +187 -149
- package/dist/granular/ui/components/CommandPalette/CommandPalette.js.map +1 -1
- package/dist/granular/ui/components/DataGrid/DataGrid.js +92 -92
- package/dist/granular/ui/components/DataGrid/DataGrid.js.map +1 -1
- package/dist/granular/ui/components/DatePicker/DatePickerCalendar.js +154 -139
- package/dist/granular/ui/components/DatePicker/DatePickerCalendar.js.map +1 -1
- package/dist/granular/ui/components/Dialog/AlertDialog.js +73 -40
- package/dist/granular/ui/components/Dialog/AlertDialog.js.map +1 -1
- package/dist/granular/ui/components/Dialog/DialogContent.js +54 -48
- package/dist/granular/ui/components/Dialog/DialogContent.js.map +1 -1
- package/dist/granular/ui/components/Dialog/DialogDescription.js +31 -31
- package/dist/granular/ui/components/Dialog/DialogDescription.js.map +1 -1
- package/dist/granular/ui/components/Dialog/DialogTitle.js +30 -30
- package/dist/granular/ui/components/Dialog/DialogTitle.js.map +1 -1
- package/dist/granular/ui/components/Drawer/Drawer.js.map +1 -1
- package/dist/granular/ui/components/Dropdown/Dropdown.js.map +1 -1
- package/dist/granular/ui/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/granular/ui/components/FileUpload/FileUpload.js.map +1 -1
- package/dist/granular/ui/components/Form/Form.js +38 -37
- package/dist/granular/ui/components/Form/Form.js.map +1 -1
- package/dist/granular/ui/components/Form/FormField.js +28 -26
- package/dist/granular/ui/components/Form/FormField.js.map +1 -1
- package/dist/granular/ui/components/Header/Header.js.map +1 -1
- package/dist/granular/ui/components/Header/components/HeaderActions.js.map +1 -1
- package/dist/granular/ui/components/Header/components/HeaderHamburger.js.map +1 -1
- package/dist/granular/ui/components/Header/components/HeaderLogo.js.map +1 -1
- package/dist/granular/ui/components/Header/components/HeaderMobileMenu.js.map +1 -1
- package/dist/granular/ui/components/Header/components/HeaderNavigation.js.map +1 -1
- package/dist/granular/ui/components/Header/contexts/HeaderContext.js.map +1 -1
- package/dist/granular/ui/components/Menu/Menu.js.map +1 -1
- package/dist/granular/ui/components/Modal/Modal.js +98 -86
- package/dist/granular/ui/components/Modal/Modal.js.map +1 -1
- package/dist/granular/ui/components/MultiSelect/MultiSelect.js +122 -106
- package/dist/granular/ui/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/granular/ui/components/Navigation/Navigation.js.map +1 -1
- package/dist/granular/ui/components/PageHeader/PageHeader.js.map +1 -1
- package/dist/granular/ui/components/Pagination/Pagination.js.map +1 -1
- package/dist/granular/ui/components/Popover/Popover.js.map +1 -1
- package/dist/granular/ui/components/Rating/Rating.js.map +1 -1
- package/dist/granular/ui/components/SearchInput/SearchInput.js.map +1 -1
- package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarGroup.js +82 -64
- package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarGroup.js.map +1 -1
- package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarItem.js +30 -29
- package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarItem.js.map +1 -1
- package/dist/granular/ui/components/SideNavbar/components/SideNavbarResizeHandle.js +37 -35
- package/dist/granular/ui/components/SideNavbar/components/SideNavbarResizeHandle.js.map +1 -1
- package/dist/granular/ui/components/SideNavbar/providers/SideNavbarStateProvider.js +57 -57
- package/dist/granular/ui/components/SideNavbar/providers/SideNavbarStateProvider.js.map +1 -1
- package/dist/granular/ui/components/Stepper/Stepper.js +102 -94
- package/dist/granular/ui/components/Stepper/Stepper.js.map +1 -1
- package/dist/granular/ui/components/Table/Table.js +41 -35
- package/dist/granular/ui/components/Table/Table.js.map +1 -1
- package/dist/granular/ui/components/Table/TableActions/TableActions.js.map +1 -1
- package/dist/granular/ui/components/Table/TableFilters/TableFilters.js +49 -46
- package/dist/granular/ui/components/Table/TableFilters/TableFilters.js.map +1 -1
- package/dist/granular/ui/components/Table/TablePagination/TablePagination.js.map +1 -1
- package/dist/granular/ui/components/Table/TableProvider.js +82 -80
- package/dist/granular/ui/components/Table/TableProvider.js.map +1 -1
- package/dist/granular/ui/components/Table/TableRow.js +57 -53
- package/dist/granular/ui/components/Table/TableRow.js.map +1 -1
- package/dist/granular/ui/components/Table/useColumnResizing.js +53 -53
- package/dist/granular/ui/components/Table/useColumnResizing.js.map +1 -1
- package/dist/granular/ui/components/TimePicker/TimePicker.js +149 -103
- package/dist/granular/ui/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/granular/ui/components/Timeline/Timeline.js.map +1 -1
- package/dist/granular/ui/hooks/useFocusRestore.js +14 -15
- package/dist/granular/ui/hooks/useFocusRestore.js.map +1 -1
- package/dist/granular/ui/primitives/Badge/Badge.js.map +1 -1
- package/dist/granular/ui/primitives/Button/Button.js +86 -104
- package/dist/granular/ui/primitives/Button/Button.js.map +1 -1
- package/dist/granular/ui/primitives/Checkbox/Checkbox.js.map +1 -1
- package/dist/granular/ui/primitives/Chip/Chip.js +91 -71
- package/dist/granular/ui/primitives/Chip/Chip.js.map +1 -1
- package/dist/granular/ui/primitives/ErrorMessage/ErrorMessage.js.map +1 -1
- package/dist/granular/ui/primitives/Input/Input.js.map +1 -1
- package/dist/granular/ui/primitives/Label/Label.js.map +1 -1
- package/dist/granular/ui/primitives/NavLink/NavLink.js.map +1 -1
- package/dist/granular/ui/primitives/Radio/Radio.js.map +1 -1
- package/dist/granular/ui/primitives/Select/Select.js.map +1 -1
- package/dist/granular/ui/primitives/Separator/Separator.js.map +1 -1
- package/dist/granular/ui/primitives/Skeleton/Skeleton.js.map +1 -1
- package/dist/granular/ui/primitives/Slider/Slider.js.map +1 -1
- package/dist/granular/ui/primitives/Spinner/Spinner.js.map +1 -1
- package/dist/granular/ui/primitives/Switch/Switch.js.map +1 -1
- package/dist/granular/ui/primitives/Tooltip/Tooltip.js.map +1 -1
- package/dist/granular/ui/providers/DialogContext.js.map +1 -1
- package/dist/granular/ui/providers/DialogProvider.js +24 -20
- package/dist/granular/ui/providers/DialogProvider.js.map +1 -1
- package/dist/index.cjs +144 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5896 -5609
- package/dist/index.js.map +1 -1
- package/dist/react-design-system.css +1 -1
- package/dist/server/index.cjs +13 -13
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +1050 -789
- package/dist/server/index.js.map +1 -1
- package/dist/ui/components/Autocomplete/Autocomplete.d.ts +21 -0
- package/dist/ui/components/Autocomplete/AutocompleteList.d.ts +4 -0
- package/dist/ui/components/Autocomplete/AutocompleteOption.d.ts +8 -0
- package/dist/ui/components/Breadcrumb/Breadcrumb.d.ts +0 -1
- package/dist/ui/components/ColorPicker/ColorPicker.d.ts +0 -1
- package/dist/ui/components/CommandPalette/CommandPalette.d.ts +0 -1
- package/dist/ui/components/DataGrid/DataGrid.d.ts +0 -1
- package/dist/ui/components/Dialog/DialogContent.d.ts +20 -1
- package/dist/ui/components/Drawer/Drawer.d.ts +0 -1
- package/dist/ui/components/Dropdown/Dropdown.d.ts +0 -1
- package/dist/ui/components/EmptyState/EmptyState.d.ts +0 -1
- package/dist/ui/components/FileUpload/FileUpload.d.ts +0 -1
- package/dist/ui/components/Form/FormField.d.ts +7 -0
- package/dist/ui/components/Header/Header.d.ts +1 -1
- package/dist/ui/components/Header/components/HeaderActions.d.ts +1 -1
- package/dist/ui/components/Header/components/HeaderHamburger.d.ts +1 -1
- package/dist/ui/components/Header/components/HeaderLogo.d.ts +1 -1
- package/dist/ui/components/Header/components/HeaderMobileMenu.d.ts +1 -1
- package/dist/ui/components/Header/components/HeaderNavigation.d.ts +1 -1
- package/dist/ui/components/Header/contexts/HeaderContext.d.ts +1 -1
- package/dist/ui/components/Menu/Menu.d.ts +0 -1
- package/dist/ui/components/Modal/Modal.d.ts +1 -2
- package/dist/ui/components/Navigation/Navigation.d.ts +1 -1
- package/dist/ui/components/PageHeader/PageHeader.d.ts +1 -1
- package/dist/ui/components/Pagination/Pagination.d.ts +0 -1
- package/dist/ui/components/Popover/Popover.d.ts +0 -1
- package/dist/ui/components/Rating/Rating.d.ts +0 -1
- package/dist/ui/components/SearchInput/SearchInput.d.ts +0 -1
- package/dist/ui/components/Stepper/Stepper.d.ts +0 -1
- package/dist/ui/components/Table/TableActions/TableActions.d.ts +0 -1
- package/dist/ui/components/Table/TableFilters/TableFilters.d.ts +0 -1
- package/dist/ui/components/Table/TablePagination/TablePagination.d.ts +0 -1
- package/dist/ui/components/TimePicker/TimePicker.d.ts +0 -1
- package/dist/ui/components/Timeline/Timeline.d.ts +0 -1
- package/dist/ui/primitives/Checkbox/Checkbox.d.ts +0 -1
- package/dist/ui/primitives/Chip/Chip.d.ts +21 -0
- package/dist/ui/primitives/ErrorMessage/ErrorMessage.d.ts +0 -1
- package/dist/ui/primitives/Input/Input.d.ts +0 -1
- package/dist/ui/primitives/Label/Label.d.ts +0 -1
- package/dist/ui/primitives/NavLink/NavLink.d.ts +1 -1
- package/dist/ui/primitives/Radio/Radio.d.ts +0 -1
- package/dist/ui/primitives/Select/Select.d.ts +0 -1
- package/dist/ui/primitives/Skeleton/Skeleton.d.ts +0 -1
- package/dist/ui/primitives/Slider/Slider.d.ts +0 -1
- package/dist/ui/primitives/Switch/Switch.d.ts +0 -1
- package/dist/ui/primitives/Tooltip/Tooltip.d.ts +0 -1
- package/dist/ui/providers/DialogContext.d.ts +8 -0
- package/dist/ui/server.d.ts +2 -0
- package/package.json +7 -7
|
@@ -1,126 +1,129 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
2
|
+
var re = Object.defineProperty, ne = Object.defineProperties;
|
|
3
|
+
var ae = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var T = Object.getOwnPropertySymbols;
|
|
5
|
+
var ue = Object.prototype.hasOwnProperty, ce = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var U = (c, l, r) => l in c ? re(c, l, { enumerable: !0, configurable: !0, writable: !0, value: r }) : c[l] = r, q = (c, l) => {
|
|
7
7
|
for (var r in l || (l = {}))
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
for (var r of
|
|
11
|
-
|
|
8
|
+
ue.call(l, r) && U(c, r, l[r]);
|
|
9
|
+
if (T)
|
|
10
|
+
for (var r of T(l))
|
|
11
|
+
ce.call(l, r) && U(c, r, l[r]);
|
|
12
12
|
return c;
|
|
13
|
-
},
|
|
14
|
-
import { jsxs as
|
|
15
|
-
import { forwardRef as
|
|
16
|
-
import
|
|
17
|
-
import { Check as
|
|
18
|
-
import
|
|
19
|
-
import { cn as
|
|
20
|
-
import { getSpacingClass as
|
|
21
|
-
import { getRadiusClass as
|
|
22
|
-
const
|
|
13
|
+
}, z = (c, l) => ne(c, ae(l));
|
|
14
|
+
import { jsxs as G, jsx as h } from "react/jsx-runtime";
|
|
15
|
+
import { forwardRef as oe, useId as fe, useState as O, useRef as E, useEffect as de } from "react";
|
|
16
|
+
import me from "../../primitives/Chip/Chip.js";
|
|
17
|
+
import { Check as pe } from "lucide-react";
|
|
18
|
+
import ve from "../Autocomplete/AutocompleteList.js";
|
|
19
|
+
import { cn as w } from "../../utils/cn.js";
|
|
20
|
+
import { getSpacingClass as L } from "../../tokens/spacing.js";
|
|
21
|
+
import { getRadiusClass as he } from "../../tokens/radius.js";
|
|
22
|
+
const we = oe(
|
|
23
23
|
function({
|
|
24
24
|
options: l,
|
|
25
25
|
value: r,
|
|
26
|
-
defaultValue:
|
|
26
|
+
defaultValue: J = [],
|
|
27
27
|
onChange: n,
|
|
28
|
-
onSelect:
|
|
29
|
-
placeholder:
|
|
30
|
-
loading:
|
|
31
|
-
disabled:
|
|
32
|
-
emptyMessage:
|
|
33
|
-
maxSelected:
|
|
34
|
-
showSelectAll:
|
|
35
|
-
className:
|
|
36
|
-
inputClassName:
|
|
37
|
-
size:
|
|
38
|
-
label:
|
|
39
|
-
},
|
|
40
|
-
const
|
|
28
|
+
onSelect: a,
|
|
29
|
+
placeholder: P = "Select options...",
|
|
30
|
+
loading: F = !1,
|
|
31
|
+
disabled: A = !1,
|
|
32
|
+
emptyMessage: $ = "No options found",
|
|
33
|
+
maxSelected: d,
|
|
34
|
+
showSelectAll: Q = !1,
|
|
35
|
+
className: W = "",
|
|
36
|
+
inputClassName: X = "",
|
|
37
|
+
size: j = "md",
|
|
38
|
+
label: B
|
|
39
|
+
}, b) {
|
|
40
|
+
const I = fe(), R = `${I}-list`, [Y, g] = O(J), [k, p] = O(!1), [f, m] = O(-1), [V, N] = O(""), x = E(null), Z = E(null), K = E(null), v = r !== void 0, i = v ? r : Y, y = l.filter(
|
|
41
41
|
(e) => i.includes(e.value)
|
|
42
|
-
),
|
|
42
|
+
), u = (() => {
|
|
43
43
|
let e = l;
|
|
44
|
-
return
|
|
45
|
-
(t) => t.label.toLowerCase().includes(
|
|
44
|
+
return V.trim() && (e = l.filter(
|
|
45
|
+
(t) => t.label.toLowerCase().includes(V.toLowerCase())
|
|
46
46
|
)), e;
|
|
47
|
-
})(),
|
|
47
|
+
})(), _ = u.length > 0, C = (e) => {
|
|
48
48
|
const t = e.target.value;
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
if (e.disabled ||
|
|
49
|
+
N(t), p(!0), m(-1);
|
|
50
|
+
}, M = (e) => {
|
|
51
|
+
if (e.disabled || d && i.length >= d && !i.includes(e.value))
|
|
52
52
|
return;
|
|
53
53
|
const t = i.includes(e.value) ? i.filter((s) => s !== e.value) : [...i, e.value];
|
|
54
|
-
|
|
55
|
-
},
|
|
56
|
-
const e =
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
const e =
|
|
54
|
+
v || g(t), n == null || n(t), a == null || a(l.filter((s) => t.includes(s.value))), N(""), m(-1);
|
|
55
|
+
}, S = () => {
|
|
56
|
+
const e = u.filter((o) => !o.disabled).map((o) => o.value), t = [.../* @__PURE__ */ new Set([...i, ...e])], s = d ? t.slice(0, d) : t;
|
|
57
|
+
v || g(s), n == null || n(s), a == null || a(l.filter((o) => s.includes(o.value)));
|
|
58
|
+
}, ee = () => {
|
|
59
|
+
const e = u.map((s) => s.value), t = i.filter(
|
|
60
60
|
(s) => !e.includes(s)
|
|
61
61
|
);
|
|
62
|
-
|
|
63
|
-
},
|
|
62
|
+
v || g(t), n == null || n(t), a == null || a(l.filter((s) => t.includes(s.value)));
|
|
63
|
+
}, H = (e) => {
|
|
64
|
+
if (A) return;
|
|
64
65
|
const t = i.filter((s) => s !== e);
|
|
65
|
-
|
|
66
|
-
},
|
|
67
|
-
if (!
|
|
68
|
-
(e.key === "ArrowDown" || e.key === "Enter") &&
|
|
66
|
+
v || g(t), n == null || n(t), a == null || a(l.filter((s) => t.includes(s.value)));
|
|
67
|
+
}, te = (e) => {
|
|
68
|
+
if (!k || u.length === 0) {
|
|
69
|
+
(e.key === "ArrowDown" || e.key === "Enter") && p(!0), e.key === "Backspace" && V === "" && y.length > 0 && H(y[y.length - 1].value);
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
72
|
switch (e.key) {
|
|
72
73
|
case "ArrowDown":
|
|
73
|
-
e.preventDefault(),
|
|
74
|
-
(t) => t <
|
|
74
|
+
e.preventDefault(), m(
|
|
75
|
+
(t) => t < u.length - 1 ? t + 1 : 0
|
|
75
76
|
);
|
|
76
77
|
break;
|
|
77
78
|
case "ArrowUp":
|
|
78
|
-
e.preventDefault(),
|
|
79
|
-
(t) => t > 0 ? t - 1 :
|
|
79
|
+
e.preventDefault(), m(
|
|
80
|
+
(t) => t > 0 ? t - 1 : u.length - 1
|
|
80
81
|
);
|
|
81
82
|
break;
|
|
82
83
|
case "Enter":
|
|
83
|
-
e.preventDefault(),
|
|
84
|
+
e.preventDefault(), f >= 0 && f < u.length && M(u[f]);
|
|
84
85
|
break;
|
|
85
86
|
case "Escape":
|
|
86
|
-
e.preventDefault(),
|
|
87
|
+
e.preventDefault(), p(!1), m(-1);
|
|
87
88
|
break;
|
|
88
89
|
}
|
|
89
90
|
};
|
|
90
|
-
|
|
91
|
-
if (!
|
|
91
|
+
de(() => {
|
|
92
|
+
if (!k) return;
|
|
92
93
|
const e = (t) => {
|
|
93
|
-
|
|
94
|
+
var o;
|
|
95
|
+
const s = t.target;
|
|
96
|
+
x.current && !x.current.contains(s) && !((o = K.current) != null && o.contains(s)) && (p(!1), m(-1), N(""));
|
|
94
97
|
};
|
|
95
98
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
96
|
-
}, [
|
|
97
|
-
const
|
|
98
|
-
return /* @__PURE__ */
|
|
99
|
-
/* @__PURE__ */
|
|
99
|
+
}, [k]);
|
|
100
|
+
const le = u.filter((e) => !e.disabled).every((e) => i.includes(e.value)), D = k && (_ || F || !!$), se = d != null && i.length >= d, ie = D && f >= 0 && f < u.length ? `${R}-option-${f}` : void 0;
|
|
101
|
+
return /* @__PURE__ */ G("div", { ref: x, className: w("relative", W), children: [
|
|
102
|
+
/* @__PURE__ */ h(
|
|
100
103
|
"label",
|
|
101
104
|
{
|
|
102
|
-
htmlFor:
|
|
103
|
-
className:
|
|
105
|
+
htmlFor: I,
|
|
106
|
+
className: w(
|
|
104
107
|
"block",
|
|
105
|
-
|
|
108
|
+
L("sm", "mb"),
|
|
106
109
|
"text-sm",
|
|
107
110
|
"font-medium",
|
|
108
111
|
"text-fg-primary"
|
|
109
112
|
),
|
|
110
|
-
children:
|
|
113
|
+
children: B
|
|
111
114
|
}
|
|
112
115
|
),
|
|
113
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ G(
|
|
114
117
|
"div",
|
|
115
118
|
{
|
|
116
|
-
className:
|
|
119
|
+
className: w(
|
|
117
120
|
"flex",
|
|
118
121
|
"flex-wrap",
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
L("sm", "gap"),
|
|
123
|
+
L("sm", "p"),
|
|
121
124
|
"border",
|
|
122
125
|
"border-line-default",
|
|
123
|
-
|
|
126
|
+
he("md"),
|
|
124
127
|
"min-h-10",
|
|
125
128
|
"focus-within:outline-none",
|
|
126
129
|
"focus-within:ring-2",
|
|
@@ -129,65 +132,78 @@ const me = ne(
|
|
|
129
132
|
"focus-within:ring-line-brand"
|
|
130
133
|
),
|
|
131
134
|
children: [
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
y.map((e) => /* @__PURE__ */ h(
|
|
136
|
+
me,
|
|
134
137
|
{
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
disabled: A,
|
|
139
|
+
onRemove: () => H(e.value),
|
|
140
|
+
size: j === "sm" ? "sm" : j === "lg" ? "lg" : "md",
|
|
137
141
|
children: e.label
|
|
138
142
|
},
|
|
139
143
|
e.value
|
|
140
144
|
)),
|
|
141
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ h(
|
|
142
146
|
"input",
|
|
143
147
|
{
|
|
144
|
-
id:
|
|
148
|
+
id: I,
|
|
145
149
|
ref: (e) => {
|
|
146
|
-
typeof
|
|
150
|
+
typeof b == "function" ? b(e) : b && (b.current = e), Z.current = e;
|
|
147
151
|
},
|
|
148
152
|
type: "text",
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
role: "combobox",
|
|
154
|
+
"aria-expanded": D,
|
|
155
|
+
"aria-haspopup": "listbox",
|
|
156
|
+
"aria-controls": D ? R : void 0,
|
|
157
|
+
"aria-autocomplete": "list",
|
|
158
|
+
"aria-activedescendant": ie,
|
|
159
|
+
value: V,
|
|
160
|
+
onChange: C,
|
|
161
|
+
onKeyDown: te,
|
|
162
|
+
onFocus: () => p(!0),
|
|
163
|
+
placeholder: i.length === 0 ? P : "",
|
|
164
|
+
disabled: A,
|
|
165
|
+
className: w(
|
|
156
166
|
"flex-1",
|
|
157
167
|
"min-w-32",
|
|
158
168
|
"outline-none",
|
|
159
169
|
"bg-transparent",
|
|
160
|
-
|
|
170
|
+
X
|
|
161
171
|
)
|
|
162
172
|
}
|
|
163
173
|
)
|
|
164
174
|
]
|
|
165
175
|
}
|
|
166
176
|
),
|
|
167
|
-
|
|
168
|
-
|
|
177
|
+
D && /* @__PURE__ */ h(
|
|
178
|
+
ve,
|
|
169
179
|
{
|
|
170
|
-
ref:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
180
|
+
ref: K,
|
|
181
|
+
id: R,
|
|
182
|
+
selectedValues: i,
|
|
183
|
+
"aria-label": B,
|
|
184
|
+
options: u.map((e) => z(q({}, e), {
|
|
185
|
+
// Once the cap is hit, not-yet-selected options are disabled
|
|
186
|
+
// so they stop accepting clicks silently (maxSelected was a
|
|
187
|
+
// no-op with no affordance before).
|
|
188
|
+
disabled: e.disabled || se && !i.includes(e.value),
|
|
189
|
+
icon: i.includes(e.value) ? /* @__PURE__ */ h(pe, { className: w("h-4", "w-4", "text-fg-brand") }) : e.icon
|
|
174
190
|
})),
|
|
175
|
-
highlightedIndex:
|
|
176
|
-
onSelect:
|
|
177
|
-
loading:
|
|
178
|
-
emptyMessage:
|
|
179
|
-
containerRef:
|
|
180
|
-
showSelectAll:
|
|
181
|
-
allSelected:
|
|
182
|
-
onSelectAll:
|
|
183
|
-
onDeselectAll:
|
|
191
|
+
highlightedIndex: f,
|
|
192
|
+
onSelect: M,
|
|
193
|
+
loading: F,
|
|
194
|
+
emptyMessage: $,
|
|
195
|
+
containerRef: x,
|
|
196
|
+
showSelectAll: Q && u.length > 0,
|
|
197
|
+
allSelected: le,
|
|
198
|
+
onSelectAll: S,
|
|
199
|
+
onDeselectAll: ee
|
|
184
200
|
}
|
|
185
201
|
)
|
|
186
202
|
] });
|
|
187
203
|
}
|
|
188
204
|
);
|
|
189
|
-
|
|
205
|
+
we.displayName = "MultiSelect";
|
|
190
206
|
export {
|
|
191
|
-
|
|
207
|
+
we as default
|
|
192
208
|
};
|
|
193
209
|
//# sourceMappingURL=MultiSelect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelect.js","sources":["../../../../../src/ui/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useRef, useEffect, useId, forwardRef } from \"react\";\nimport Chip from \"../../primitives/Chip/Chip\";\nimport { Check } from \"lucide-react\";\nimport AutocompleteList from \"../Autocomplete/AutocompleteList\";\nimport type { AutocompleteOptionType } from \"../Autocomplete/AutocompleteOption\";\nimport { cn } from \"../../utils\";\nimport { getSpacingClass } from \"../../tokens\";\nimport { getRadiusClass } from \"../../tokens\";\n\nexport interface MultiSelectProps {\n options: AutocompleteOptionType[];\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n onSelect?: (options: AutocompleteOptionType[]) => void;\n placeholder?: string;\n loading?: boolean;\n disabled?: boolean;\n emptyMessage?: string;\n maxSelected?: number;\n showSelectAll?: boolean;\n className?: string;\n inputClassName?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /**\n * Required label for the multi-select input. Becomes the accessible\n * name via <label htmlFor>. Make this a real domain term (\"Tags\",\n * \"Select fruits\"), not the element type (\"multi-select\" / \"input\").\n */\n label: string;\n}\n\n/**\n * MultiSelect Component\n *\n * A multi-select component with chips for selected items.\n * Supports keyboard navigation, loading states, and custom filtering.\n *\n * @example\n * ```tsx\n * <MultiSelect\n * options={[\n * { value: '1', label: 'Option 1' },\n * { value: '2', label: 'Option 2' },\n * ]}\n * onSelect={(options) => console.log(options)}\n * />\n * ```\n */\nconst MultiSelect = forwardRef<HTMLInputElement, MultiSelectProps>(\n function MultiSelect(\n {\n options,\n value: controlledValue,\n defaultValue = [],\n onChange,\n onSelect,\n placeholder = \"Select options...\",\n loading = false,\n disabled = false,\n emptyMessage = \"No options found\",\n maxSelected,\n showSelectAll = false,\n className = \"\",\n inputClassName = \"\",\n size = \"md\",\n label,\n },\n ref,\n ) {\n const inputId = useId();\n const [internalValue, setInternalValue] = useState<string[]>(defaultValue);\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [searchValue, setSearchValue] = useState(\"\");\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n // Get selected options\n const selectedOptions = options.filter((opt) =>\n selectedValues.includes(opt.value),\n );\n\n // Filter options (exclude already selected if needed, or show all)\n const getFilteredOptions = (): AutocompleteOptionType[] => {\n let filtered = options;\n\n if (searchValue.trim()) {\n filtered = options.filter((option) =>\n option.label.toLowerCase().includes(searchValue.toLowerCase()),\n );\n }\n\n return filtered;\n };\n\n const filteredOptions = getFilteredOptions();\n const hasOptions = filteredOptions.length > 0;\n\n // Handle input change\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setSearchValue(newValue);\n setIsOpen(true);\n setHighlightedIndex(-1);\n };\n\n // Handle option toggle\n const handleToggleOption = (option: AutocompleteOptionType) => {\n if (option.disabled) return;\n if (\n maxSelected &&\n selectedValues.length >= maxSelected &&\n !selectedValues.includes(option.value)\n ) {\n return;\n }\n\n const newValues = selectedValues.includes(option.value)\n ? selectedValues.filter((v) => v !== option.value)\n : [...selectedValues, option.value];\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n setSearchValue(\"\");\n };\n\n // Handle select all\n const handleSelectAll = () => {\n const allValues = filteredOptions\n .filter((opt) => !opt.disabled)\n .map((opt) => opt.value);\n const newValues = [...new Set([...selectedValues, ...allValues])];\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle deselect all\n const handleDeselectAll = () => {\n const filteredValues = filteredOptions.map((opt) => opt.value);\n const newValues = selectedValues.filter(\n (v) => !filteredValues.includes(v),\n );\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle remove chip\n const handleRemoveChip = (value: string) => {\n const newValues = selectedValues.filter((v) => v !== value);\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || filteredOptions.length === 0) {\n if (e.key === \"ArrowDown\" || e.key === \"Enter\") {\n setIsOpen(true);\n }\n // Remove last chip on backspace\n if (\n e.key === \"Backspace\" &&\n searchValue === \"\" &&\n selectedValues.length > 0\n ) {\n handleRemoveChip(selectedValues[selectedValues.length - 1]);\n }\n return;\n }\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setHighlightedIndex((prev) =>\n prev < filteredOptions.length - 1 ? prev + 1 : 0,\n );\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setHighlightedIndex((prev) =>\n prev > 0 ? prev - 1 : filteredOptions.length - 1,\n );\n break;\n case \"Enter\":\n e.preventDefault();\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ) {\n handleToggleOption(filteredOptions[highlightedIndex]);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n setHighlightedIndex(-1);\n break;\n }\n };\n\n // Close on click outside\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n setHighlightedIndex(-1);\n setSearchValue(\"\");\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen]);\n\n // Check if all filtered options are selected\n const allSelected = filteredOptions\n .filter((opt) => !opt.disabled)\n .every((opt) => selectedValues.includes(opt.value));\n\n const shouldShowList = isOpen && (hasOptions || loading || emptyMessage);\n\n return (\n <div ref={containerRef} className={cn(\"relative\", className)}>\n <label\n htmlFor={inputId}\n className={cn(\n \"block\",\n getSpacingClass(\"sm\", \"mb\"),\n \"text-sm\",\n \"font-medium\",\n \"text-fg-primary\",\n )}\n >\n {label}\n </label>\n <div\n className={cn(\n \"flex\",\n \"flex-wrap\",\n getSpacingClass(\"sm\", \"gap\"),\n getSpacingClass(\"sm\", \"p\"),\n \"border\",\n \"border-line-default\",\n getRadiusClass(\"md\"),\n \"min-h-10\",\n \"focus-within:outline-none\",\n \"focus-within:ring-2\",\n \"focus-within:ring-offset-2\",\n \"focus-within:border-line-brand\",\n \"focus-within:ring-line-brand\",\n )}\n >\n {selectedOptions.map((option) => (\n <Chip\n key={option.value}\n onRemove={() => handleRemoveChip(option.value)}\n size={size === \"sm\" ? \"sm\" : size === \"lg\" ? \"lg\" : \"md\"}\n >\n {option.label}\n </Chip>\n ))}\n <input\n id={inputId}\n ref={(node) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (\n ref as React.MutableRefObject<HTMLInputElement | null>\n ).current = node;\n }\n inputRef.current = node;\n }}\n type=\"text\"\n value={searchValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsOpen(true)}\n placeholder={selectedValues.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n className={cn(\n \"flex-1\",\n \"min-w-32\",\n \"outline-none\",\n \"bg-transparent\",\n inputClassName,\n )}\n />\n </div>\n\n {shouldShowList && (\n <AutocompleteList\n ref={listRef}\n // Cascade the input's accessible-name source to the\n // listbox portal — axe `aria-input-field-name` flags a\n // role=\"listbox\" without aria-label / aria-labelledby.\n // MultiSelect's `label` is TS-required, so the listbox\n // always inherits a name.\n aria-label={label}\n options={filteredOptions.map((opt) => ({\n ...opt,\n icon: selectedValues.includes(opt.value) ? (\n <Check className={cn(\"h-4\", \"w-4\", \"text-fg-brand\")} />\n ) : (\n opt.icon\n ),\n }))}\n highlightedIndex={highlightedIndex}\n onSelect={handleToggleOption}\n loading={loading}\n emptyMessage={emptyMessage}\n containerRef={containerRef}\n showSelectAll={showSelectAll && filteredOptions.length > 0}\n allSelected={allSelected}\n onSelectAll={handleSelectAll}\n onDeselectAll={handleDeselectAll}\n />\n )}\n </div>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","forwardRef","options","controlledValue","defaultValue","onChange","onSelect","placeholder","loading","disabled","emptyMessage","maxSelected","showSelectAll","className","inputClassName","size","label","ref","inputId","useId","internalValue","setInternalValue","useState","isOpen","setIsOpen","highlightedIndex","setHighlightedIndex","searchValue","setSearchValue","containerRef","useRef","inputRef","listRef","isControlled","selectedValues","selectedOptions","opt","filteredOptions","filtered","option","hasOptions","handleInputChange","newValue","handleToggleOption","newValues","v","handleSelectAll","allValues","handleDeselectAll","filteredValues","handleRemoveChip","value","handleKeyDown","prev","useEffect","handleClickOutside","e","allSelected","shouldShowList","jsxs","cn","jsx","getSpacingClass","getRadiusClass","Chip","node","AutocompleteList","__spreadProps","__spreadValues","Check"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MultiSelect.js","sources":["../../../../../src/ui/components/MultiSelect/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useRef, useEffect, useId, forwardRef } from \"react\";\nimport Chip from \"../../primitives/Chip/Chip\";\nimport { Check } from \"lucide-react\";\nimport AutocompleteList from \"../Autocomplete/AutocompleteList\";\nimport type { AutocompleteOptionType } from \"../Autocomplete/AutocompleteOption\";\nimport { cn } from \"../../utils\";\nimport { getSpacingClass } from \"../../tokens\";\nimport { getRadiusClass } from \"../../tokens\";\n\nexport interface MultiSelectProps {\n options: AutocompleteOptionType[];\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n onSelect?: (options: AutocompleteOptionType[]) => void;\n placeholder?: string;\n loading?: boolean;\n disabled?: boolean;\n emptyMessage?: string;\n maxSelected?: number;\n showSelectAll?: boolean;\n className?: string;\n inputClassName?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /**\n * Required label for the multi-select input. Becomes the accessible\n * name via <label htmlFor>. Make this a real domain term (\"Tags\",\n * \"Select fruits\"), not the element type (\"multi-select\" / \"input\").\n */\n label: string;\n}\n\n/**\n * MultiSelect Component\n *\n * A multi-select component with chips for selected items.\n * Supports keyboard navigation, loading states, and custom filtering.\n *\n * @example\n * ```tsx\n * <MultiSelect\n * options={[\n * { value: '1', label: 'Option 1' },\n * { value: '2', label: 'Option 2' },\n * ]}\n * onSelect={(options) => console.log(options)}\n * />\n * ```\n */\nconst MultiSelect = forwardRef<HTMLInputElement, MultiSelectProps>(\n function MultiSelect(\n {\n options,\n value: controlledValue,\n defaultValue = [],\n onChange,\n onSelect,\n placeholder = \"Select options...\",\n loading = false,\n disabled = false,\n emptyMessage = \"No options found\",\n maxSelected,\n showSelectAll = false,\n className = \"\",\n inputClassName = \"\",\n size = \"md\",\n label,\n },\n ref,\n ) {\n const inputId = useId();\n const listId = `${inputId}-list`;\n const [internalValue, setInternalValue] = useState<string[]>(defaultValue);\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [searchValue, setSearchValue] = useState(\"\");\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n // Get selected options\n const selectedOptions = options.filter((opt) =>\n selectedValues.includes(opt.value),\n );\n\n // Filter options (exclude already selected if needed, or show all)\n const getFilteredOptions = (): AutocompleteOptionType[] => {\n let filtered = options;\n\n if (searchValue.trim()) {\n filtered = options.filter((option) =>\n option.label.toLowerCase().includes(searchValue.toLowerCase()),\n );\n }\n\n return filtered;\n };\n\n const filteredOptions = getFilteredOptions();\n const hasOptions = filteredOptions.length > 0;\n\n // Handle input change\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setSearchValue(newValue);\n setIsOpen(true);\n setHighlightedIndex(-1);\n };\n\n // Handle option toggle\n const handleToggleOption = (option: AutocompleteOptionType) => {\n if (option.disabled) return;\n if (\n maxSelected &&\n selectedValues.length >= maxSelected &&\n !selectedValues.includes(option.value)\n ) {\n return;\n }\n\n const newValues = selectedValues.includes(option.value)\n ? selectedValues.filter((v) => v !== option.value)\n : [...selectedValues, option.value];\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n setSearchValue(\"\");\n // Clearing the search reverts filteredOptions to the full list, so a\n // stale highlightedIndex would point at a different row — reset it.\n setHighlightedIndex(-1);\n };\n\n // Handle select all\n const handleSelectAll = () => {\n const allValues = filteredOptions\n .filter((opt) => !opt.disabled)\n .map((opt) => opt.value);\n const merged = [...new Set([...selectedValues, ...allValues])];\n // Respect maxSelected — the single-toggle path enforces it, so\n // Select All must not be able to overshoot the cap.\n const newValues = maxSelected ? merged.slice(0, maxSelected) : merged;\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle deselect all\n const handleDeselectAll = () => {\n const filteredValues = filteredOptions.map((opt) => opt.value);\n const newValues = selectedValues.filter(\n (v) => !filteredValues.includes(v),\n );\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle remove chip\n const handleRemoveChip = (value: string) => {\n if (disabled) return;\n const newValues = selectedValues.filter((v) => v !== value);\n\n if (!isControlled) {\n setInternalValue(newValues);\n }\n\n onChange?.(newValues);\n onSelect?.(options.filter((opt) => newValues.includes(opt.value)));\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || filteredOptions.length === 0) {\n if (e.key === \"ArrowDown\" || e.key === \"Enter\") {\n setIsOpen(true);\n }\n // Remove last chip on backspace\n if (\n e.key === \"Backspace\" &&\n searchValue === \"\" &&\n selectedOptions.length > 0\n ) {\n // Remove the LAST VISIBLE chip — chips render from\n // selectedOptions (options order), which can differ from\n // selectedValues (insertion order).\n handleRemoveChip(selectedOptions[selectedOptions.length - 1].value);\n }\n return;\n }\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setHighlightedIndex((prev) =>\n prev < filteredOptions.length - 1 ? prev + 1 : 0,\n );\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setHighlightedIndex((prev) =>\n prev > 0 ? prev - 1 : filteredOptions.length - 1,\n );\n break;\n case \"Enter\":\n e.preventDefault();\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ) {\n handleToggleOption(filteredOptions[highlightedIndex]);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n setHighlightedIndex(-1);\n break;\n }\n };\n\n // Close on click outside\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n // The list is portalled to document.body (outside containerRef),\n // so without the listRef check a mousedown on an option closed the\n // list before its click toggled the selection.\n if (\n containerRef.current &&\n !containerRef.current.contains(target) &&\n !listRef.current?.contains(target)\n ) {\n setIsOpen(false);\n setHighlightedIndex(-1);\n setSearchValue(\"\");\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen]);\n\n // Check if all filtered options are selected\n const allSelected = filteredOptions\n .filter((opt) => !opt.disabled)\n .every((opt) => selectedValues.includes(opt.value));\n\n const shouldShowList =\n isOpen && (hasOptions || loading || Boolean(emptyMessage));\n const atCap = maxSelected != null && selectedValues.length >= maxSelected;\n const activeOptionId =\n shouldShowList &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ? `${listId}-option-${highlightedIndex}`\n : undefined;\n\n return (\n <div ref={containerRef} className={cn(\"relative\", className)}>\n <label\n htmlFor={inputId}\n className={cn(\n \"block\",\n getSpacingClass(\"sm\", \"mb\"),\n \"text-sm\",\n \"font-medium\",\n \"text-fg-primary\",\n )}\n >\n {label}\n </label>\n <div\n className={cn(\n \"flex\",\n \"flex-wrap\",\n getSpacingClass(\"sm\", \"gap\"),\n getSpacingClass(\"sm\", \"p\"),\n \"border\",\n \"border-line-default\",\n getRadiusClass(\"md\"),\n \"min-h-10\",\n \"focus-within:outline-none\",\n \"focus-within:ring-2\",\n \"focus-within:ring-offset-2\",\n \"focus-within:border-line-brand\",\n \"focus-within:ring-line-brand\",\n )}\n >\n {selectedOptions.map((option) => (\n <Chip\n key={option.value}\n disabled={disabled}\n onRemove={() => handleRemoveChip(option.value)}\n size={size === \"sm\" ? \"sm\" : size === \"lg\" ? \"lg\" : \"md\"}\n >\n {option.label}\n </Chip>\n ))}\n <input\n id={inputId}\n ref={(node) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (\n ref as React.MutableRefObject<HTMLInputElement | null>\n ).current = node;\n }\n inputRef.current = node;\n }}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={shouldShowList}\n aria-haspopup=\"listbox\"\n aria-controls={shouldShowList ? listId : undefined}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeOptionId}\n value={searchValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsOpen(true)}\n placeholder={selectedValues.length === 0 ? placeholder : \"\"}\n disabled={disabled}\n className={cn(\n \"flex-1\",\n \"min-w-32\",\n \"outline-none\",\n \"bg-transparent\",\n inputClassName,\n )}\n />\n </div>\n\n {shouldShowList && (\n <AutocompleteList\n ref={listRef}\n // Cascade the input's accessible-name source to the\n // listbox portal — axe `aria-input-field-name` flags a\n // role=\"listbox\" without aria-label / aria-labelledby.\n // MultiSelect's `label` is TS-required, so the listbox\n // always inherits a name.\n id={listId}\n selectedValues={selectedValues}\n aria-label={label}\n options={filteredOptions.map((opt) => ({\n ...opt,\n // Once the cap is hit, not-yet-selected options are disabled\n // so they stop accepting clicks silently (maxSelected was a\n // no-op with no affordance before).\n disabled:\n opt.disabled || (atCap && !selectedValues.includes(opt.value)),\n icon: selectedValues.includes(opt.value) ? (\n <Check className={cn(\"h-4\", \"w-4\", \"text-fg-brand\")} />\n ) : (\n opt.icon\n ),\n }))}\n highlightedIndex={highlightedIndex}\n onSelect={handleToggleOption}\n loading={loading}\n emptyMessage={emptyMessage}\n containerRef={containerRef}\n showSelectAll={showSelectAll && filteredOptions.length > 0}\n allSelected={allSelected}\n onSelectAll={handleSelectAll}\n onDeselectAll={handleDeselectAll}\n />\n )}\n </div>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","forwardRef","options","controlledValue","defaultValue","onChange","onSelect","placeholder","loading","disabled","emptyMessage","maxSelected","showSelectAll","className","inputClassName","size","label","ref","inputId","useId","listId","internalValue","setInternalValue","useState","isOpen","setIsOpen","highlightedIndex","setHighlightedIndex","searchValue","setSearchValue","containerRef","useRef","inputRef","listRef","isControlled","selectedValues","selectedOptions","opt","filteredOptions","filtered","option","hasOptions","handleInputChange","newValue","handleToggleOption","newValues","v","handleSelectAll","allValues","merged","handleDeselectAll","filteredValues","handleRemoveChip","value","handleKeyDown","prev","useEffect","handleClickOutside","e","target","_a","allSelected","shouldShowList","atCap","activeOptionId","jsxs","cn","jsx","getSpacingClass","getRadiusClass","Chip","node","AutocompleteList","__spreadProps","__spreadValues","Check"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Navigation.js","sources":["../../../../../src/ui/components/Navigation/Navigation.tsx"],"sourcesContent":["/**\n * Navigation Component\n *\n * Horizontal or vertical navigation component using NavLink internally.\n *\n * @see EPIC-003: Navigation Component
|
|
1
|
+
{"version":3,"file":"Navigation.js","sources":["../../../../../src/ui/components/Navigation/Navigation.tsx"],"sourcesContent":["/**\n * Navigation Component\n *\n * Horizontal or vertical navigation component using NavLink internally.\n *\n * @see EPIC-003: Navigation Component\n * @see RFC-005: Navigation Composition Pattern (APPROVED)\n */\n\n\"use client\";\n\nimport { useMemo } from \"react\";\nimport { NavLink } from \"../../primitives/NavLink\";\nimport type { NavigationProps } from \"./types\";\nimport { cn, cva } from \"../../utils\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\n\n/**\n * Navigation Variants using CVA\n * Type-safe variant system for Navigation component\n */\nconst navigationVariants = cva(\n // Base classes\n cn(\"flex\", \"items-center\", getSpacingClass(\"sm\", \"gap\")),\n {\n variants: {\n orientation: {\n horizontal: \"flex-row\",\n vertical: \"flex-col\",\n },\n variant: {\n default: \"\",\n pills: \"\",\n tabs: \"\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n variant: \"default\",\n },\n compoundVariants: [\n {\n orientation: \"vertical\",\n variant: \"default\",\n class: \"items-stretch\",\n },\n {\n orientation: \"vertical\",\n variant: \"pills\",\n class: \"items-stretch\",\n },\n {\n orientation: \"vertical\",\n variant: \"tabs\",\n class: \"items-stretch\",\n },\n ],\n },\n);\n\n/**\n * Navigation Component\n *\n * Navigation component that uses NavLink internally.\n * Supports horizontal and vertical orientations, variants, and icons.\n *\n * @example\n * ```tsx\n * <Navigation\n * items={[\n * { href: '/home', label: 'Home', active: true },\n * { href: '/about', label: 'About' },\n * ]}\n * orientation=\"horizontal\"\n * variant=\"default\"\n * />\n * ```\n */\n/**\n * Navigation Component (Internal with pathname detection)\n *\n * Internal component that can use Next.js usePathname hook.\n */\nfunction NavigationWithPathname({\n items,\n orientation = \"horizontal\",\n variant = \"default\",\n className,\n \"aria-label\": ariaLabel = \"Main navigation\",\n bare = false,\n pathname: providedPathname,\n ...props\n}: NavigationProps & { pathname?: string }) {\n // Pathname channel: explicit prop wins. Falls back to\n // window.location.pathname so a non-Next.js app still gets initial\n // active-state highlighting. Note: window.location does not re-render\n // on client-side navigation — Next.js apps should pass\n // `pathname={usePathname()}` explicitly for reactive updates.\n const currentPathname: string | undefined =\n providedPathname ??\n (typeof window !== \"undefined\" ? window.location.pathname : undefined);\n\n // Calculate active state for items\n const itemsWithActive = useMemo(() => {\n return items.map((item) => {\n // Manual active prop has priority\n if (item.active !== undefined) {\n return item;\n }\n\n // Auto-detect if pathname is available\n if (currentPathname) {\n const isActive =\n currentPathname === item.href ||\n (item.href !== \"/\" && currentPathname.startsWith(`${item.href}/`));\n return { ...item, active: isActive };\n }\n\n // Default to false\n return { ...item, active: false };\n });\n }, [items, currentPathname]);\n\n const content = (\n <>\n {itemsWithActive.map((item, index) => {\n // Map Navigation variants to NavLink variants\n const navLinkVariant =\n variant === \"pills\"\n ? \"background\"\n : variant === \"tabs\"\n ? \"underline\"\n : \"default\";\n\n return (\n <NavLink\n key={item.href || index}\n href={item.href}\n active={item.active}\n disabled={item.disabled}\n variant={navLinkVariant}\n className={cn(\n \"flex items-center\",\n getSpacingClass(\"sm\", \"gap\"),\n orientation === \"vertical\" && \"w-full justify-start\",\n item.className,\n )}\n >\n {item.icon && (\n <span className=\"flex-shrink-0\" aria-hidden=\"true\">\n {item.icon}\n </span>\n )}\n <span>{item.label}</span>\n {item.badge && <span className=\"ml-auto\">{item.badge}</span>}\n </NavLink>\n );\n })}\n </>\n );\n\n // Bare mode: Just render content without nav wrapper\n // Useful when used inside Header.Navigation which provides the nav wrapper\n if (bare) {\n return (\n <div\n className={cn(navigationVariants({ orientation, variant }), className)}\n {...props}\n >\n {content}\n </div>\n );\n }\n\n // Normal mode: Create nav element\n return (\n <nav\n className={cn(navigationVariants({ orientation, variant }), className)}\n aria-label={ariaLabel}\n {...props}\n >\n {content}\n </nav>\n );\n}\n\n/**\n * Navigation Component (Public API)\n *\n * Wrapper that handles Next.js integration safely.\n * Always uses NavigationWithPathname which will try to auto-detect pathname.\n */\nexport function Navigation(props: NavigationProps) {\n return <NavigationWithPathname {...props} pathname={props.pathname} />;\n}\n\nexport default Navigation;\n"],"names":["navigationVariants","cva","cn","getSpacingClass","NavigationWithPathname","_a","_b","items","orientation","variant","className","ariaLabel","bare","providedPathname","props","__objRest","currentPathname","itemsWithActive","useMemo","item","isActive","__spreadProps","__spreadValues","content","jsx","Fragment","index","navLinkVariant","jsxs","NavLink","Navigation"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","sources":["../../../../../src/ui/components/PageHeader/PageHeader.tsx"],"sourcesContent":["/**\n * PageHeader Component\n *\n * Page header component with title, description, breadcrumb, and actions.\n *\n * @see EPIC-004: PageHeader Component
|
|
1
|
+
{"version":3,"file":"PageHeader.js","sources":["../../../../../src/ui/components/PageHeader/PageHeader.tsx"],"sourcesContent":["/**\n * PageHeader Component\n *\n * Page header component with title, description, breadcrumb, and actions.\n *\n * @see EPIC-004: PageHeader Component\n */\n\nimport Breadcrumb from \"../Breadcrumb/Breadcrumb\";\nimport Text from \"../../primitives/Text/Text\";\nimport type { PageHeaderProps } from \"./types\";\nimport { cn, cva } from \"../../utils\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\n\n/**\n * PageHeader Variants using CVA\n * Type-safe variant system for PageHeader component\n */\nconst pageHeaderVariants = cva(\n // Base classes\n cn(\"w-full\", \"flex\", \"flex-col\", getSpacingClass(\"sm\", \"gap\")),\n {\n variants: {\n variant: {\n default: cn(getSpacingClass(\"base\", \"mb\")),\n compact: cn(getSpacingClass(\"sm\", \"mb\")),\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\n/**\n * PageHeader Component\n *\n * Page header with title, description, breadcrumb, and actions.\n *\n * @example\n * ```tsx\n * <PageHeader\n * title=\"Page Title\"\n * description=\"Page description\"\n * breadcrumb={[\n * { label: 'Home', href: '/' },\n * { label: 'Page', href: '/page' },\n * ]}\n * actions={<Button>Action</Button>}\n * />\n * ```\n */\nexport function PageHeader({\n title,\n description,\n breadcrumb,\n actions,\n variant = \"default\",\n className,\n ...props\n}: PageHeaderProps) {\n return (\n <div className={cn(pageHeaderVariants({ variant }), className)} {...props}>\n {/* Breadcrumb */}\n {breadcrumb && breadcrumb.length > 0 && <Breadcrumb items={breadcrumb} />}\n\n {/* Title and Actions Row */}\n <div\n className={`flex items-start justify-between ${getSpacingClass(\"base\", \"gap\")}`}\n >\n {/* Title and Description */}\n <div className=\"flex-1 min-w-0\">\n <Text\n variant=\"heading\"\n as=\"h1\"\n className={`${getSpacingClass(\"sm\", \"mb\")} text-2xl font-bold`}\n >\n {title}\n </Text>\n {description && (\n <Text variant=\"body\" className=\"text-fg-secondary\">\n {description}\n </Text>\n )}\n </div>\n\n {/* Actions */}\n {actions && (\n <div\n className={`flex items-center ${getSpacingClass(\"sm\", \"gap\")} flex-shrink-0`}\n >\n {actions}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport default PageHeader;\n"],"names":["pageHeaderVariants","cva","cn","getSpacingClass","PageHeader","_a","_b","title","description","breadcrumb","actions","variant","className","props","__objRest","jsxs","__spreadProps","__spreadValues","jsx","Breadcrumb","Text"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAMA,IAAqBC;AAAA;AAAA,EAEzBC,EAAG,UAAU,QAAQ,YAAYC,EAAgB,MAAM,KAAK,CAAC;AAAA,EAC7D;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAASD,EAAGC,EAAgB,QAAQ,IAAI,CAAC;AAAA,QACzC,SAASD,EAAGC,EAAgB,MAAM,IAAI,CAAC;AAAA,MAAA;AAAA,IACzC;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;AAoBO,SAASC,EAAWC,GAQP;AARO,MAAAC,IAAAD,GACzB;AAAA,WAAAE;AAAA,IACA,aAAAC;AAAA,IACA,YAAAC;AAAA,IACA,SAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,WAAAC;AAAA,MANyBN,GAOtBO,IAAAC,EAPsBR,GAOtB;AAAA,IANH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,SACE,gBAAAS,EAAC,OAAAC,EAAAC,EAAA,EAAI,WAAWf,EAAGF,EAAmB,EAAE,SAAAW,EAAA,CAAS,GAAGC,CAAS,KAAOC,IAAnE,EAEE,UAAA;AAAA,IAAAJ,KAAcA,EAAW,SAAS,KAAK,gBAAAS,EAACC,GAAA,EAAW,OAAOV,GAAY;AAAA,IAGvE,gBAAAM;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,oCAAoCZ,EAAgB,QAAQ,KAAK,CAAC;AAAA,QAG7E,UAAA;AAAA,UAAA,gBAAAY,EAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,YAAA,gBAAAG;AAAA,cAACE;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,IAAG;AAAA,gBACH,WAAW,GAAGjB,EAAgB,MAAM,IAAI,CAAC;AAAA,gBAExC,UAAAI;AAAA,cAAA;AAAA,YAAA;AAAA,YAEFC,KACC,gBAAAU,EAACE,GAAA,EAAK,SAAQ,QAAO,WAAU,qBAC5B,UAAAZ,EAAA,CACH;AAAA,UAAA,GAEJ;AAAA,UAGCE,KACC,gBAAAQ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW,qBAAqBf,EAAgB,MAAM,KAAK,CAAC;AAAA,cAE3D,UAAAO;AAAA,YAAA;AAAA,UAAA;AAAA,QACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAEJ,IACF;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.js","sources":["../../../../../src/ui/components/Pagination/Pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { Button } from \"../../primitives\";\nimport { cn } from \"../../utils\";\nimport { getSpacingClass, getTypographySizeFromFontSize } from \"../../tokens\";\n\ninterface Props extends HTMLAttributes<HTMLDivElement> {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n totalItems?: number;\n itemsPerPage?: number;\n showPageInfo?: boolean;\n}\n\n/**\n * Pagination Component\n *\n * A pagination component for navigating through pages of data.\n
|
|
1
|
+
{"version":3,"file":"Pagination.js","sources":["../../../../../src/ui/components/Pagination/Pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { Button } from \"../../primitives\";\nimport { cn } from \"../../utils\";\nimport { getSpacingClass, getTypographySizeFromFontSize } from \"../../tokens\";\n\ninterface Props extends HTMLAttributes<HTMLDivElement> {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n totalItems?: number;\n itemsPerPage?: number;\n showPageInfo?: boolean;\n}\n\n/**\n * Pagination Component\n *\n * A pagination component for navigating through pages of data.\n *\n * @example\n * ```tsx\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * onPageChange={(page) => setPage(page)}\n * totalItems={100}\n * itemsPerPage={10}\n * />\n * ```\n */\nexport default function Pagination({\n currentPage,\n totalPages,\n onPageChange,\n totalItems,\n itemsPerPage,\n showPageInfo = true,\n className = \"\",\n ...props\n}: Props) {\n const handlePrevious = () => {\n if (currentPage > 1) {\n onPageChange(currentPage - 1);\n }\n };\n\n const handleNext = () => {\n if (currentPage < totalPages) {\n onPageChange(currentPage + 1);\n }\n };\n\n const handlePageClick = (page: number) => {\n if (page >= 1 && page <= totalPages && page !== currentPage) {\n onPageChange(page);\n }\n };\n\n const getPageNumbers = () => {\n const pages: (number | string)[] = [];\n const maxVisible = 5;\n\n if (totalPages <= maxVisible) {\n for (let i = 1; i <= totalPages; i++) {\n pages.push(i);\n }\n } else {\n if (currentPage <= 3) {\n for (let i = 1; i <= 4; i++) {\n pages.push(i);\n }\n pages.push(\"ellipsis\");\n pages.push(totalPages);\n } else if (currentPage >= totalPages - 2) {\n pages.push(1);\n pages.push(\"ellipsis\");\n for (let i = totalPages - 3; i <= totalPages; i++) {\n pages.push(i);\n }\n } else {\n pages.push(1);\n pages.push(\"ellipsis\");\n for (let i = currentPage - 1; i <= currentPage + 1; i++) {\n pages.push(i);\n }\n pages.push(\"ellipsis\");\n pages.push(totalPages);\n }\n }\n\n return pages;\n };\n\n const startItem =\n totalItems && itemsPerPage\n ? (currentPage - 1) * itemsPerPage + 1\n : undefined;\n const endItem =\n totalItems && itemsPerPage\n ? Math.min(currentPage * itemsPerPage, totalItems)\n : undefined;\n\n const classes = cn(\n \"flex\",\n \"items-center\",\n \"justify-between\",\n getSpacingClass(\"base\", \"px\"),\n getSpacingClass(\"md\", \"py\"),\n className,\n );\n\n return (\n <nav className={classes} aria-label=\"Pagination\" {...props}>\n <div className={cn(\"flex\", \"items-center\", getSpacingClass(\"sm\", \"gap\"))}>\n <Button\n variant=\"secondary\"\n onClick={handlePrevious}\n disabled={currentPage === 1}\n size=\"sm\"\n >\n Previous\n </Button>\n <div\n className={cn(\"flex\", \"items-center\", getSpacingClass(\"xs\", \"gap\"))}\n >\n {getPageNumbers().map((page, index) => {\n if (page === \"ellipsis\") {\n return (\n <span\n key={`ellipsis-${index}`}\n className={cn(\n getSpacingClass(\"sm\", \"px\"),\n \"text-fg-tertiary\",\n )}\n >\n ...\n </span>\n );\n }\n\n const pageNum = page as number;\n const isActive = pageNum === currentPage;\n\n return (\n <Button\n key={pageNum}\n variant={isActive ? \"primary\" : \"ghost\"}\n onClick={() => handlePageClick(pageNum)}\n size=\"sm\"\n aria-current={isActive ? \"page\" : undefined}\n aria-label={`Go to page ${pageNum}`}\n >\n {pageNum}\n </Button>\n );\n })}\n </div>\n <Button\n variant=\"secondary\"\n onClick={handleNext}\n disabled={currentPage === totalPages}\n size=\"sm\"\n >\n Next\n </Button>\n </div>\n {showPageInfo && totalItems && itemsPerPage && (\n <div\n className={cn(getTypographySizeFromFontSize(\"sm\"), \"text-fg-primary\")}\n >\n Showing {startItem} to {endItem} of {totalItems} results\n </div>\n )}\n </nav>\n );\n}\n"],"names":["Pagination","_a","_b","currentPage","totalPages","onPageChange","totalItems","itemsPerPage","showPageInfo","className","props","__objRest","handlePrevious","handleNext","handlePageClick","page","getPageNumbers","pages","i","startItem","endItem","classes","cn","getSpacingClass","__spreadProps","__spreadValues","jsxs","jsx","Button","index","pageNum","isActive","getTypographySizeFromFontSize"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAwBA,EAAWC,GASzB;AATyB,MAAAC,IAAAD,GACjC;AAAA,iBAAAE;AAAA,IACA,YAAAC;AAAA,IACA,cAAAC;AAAA,IACA,YAAAC;AAAA,IACA,cAAAC;AAAA,IACA,cAAAC,IAAe;AAAA,IACf,WAAAC,IAAY;AAAA,MAPqBP,GAQ9BQ,IAAAC,EAR8BT,GAQ9B;AAAA,IAPH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,QAAMU,IAAiB,MAAM;AAC3B,IAAIT,IAAc,KAChBE,EAAaF,IAAc,CAAC;AAAA,EAEhC,GAEMU,IAAa,MAAM;AACvB,IAAIV,IAAcC,KAChBC,EAAaF,IAAc,CAAC;AAAA,EAEhC,GAEMW,IAAkB,CAACC,MAAiB;AACxC,IAAIA,KAAQ,KAAKA,KAAQX,KAAcW,MAASZ,KAC9CE,EAAaU,CAAI;AAAA,EAErB,GAEMC,IAAiB,MAAM;AAC3B,UAAMC,IAA6B,CAAA;AAGnC,QAAIb,KAAc;AAChB,eAASc,IAAI,GAAGA,KAAKd,GAAYc;AAC/B,QAAAD,EAAM,KAAKC,CAAC;AAAA,aAGVf,KAAe,GAAG;AACpB,eAASe,IAAI,GAAGA,KAAK,GAAGA;AACtB,QAAAD,EAAM,KAAKC,CAAC;AAEd,MAAAD,EAAM,KAAK,UAAU,GACrBA,EAAM,KAAKb,CAAU;AAAA,IACvB,WAAWD,KAAeC,IAAa,GAAG;AACxC,MAAAa,EAAM,KAAK,CAAC,GACZA,EAAM,KAAK,UAAU;AACrB,eAASC,IAAId,IAAa,GAAGc,KAAKd,GAAYc;AAC5C,QAAAD,EAAM,KAAKC,CAAC;AAAA,IAEhB,OAAO;AACL,MAAAD,EAAM,KAAK,CAAC,GACZA,EAAM,KAAK,UAAU;AACrB,eAASC,IAAIf,IAAc,GAAGe,KAAKf,IAAc,GAAGe;AAClD,QAAAD,EAAM,KAAKC,CAAC;AAEd,MAAAD,EAAM,KAAK,UAAU,GACrBA,EAAM,KAAKb,CAAU;AAAA,IACvB;AAGF,WAAOa;AAAA,EACT,GAEME,IACJb,KAAcC,KACTJ,IAAc,KAAKI,IAAe,IACnC,QACAa,IACJd,KAAcC,IACV,KAAK,IAAIJ,IAAcI,GAAcD,CAAU,IAC/C,QAEAe,IAAUC;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACAC,EAAgB,QAAQ,IAAI;AAAA,IAC5BA,EAAgB,MAAM,IAAI;AAAA,IAC1Bd;AAAA,EAAA;AAGF,2BACG,OAAAe,EAAAC,EAAA,EAAI,WAAWJ,GAAS,cAAW,gBAAiBX,IAApD,EACC,UAAA;AAAA,IAAA,gBAAAgB,EAAC,OAAA,EAAI,WAAWJ,EAAG,QAAQ,gBAAgBC,EAAgB,MAAM,KAAK,CAAC,GACrE,UAAA;AAAA,MAAA,gBAAAI;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAShB;AAAA,UACT,UAAUT,MAAgB;AAAA,UAC1B,MAAK;AAAA,UACN,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGD,gBAAAwB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAWL,EAAG,QAAQ,gBAAgBC,EAAgB,MAAM,KAAK,CAAC;AAAA,UAEjE,UAAAP,EAAA,EAAiB,IAAI,CAACD,GAAMc,MAAU;AACrC,gBAAId,MAAS;AACX,qBACE,gBAAAY;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,WAAWL;AAAA,oBACTC,EAAgB,MAAM,IAAI;AAAA,oBAC1B;AAAA,kBAAA;AAAA,kBAEH,UAAA;AAAA,gBAAA;AAAA,gBALM,YAAYM,CAAK;AAAA,cAAA;AAW5B,kBAAMC,IAAUf,GACVgB,IAAWD,MAAY3B;AAE7B,mBACE,gBAAAwB;AAAA,cAACC;AAAA,cAAA;AAAA,gBAEC,SAASG,IAAW,YAAY;AAAA,gBAChC,SAAS,MAAMjB,EAAgBgB,CAAO;AAAA,gBACtC,MAAK;AAAA,gBACL,gBAAcC,IAAW,SAAS;AAAA,gBAClC,cAAY,cAAcD,CAAO;AAAA,gBAEhC,UAAAA;AAAA,cAAA;AAAA,cAPIA;AAAA,YAAA;AAAA,UAUX,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,MAEH,gBAAAH;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAASf;AAAA,UACT,UAAUV,MAAgBC;AAAA,UAC1B,MAAK;AAAA,UACN,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAED,GACF;AAAA,IACCI,KAAgBF,KAAcC,KAC7B,gBAAAmB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWJ,EAAGU,EAA8B,IAAI,GAAG,iBAAiB;AAAA,QACrE,UAAA;AAAA,UAAA;AAAA,UACUb;AAAA,UAAU;AAAA,UAAKC;AAAA,UAAQ;AAAA,UAAKd;AAAA,UAAW;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAClD,IAEJ;AAEJ;"}
|