@craftzbay/ui 0.10.0 → 0.11.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 +14 -8
- package/dist-lib/__tests__/helpers/color.d.ts +9 -0
- package/dist-lib/__tests__/helpers/theme.d.ts +18 -0
- package/dist-lib/components/ui/Accordion.js +18 -7
- package/dist-lib/components/ui/Accordion.js.map +1 -1
- package/dist-lib/components/ui/Alert.d.ts +16 -0
- package/dist-lib/components/ui/Alert.js +47 -34
- package/dist-lib/components/ui/Alert.js.map +1 -1
- package/dist-lib/components/ui/Avatar.d.ts +1 -1
- package/dist-lib/components/ui/Avatar.js +45 -47
- package/dist-lib/components/ui/Avatar.js.map +1 -1
- package/dist-lib/components/ui/Badge.d.ts +3 -1
- package/dist-lib/components/ui/Badge.js +24 -15
- package/dist-lib/components/ui/Badge.js.map +1 -1
- package/dist-lib/components/ui/Breadcrumbs.d.ts +2 -0
- package/dist-lib/components/ui/Breadcrumbs.js +46 -28
- package/dist-lib/components/ui/Breadcrumbs.js.map +1 -1
- package/dist-lib/components/ui/Button.d.ts +5 -3
- package/dist-lib/components/ui/Button.js +59 -45
- package/dist-lib/components/ui/Button.js.map +1 -1
- package/dist-lib/components/ui/Calendar.d.ts +1 -1
- package/dist-lib/components/ui/Calendar.js +87 -59
- package/dist-lib/components/ui/Calendar.js.map +1 -1
- package/dist-lib/components/ui/Card.d.ts +2 -0
- package/dist-lib/components/ui/Card.js +48 -67
- package/dist-lib/components/ui/Card.js.map +1 -1
- package/dist-lib/components/ui/Carousel.d.ts +6 -6
- package/dist-lib/components/ui/Carousel.js +133 -102
- package/dist-lib/components/ui/Carousel.js.map +1 -1
- package/dist-lib/components/ui/Chart.d.ts +49 -10
- package/dist-lib/components/ui/Chart.js +415 -181
- package/dist-lib/components/ui/Chart.js.map +1 -1
- package/dist-lib/components/ui/Checkbox.js +42 -28
- package/dist-lib/components/ui/Checkbox.js.map +1 -1
- package/dist-lib/components/ui/Combobox.d.ts +2 -0
- package/dist-lib/components/ui/Combobox.js +142 -111
- package/dist-lib/components/ui/Combobox.js.map +1 -1
- package/dist-lib/components/ui/CommandPalette.d.ts +6 -3
- package/dist-lib/components/ui/CommandPalette.js +92 -87
- package/dist-lib/components/ui/CommandPalette.js.map +1 -1
- package/dist-lib/components/ui/ContextMenu.d.ts +7 -2
- package/dist-lib/components/ui/ContextMenu.js +77 -62
- package/dist-lib/components/ui/ContextMenu.js.map +1 -1
- package/dist-lib/components/ui/DataGrid.d.ts +17 -4
- package/dist-lib/components/ui/DataGrid.js +65 -50
- package/dist-lib/components/ui/DataGrid.js.map +1 -1
- package/dist-lib/components/ui/DatePicker.js +118 -99
- package/dist-lib/components/ui/DatePicker.js.map +1 -1
- package/dist-lib/components/ui/DesignSystemProvider.d.ts +94 -40
- package/dist-lib/components/ui/DesignSystemProvider.js +111 -55
- package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -1
- package/dist-lib/components/ui/Dialog.d.ts +18 -3
- package/dist-lib/components/ui/Dialog.js +105 -80
- package/dist-lib/components/ui/Dialog.js.map +1 -1
- package/dist-lib/components/ui/Drawer.d.ts +17 -2
- package/dist-lib/components/ui/Drawer.js +89 -55
- package/dist-lib/components/ui/Drawer.js.map +1 -1
- package/dist-lib/components/ui/DropdownMenu.js +14 -9
- package/dist-lib/components/ui/DropdownMenu.js.map +1 -1
- package/dist-lib/components/ui/EmptyState.d.ts +2 -0
- package/dist-lib/components/ui/EmptyState.js +30 -16
- package/dist-lib/components/ui/EmptyState.js.map +1 -1
- package/dist-lib/components/ui/ErrorState.d.ts +13 -2
- package/dist-lib/components/ui/ErrorState.js +44 -23
- package/dist-lib/components/ui/ErrorState.js.map +1 -1
- package/dist-lib/components/ui/FileUpload.js +59 -56
- package/dist-lib/components/ui/FileUpload.js.map +1 -1
- package/dist-lib/components/ui/Form.d.ts +15 -2
- package/dist-lib/components/ui/Form.js +97 -71
- package/dist-lib/components/ui/Form.js.map +1 -1
- package/dist-lib/components/ui/Icon.d.ts +1 -1
- package/dist-lib/components/ui/Icon.js +20 -14
- package/dist-lib/components/ui/Icon.js.map +1 -1
- package/dist-lib/components/ui/IconButton.d.ts +2 -2
- package/dist-lib/components/ui/IconButton.js +28 -20
- package/dist-lib/components/ui/IconButton.js.map +1 -1
- package/dist-lib/components/ui/Input.d.ts +3 -1
- package/dist-lib/components/ui/Input.js +92 -78
- package/dist-lib/components/ui/Input.js.map +1 -1
- package/dist-lib/components/ui/Kbd.js +1 -1
- package/dist-lib/components/ui/Kbd.js.map +1 -1
- package/dist-lib/components/ui/MultiSelect.js +121 -107
- package/dist-lib/components/ui/MultiSelect.js.map +1 -1
- package/dist-lib/components/ui/Pagination.js +67 -62
- package/dist-lib/components/ui/Pagination.js.map +1 -1
- package/dist-lib/components/ui/Popover.js +14 -14
- package/dist-lib/components/ui/Popover.js.map +1 -1
- package/dist-lib/components/ui/Progress.d.ts +3 -3
- package/dist-lib/components/ui/Progress.js +77 -72
- package/dist-lib/components/ui/Progress.js.map +1 -1
- package/dist-lib/components/ui/RadioGroup.d.ts +1 -1
- package/dist-lib/components/ui/RadioGroup.js +69 -52
- package/dist-lib/components/ui/RadioGroup.js.map +1 -1
- package/dist-lib/components/ui/RelativeTime.d.ts +19 -0
- package/dist-lib/components/ui/RelativeTime.js +31 -0
- package/dist-lib/components/ui/RelativeTime.js.map +1 -0
- package/dist-lib/components/ui/ScrollArea.d.ts +9 -1
- package/dist-lib/components/ui/ScrollArea.js +43 -27
- package/dist-lib/components/ui/ScrollArea.js.map +1 -1
- package/dist-lib/components/ui/Select.d.ts +6 -1
- package/dist-lib/components/ui/Select.js +79 -71
- package/dist-lib/components/ui/Select.js.map +1 -1
- package/dist-lib/components/ui/Separator.js +1 -1
- package/dist-lib/components/ui/Separator.js.map +1 -1
- package/dist-lib/components/ui/Sheet.d.ts +9 -0
- package/dist-lib/components/ui/Sheet.js +69 -46
- package/dist-lib/components/ui/Sheet.js.map +1 -1
- package/dist-lib/components/ui/Sidebar.d.ts +12 -9
- package/dist-lib/components/ui/Sidebar.js +152 -109
- package/dist-lib/components/ui/Sidebar.js.map +1 -1
- package/dist-lib/components/ui/Skeleton.d.ts +13 -2
- package/dist-lib/components/ui/Skeleton.js +15 -14
- package/dist-lib/components/ui/Skeleton.js.map +1 -1
- package/dist-lib/components/ui/Slider.js +41 -29
- package/dist-lib/components/ui/Slider.js.map +1 -1
- package/dist-lib/components/ui/Snackbar.js +23 -22
- package/dist-lib/components/ui/Snackbar.js.map +1 -1
- package/dist-lib/components/ui/Spinner.js +18 -6
- package/dist-lib/components/ui/Spinner.js.map +1 -1
- package/dist-lib/components/ui/Stepper.d.ts +6 -0
- package/dist-lib/components/ui/Stepper.js +71 -48
- package/dist-lib/components/ui/Stepper.js.map +1 -1
- package/dist-lib/components/ui/Switch.js +46 -43
- package/dist-lib/components/ui/Switch.js.map +1 -1
- package/dist-lib/components/ui/Table.d.ts +33 -5
- package/dist-lib/components/ui/Table.js +141 -119
- package/dist-lib/components/ui/Table.js.map +1 -1
- package/dist-lib/components/ui/Tabs.js +50 -48
- package/dist-lib/components/ui/Tabs.js.map +1 -1
- package/dist-lib/components/ui/TagInput.js +45 -45
- package/dist-lib/components/ui/TagInput.js.map +1 -1
- package/dist-lib/components/ui/Textarea.js +65 -54
- package/dist-lib/components/ui/Textarea.js.map +1 -1
- package/dist-lib/components/ui/Timeline.js +39 -35
- package/dist-lib/components/ui/Timeline.js.map +1 -1
- package/dist-lib/components/ui/Toast.js +44 -57
- package/dist-lib/components/ui/Toast.js.map +1 -1
- package/dist-lib/components/ui/Tooltip.d.ts +4 -1
- package/dist-lib/components/ui/Tooltip.js +24 -22
- package/dist-lib/components/ui/Tooltip.js.map +1 -1
- package/dist-lib/components/ui/TopNav.d.ts +7 -3
- package/dist-lib/components/ui/TopNav.js +35 -25
- package/dist-lib/components/ui/TopNav.js.map +1 -1
- package/dist-lib/components/ui/Tree.d.ts +15 -10
- package/dist-lib/components/ui/Tree.js +82 -79
- package/dist-lib/components/ui/Tree.js.map +1 -1
- package/dist-lib/hooks/use-debounce.d.ts +19 -0
- package/dist-lib/hooks/use-debounce.js +36 -0
- package/dist-lib/hooks/use-debounce.js.map +1 -0
- package/dist-lib/hooks/use-delayed-loading.d.ts +21 -0
- package/dist-lib/hooks/use-delayed-loading.js +20 -0
- package/dist-lib/hooks/use-delayed-loading.js.map +1 -0
- package/dist-lib/hooks/use-field-ids.d.ts +2 -1
- package/dist-lib/hooks/use-field-ids.js +9 -9
- package/dist-lib/hooks/use-field-ids.js.map +1 -1
- package/dist-lib/hooks/use-media-query.d.ts +3 -1
- package/dist-lib/hooks/use-media-query.js +16 -12
- package/dist-lib/hooks/use-media-query.js.map +1 -1
- package/dist-lib/hooks/use-modifier-key.d.ts +13 -0
- package/dist-lib/hooks/use-modifier-key.js +19 -0
- package/dist-lib/hooks/use-modifier-key.js.map +1 -0
- package/dist-lib/hooks/use-toast.d.ts +7 -2
- package/dist-lib/hooks/use-toast.js +61 -30
- package/dist-lib/hooks/use-toast.js.map +1 -1
- package/dist-lib/icons/index.d.ts +9 -0
- package/dist-lib/icons/index.js +148 -130
- package/dist-lib/icons/index.js.map +1 -1
- package/dist-lib/illustrations/index.d.ts +1 -0
- package/dist-lib/illustrations/index.js +15 -6
- package/dist-lib/illustrations/index.js.map +1 -1
- package/dist-lib/index.d.ts +6 -0
- package/dist-lib/index.js +280 -260
- package/dist-lib/index.js.map +1 -1
- package/dist-lib/lib/format.d.ts +65 -0
- package/dist-lib/lib/format.js +95 -0
- package/dist-lib/lib/format.js.map +1 -0
- package/dist-lib/lib/return-focus.d.ts +11 -0
- package/dist-lib/lib/return-focus.js +12 -0
- package/dist-lib/lib/return-focus.js.map +1 -0
- package/dist-lib/lib/strings.d.ts +62 -1
- package/dist-lib/lib/strings.js +75 -19
- package/dist-lib/lib/strings.js.map +1 -1
- package/dist-lib/lib/strings.mn.js +50 -5
- package/dist-lib/lib/strings.mn.js.map +1 -1
- package/dist-lib/styles.css +1 -1
- package/dist-lib/theme.css +141 -78
- package/package.json +10 -3
|
@@ -1,69 +1,72 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs as n, jsx as t } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef as
|
|
4
|
-
import * as
|
|
5
|
-
import { Command as
|
|
6
|
-
import { X as
|
|
7
|
-
import { cn as
|
|
8
|
-
import { useStrings as
|
|
9
|
-
import { formatString as
|
|
10
|
-
import { useFieldIds as
|
|
11
|
-
const
|
|
3
|
+
import { forwardRef as Y, useState as N, useRef as O, useCallback as k, useMemo as P } from "react";
|
|
4
|
+
import * as g from "@radix-ui/react-popover";
|
|
5
|
+
import { Command as b } from "cmdk";
|
|
6
|
+
import { X as j, ChevronsUpDown as Z, Check as _ } from "../../icons/index.js";
|
|
7
|
+
import { cn as a } from "../../lib/utils.js";
|
|
8
|
+
import { useStrings as ee } from "../../hooks/use-strings.js";
|
|
9
|
+
import { formatString as te } from "../../lib/strings.js";
|
|
10
|
+
import { useFieldIds as re } from "../../hooks/use-field-ids.js";
|
|
11
|
+
const oe = Y(function({
|
|
12
12
|
options: l,
|
|
13
13
|
value: r,
|
|
14
14
|
onChange: s,
|
|
15
|
-
label:
|
|
15
|
+
label: d,
|
|
16
16
|
helperText: h,
|
|
17
17
|
error: x,
|
|
18
18
|
placeholder: B,
|
|
19
|
-
emptyText:
|
|
20
|
-
maxVisibleChips:
|
|
21
|
-
clearable:
|
|
22
|
-
disabled:
|
|
23
|
-
id:
|
|
19
|
+
emptyText: L,
|
|
20
|
+
maxVisibleChips: M = 3,
|
|
21
|
+
clearable: E = !0,
|
|
22
|
+
disabled: c,
|
|
23
|
+
id: S,
|
|
24
24
|
className: K
|
|
25
25
|
}, U) {
|
|
26
|
-
const
|
|
26
|
+
const i = ee(), z = B ?? i.multiSelect.placeholder, $ = L ?? i.multiSelect.empty, v = !!x, { fieldId: u, helperId: q, errorId: H, describedBy: Q } = re(S, {
|
|
27
27
|
hasHelper: !!h,
|
|
28
|
-
hasError:
|
|
29
|
-
}), [
|
|
30
|
-
_(() => {
|
|
31
|
-
var e;
|
|
32
|
-
a && V((e = z.current) == null ? void 0 : e.id);
|
|
33
|
-
}, [a]);
|
|
34
|
-
const b = F(() => l.filter((e) => r.includes(e.value)), [l, r]), I = O(
|
|
28
|
+
hasError: v
|
|
29
|
+
}), [f, m] = N(!1), [p, X] = N(""), C = O(null), I = O(null), [G, J] = N(void 0), T = k((e) => J(e == null ? void 0 : e.id), []), w = P(() => l.filter((e) => r.includes(e.value)), [l, r]), D = k(
|
|
35
30
|
(e) => {
|
|
36
31
|
r.includes(e) ? s(r.filter((o) => o !== e)) : s([...r, e]);
|
|
37
32
|
},
|
|
38
33
|
[r, s]
|
|
39
|
-
),
|
|
40
|
-
e.key === "Backspace" &&
|
|
41
|
-
},
|
|
42
|
-
() => l.filter((e) => e.label.toLowerCase().includes(
|
|
43
|
-
[l,
|
|
44
|
-
),
|
|
45
|
-
return /* @__PURE__ */ n("div", { ref: U, className:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
), V = k(() => s([]), [s]), W = (e) => {
|
|
35
|
+
e.key === "Backspace" && p === "" && r.length > 0 ? s(r.slice(0, -1)) : (e.key === "ArrowDown" || e.key === "ArrowUp") && !f && m(!0);
|
|
36
|
+
}, R = P(
|
|
37
|
+
() => l.filter((e) => e.label.toLowerCase().includes(p.toLowerCase())),
|
|
38
|
+
[l, p]
|
|
39
|
+
), y = w.slice(0, M), A = w.length - y.length;
|
|
40
|
+
return /* @__PURE__ */ n("div", { ref: U, className: a("flex flex-col gap-1.5", K), children: [
|
|
41
|
+
d && /* @__PURE__ */ t(
|
|
42
|
+
"label",
|
|
43
|
+
{
|
|
44
|
+
id: `${u}-label`,
|
|
45
|
+
htmlFor: u,
|
|
46
|
+
className: "text-foreground text-sm font-medium",
|
|
47
|
+
children: d
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ t(b, { shouldFilter: !1, className: "flex w-full flex-col", children: /* @__PURE__ */ n(g.Root, { open: f, onOpenChange: m, children: [
|
|
51
|
+
/* @__PURE__ */ t(g.Anchor, { asChild: !0, children: /* @__PURE__ */ n(
|
|
49
52
|
"div",
|
|
50
53
|
{
|
|
51
|
-
ref:
|
|
52
|
-
"aria-disabled":
|
|
53
|
-
className:
|
|
54
|
+
ref: I,
|
|
55
|
+
"aria-disabled": c || void 0,
|
|
56
|
+
className: a(
|
|
54
57
|
"bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm",
|
|
55
58
|
"transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
|
|
56
59
|
"focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2",
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
v ? "border-danger focus-within:border-danger focus-within:ring-danger" : "border-border-input focus-within:border-accent focus-within:ring-ring",
|
|
61
|
+
c && "pointer-events-none opacity-50"
|
|
59
62
|
),
|
|
60
63
|
onClick: () => {
|
|
61
64
|
var e;
|
|
62
|
-
(e =
|
|
65
|
+
(e = C.current) == null || e.focus(), c || m(!0);
|
|
63
66
|
},
|
|
64
67
|
children: [
|
|
65
68
|
/* @__PURE__ */ n("div", { className: "flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden", children: [
|
|
66
|
-
|
|
69
|
+
y.map((e) => /* @__PURE__ */ n(
|
|
67
70
|
"span",
|
|
68
71
|
{
|
|
69
72
|
className: "bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium",
|
|
@@ -73,70 +76,73 @@ const ne = Z(function({
|
|
|
73
76
|
"button",
|
|
74
77
|
{
|
|
75
78
|
type: "button",
|
|
76
|
-
"aria-label":
|
|
77
|
-
className: "text-on-accent-soft hover:text-foreground focus-visible:ring-ring inline-flex items-center rounded-sm outline-none focus-visible:ring-2",
|
|
79
|
+
"aria-label": te(i.multiSelect.remove, { label: e.label }),
|
|
80
|
+
className: "text-on-accent-soft hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative inline-flex items-center rounded-sm outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1",
|
|
78
81
|
onClick: (o) => {
|
|
79
|
-
o.stopPropagation(),
|
|
82
|
+
o.stopPropagation(), D(e.value);
|
|
80
83
|
},
|
|
81
|
-
children: /* @__PURE__ */ t(
|
|
84
|
+
children: /* @__PURE__ */ t(j, { className: "size-3", "aria-hidden": !0 })
|
|
82
85
|
}
|
|
83
86
|
)
|
|
84
87
|
]
|
|
85
88
|
},
|
|
86
89
|
e.value
|
|
87
90
|
)),
|
|
88
|
-
|
|
91
|
+
A > 0 && /* @__PURE__ */ n("span", { className: "bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium", children: [
|
|
89
92
|
"+",
|
|
90
|
-
|
|
93
|
+
A
|
|
91
94
|
] }),
|
|
92
95
|
/* @__PURE__ */ t(
|
|
93
96
|
"input",
|
|
94
97
|
{
|
|
95
|
-
ref:
|
|
96
|
-
id:
|
|
98
|
+
ref: C,
|
|
99
|
+
id: u,
|
|
97
100
|
type: "text",
|
|
98
101
|
autoComplete: "off",
|
|
99
|
-
value:
|
|
100
|
-
onChange: (e) =>
|
|
101
|
-
onFocus: () =>
|
|
102
|
-
onKeyDown:
|
|
103
|
-
placeholder:
|
|
102
|
+
value: p,
|
|
103
|
+
onChange: (e) => X(e.target.value),
|
|
104
|
+
onFocus: () => m(!0),
|
|
105
|
+
onKeyDown: W,
|
|
106
|
+
placeholder: y.length === 0 ? z : void 0,
|
|
104
107
|
role: "combobox",
|
|
105
|
-
"aria-expanded":
|
|
106
|
-
"aria-controls":
|
|
108
|
+
"aria-expanded": f,
|
|
109
|
+
"aria-controls": f ? G : void 0,
|
|
107
110
|
"aria-haspopup": "listbox",
|
|
108
111
|
"aria-autocomplete": "list",
|
|
109
|
-
"aria-
|
|
110
|
-
"aria-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
"aria-labelledby": d ? `${u}-label` : void 0,
|
|
113
|
+
"aria-label": d || S ? void 0 : z,
|
|
114
|
+
"aria-invalid": v || void 0,
|
|
115
|
+
"aria-describedby": Q,
|
|
116
|
+
className: "placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-lg outline-none md:text-sm",
|
|
117
|
+
disabled: c
|
|
113
118
|
}
|
|
114
119
|
)
|
|
115
120
|
] }),
|
|
116
121
|
/* @__PURE__ */ n("span", { className: "flex shrink-0 items-center gap-1 pl-1", children: [
|
|
117
|
-
|
|
122
|
+
E && w.length > 0 && /* @__PURE__ */ t(
|
|
118
123
|
"button",
|
|
119
124
|
{
|
|
120
125
|
type: "button",
|
|
121
|
-
"aria-label":
|
|
126
|
+
"aria-label": i.multiSelect.clearAll,
|
|
122
127
|
onClick: (e) => {
|
|
123
|
-
e.stopPropagation(),
|
|
128
|
+
e.stopPropagation(), V();
|
|
124
129
|
},
|
|
125
|
-
className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring rounded-sm outline-none focus-visible:ring-2",
|
|
126
|
-
children: /* @__PURE__ */ t(
|
|
130
|
+
className: "text-foreground-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background inline-flex size-6 shrink-0 items-center justify-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
131
|
+
children: /* @__PURE__ */ t(j, { className: "size-4", "aria-hidden": !0 })
|
|
127
132
|
}
|
|
128
133
|
),
|
|
129
|
-
/* @__PURE__ */ t(
|
|
134
|
+
/* @__PURE__ */ t(Z, { className: "text-foreground-subtle size-4", "aria-hidden": !0 })
|
|
130
135
|
] })
|
|
131
136
|
]
|
|
132
137
|
}
|
|
133
138
|
) }),
|
|
134
|
-
/* @__PURE__ */ t(
|
|
135
|
-
|
|
139
|
+
/* @__PURE__ */ t(g.Portal, { children: /* @__PURE__ */ t(
|
|
140
|
+
g.Content,
|
|
136
141
|
{
|
|
137
142
|
align: "start",
|
|
138
143
|
sideOffset: 4,
|
|
139
|
-
|
|
144
|
+
"aria-label": i.command.suggestions,
|
|
145
|
+
className: a(
|
|
140
146
|
"border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md",
|
|
141
147
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
142
148
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
@@ -144,53 +150,61 @@ const ne = Z(function({
|
|
|
144
150
|
),
|
|
145
151
|
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
146
152
|
onInteractOutside: (e) => {
|
|
147
|
-
var
|
|
153
|
+
var F;
|
|
148
154
|
const o = e.target;
|
|
149
|
-
o && ((
|
|
155
|
+
o && ((F = I.current) != null && F.contains(o)) && e.preventDefault();
|
|
150
156
|
},
|
|
151
|
-
children: /* @__PURE__ */ n(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
"
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
157
|
+
children: /* @__PURE__ */ n(
|
|
158
|
+
b.List,
|
|
159
|
+
{
|
|
160
|
+
ref: T,
|
|
161
|
+
label: i.command.suggestions,
|
|
162
|
+
className: "max-h-64 overflow-y-auto p-1",
|
|
163
|
+
children: [
|
|
164
|
+
R.map((e) => {
|
|
165
|
+
const o = r.includes(e.value);
|
|
166
|
+
return /* @__PURE__ */ n(
|
|
167
|
+
b.Item,
|
|
168
|
+
{
|
|
169
|
+
value: e.value,
|
|
170
|
+
disabled: e.disabled,
|
|
171
|
+
onSelect: () => D(e.value),
|
|
172
|
+
className: a(
|
|
173
|
+
"text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm",
|
|
174
|
+
"data-[selected=true]:bg-background-muted",
|
|
175
|
+
"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"
|
|
176
|
+
),
|
|
177
|
+
children: [
|
|
178
|
+
/* @__PURE__ */ t(
|
|
179
|
+
"span",
|
|
180
|
+
{
|
|
181
|
+
"aria-hidden": !0,
|
|
182
|
+
className: a(
|
|
183
|
+
"flex size-4 items-center justify-center rounded-sm border",
|
|
184
|
+
o ? "border-accent bg-accent text-on-accent" : "border-border-input"
|
|
185
|
+
),
|
|
186
|
+
children: o && /* @__PURE__ */ t(_, { className: "size-3", "aria-hidden": !0 })
|
|
187
|
+
}
|
|
173
188
|
),
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
e.
|
|
179
|
-
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
] })
|
|
189
|
+
/* @__PURE__ */ t("span", { className: "flex-1", children: e.label }),
|
|
190
|
+
e.description && /* @__PURE__ */ t("span", { className: "text-foreground-subtle text-xs", children: e.description })
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
e.value
|
|
194
|
+
);
|
|
195
|
+
}),
|
|
196
|
+
R.length === 0 && /* @__PURE__ */ t(b.Empty, { className: "text-foreground-subtle px-2 py-6 text-center text-sm", children: $ })
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
)
|
|
186
200
|
}
|
|
187
201
|
) })
|
|
188
202
|
] }) }),
|
|
189
|
-
x ? /* @__PURE__ */ t("p", { id:
|
|
203
|
+
x ? /* @__PURE__ */ t("p", { id: H, className: "text-danger-text text-xs", children: x }) : h ? /* @__PURE__ */ t("p", { id: q, className: "text-foreground-subtle text-xs", children: h }) : null
|
|
190
204
|
] });
|
|
191
205
|
});
|
|
192
|
-
|
|
206
|
+
oe.displayName = "MultiSelect";
|
|
193
207
|
export {
|
|
194
|
-
|
|
208
|
+
oe as MultiSelect
|
|
195
209
|
};
|
|
196
210
|
//# sourceMappingURL=MultiSelect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelect.js","sources":["../../../src/components/ui/MultiSelect.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Check, ChevronsUpDown, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface MultiSelectOption {\n /** Stable, unique value submitted in `onChange`. */\n value: string;\n /** Visible label shown both in the menu and in the selected chip. */\n label: string;\n /** Optional secondary text shown after the label in the menu. */\n description?: string;\n /** Disable selecting this option. */\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n /** All possible options. */\n options: MultiSelectOption[];\n /** Currently selected values. Controlled. */\n value: string[];\n /** Called whenever the selection changes. */\n onChange: (next: string[]) => void;\n /** Visible label above the field. */\n label?: ReactNode;\n /** Hint below the field. Hidden when `error` is set. */\n helperText?: ReactNode;\n /** Validation message. */\n error?: ReactNode;\n /** Empty-state placeholder shown when nothing is selected. */\n placeholder?: string;\n /** Text shown when no options match the search. */\n emptyText?: string;\n /** Max number of chips rendered inline; remainder shown as \"+N more\". */\n maxVisibleChips?: number;\n /** Whether the user can clear all selections with a single click. */\n clearable?: boolean;\n /** Disable the entire field. */\n disabled?: boolean;\n /** Consumer-supplied id for the search input (label association). */\n id?: string;\n className?: string;\n}\n\n/**\n * Chip-based multi-select with a searchable menu (cmdk under the hood).\n *\n * Keyboard:\n * - Backspace on the input with empty query removes the last chip\n * - ArrowUp / ArrowDown move the highlight, Enter toggles the highlighted option\n * - Escape closes the menu\n *\n * @example Tag picker\n * <MultiSelect label=\"Tags\"\n * options={tags}\n * value={selected}\n * onChange={setSelected}\n * placeholder=\"Pick tags\" />\n *\n * @example Bounded with overflow chip\n * <MultiSelect options={users}\n * value={value}\n * onChange={setValue}\n * maxVisibleChips={3} />\n *\n * @do Cap `maxVisibleChips` (3–5) on narrow surfaces so the field doesn't\n * reflow as the user adds selections.\n * @dont Use MultiSelect for fewer than ~6 options. CheckboxGroup is clearer.\n */\nexport const MultiSelect = forwardRef<HTMLDivElement, MultiSelectProps>(function MultiSelect(\n {\n options,\n value,\n onChange,\n label,\n helperText,\n error,\n placeholder: placeholderProp,\n emptyText: emptyTextProp,\n maxVisibleChips = 3,\n clearable = true,\n disabled,\n id,\n className,\n },\n ref,\n) {\n const strings = useStrings();\n const placeholder = placeholderProp ?? strings.multiSelect.placeholder;\n const emptyText = emptyTextProp ?? strings.multiSelect.empty;\n const isError = Boolean(error);\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: isError,\n });\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // cmdk assigns its own id to the list (ours is ignored), so read it back\n // once the portal mounts to keep aria-controls truthful.\n const listRef = useRef<HTMLDivElement>(null);\n const [listId, setListId] = useState<string | undefined>(undefined);\n useEffect(() => {\n if (open) setListId(listRef.current?.id);\n }, [open]);\n\n const selected = useMemo(() => options.filter((o) => value.includes(o.value)), [options, value]);\n\n const toggle = useCallback(\n (v: string) => {\n if (value.includes(v)) onChange(value.filter((x) => x !== v));\n else onChange([...value, v]);\n },\n [value, onChange],\n );\n\n const clear = useCallback(() => onChange([]), [onChange]);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Backspace' && query === '' && value.length > 0) {\n onChange(value.slice(0, -1));\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !open) {\n setOpen(true);\n }\n };\n\n const filtered = useMemo(\n () => options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())),\n [options, query],\n );\n\n const visibleChips = selected.slice(0, maxVisibleChips);\n const overflow = selected.length - visibleChips.length;\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label htmlFor={fieldId} className=\"text-foreground text-sm font-medium\">\n {label}\n </label>\n )}\n\n {/* The Command root wraps the whole field so cmdk's root keydown handler\n (ArrowUp/Down/Enter) sees the input even though the list is portaled.\n A plain <input> is used instead of Command.Input because cmdk forces\n its own id / aria-* on that element, breaking the label association. */}\n <CommandPrimitive shouldFilter={false} className=\"flex w-full flex-col\">\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Anchor asChild>\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- click-to-focus wrapper; the <input role=\"combobox\"> inside owns keyboard handling */}\n <div\n ref={fieldRef}\n aria-disabled={disabled || undefined}\n className={cn(\n 'bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2',\n isError\n ? 'border-danger focus-within:border-danger focus-within:ring-danger'\n : 'border-border focus-within:border-accent focus-within:ring-ring',\n disabled && 'pointer-events-none opacity-50',\n )}\n onClick={() => {\n inputRef.current?.focus();\n if (!disabled) setOpen(true);\n }}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden\">\n {visibleChips.map((opt) => (\n <span\n key={opt.value}\n className=\"bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium\"\n >\n <span className=\"truncate\" title={opt.label}>\n {opt.label}\n </span>\n <button\n type=\"button\"\n aria-label={formatString(strings.multiSelect.remove, { label: opt.label })}\n className=\"text-on-accent-soft hover:text-foreground focus-visible:ring-ring inline-flex items-center rounded-sm outline-none focus-visible:ring-2\"\n onClick={(e) => {\n e.stopPropagation();\n toggle(opt.value);\n }}\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n </span>\n ))}\n {overflow > 0 && (\n <span className=\"bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium\">\n +{overflow}\n </span>\n )}\n <input\n ref={inputRef}\n id={fieldId}\n type=\"text\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onFocus={() => setOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={visibleChips.length === 0 ? placeholder : undefined}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? listId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className=\"placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-sm outline-none\"\n disabled={disabled}\n />\n </div>\n <span className=\"flex shrink-0 items-center gap-1 pl-1\">\n {clearable && selected.length > 0 && (\n <button\n type=\"button\"\n aria-label={strings.multiSelect.clearAll}\n onClick={(e) => {\n e.stopPropagation();\n clear();\n }}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring rounded-sm outline-none focus-visible:ring-2\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n <ChevronsUpDown className=\"text-foreground-subtle size-4\" aria-hidden />\n </span>\n </div>\n </PopoverPrimitive.Anchor>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n align=\"start\"\n sideOffset={4}\n className={cn(\n 'border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n )}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onInteractOutside={(e) => {\n // Clicks inside the anchor (chips, clear) must not close the menu.\n const target = e.target as Node | null;\n if (target && fieldRef.current?.contains(target)) e.preventDefault();\n }}\n >\n <CommandPrimitive.List ref={listRef} className=\"max-h-64 overflow-y-auto p-1\">\n {filtered.map((opt) => {\n const isSelected = value.includes(opt.value);\n return (\n <CommandPrimitive.Item\n key={opt.value}\n value={opt.value}\n disabled={opt.disabled}\n onSelect={() => toggle(opt.value)}\n className={cn(\n 'text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm',\n 'data-[selected=true]:bg-background-muted',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n )}\n >\n <span\n aria-hidden\n className={cn(\n 'flex size-4 items-center justify-center rounded-sm border',\n isSelected ? 'border-accent bg-accent text-on-accent' : 'border-border',\n )}\n >\n {isSelected && <Check className=\"size-3\" aria-hidden />}\n </span>\n <span className=\"flex-1\">{opt.label}</span>\n {opt.description && (\n <span className=\"text-foreground-subtle text-xs\">{opt.description}</span>\n )}\n </CommandPrimitive.Item>\n );\n })}\n {filtered.length === 0 && (\n <CommandPrimitive.Empty className=\"text-foreground-subtle px-2 py-6 text-center text-sm\">\n {emptyText}\n </CommandPrimitive.Empty>\n )}\n </CommandPrimitive.List>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n </CommandPrimitive>\n\n {error ? (\n <p id={errorId} role=\"alert\" className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nMultiSelect.displayName = 'MultiSelect';\n"],"names":["MultiSelect","forwardRef","options","value","onChange","label","helperText","error","placeholderProp","emptyTextProp","maxVisibleChips","clearable","disabled","id","className","ref","strings","useStrings","placeholder","emptyText","isError","fieldId","helperId","errorId","describedBy","useFieldIds","open","setOpen","useState","query","setQuery","inputRef","useRef","fieldRef","listRef","listId","setListId","useEffect","_a","selected","useMemo","o","toggle","useCallback","v","x","clear","handleKeyDown","filtered","visibleChips","overflow","cn","jsx","CommandPrimitive","jsxs","PopoverPrimitive","opt","formatString","e","X","ChevronsUpDown","target","isSelected","Check"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MultiSelect.js","sources":["../../../src/components/ui/MultiSelect.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Check, ChevronsUpDown, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface MultiSelectOption {\n /** Stable, unique value submitted in `onChange`. */\n value: string;\n /** Visible label shown both in the menu and in the selected chip. */\n label: string;\n /** Optional secondary text shown after the label in the menu. */\n description?: string;\n /** Disable selecting this option. */\n disabled?: boolean;\n}\n\nexport interface MultiSelectProps {\n /** All possible options. */\n options: MultiSelectOption[];\n /** Currently selected values. Controlled. */\n value: string[];\n /** Called whenever the selection changes. */\n onChange: (next: string[]) => void;\n /** Visible label above the field. */\n label?: ReactNode;\n /** Hint below the field. Hidden when `error` is set. */\n helperText?: ReactNode;\n /** Validation message. */\n error?: ReactNode;\n /** Empty-state placeholder shown when nothing is selected. */\n placeholder?: string;\n /** Text shown when no options match the search. */\n emptyText?: string;\n /** Max number of chips rendered inline; remainder shown as \"+N more\". */\n maxVisibleChips?: number;\n /** Whether the user can clear all selections with a single click. */\n clearable?: boolean;\n /** Disable the entire field. */\n disabled?: boolean;\n /** Consumer-supplied id for the search input (label association). */\n id?: string;\n className?: string;\n}\n\n/**\n * Chip-based multi-select with a searchable menu (cmdk under the hood).\n *\n * Keyboard:\n * - Backspace on the input with empty query removes the last chip\n * - ArrowUp / ArrowDown move the highlight, Enter toggles the highlighted option\n * - Escape closes the menu\n *\n * @example Tag picker\n * <MultiSelect label=\"Tags\"\n * options={tags}\n * value={selected}\n * onChange={setSelected}\n * placeholder=\"Pick tags\" />\n *\n * @example Bounded with overflow chip\n * <MultiSelect options={users}\n * value={value}\n * onChange={setValue}\n * maxVisibleChips={3} />\n *\n * @do Cap `maxVisibleChips` (3–5) on narrow surfaces so the field doesn't\n * reflow as the user adds selections.\n * @dont Use MultiSelect for fewer than ~6 options. CheckboxGroup is clearer.\n */\nexport const MultiSelect = forwardRef<HTMLDivElement, MultiSelectProps>(function MultiSelect(\n {\n options,\n value,\n onChange,\n label,\n helperText,\n error,\n placeholder: placeholderProp,\n emptyText: emptyTextProp,\n maxVisibleChips = 3,\n clearable = true,\n disabled,\n id,\n className,\n },\n ref,\n) {\n const strings = useStrings();\n const placeholder = placeholderProp ?? strings.multiSelect.placeholder;\n const emptyText = emptyTextProp ?? strings.multiSelect.empty;\n const isError = Boolean(error);\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: isError,\n });\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // cmdk assigns its own id to the list (ours is ignored), so read it back\n // from the node once the portal mounts to keep aria-controls truthful.\n const [listId, setListId] = useState<string | undefined>(undefined);\n const listRef = useCallback((el: HTMLDivElement | null) => setListId(el?.id), []);\n\n const selected = useMemo(() => options.filter((o) => value.includes(o.value)), [options, value]);\n\n const toggle = useCallback(\n (v: string) => {\n if (value.includes(v)) onChange(value.filter((x) => x !== v));\n else onChange([...value, v]);\n },\n [value, onChange],\n );\n\n const clear = useCallback(() => onChange([]), [onChange]);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Backspace' && query === '' && value.length > 0) {\n onChange(value.slice(0, -1));\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !open) {\n setOpen(true);\n }\n };\n\n const filtered = useMemo(\n () => options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())),\n [options, query],\n );\n\n const visibleChips = selected.slice(0, maxVisibleChips);\n const overflow = selected.length - visibleChips.length;\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n id={`${fieldId}-label`}\n htmlFor={fieldId}\n className=\"text-foreground text-sm font-medium\"\n >\n {label}\n </label>\n )}\n\n {/* The Command root wraps the whole field so cmdk's root keydown handler\n (ArrowUp/Down/Enter) sees the input even though the list is portaled.\n A plain <input> is used instead of Command.Input because cmdk forces\n its own id / aria-* on that element, breaking the label association. */}\n <CommandPrimitive shouldFilter={false} className=\"flex w-full flex-col\">\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Anchor asChild>\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- click-to-focus wrapper; the <input role=\"combobox\"> inside owns keyboard handling */}\n <div\n ref={fieldRef}\n aria-disabled={disabled || undefined}\n className={cn(\n 'bg-card flex h-9 w-full cursor-text items-center gap-1.5 overflow-hidden rounded-md border px-2 py-1 text-sm',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2',\n isError\n ? 'border-danger focus-within:border-danger focus-within:ring-danger'\n : 'border-border-input focus-within:border-accent focus-within:ring-ring',\n disabled && 'pointer-events-none opacity-50',\n )}\n onClick={() => {\n inputRef.current?.focus();\n if (!disabled) setOpen(true);\n }}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden\">\n {visibleChips.map((opt) => (\n <span\n key={opt.value}\n className=\"bg-accent-soft text-on-accent-soft inline-flex max-w-[10rem] shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium\"\n >\n <span className=\"truncate\" title={opt.label}>\n {opt.label}\n </span>\n <button\n type=\"button\"\n aria-label={formatString(strings.multiSelect.remove, { label: opt.label })}\n className=\"text-on-accent-soft hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative inline-flex items-center rounded-sm outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1\"\n onClick={(e) => {\n e.stopPropagation();\n toggle(opt.value);\n }}\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n </span>\n ))}\n {overflow > 0 && (\n <span className=\"bg-background-muted text-foreground-muted shrink-0 rounded-md px-1.5 py-0.5 text-xs font-medium\">\n +{overflow}\n </span>\n )}\n <input\n ref={inputRef}\n id={fieldId}\n type=\"text\"\n autoComplete=\"off\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onFocus={() => setOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={visibleChips.length === 0 ? placeholder : undefined}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? listId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n // Unlabelled field: name the input after the placeholder. A\n // consumer `id` implies an external <label htmlFor>.\n aria-labelledby={label ? `${fieldId}-label` : undefined}\n aria-label={label || id ? undefined : placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className=\"placeholder:text-foreground-subtle min-w-[6ch] flex-1 bg-transparent text-lg outline-none md:text-sm\"\n disabled={disabled}\n />\n </div>\n <span className=\"flex shrink-0 items-center gap-1 pl-1\">\n {clearable && selected.length > 0 && (\n <button\n type=\"button\"\n aria-label={strings.multiSelect.clearAll}\n onClick={(e) => {\n e.stopPropagation();\n clear();\n }}\n className=\"text-foreground-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background inline-flex size-6 shrink-0 items-center justify-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-2\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n )}\n <ChevronsUpDown className=\"text-foreground-subtle size-4\" aria-hidden />\n </span>\n </div>\n </PopoverPrimitive.Anchor>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n align=\"start\"\n sideOffset={4}\n // Radix gives the content role=\"dialog\"; a dialog needs a name.\n aria-label={strings.command.suggestions}\n className={cn(\n 'border-border bg-popover text-popover-foreground z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-lg border shadow-md',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n )}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onInteractOutside={(e) => {\n // Clicks inside the anchor (chips, clear) must not close the menu.\n const target = e.target as Node | null;\n if (target && fieldRef.current?.contains(target)) e.preventDefault();\n }}\n >\n <CommandPrimitive.List\n ref={listRef}\n label={strings.command.suggestions}\n className=\"max-h-64 overflow-y-auto p-1\"\n >\n {filtered.map((opt) => {\n const isSelected = value.includes(opt.value);\n return (\n <CommandPrimitive.Item\n key={opt.value}\n value={opt.value}\n disabled={opt.disabled}\n onSelect={() => toggle(opt.value)}\n className={cn(\n 'text-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm',\n 'data-[selected=true]:bg-background-muted',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n )}\n >\n <span\n aria-hidden\n className={cn(\n 'flex size-4 items-center justify-center rounded-sm border',\n isSelected\n ? 'border-accent bg-accent text-on-accent'\n : 'border-border-input',\n )}\n >\n {isSelected && <Check className=\"size-3\" aria-hidden />}\n </span>\n <span className=\"flex-1\">{opt.label}</span>\n {opt.description && (\n <span className=\"text-foreground-subtle text-xs\">{opt.description}</span>\n )}\n </CommandPrimitive.Item>\n );\n })}\n {filtered.length === 0 && (\n <CommandPrimitive.Empty className=\"text-foreground-subtle px-2 py-6 text-center text-sm\">\n {emptyText}\n </CommandPrimitive.Empty>\n )}\n </CommandPrimitive.List>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n </CommandPrimitive>\n\n {error ? (\n <p id={errorId} className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nMultiSelect.displayName = 'MultiSelect';\n"],"names":["MultiSelect","forwardRef","options","value","onChange","label","helperText","error","placeholderProp","emptyTextProp","maxVisibleChips","clearable","disabled","id","className","ref","strings","useStrings","placeholder","emptyText","isError","fieldId","helperId","errorId","describedBy","useFieldIds","open","setOpen","useState","query","setQuery","inputRef","useRef","fieldRef","listId","setListId","listRef","useCallback","el","selected","useMemo","o","toggle","v","x","clear","handleKeyDown","filtered","visibleChips","overflow","cn","jsx","CommandPrimitive","jsxs","PopoverPrimitive","_a","opt","formatString","e","X","ChevronsUpDown","target","isSelected","Check"],"mappings":";;;;;;;;;;AAmFO,MAAMA,KAAcC,EAA6C,SACtE;AAAA,EACE,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,YAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAaC;AAAA,EACb,WAAWC;AAAA,EACX,iBAAAC,IAAkB;AAAA,EAClB,WAAAC,IAAY;AAAA,EACZ,UAAAC;AAAA,EACA,IAAAC;AAAA,EACA,WAAAC;AACF,GACAC,GACA;AACA,QAAMC,IAAUC,GAAA,GACVC,IAAcV,KAAmBQ,EAAQ,YAAY,aACrDG,IAAYV,KAAiBO,EAAQ,YAAY,OACjDI,IAAU,EAAQb,GAClB,EAAE,SAAAc,GAAS,UAAAC,GAAU,SAAAC,GAAS,aAAAC,EAAA,IAAgBC,GAAYZ,GAAI;AAAA,IAClE,WAAW,EAAQP;AAAA,IACnB,UAAUc;AAAA,EAAA,CACX,GAEK,CAACM,GAAMC,CAAO,IAAIC,EAAS,EAAK,GAChC,CAACC,GAAOC,CAAQ,IAAIF,EAAS,EAAE,GAC/BG,IAAWC,EAAyB,IAAI,GACxCC,IAAWD,EAAuB,IAAI,GAGtC,CAACE,GAAQC,CAAS,IAAIP,EAA6B,MAAS,GAC5DQ,IAAUC,EAAY,CAACC,MAA8BH,EAAUG,KAAA,gBAAAA,EAAI,EAAE,GAAG,EAAE,GAE1EC,IAAWC,EAAQ,MAAMtC,EAAQ,OAAO,CAACuC,MAAMtC,EAAM,SAASsC,EAAE,KAAK,CAAC,GAAG,CAACvC,GAASC,CAAK,CAAC,GAEzFuC,IAASL;AAAA,IACb,CAACM,MAAc;AACb,MAAIxC,EAAM,SAASwC,CAAC,IAAGvC,EAASD,EAAM,OAAO,CAACyC,MAAMA,MAAMD,CAAC,CAAC,IACvDvC,EAAS,CAAC,GAAGD,GAAOwC,CAAC,CAAC;AAAA,IAC7B;AAAA,IACA,CAACxC,GAAOC,CAAQ;AAAA,EAAA,GAGZyC,IAAQR,EAAY,MAAMjC,EAAS,CAAA,CAAE,GAAG,CAACA,CAAQ,CAAC,GAElD0C,IAAgB,CAAC,MAAuC;AAC5D,IAAI,EAAE,QAAQ,eAAejB,MAAU,MAAM1B,EAAM,SAAS,IAC1DC,EAASD,EAAM,MAAM,GAAG,EAAE,CAAC,KACjB,EAAE,QAAQ,eAAe,EAAE,QAAQ,cAAc,CAACuB,KAC5DC,EAAQ,EAAI;AAAA,EAEhB,GAEMoB,IAAWP;AAAA,IACf,MAAMtC,EAAQ,OAAO,CAACuC,MAAMA,EAAE,MAAM,YAAA,EAAc,SAASZ,EAAM,YAAA,CAAa,CAAC;AAAA,IAC/E,CAAC3B,GAAS2B,CAAK;AAAA,EAAA,GAGXmB,IAAeT,EAAS,MAAM,GAAG7B,CAAe,GAChDuC,IAAWV,EAAS,SAASS,EAAa;AAEhD,2BACG,OAAA,EAAI,KAAAjC,GAAU,WAAWmC,EAAG,yBAAyBpC,CAAS,GAC5D,UAAA;AAAA,IAAAT,KACC,gBAAA8C;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAI,GAAG9B,CAAO;AAAA,QACd,SAASA;AAAA,QACT,WAAU;AAAA,QAET,UAAAhB;AAAA,MAAA;AAAA,IAAA;AAAA,IAQL,gBAAA8C,EAACC,GAAA,EAAiB,cAAc,IAAO,WAAU,wBAC/C,UAAA,gBAAAC,EAACC,EAAiB,MAAjB,EAAsB,MAAA5B,GAAY,cAAcC,GAC/C,UAAA;AAAA,MAAA,gBAAAwB,EAACG,EAAiB,QAAjB,EAAwB,SAAO,IAE9B,UAAA,gBAAAD;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,KAAKpB;AAAA,UACL,iBAAerB,KAAY;AAAA,UAC3B,WAAWsC;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA9B,IACI,sEACA;AAAA,YACJR,KAAY;AAAA,UAAA;AAAA,UAEd,SAAS,MAAM;;AACb,aAAA2C,IAAAxB,EAAS,YAAT,QAAAwB,EAAkB,SACb3C,KAAUe,EAAQ,EAAI;AAAA,UAC7B;AAAA,UAEA,UAAA;AAAA,YAAA,gBAAA0B,EAAC,OAAA,EAAI,WAAU,4DACZ,UAAA;AAAA,cAAAL,EAAa,IAAI,CAACQ,MACjB,gBAAAH;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,WAAU;AAAA,kBAEV,UAAA;AAAA,oBAAA,gBAAAF,EAAC,UAAK,WAAU,YAAW,OAAOK,EAAI,OACnC,YAAI,MAAA,CACP;AAAA,oBACA,gBAAAL;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,MAAK;AAAA,wBACL,cAAYM,GAAazC,EAAQ,YAAY,QAAQ,EAAE,OAAOwC,EAAI,OAAO;AAAA,wBACzE,WAAU;AAAA,wBACV,SAAS,CAACE,MAAM;AACd,0BAAAA,EAAE,gBAAA,GACFhB,EAAOc,EAAI,KAAK;AAAA,wBAClB;AAAA,wBAEA,UAAA,gBAAAL,EAACQ,GAAA,EAAE,WAAU,UAAS,eAAW,GAAA,CAAC;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACpC;AAAA,gBAAA;AAAA,gBAhBKH,EAAI;AAAA,cAAA,CAkBZ;AAAA,cACAP,IAAW,KACV,gBAAAI,EAAC,QAAA,EAAK,WAAU,mGAAkG,UAAA;AAAA,gBAAA;AAAA,gBAC9GJ;AAAA,cAAA,GACJ;AAAA,cAEF,gBAAAE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,KAAKpB;AAAA,kBACL,IAAIV;AAAA,kBACJ,MAAK;AAAA,kBACL,cAAa;AAAA,kBACb,OAAOQ;AAAA,kBACP,UAAU,CAAC,MAAMC,EAAS,EAAE,OAAO,KAAK;AAAA,kBACxC,SAAS,MAAMH,EAAQ,EAAI;AAAA,kBAC3B,WAAWmB;AAAA,kBACX,aAAaE,EAAa,WAAW,IAAI9B,IAAc;AAAA,kBACvD,MAAK;AAAA,kBACL,iBAAeQ;AAAA,kBACf,iBAAeA,IAAOQ,IAAS;AAAA,kBAC/B,iBAAc;AAAA,kBACd,qBAAkB;AAAA,kBAGlB,mBAAiB7B,IAAQ,GAAGgB,CAAO,WAAW;AAAA,kBAC9C,cAAYhB,KAASQ,IAAK,SAAYK;AAAA,kBACtC,gBAAcE,KAAW;AAAA,kBACzB,oBAAkBI;AAAA,kBAClB,WAAU;AAAA,kBACV,UAAAZ;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF,GACF;AAAA,YACA,gBAAAyC,EAAC,QAAA,EAAK,WAAU,yCACb,UAAA;AAAA,cAAA1C,KAAa4B,EAAS,SAAS,KAC9B,gBAAAY;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAYnC,EAAQ,YAAY;AAAA,kBAChC,SAAS,CAAC,MAAM;AACd,sBAAE,gBAAA,GACF6B,EAAA;AAAA,kBACF;AAAA,kBACA,WAAU;AAAA,kBAEV,UAAA,gBAAAM,EAACQ,GAAA,EAAE,WAAU,UAAS,eAAW,GAAA,CAAC;AAAA,gBAAA;AAAA,cAAA;AAAA,cAGtC,gBAAAR,EAACS,GAAA,EAAe,WAAU,iCAAgC,eAAW,GAAA,CAAC;AAAA,YAAA,EAAA,CACxE;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA,GAEJ;AAAA,MAEA,gBAAAT,EAACG,EAAiB,QAAjB,EACC,UAAA,gBAAAH;AAAA,QAACG,EAAiB;AAAA,QAAjB;AAAA,UACC,OAAM;AAAA,UACN,YAAY;AAAA,UAEZ,cAAYtC,EAAQ,QAAQ;AAAA,UAC5B,WAAWkC;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,UAEF,iBAAiB,CAAC,MAAM,EAAE,eAAA;AAAA,UAC1B,mBAAmB,CAAC,MAAM;;AAExB,kBAAMW,IAAS,EAAE;AACjB,YAAIA,OAAUN,IAAAtB,EAAS,YAAT,QAAAsB,EAAkB,SAASM,SAAW,eAAA;AAAA,UACtD;AAAA,UAEA,UAAA,gBAAAR;AAAA,YAACD,EAAiB;AAAA,YAAjB;AAAA,cACC,KAAKhB;AAAA,cACL,OAAOpB,EAAQ,QAAQ;AAAA,cACvB,WAAU;AAAA,cAET,UAAA;AAAA,gBAAA+B,EAAS,IAAI,CAACS,MAAQ;AACrB,wBAAMM,IAAa3D,EAAM,SAASqD,EAAI,KAAK;AAC3C,yBACE,gBAAAH;AAAA,oBAACD,EAAiB;AAAA,oBAAjB;AAAA,sBAEC,OAAOI,EAAI;AAAA,sBACX,UAAUA,EAAI;AAAA,sBACd,UAAU,MAAMd,EAAOc,EAAI,KAAK;AAAA,sBAChC,WAAWN;AAAA,wBACT;AAAA,wBACA;AAAA,wBACA;AAAA,sBAAA;AAAA,sBAGF,UAAA;AAAA,wBAAA,gBAAAC;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BACC,eAAW;AAAA,4BACX,WAAWD;AAAA,8BACT;AAAA,8BACAY,IACI,2CACA;AAAA,4BAAA;AAAA,4BAGL,eAAc,gBAAAX,EAACY,GAAA,EAAM,WAAU,UAAS,eAAW,GAAA,CAAC;AAAA,0BAAA;AAAA,wBAAA;AAAA,wBAEvD,gBAAAZ,EAAC,QAAA,EAAK,WAAU,UAAU,YAAI,OAAM;AAAA,wBACnCK,EAAI,eACH,gBAAAL,EAAC,UAAK,WAAU,kCAAkC,YAAI,YAAA,CAAY;AAAA,sBAAA;AAAA,oBAAA;AAAA,oBAvB/DK,EAAI;AAAA,kBAAA;AAAA,gBA2Bf,CAAC;AAAA,gBACAT,EAAS,WAAW,KACnB,gBAAAI,EAACC,EAAiB,OAAjB,EAAuB,WAAU,wDAC/B,UAAAjC,EAAA,CACH;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QAEJ;AAAA,MAAA,EACF,CACF;AAAA,IAAA,EAAA,CACF,EAAA,CACF;AAAA,IAECZ,IACC,gBAAA4C,EAAC,KAAA,EAAE,IAAI5B,GAAS,WAAU,4BACvB,UAAAhB,EAAA,CACH,IACED,sBACD,KAAA,EAAE,IAAIgB,GAAU,WAAU,kCACxB,aACH,IACE;AAAA,EAAA,GACN;AAEJ,CAAC;AAEDtB,GAAY,cAAc;"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { forwardRef as
|
|
4
|
-
import { ChevronsLeft as
|
|
2
|
+
import { jsxs as d, jsx as i } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as A, useId as B, useMemo as E } from "react";
|
|
4
|
+
import { ChevronsLeft as T, ChevronLeft as V, ChevronRight as _, ChevronsRight as $ } from "../../icons/index.js";
|
|
5
5
|
import { cn as g } from "../../lib/utils.js";
|
|
6
|
-
import { useStrings as
|
|
7
|
-
import { defaultStrings as
|
|
8
|
-
import { Select as
|
|
9
|
-
function
|
|
6
|
+
import { useStrings as q } from "../../hooks/use-strings.js";
|
|
7
|
+
import { defaultStrings as z, formatString as h } from "../../lib/strings.js";
|
|
8
|
+
import { Select as D, SelectTrigger as G, SelectContent as H, SelectItem as K } from "./Select.js";
|
|
9
|
+
function y(r) {
|
|
10
10
|
return {
|
|
11
|
-
showing: (e,
|
|
11
|
+
showing: (e, t, c) => h(r.showing, { from: e, to: t, total: c }),
|
|
12
12
|
rowsPerPage: r.rowsPerPage,
|
|
13
13
|
first: r.first,
|
|
14
14
|
last: r.last,
|
|
@@ -19,61 +19,61 @@ function p(r) {
|
|
|
19
19
|
nav: r.nav
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
22
|
+
const ee = y(
|
|
23
|
+
z.pagination
|
|
24
24
|
);
|
|
25
|
-
function
|
|
26
|
-
if (e <=
|
|
27
|
-
const c = 1,
|
|
28
|
-
|
|
29
|
-
for (let l =
|
|
30
|
-
return
|
|
25
|
+
function Q(r, e, t = 7) {
|
|
26
|
+
if (e <= t) return Array.from({ length: e }, (l, f) => f + 1);
|
|
27
|
+
const c = 1, s = [], a = Math.max(2, r - c), u = Math.min(e - 1, r + c);
|
|
28
|
+
s.push(1), a > 2 && s.push("gap");
|
|
29
|
+
for (let l = a; l <= u; l++) s.push(l);
|
|
30
|
+
return u < e - 1 && s.push("gap"), s.push(e), s;
|
|
31
31
|
}
|
|
32
|
-
const
|
|
32
|
+
const U = A(function({
|
|
33
33
|
page: e,
|
|
34
|
-
pageCount:
|
|
34
|
+
pageCount: t,
|
|
35
35
|
onPageChange: c,
|
|
36
|
-
totalItems:
|
|
37
|
-
pageSize:
|
|
38
|
-
pageSizeOptions:
|
|
36
|
+
totalItems: s,
|
|
37
|
+
pageSize: a,
|
|
38
|
+
pageSizeOptions: u,
|
|
39
39
|
onPageSizeChange: l,
|
|
40
|
-
showJump:
|
|
41
|
-
labels:
|
|
42
|
-
className:
|
|
43
|
-
"aria-label":
|
|
44
|
-
...
|
|
45
|
-
},
|
|
46
|
-
const
|
|
47
|
-
n < 1 || n >
|
|
40
|
+
showJump: f = !0,
|
|
41
|
+
labels: P,
|
|
42
|
+
className: j,
|
|
43
|
+
"aria-label": C,
|
|
44
|
+
...L
|
|
45
|
+
}, M) {
|
|
46
|
+
const R = q(), o = { ...y(R.pagination), ...P }, v = B(), S = E(() => Q(e, t), [e, t]), x = !s || t <= 0, N = a === void 0 ? void 0 : x ? 0 : (e - 1) * a + 1, p = a === void 0 || s === void 0 ? void 0 : x ? 0 : Math.min(e * a, s), k = e <= 1 || t <= 0, w = e >= t, m = (n) => {
|
|
47
|
+
n < 1 || n > t || n === e || c(n);
|
|
48
48
|
};
|
|
49
|
-
return /* @__PURE__ */
|
|
49
|
+
return /* @__PURE__ */ d(
|
|
50
50
|
"nav",
|
|
51
51
|
{
|
|
52
|
-
ref:
|
|
53
|
-
"aria-label":
|
|
54
|
-
className: g("flex flex-wrap items-center justify-between gap-3",
|
|
55
|
-
...
|
|
52
|
+
ref: M,
|
|
53
|
+
"aria-label": C ?? o.nav,
|
|
54
|
+
className: g("flex flex-wrap items-center justify-between gap-3", j),
|
|
55
|
+
...L,
|
|
56
56
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
/* @__PURE__ */ d("div", { className: "text-foreground-muted flex items-center gap-3 text-sm", children: [
|
|
58
|
+
s !== void 0 && a !== void 0 && N !== void 0 && p !== void 0 && /* @__PURE__ */ i("span", { className: "tabular", children: o.showing(N, p, s) }),
|
|
59
|
+
u && l && a !== void 0 && /* @__PURE__ */ d("div", { className: "flex items-center gap-2", children: [
|
|
60
60
|
/* @__PURE__ */ i("label", { htmlFor: v, className: "sr-only", children: o.rowsPerPage }),
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
/* @__PURE__ */ i(
|
|
63
|
-
/* @__PURE__ */ i(
|
|
61
|
+
/* @__PURE__ */ d(D, { value: String(a), onValueChange: (n) => l(Number(n)), children: [
|
|
62
|
+
/* @__PURE__ */ i(G, { id: v, size: "sm", className: "w-[7.5rem] whitespace-nowrap" }),
|
|
63
|
+
/* @__PURE__ */ i(H, { children: u.map((n) => /* @__PURE__ */ i(K, { value: String(n), children: o.perPage(n) }, n)) })
|
|
64
64
|
] })
|
|
65
65
|
] })
|
|
66
66
|
] }),
|
|
67
|
-
/* @__PURE__ */
|
|
68
|
-
|
|
67
|
+
/* @__PURE__ */ d("ul", { className: "flex items-center gap-1", children: [
|
|
68
|
+
f && /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
|
|
69
69
|
"button",
|
|
70
70
|
{
|
|
71
71
|
type: "button",
|
|
72
72
|
"aria-label": o.first,
|
|
73
|
-
disabled:
|
|
74
|
-
onClick: () =>
|
|
73
|
+
disabled: k,
|
|
74
|
+
onClick: () => m(1),
|
|
75
75
|
className: b,
|
|
76
|
-
children: /* @__PURE__ */ i(
|
|
76
|
+
children: /* @__PURE__ */ i(T, { className: "size-4", "aria-hidden": !0 })
|
|
77
77
|
}
|
|
78
78
|
) }),
|
|
79
79
|
/* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
|
|
@@ -81,20 +81,25 @@ const H = R(function({
|
|
|
81
81
|
{
|
|
82
82
|
type: "button",
|
|
83
83
|
"aria-label": o.prev,
|
|
84
|
-
disabled:
|
|
85
|
-
onClick: () =>
|
|
84
|
+
disabled: k,
|
|
85
|
+
onClick: () => m(e - 1),
|
|
86
86
|
className: b,
|
|
87
|
-
children: /* @__PURE__ */ i(
|
|
87
|
+
children: /* @__PURE__ */ i(V, { className: "size-4", "aria-hidden": !0 })
|
|
88
88
|
}
|
|
89
89
|
) }),
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
/* @__PURE__ */ d("li", { className: "tabular text-foreground-muted px-2 text-sm sm:hidden", "aria-current": "page", children: [
|
|
91
|
+
e,
|
|
92
|
+
" / ",
|
|
93
|
+
t
|
|
94
|
+
] }),
|
|
95
|
+
S.map(
|
|
96
|
+
(n, F) => n === "gap" ? /* @__PURE__ */ i("li", { className: "text-foreground-subtle hidden px-2 sm:block", children: "…" }, `gap-${F}`) : /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
|
|
92
97
|
"button",
|
|
93
98
|
{
|
|
94
99
|
type: "button",
|
|
95
100
|
"aria-label": o.page(n),
|
|
96
101
|
"aria-current": n === e ? "page" : void 0,
|
|
97
|
-
onClick: () =>
|
|
102
|
+
onClick: () => m(n),
|
|
98
103
|
className: g(
|
|
99
104
|
"tabular inline-flex size-8 items-center justify-center rounded-md text-sm outline-none",
|
|
100
105
|
"transition-colors duration-[var(--duration-fast)]",
|
|
@@ -110,21 +115,21 @@ const H = R(function({
|
|
|
110
115
|
{
|
|
111
116
|
type: "button",
|
|
112
117
|
"aria-label": o.next,
|
|
113
|
-
disabled:
|
|
114
|
-
onClick: () =>
|
|
118
|
+
disabled: w,
|
|
119
|
+
onClick: () => m(e + 1),
|
|
115
120
|
className: b,
|
|
116
|
-
children: /* @__PURE__ */ i(
|
|
121
|
+
children: /* @__PURE__ */ i(_, { className: "size-4", "aria-hidden": !0 })
|
|
117
122
|
}
|
|
118
123
|
) }),
|
|
119
|
-
|
|
124
|
+
f && /* @__PURE__ */ i("li", { className: "hidden sm:block", children: /* @__PURE__ */ i(
|
|
120
125
|
"button",
|
|
121
126
|
{
|
|
122
127
|
type: "button",
|
|
123
128
|
"aria-label": o.last,
|
|
124
|
-
disabled:
|
|
125
|
-
onClick: () =>
|
|
129
|
+
disabled: w,
|
|
130
|
+
onClick: () => m(t),
|
|
126
131
|
className: b,
|
|
127
|
-
children: /* @__PURE__ */ i(
|
|
132
|
+
children: /* @__PURE__ */ i($, { className: "size-4", "aria-hidden": !0 })
|
|
128
133
|
}
|
|
129
134
|
) })
|
|
130
135
|
] })
|
|
@@ -132,7 +137,7 @@ const H = R(function({
|
|
|
132
137
|
}
|
|
133
138
|
);
|
|
134
139
|
});
|
|
135
|
-
|
|
140
|
+
U.displayName = "Pagination";
|
|
136
141
|
const b = g(
|
|
137
142
|
"inline-flex size-8 items-center justify-center rounded-md text-foreground-muted",
|
|
138
143
|
"transition-colors duration-[var(--duration-fast)]",
|
|
@@ -141,8 +146,8 @@ const b = g(
|
|
|
141
146
|
"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
142
147
|
);
|
|
143
148
|
export {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
U as Pagination,
|
|
150
|
+
ee as defaultPaginationLabels,
|
|
151
|
+
y as paginationLabelsFromStrings
|
|
147
152
|
};
|
|
148
153
|
//# sourceMappingURL=Pagination.js.map
|