@apliteni/apliteni-ui 0.26.0 → 0.30.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 +2 -2
- package/package.json +1 -1
- package/react/README.md +111 -2
- package/react/dist/index.css +11 -13
- package/react/dist/index.d.ts +111 -4
- package/react/dist/index.js +811 -167
- package/src/components/back.js +57 -0
- package/src/components/command-palette.js +597 -0
- package/src/components/confirm.js +3 -2
- package/src/components/drawer.js +31 -2
- package/src/components/dropdown.js +192 -17
- package/src/components/feedback.js +2 -2
- package/src/components/index.js +5 -2
- package/src/components/loading.js +3 -2
- package/src/components/nav.js +15 -7
- package/src/components/overlay.js +67 -14
- package/src/components/pagination.js +344 -0
- package/src/components/shell.js +11 -2
- package/src/components/tabs.js +7 -1
- package/src/components/tooltip.js +237 -0
- package/src/components/topbar.js +9 -4
- package/src/index.css +4 -0
- package/src/index.js +4 -0
- package/src/inline.js +8 -0
- package/src/motion.js +43 -2
- package/src/styles/back.css +42 -0
- package/src/styles/badge.css +5 -7
- package/src/styles/base.css +8 -7
- package/src/styles/button.css +14 -0
- package/src/styles/card.css +12 -8
- package/src/styles/code.css +3 -4
- package/src/styles/command-palette.css +321 -0
- package/src/styles/confirm.css +11 -11
- package/src/styles/drawer.css +57 -15
- package/src/styles/dropdown.css +70 -11
- package/src/styles/feedback.css +2 -0
- package/src/styles/footer.css +3 -4
- package/src/styles/input.css +7 -1
- package/src/styles/layout.css +3 -2
- package/src/styles/loading.css +5 -0
- package/src/styles/nav.css +12 -8
- package/src/styles/pagination.css +124 -0
- package/src/styles/success.css +3 -2
- package/src/styles/table.css +4 -5
- package/src/styles/tabs.css +3 -0
- package/src/styles/tooltip.css +65 -0
- package/src/styles/topbar.css +3 -4
- package/src/tokens/tokens.css +14 -8
package/react/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var cx = (...a) => a.filter(Boolean).join(" ");
|
|
|
20
20
|
function Button({
|
|
21
21
|
variant = "secondary",
|
|
22
22
|
size = "md",
|
|
23
|
-
icon:
|
|
23
|
+
icon: icon3,
|
|
24
24
|
iconRight,
|
|
25
25
|
iconOnly,
|
|
26
26
|
block,
|
|
@@ -38,7 +38,7 @@ function Button({
|
|
|
38
38
|
iconOnly && "ui-btn--icon"
|
|
39
39
|
);
|
|
40
40
|
const labelled = rest["aria-label"] != null || rest["aria-labelledby"] != null;
|
|
41
|
-
const fallback = typeof children === "string" && children.trim() ? children.trim() :
|
|
41
|
+
const fallback = typeof children === "string" && children.trim() ? children.trim() : icon3;
|
|
42
42
|
const named = iconOnly && !labelled && fallback ? { "aria-label": fallback, title: rest.title ?? fallback } : {};
|
|
43
43
|
return /* @__PURE__ */ jsxs(
|
|
44
44
|
"button",
|
|
@@ -51,7 +51,7 @@ function Button({
|
|
|
51
51
|
...rest,
|
|
52
52
|
...named,
|
|
53
53
|
children: [
|
|
54
|
-
|
|
54
|
+
icon3 && /* @__PURE__ */ jsx2(Icon, { name: icon3 }),
|
|
55
55
|
!iconOnly && children != null && /* @__PURE__ */ jsx2("span", { children }),
|
|
56
56
|
iconRight && /* @__PURE__ */ jsx2(Icon, { name: iconRight }),
|
|
57
57
|
busy && /* @__PURE__ */ jsxs("span", { className: "ui-btn__bars", children: [
|
|
@@ -72,18 +72,30 @@ function Badge({ variant = "neutral", children }) {
|
|
|
72
72
|
|
|
73
73
|
// src/primitives/Card.tsx
|
|
74
74
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
75
|
-
function Card({ title, sub, children }) {
|
|
75
|
+
function Card({ title, sub, level = 2, children }) {
|
|
76
|
+
const n = Number(level);
|
|
77
|
+
const Heading = `h${[2, 3, 4, 5, 6].includes(n) ? n : 2}`;
|
|
78
|
+
const titled = title != null && title !== false && title !== "";
|
|
76
79
|
return /* @__PURE__ */ jsxs2("div", { className: "ui-card", children: [
|
|
77
|
-
|
|
80
|
+
titled && /* @__PURE__ */ jsx4(Heading, { className: "ui-card__title", children: title }),
|
|
78
81
|
sub != null && /* @__PURE__ */ jsx4("div", { className: "ui-card__sub", children: sub }),
|
|
79
82
|
children
|
|
80
83
|
] });
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
// src/Modal.tsx
|
|
84
|
-
import {
|
|
87
|
+
import { useRef as useRef2 } from "react";
|
|
85
88
|
import { createPortal } from "react-dom";
|
|
86
|
-
|
|
89
|
+
|
|
90
|
+
// src/dialog.ts
|
|
91
|
+
import {
|
|
92
|
+
createContext,
|
|
93
|
+
useContext,
|
|
94
|
+
useEffect,
|
|
95
|
+
useLayoutEffect,
|
|
96
|
+
useRef,
|
|
97
|
+
useState
|
|
98
|
+
} from "react";
|
|
87
99
|
var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), details > summary:first-of-type';
|
|
88
100
|
function tabbable(el) {
|
|
89
101
|
const tabindex = el.getAttribute("tabindex");
|
|
@@ -103,75 +115,682 @@ var dismissOnScrim = (onClose) => (e) => {
|
|
|
103
115
|
e.preventDefault();
|
|
104
116
|
onClose();
|
|
105
117
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
118
|
+
var useIsoLayoutEffect = typeof document === "undefined" ? useEffect : useLayoutEffect;
|
|
119
|
+
function transitionMs(el) {
|
|
120
|
+
const cs = getComputedStyle(el);
|
|
121
|
+
const times = (list) => list.split(",").map((t) => {
|
|
122
|
+
const n = Number.parseFloat(t);
|
|
123
|
+
if (!Number.isFinite(n)) return 0;
|
|
124
|
+
return t.trim().endsWith("ms") ? n : n * 1e3;
|
|
125
|
+
});
|
|
126
|
+
const durations = times(cs.transitionDuration);
|
|
127
|
+
const delays = times(cs.transitionDelay);
|
|
128
|
+
return Math.max(0, ...durations.map((d, i) => d + delays[i % delays.length]));
|
|
129
|
+
}
|
|
130
|
+
var DialogScope = createContext(null);
|
|
131
|
+
var stack = [];
|
|
132
|
+
var leaving = /* @__PURE__ */ new Set();
|
|
133
|
+
var marked = [];
|
|
134
|
+
var listening = false;
|
|
135
|
+
var firstIn = (entry) => (entry.body ? tabbablesIn(entry.body) : [])[0] || entry.panel;
|
|
136
|
+
function trapTab(panel, e) {
|
|
137
|
+
const items = tabbablesIn(panel);
|
|
138
|
+
if (items.length === 0) {
|
|
139
|
+
e.preventDefault();
|
|
140
|
+
panel.focus();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const first = items[0];
|
|
144
|
+
const last = items[items.length - 1];
|
|
145
|
+
const focused = document.activeElement;
|
|
146
|
+
if (!panel.contains(focused)) {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
first.focus();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (!e.shiftKey && focused === last) {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
first.focus();
|
|
154
|
+
} else if (e.shiftKey && (focused === first || focused === panel)) {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
last.focus();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function onKey(e) {
|
|
160
|
+
const top = stack[stack.length - 1];
|
|
161
|
+
if (!top) return;
|
|
162
|
+
if (e.key === "Escape") top.close();
|
|
163
|
+
else if (e.key === "Tab") trapTab(top.panel, e);
|
|
164
|
+
}
|
|
165
|
+
function sync() {
|
|
166
|
+
for (const [el, was] of marked) if (!was) el.removeAttribute("inert");
|
|
167
|
+
marked = [];
|
|
168
|
+
const top = stack[stack.length - 1];
|
|
169
|
+
for (let node = top?.root; node?.parentElement && node !== document.body; node = node.parentElement) {
|
|
170
|
+
for (const sib of Array.from(node.parentElement.children)) {
|
|
171
|
+
if (sib === node || leaving.has(sib)) continue;
|
|
172
|
+
marked.push([sib, sib.hasAttribute("inert")]);
|
|
173
|
+
sib.setAttribute("inert", "");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
leaving.forEach((el) => {
|
|
177
|
+
el.toggleAttribute("inert", true);
|
|
178
|
+
if (el.getAttribute("aria-hidden") !== "true") el.setAttribute("aria-hidden", "true");
|
|
179
|
+
});
|
|
180
|
+
if (Boolean(top) !== listening) {
|
|
181
|
+
listening = Boolean(top);
|
|
182
|
+
if (listening) document.addEventListener("keydown", onKey);
|
|
183
|
+
else document.removeEventListener("keydown", onKey);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function returnFocus(opener) {
|
|
187
|
+
const live = opener && !opener.isConnected && opener.id ? document.getElementById(opener.id) : opener;
|
|
188
|
+
if (live?.isConnected) live.focus?.();
|
|
189
|
+
if (document.activeElement !== live) document.activeElement?.blur?.();
|
|
190
|
+
}
|
|
191
|
+
function enter(entry) {
|
|
192
|
+
const at = stack.findIndex((e) => {
|
|
193
|
+
for (let s = e.scope.parent; s; s = s.parent) if (s === entry.scope) return true;
|
|
194
|
+
return false;
|
|
195
|
+
});
|
|
196
|
+
if (at !== -1) {
|
|
197
|
+
entry.opener = stack[at].opener;
|
|
198
|
+
stack[at].opener = null;
|
|
199
|
+
stack.splice(at, 0, entry);
|
|
200
|
+
sync();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const covered = stack[stack.length - 1];
|
|
204
|
+
if (covered?.panel.contains(document.activeElement)) covered.resume = document.activeElement;
|
|
205
|
+
stack.push(entry);
|
|
206
|
+
sync();
|
|
207
|
+
firstIn(entry).focus();
|
|
208
|
+
}
|
|
209
|
+
function exit(entry) {
|
|
210
|
+
const at = stack.indexOf(entry);
|
|
211
|
+
if (at === -1) return;
|
|
212
|
+
stack.splice(at, 1);
|
|
213
|
+
const above = stack[at];
|
|
214
|
+
if (above && (!above.opener || entry.root.contains(above.opener))) above.opener = entry.opener;
|
|
215
|
+
sync();
|
|
216
|
+
if (above) return;
|
|
217
|
+
const next = stack[stack.length - 1];
|
|
218
|
+
if (!next) {
|
|
219
|
+
returnFocus(entry.opener);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const back = [entry.opener, next.resume].find((el) => el?.isConnected && next.panel.contains(el));
|
|
223
|
+
(back ?? firstIn(next)).focus();
|
|
224
|
+
}
|
|
225
|
+
var EXIT_SLACK_MS = 50;
|
|
226
|
+
function usePresence(open, root, panel) {
|
|
227
|
+
const [present, setPresent] = useState(open);
|
|
228
|
+
const [entered, setEntered] = useState(false);
|
|
229
|
+
if (open && !present) setPresent(true);
|
|
230
|
+
const shown = open && entered;
|
|
231
|
+
useIsoLayoutEffect(() => {
|
|
232
|
+
if (!open || entered || !panel.current) return;
|
|
233
|
+
panel.current.getBoundingClientRect();
|
|
234
|
+
setEntered(true);
|
|
235
|
+
}, [open, entered]);
|
|
236
|
+
useIsoLayoutEffect(() => {
|
|
237
|
+
const el = root.current;
|
|
238
|
+
if (open || !present || !el) return;
|
|
239
|
+
leaving.add(el);
|
|
240
|
+
sync();
|
|
241
|
+
return () => {
|
|
242
|
+
leaving.delete(el);
|
|
243
|
+
el.removeAttribute("inert");
|
|
244
|
+
el.removeAttribute("aria-hidden");
|
|
245
|
+
sync();
|
|
137
246
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
247
|
+
}, [open, present]);
|
|
248
|
+
useIsoLayoutEffect(() => {
|
|
249
|
+
if (open || !present) return;
|
|
250
|
+
let done = false;
|
|
251
|
+
const finish = () => {
|
|
252
|
+
if (done) return;
|
|
253
|
+
done = true;
|
|
254
|
+
setPresent(false);
|
|
255
|
+
setEntered(false);
|
|
256
|
+
};
|
|
257
|
+
const el = panel.current;
|
|
258
|
+
if (!el) {
|
|
259
|
+
finish();
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const onEnd = (e) => {
|
|
263
|
+
if (e.target === el) finish();
|
|
264
|
+
};
|
|
265
|
+
el.addEventListener("transitionend", onEnd);
|
|
266
|
+
const timer = setTimeout(finish, transitionMs(el) + EXIT_SLACK_MS);
|
|
147
267
|
return () => {
|
|
148
|
-
|
|
149
|
-
|
|
268
|
+
done = true;
|
|
269
|
+
el.removeEventListener("transitionend", onEnd);
|
|
270
|
+
clearTimeout(timer);
|
|
150
271
|
};
|
|
151
|
-
}, [open]);
|
|
272
|
+
}, [open, present]);
|
|
273
|
+
return { mounted: present, shown };
|
|
274
|
+
}
|
|
275
|
+
function useDialog(active, { root, panel, body }, onClose) {
|
|
276
|
+
const parent = useContext(DialogScope);
|
|
277
|
+
const [scope] = useState(() => ({ parent }));
|
|
278
|
+
const close = useRef(onClose);
|
|
279
|
+
useIsoLayoutEffect(() => {
|
|
280
|
+
close.current = onClose;
|
|
281
|
+
});
|
|
152
282
|
useEffect(() => {
|
|
153
|
-
if (!
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
283
|
+
if (!active || !root.current || !panel.current) return;
|
|
284
|
+
const entry = {
|
|
285
|
+
scope,
|
|
286
|
+
root: root.current,
|
|
287
|
+
panel: panel.current,
|
|
288
|
+
body: body.current,
|
|
289
|
+
close: () => close.current(),
|
|
290
|
+
opener: document.activeElement,
|
|
291
|
+
resume: null
|
|
292
|
+
};
|
|
293
|
+
enter(entry);
|
|
294
|
+
return () => exit(entry);
|
|
295
|
+
}, [active]);
|
|
296
|
+
return scope;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/Modal.tsx
|
|
300
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
301
|
+
function Modal({ open, title, onClose, footer, children }) {
|
|
302
|
+
const root = useRef2(null);
|
|
303
|
+
const panel = useRef2(null);
|
|
304
|
+
const body = useRef2(null);
|
|
305
|
+
const { mounted, shown } = usePresence(open, root, panel);
|
|
306
|
+
const scope = useDialog(shown, { root, panel, body }, onClose);
|
|
307
|
+
if (!mounted) return null;
|
|
159
308
|
return createPortal(
|
|
160
|
-
/* @__PURE__ */ jsx5("div", { className: "rx-scrim", onMouseDown: dismissOnScrim(onClose), children: /* @__PURE__ */ jsxs3("div", { className: "rx-modal", role: "dialog", "aria-modal": "true", "aria-label": title, tabIndex: -1, ref: panel, children: [
|
|
309
|
+
/* @__PURE__ */ jsx5(DialogScope.Provider, { value: scope, children: /* @__PURE__ */ jsx5("div", { className: shown ? "rx-scrim is-open" : "rx-scrim", ref: root, onMouseDown: dismissOnScrim(onClose), children: /* @__PURE__ */ jsxs3("div", { className: "rx-modal", role: "dialog", "aria-modal": "true", "aria-label": title, tabIndex: -1, ref: panel, children: [
|
|
161
310
|
/* @__PURE__ */ jsxs3("div", { className: "rx-modal__head", children: [
|
|
162
311
|
/* @__PURE__ */ jsx5("div", { className: "rx-modal__title", children: title }),
|
|
163
312
|
/* @__PURE__ */ jsx5(Button, { variant: "ghost", size: "sm", iconOnly: true, icon: "x", "aria-label": "Close", onClick: onClose })
|
|
164
313
|
] }),
|
|
165
|
-
/* @__PURE__ */ jsx5("div", { className: "rx-modal__body", children }),
|
|
314
|
+
/* @__PURE__ */ jsx5("div", { className: "rx-modal__body", ref: body, children }),
|
|
166
315
|
footer && /* @__PURE__ */ jsx5("div", { className: "rx-modal__foot", children: footer })
|
|
316
|
+
] }) }) }),
|
|
317
|
+
document.body
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/Drawer.tsx
|
|
322
|
+
import { useId, useRef as useRef3 } from "react";
|
|
323
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
324
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
325
|
+
function Drawer({
|
|
326
|
+
open,
|
|
327
|
+
title,
|
|
328
|
+
onClose,
|
|
329
|
+
side = "right",
|
|
330
|
+
size = "md",
|
|
331
|
+
footer,
|
|
332
|
+
children,
|
|
333
|
+
closeLabel = "Close"
|
|
334
|
+
}) {
|
|
335
|
+
const root = useRef3(null);
|
|
336
|
+
const panel = useRef3(null);
|
|
337
|
+
const body = useRef3(null);
|
|
338
|
+
const titleId = useId();
|
|
339
|
+
const { mounted, shown } = usePresence(open, root, panel);
|
|
340
|
+
const scope = useDialog(shown, { root, panel, body }, onClose);
|
|
341
|
+
if (!mounted) return null;
|
|
342
|
+
const cls = ["ui-drawer", `ui-drawer--${side}`, `ui-drawer--${size}`, shown && "is-open"].filter(Boolean).join(" ");
|
|
343
|
+
return createPortal2(
|
|
344
|
+
/* @__PURE__ */ jsx6(DialogScope.Provider, { value: scope, children: /* @__PURE__ */ jsxs4("div", { className: cls, ref: root, children: [
|
|
345
|
+
/* @__PURE__ */ jsx6("div", { className: "ui-drawer__scrim", onMouseDown: dismissOnScrim(onClose) }),
|
|
346
|
+
/* @__PURE__ */ jsxs4(
|
|
347
|
+
"aside",
|
|
348
|
+
{
|
|
349
|
+
className: "ui-drawer__panel",
|
|
350
|
+
role: "dialog",
|
|
351
|
+
"aria-modal": "true",
|
|
352
|
+
"aria-labelledby": titleId,
|
|
353
|
+
tabIndex: -1,
|
|
354
|
+
ref: panel,
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsxs4("header", { className: "ui-drawer__header", children: [
|
|
357
|
+
/* @__PURE__ */ jsx6("h2", { className: "ui-drawer__title", id: titleId, children: title }),
|
|
358
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "ui-drawer__close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ jsx6(Icon, { name: "x" }) })
|
|
359
|
+
] }),
|
|
360
|
+
/* @__PURE__ */ jsx6("div", { className: "ui-drawer__body", ref: body, children }),
|
|
361
|
+
footer && /* @__PURE__ */ jsx6("footer", { className: "ui-drawer__footer", children: footer })
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
)
|
|
167
365
|
] }) }),
|
|
168
366
|
document.body
|
|
169
367
|
);
|
|
170
368
|
}
|
|
171
369
|
|
|
370
|
+
// src/CommandPalette.tsx
|
|
371
|
+
import { useCallback, useEffect as useEffect2, useId as useId2, useMemo, useRef as useRef4, useState as useState2 } from "react";
|
|
372
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
373
|
+
import { rankGroups, icon as icon2 } from "@apliteni/apliteni-ui";
|
|
374
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
375
|
+
var cx2 = (...a) => a.filter(Boolean).join(" ");
|
|
376
|
+
var Glyph = ({ name, className }) => /* @__PURE__ */ jsx7("span", { className, "aria-hidden": "true", dangerouslySetInnerHTML: { __html: icon2(name) } });
|
|
377
|
+
var keysOf = (shortcut) => shortcut == null ? [] : Array.isArray(shortcut) ? shortcut : [shortcut];
|
|
378
|
+
function CommandPalette({
|
|
379
|
+
open,
|
|
380
|
+
onClose,
|
|
381
|
+
groups,
|
|
382
|
+
onSelect,
|
|
383
|
+
label = "Command palette",
|
|
384
|
+
placeholder = "Search or run a command\u2026",
|
|
385
|
+
empty = "No matches",
|
|
386
|
+
density = "compact",
|
|
387
|
+
hint = true,
|
|
388
|
+
rank = true,
|
|
389
|
+
onQueryChange
|
|
390
|
+
}) {
|
|
391
|
+
const uid = useId2().replace(/:/g, "");
|
|
392
|
+
const root = useRef4(null);
|
|
393
|
+
const panel = useRef4(null);
|
|
394
|
+
const search = useRef4(null);
|
|
395
|
+
const [query, setQuery] = useState2("");
|
|
396
|
+
const [at, setAt] = useState2(0);
|
|
397
|
+
useEffect2(() => {
|
|
398
|
+
if (open) {
|
|
399
|
+
setQuery("");
|
|
400
|
+
setAt(0);
|
|
401
|
+
}
|
|
402
|
+
}, [open]);
|
|
403
|
+
const shown = useMemo(
|
|
404
|
+
() => (rank ? rankGroups(groups, query) : groups).filter((g) => g.items.length),
|
|
405
|
+
[groups, query, rank]
|
|
406
|
+
);
|
|
407
|
+
const rows = useMemo(() => shown.flatMap((g) => g.items).filter((it) => !isDisabled(it)), [shown]);
|
|
408
|
+
const active = rows[Math.min(at, rows.length - 1)];
|
|
409
|
+
useEffect2(() => {
|
|
410
|
+
setAt(0);
|
|
411
|
+
}, [query]);
|
|
412
|
+
const scope = useDialog(open, { root, panel, body: search }, onClose);
|
|
413
|
+
const run = useCallback((item, newTab) => {
|
|
414
|
+
if (isDisabled(item)) return;
|
|
415
|
+
onSelect?.(item, { newTab });
|
|
416
|
+
if (item.danger && item.onConfirm) {
|
|
417
|
+
item.onConfirm();
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
onClose();
|
|
421
|
+
if (!item.href) return;
|
|
422
|
+
if (newTab) window.open(item.href, "_blank", "noopener");
|
|
423
|
+
else window.location.href = item.href;
|
|
424
|
+
}, [onClose, onSelect]);
|
|
425
|
+
const onKeyDown = (e) => {
|
|
426
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
427
|
+
if (!rows.length) return;
|
|
428
|
+
e.preventDefault();
|
|
429
|
+
const step = e.key === "ArrowDown" ? 1 : -1;
|
|
430
|
+
setAt((was) => (was + step + rows.length) % rows.length);
|
|
431
|
+
} else if (e.key === "Enter") {
|
|
432
|
+
if (!active) return;
|
|
433
|
+
e.preventDefault();
|
|
434
|
+
run(active, e.metaKey || e.ctrlKey);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
if (!open) return null;
|
|
438
|
+
const listId = `${uid}-list`;
|
|
439
|
+
let n = 0;
|
|
440
|
+
return createPortal3(
|
|
441
|
+
/* @__PURE__ */ jsx7(DialogScope.Provider, { value: scope, children: /* @__PURE__ */ jsxs5("div", { className: cx2("ui-cmdk", density === "roomy" && "ui-cmdk--roomy", "is-open"), ref: root, children: [
|
|
442
|
+
/* @__PURE__ */ jsx7("div", { className: "ui-cmdk__scrim", onMouseDown: dismissOnScrim(onClose) }),
|
|
443
|
+
/* @__PURE__ */ jsxs5(
|
|
444
|
+
"div",
|
|
445
|
+
{
|
|
446
|
+
className: "ui-cmdk__panel",
|
|
447
|
+
role: "dialog",
|
|
448
|
+
"aria-modal": "true",
|
|
449
|
+
"aria-label": label,
|
|
450
|
+
tabIndex: -1,
|
|
451
|
+
ref: panel,
|
|
452
|
+
onKeyDown,
|
|
453
|
+
children: [
|
|
454
|
+
/* @__PURE__ */ jsxs5("div", { className: "ui-cmdk__search", ref: search, children: [
|
|
455
|
+
/* @__PURE__ */ jsx7(Glyph, { name: "search", className: "ui-cmdk__search-ic" }),
|
|
456
|
+
/* @__PURE__ */ jsx7(
|
|
457
|
+
"input",
|
|
458
|
+
{
|
|
459
|
+
className: "ui-cmdk__input",
|
|
460
|
+
type: "text",
|
|
461
|
+
role: "combobox",
|
|
462
|
+
"aria-autocomplete": "list",
|
|
463
|
+
"aria-expanded": true,
|
|
464
|
+
"aria-controls": listId,
|
|
465
|
+
"aria-label": label,
|
|
466
|
+
"aria-activedescendant": active ? rowId(uid, shown, active) : void 0,
|
|
467
|
+
placeholder,
|
|
468
|
+
value: query,
|
|
469
|
+
autoComplete: "off",
|
|
470
|
+
spellCheck: false,
|
|
471
|
+
onChange: (e) => {
|
|
472
|
+
setQuery(e.target.value);
|
|
473
|
+
onQueryChange?.(e.target.value);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
] }),
|
|
478
|
+
/* @__PURE__ */ jsx7("div", { className: "ui-cmdk__list", id: listId, role: "listbox", "aria-label": `${label} results`, children: shown.map((group, gi) => /* @__PURE__ */ jsxs5(
|
|
479
|
+
"div",
|
|
480
|
+
{
|
|
481
|
+
className: "ui-cmdk__group",
|
|
482
|
+
role: "group",
|
|
483
|
+
"aria-labelledby": group.label ? `${uid}-g${gi}` : void 0,
|
|
484
|
+
children: [
|
|
485
|
+
group.label && /* @__PURE__ */ jsx7("div", { className: "ui-cmdk__group-head", id: `${uid}-g${gi}`, children: group.label }),
|
|
486
|
+
group.items.map((item) => {
|
|
487
|
+
const disabled = isDisabled(item);
|
|
488
|
+
const id = `${uid}-o${n++}`;
|
|
489
|
+
const on = item === active;
|
|
490
|
+
return /* @__PURE__ */ jsxs5(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
id,
|
|
494
|
+
className: cx2(
|
|
495
|
+
"ui-cmdk__item",
|
|
496
|
+
item.danger && !disabled && "is-danger",
|
|
497
|
+
disabled && "is-disabled",
|
|
498
|
+
on && "is-active"
|
|
499
|
+
),
|
|
500
|
+
role: "option",
|
|
501
|
+
tabIndex: -1,
|
|
502
|
+
"aria-selected": on,
|
|
503
|
+
"aria-disabled": disabled || void 0,
|
|
504
|
+
"aria-haspopup": item.danger && item.onConfirm ? "dialog" : void 0,
|
|
505
|
+
onMouseMove: () => {
|
|
506
|
+
if (!disabled) setAt(rows.indexOf(item));
|
|
507
|
+
},
|
|
508
|
+
onClick: (e) => run(item, e.metaKey || e.ctrlKey),
|
|
509
|
+
children: [
|
|
510
|
+
item.icon && /* @__PURE__ */ jsx7(Glyph, { name: item.icon, className: "ui-cmdk__ic" }),
|
|
511
|
+
/* @__PURE__ */ jsxs5("span", { className: "ui-cmdk__main", children: [
|
|
512
|
+
/* @__PURE__ */ jsx7("span", { className: "ui-cmdk__label", children: item.label }),
|
|
513
|
+
item.description && /* @__PURE__ */ jsx7("span", { className: "ui-cmdk__desc", children: item.description })
|
|
514
|
+
] }),
|
|
515
|
+
item.badge && /* @__PURE__ */ jsx7("span", { className: "ui-cmdk__badge", children: item.badge }),
|
|
516
|
+
keysOf(item.shortcut).length > 0 && /* @__PURE__ */ jsx7("span", { className: "ui-cmdk__keys", "aria-hidden": "true", children: keysOf(item.shortcut).map((k) => /* @__PURE__ */ jsx7("kbd", { className: "ui-cmdk__key", children: k }, k)) })
|
|
517
|
+
]
|
|
518
|
+
},
|
|
519
|
+
item.id
|
|
520
|
+
);
|
|
521
|
+
})
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
group.label ?? `g${gi}`
|
|
525
|
+
)) }),
|
|
526
|
+
/* @__PURE__ */ jsx7("p", { className: "ui-cmdk__empty", hidden: countOf(shown) > 0, children: empty }),
|
|
527
|
+
/* @__PURE__ */ jsx7("p", { className: "ui-sr", role: "status", "aria-live": "polite", children: countOf(shown) === 0 ? "No results" : `${countOf(shown)} result${countOf(shown) === 1 ? "" : "s"}` }),
|
|
528
|
+
hint && /* @__PURE__ */ jsxs5("div", { className: "ui-cmdk__foot", "aria-hidden": "true", children: [
|
|
529
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
530
|
+
/* @__PURE__ */ jsx7("kbd", { className: "ui-cmdk__key", children: "\u2191" }),
|
|
531
|
+
/* @__PURE__ */ jsx7("kbd", { className: "ui-cmdk__key", children: "\u2193" }),
|
|
532
|
+
" move"
|
|
533
|
+
] }),
|
|
534
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
535
|
+
/* @__PURE__ */ jsx7("kbd", { className: "ui-cmdk__key", children: "\u21B5" }),
|
|
536
|
+
" run"
|
|
537
|
+
] }),
|
|
538
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
539
|
+
/* @__PURE__ */ jsx7("kbd", { className: "ui-cmdk__key", children: "esc" }),
|
|
540
|
+
" close"
|
|
541
|
+
] })
|
|
542
|
+
] })
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
)
|
|
546
|
+
] }) }),
|
|
547
|
+
document.body
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
var isDisabled = (item) => !!item.disabled || !!item.danger && !item.onConfirm;
|
|
551
|
+
var countOf = (groups) => groups.reduce((t, g) => t + g.items.length, 0);
|
|
552
|
+
function rowId(uid, groups, item) {
|
|
553
|
+
let n = 0;
|
|
554
|
+
for (const group of groups) {
|
|
555
|
+
for (const it of group.items) {
|
|
556
|
+
if (it === item) return `${uid}-o${n}`;
|
|
557
|
+
n += 1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return void 0;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/DataTable.tsx
|
|
564
|
+
import { useMemo as useMemo2, useState as useState4 } from "react";
|
|
565
|
+
import { DEFAULT_PAGE_SIZE as DEFAULT_PAGE_SIZE2 } from "@apliteni/apliteni-ui";
|
|
566
|
+
|
|
567
|
+
// src/Pagination.tsx
|
|
568
|
+
import { useEffect as useEffect3, useId as useId3, useRef as useRef5, useState as useState3 } from "react";
|
|
569
|
+
import { DEFAULT_PAGE_SIZE } from "@apliteni/apliteni-ui";
|
|
570
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
571
|
+
var GHOST_SM = "ui-btn ui-btn--ghost ui-btn--sm";
|
|
572
|
+
var VARIANTS = ["steps", "numbered", "jump"];
|
|
573
|
+
var cx3 = (...a) => a.filter(Boolean).join(" ");
|
|
574
|
+
var CAP = Number.MAX_SAFE_INTEGER;
|
|
575
|
+
var int = (v, fallback) => {
|
|
576
|
+
const raw = typeof v === "number" ? v : typeof v === "string" && v.trim() !== "" ? Number(v) : NaN;
|
|
577
|
+
if (!Number.isFinite(raw)) return fallback;
|
|
578
|
+
return Math.min(Math.max(Math.trunc(raw), -CAP), CAP);
|
|
579
|
+
};
|
|
580
|
+
var sizeOf = (v, fallback) => {
|
|
581
|
+
const asked = int(v, fallback);
|
|
582
|
+
return asked > 0 ? asked : fallback;
|
|
583
|
+
};
|
|
584
|
+
var fmt = (n) => n.toLocaleString("en-US");
|
|
585
|
+
function slotsFor(page, pageCount) {
|
|
586
|
+
const wanted = [1, pageCount, page - 1, page, page + 1].filter((n) => n >= 1 && n <= pageCount);
|
|
587
|
+
const shown = [...new Set(wanted)].sort((a, b) => a - b);
|
|
588
|
+
const out = [];
|
|
589
|
+
for (const n of shown) {
|
|
590
|
+
const prev = out.length ? out[out.length - 1] : null;
|
|
591
|
+
if (prev != null) {
|
|
592
|
+
if (n - prev === 2) out.push(prev + 1);
|
|
593
|
+
else if (n - prev > 2) out.push(null);
|
|
594
|
+
}
|
|
595
|
+
out.push(n);
|
|
596
|
+
}
|
|
597
|
+
return out;
|
|
598
|
+
}
|
|
599
|
+
function Pagination({
|
|
600
|
+
page = 1,
|
|
601
|
+
pageSize,
|
|
602
|
+
total = null,
|
|
603
|
+
hasMore = false,
|
|
604
|
+
pageSizes = null,
|
|
605
|
+
variant = "steps",
|
|
606
|
+
label = "Pagination",
|
|
607
|
+
loading = false,
|
|
608
|
+
id,
|
|
609
|
+
onPageChange,
|
|
610
|
+
onPageSizeChange
|
|
611
|
+
}) {
|
|
612
|
+
const auto = useId3();
|
|
613
|
+
const [draft, setDraft] = useState3("");
|
|
614
|
+
const [drafting, setDrafting] = useState3(false);
|
|
615
|
+
const nav = useRef5(null);
|
|
616
|
+
const pressed = useRef5(null);
|
|
617
|
+
const uid = id ?? auto;
|
|
618
|
+
const kind = VARIANTS.includes(variant) ? variant : "steps";
|
|
619
|
+
const size = sizeOf(pageSize, DEFAULT_PAGE_SIZE);
|
|
620
|
+
const asRows = int(total, null);
|
|
621
|
+
const counted = total != null && asRows !== null;
|
|
622
|
+
const rows = counted ? Math.max(0, asRows) : null;
|
|
623
|
+
const last = counted ? Math.max(1, Math.ceil(rows / size)) : null;
|
|
624
|
+
const at = counted ? Math.min(Math.max(1, int(page, 1)), last) : Math.min(Math.max(1, int(page, 1)), CAP - 1);
|
|
625
|
+
const [draftFor, setDraftFor] = useState3(at);
|
|
626
|
+
if (draftFor !== at) {
|
|
627
|
+
setDraftFor(at);
|
|
628
|
+
setDraft("");
|
|
629
|
+
setDrafting(false);
|
|
630
|
+
}
|
|
631
|
+
const offered = (Array.isArray(pageSizes) ? pageSizes : []).slice(0, 12).map((s) => int(s, 0)).filter((s) => s > 0);
|
|
632
|
+
const sizes = offered.length ? [.../* @__PURE__ */ new Set([...offered, size])].sort((a, b) => a - b) : [];
|
|
633
|
+
useEffect3(() => {
|
|
634
|
+
const was = pressed.current;
|
|
635
|
+
if (!was || loading) return;
|
|
636
|
+
pressed.current = null;
|
|
637
|
+
const lost = document.activeElement === document.body || document.activeElement === was;
|
|
638
|
+
if (!lost || !nav.current?.contains(was)) return;
|
|
639
|
+
if (!was.disabled) {
|
|
640
|
+
was.focus();
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
const strip = [...nav.current.querySelectorAll(".ui-pager__step")];
|
|
644
|
+
const from2 = strip.indexOf(was);
|
|
645
|
+
for (let d = 1; d < strip.length; d += 1) {
|
|
646
|
+
const near = [strip[from2 - d], strip[from2 + d]].find((el) => el && !el.disabled);
|
|
647
|
+
if (near) {
|
|
648
|
+
near.focus();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}, [at, loading]);
|
|
653
|
+
const single = counted && last === 1;
|
|
654
|
+
if (single && !sizes.length) return null;
|
|
655
|
+
const from = (at - 1) * size + 1;
|
|
656
|
+
const to = counted ? Math.min(at * size, rows) : null;
|
|
657
|
+
const status = !counted ? `Page ${fmt(at)}` : rows === 0 ? "0 of 0" : from === to ? `${fmt(from)} of ${fmt(rows)}` : `${fmt(from)}\u2013${fmt(to)} of ${fmt(rows)}`;
|
|
658
|
+
const go = (n) => onPageChange?.(n);
|
|
659
|
+
const step = (label_, target, disabled) => (
|
|
660
|
+
// A control at an end is disabled and stays where it is: removing it slides
|
|
661
|
+
// the next control under a pointer already travelling toward it.
|
|
662
|
+
/* @__PURE__ */ jsx8(
|
|
663
|
+
"button",
|
|
664
|
+
{
|
|
665
|
+
type: "button",
|
|
666
|
+
className: `${GHOST_SM} ui-pager__step`,
|
|
667
|
+
"data-page": target,
|
|
668
|
+
disabled: loading || disabled,
|
|
669
|
+
"aria-disabled": loading || disabled ? true : void 0,
|
|
670
|
+
onClick: (e) => {
|
|
671
|
+
pressed.current = e.currentTarget;
|
|
672
|
+
go(target);
|
|
673
|
+
},
|
|
674
|
+
children: label_
|
|
675
|
+
},
|
|
676
|
+
label_
|
|
677
|
+
)
|
|
678
|
+
);
|
|
679
|
+
const atStart = at === 1;
|
|
680
|
+
const atEnd = counted && at === last;
|
|
681
|
+
const ends = kind !== "numbered";
|
|
682
|
+
const commitJump = () => {
|
|
683
|
+
setDrafting(false);
|
|
684
|
+
const typed = draft.trim();
|
|
685
|
+
if (typed === "") return;
|
|
686
|
+
const n = Math.min(Math.max(1, int(typed, at)), last);
|
|
687
|
+
if (n !== at) go(n);
|
|
688
|
+
};
|
|
689
|
+
const leaveJump = (to2) => {
|
|
690
|
+
if (to2 && nav.current?.contains(to2)) {
|
|
691
|
+
setDrafting(false);
|
|
692
|
+
setDraft("");
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
commitJump();
|
|
696
|
+
};
|
|
697
|
+
let steps = null;
|
|
698
|
+
if (single) {
|
|
699
|
+
steps = null;
|
|
700
|
+
} else if (!counted) {
|
|
701
|
+
steps = /* @__PURE__ */ jsxs6("div", { className: "ui-pager__steps", children: [
|
|
702
|
+
step("Prev", Math.max(1, at - 1), atStart),
|
|
703
|
+
step("Next", at + 1, !hasMore)
|
|
704
|
+
] });
|
|
705
|
+
} else {
|
|
706
|
+
let middle = null;
|
|
707
|
+
if (kind === "numbered") {
|
|
708
|
+
middle = slotsFor(at, last).map((n, i) => n == null ? /* @__PURE__ */ jsx8("span", { className: "ui-pager__gap", "aria-hidden": "true", children: "\u2026" }, `gap${i}`) : /* @__PURE__ */ jsx8(
|
|
709
|
+
"button",
|
|
710
|
+
{
|
|
711
|
+
type: "button",
|
|
712
|
+
"data-page": n,
|
|
713
|
+
className: cx3(`${GHOST_SM} ui-pager__page`, n === at && "is-current"),
|
|
714
|
+
"aria-current": n === at ? "page" : void 0,
|
|
715
|
+
disabled: loading,
|
|
716
|
+
"aria-disabled": loading ? true : void 0,
|
|
717
|
+
onClick: () => go(n),
|
|
718
|
+
children: fmt(n)
|
|
719
|
+
},
|
|
720
|
+
n
|
|
721
|
+
));
|
|
722
|
+
} else if (kind === "jump") {
|
|
723
|
+
middle = /* @__PURE__ */ jsxs6("span", { className: "ui-pager__jump", children: [
|
|
724
|
+
/* @__PURE__ */ jsx8("label", { htmlFor: `${uid}-jump`, children: "Page" }),
|
|
725
|
+
/* @__PURE__ */ jsx8(
|
|
726
|
+
"input",
|
|
727
|
+
{
|
|
728
|
+
className: "ui-input ui-pager__jump-input",
|
|
729
|
+
id: `${uid}-jump`,
|
|
730
|
+
type: "number",
|
|
731
|
+
min: 1,
|
|
732
|
+
max: last,
|
|
733
|
+
disabled: loading,
|
|
734
|
+
value: drafting ? draft : String(at),
|
|
735
|
+
onChange: (e) => {
|
|
736
|
+
setDrafting(true);
|
|
737
|
+
setDraft(e.target.value);
|
|
738
|
+
},
|
|
739
|
+
onBlur: (e) => leaveJump(e.relatedTarget),
|
|
740
|
+
onKeyDown: (e) => {
|
|
741
|
+
if (e.key === "Enter") {
|
|
742
|
+
e.preventDefault();
|
|
743
|
+
commitJump();
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
),
|
|
748
|
+
/* @__PURE__ */ jsxs6("span", { className: "ui-pager__jump-of", children: [
|
|
749
|
+
"of ",
|
|
750
|
+
fmt(last)
|
|
751
|
+
] })
|
|
752
|
+
] });
|
|
753
|
+
}
|
|
754
|
+
steps = /* @__PURE__ */ jsxs6("div", { className: "ui-pager__steps", children: [
|
|
755
|
+
ends ? step("First", 1, atStart) : null,
|
|
756
|
+
step("Prev", Math.max(1, at - 1), atStart),
|
|
757
|
+
middle,
|
|
758
|
+
step("Next", Math.min(last, at + 1), atEnd),
|
|
759
|
+
ends ? step("Last", last, atEnd) : null
|
|
760
|
+
] });
|
|
761
|
+
}
|
|
762
|
+
return /* @__PURE__ */ jsxs6(
|
|
763
|
+
"nav",
|
|
764
|
+
{
|
|
765
|
+
ref: nav,
|
|
766
|
+
className: cx3("ui-pager", `ui-pager--${kind}`, !counted && "ui-pager--open", single && "ui-pager--single"),
|
|
767
|
+
"aria-label": label,
|
|
768
|
+
"aria-busy": loading ? true : void 0,
|
|
769
|
+
children: [
|
|
770
|
+
/* @__PURE__ */ jsx8("p", { className: "ui-pager__status", "aria-live": "polite", "aria-atomic": "true", children: status }),
|
|
771
|
+
sizes.length ? /* @__PURE__ */ jsxs6("div", { className: "ui-pager__size", children: [
|
|
772
|
+
/* @__PURE__ */ jsx8("label", { className: "ui-pager__size-label", htmlFor: `${uid}-size`, children: "Rows" }),
|
|
773
|
+
/* @__PURE__ */ jsx8(
|
|
774
|
+
"select",
|
|
775
|
+
{
|
|
776
|
+
className: "ui-select ui-pager__size-select",
|
|
777
|
+
id: `${uid}-size`,
|
|
778
|
+
disabled: loading,
|
|
779
|
+
value: size,
|
|
780
|
+
onChange: (e) => onPageSizeChange?.(Number(e.target.value)),
|
|
781
|
+
children: sizes.map((s) => /* @__PURE__ */ jsx8("option", { value: s, children: fmt(s) }, s))
|
|
782
|
+
}
|
|
783
|
+
)
|
|
784
|
+
] }) : null,
|
|
785
|
+
steps
|
|
786
|
+
]
|
|
787
|
+
}
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
172
791
|
// src/DataTable.tsx
|
|
173
|
-
import {
|
|
174
|
-
|
|
792
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
793
|
+
var NO_SORT = { key: void 0, dir: -1 };
|
|
175
794
|
function sortTableRows(rows, sort) {
|
|
176
795
|
if (sort.key === void 0) return [...rows];
|
|
177
796
|
const key = sort.key;
|
|
@@ -180,7 +799,12 @@ function sortTableRows(rows, sort) {
|
|
|
180
799
|
function DataTable({
|
|
181
800
|
columns,
|
|
182
801
|
rows,
|
|
183
|
-
pageSize
|
|
802
|
+
pageSize,
|
|
803
|
+
pageSizes = null,
|
|
804
|
+
onPageSizeChange,
|
|
805
|
+
pager = true,
|
|
806
|
+
pagerLabel,
|
|
807
|
+
loading = false,
|
|
184
808
|
selectable = true,
|
|
185
809
|
selected = /* @__PURE__ */ new Set(),
|
|
186
810
|
onToggle = () => {
|
|
@@ -188,113 +812,124 @@ function DataTable({
|
|
|
188
812
|
onTogglePage = () => {
|
|
189
813
|
},
|
|
190
814
|
sort: controlledSort,
|
|
191
|
-
onSortChange
|
|
815
|
+
onSortChange,
|
|
816
|
+
page: controlledPage,
|
|
817
|
+
onPageChange,
|
|
818
|
+
total,
|
|
819
|
+
hasMore = false
|
|
192
820
|
}) {
|
|
193
|
-
const [localSort, setLocalSort] =
|
|
821
|
+
const [localSort, setLocalSort] = useState4(
|
|
194
822
|
{ key: columns.find((c) => c.sortable)?.key, dir: -1 }
|
|
195
823
|
);
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
824
|
+
const owned = controlledPage === void 0;
|
|
825
|
+
const sort = controlledSort ?? (owned ? localSort : NO_SORT);
|
|
826
|
+
const sortIsKnown = owned || controlledSort !== void 0;
|
|
827
|
+
const [localPage, setLocalPage] = useState4(1);
|
|
828
|
+
const [localSize, setLocalSize] = useState4(DEFAULT_PAGE_SIZE2);
|
|
829
|
+
const size = sizeOf(pageSize, owned ? localSize : rows.length || DEFAULT_PAGE_SIZE2);
|
|
830
|
+
const [pagedSort, setPagedSort] = useState4(sort);
|
|
199
831
|
if (pagedSort.key !== sort.key || pagedSort.dir !== sort.dir) {
|
|
200
832
|
setPagedSort(sort);
|
|
201
|
-
|
|
833
|
+
setLocalPage(1);
|
|
202
834
|
}
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
835
|
+
const ordered = useMemo2(
|
|
836
|
+
() => owned ? sortTableRows(rows, sort) : rows,
|
|
837
|
+
[owned, rows, sort.key, sort.dir]
|
|
838
|
+
);
|
|
839
|
+
const pages = Math.max(1, Math.ceil(ordered.length / size));
|
|
840
|
+
const page = owned ? Math.min(Math.max(1, localPage), pages) : controlledPage;
|
|
841
|
+
const slice = owned ? ordered.slice((page - 1) * size, page * size) : ordered;
|
|
842
|
+
const goTo = (n) => owned ? setLocalPage(n) : onPageChange?.(n);
|
|
843
|
+
const toFirstPage = () => {
|
|
844
|
+
if (owned) setLocalPage(1);
|
|
845
|
+
else if (page !== 1) onPageChange?.(1);
|
|
846
|
+
};
|
|
207
847
|
const onSort = (key) => {
|
|
208
848
|
const next = sort.key === key ? { key, dir: sort.dir === 1 ? -1 : 1 } : { key, dir: -1 };
|
|
209
849
|
if (controlledSort === void 0) setLocalSort(next);
|
|
210
850
|
onSortChange?.(next);
|
|
211
|
-
|
|
851
|
+
toFirstPage();
|
|
212
852
|
};
|
|
213
853
|
const caret = (k) => sort.key === k ? sort.dir === 1 ? " \u25B2" : " \u25BC" : " \u2195";
|
|
214
854
|
const pageAllOn = selectable && slice.length > 0 && slice.every((r) => selected.has(r.name));
|
|
215
|
-
return /* @__PURE__ */
|
|
216
|
-
/* @__PURE__ */
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
"
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
Button,
|
|
282
|
-
{
|
|
283
|
-
variant: "ghost",
|
|
284
|
-
size: "sm",
|
|
285
|
-
iconRight: "chevronRight",
|
|
286
|
-
disabled: safePage >= pages - 1,
|
|
287
|
-
onClick: () => setPage(safePage + 1),
|
|
288
|
-
children: "Next"
|
|
855
|
+
return /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
856
|
+
/* @__PURE__ */ jsxs7(
|
|
857
|
+
"table",
|
|
858
|
+
{
|
|
859
|
+
className: "ui-table ui-table--hover ui-table--zebra",
|
|
860
|
+
"aria-busy": loading || void 0,
|
|
861
|
+
children: [
|
|
862
|
+
/* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
|
|
863
|
+
selectable ? /* @__PURE__ */ jsx9("th", { scope: "col", children: /* @__PURE__ */ jsx9(
|
|
864
|
+
"input",
|
|
865
|
+
{
|
|
866
|
+
type: "checkbox",
|
|
867
|
+
checked: pageAllOn,
|
|
868
|
+
"aria-label": "Select all rows on this page",
|
|
869
|
+
onChange: () => onTogglePage(slice.map((r) => r.name))
|
|
870
|
+
}
|
|
871
|
+
) }) : null,
|
|
872
|
+
columns.map((c) => (
|
|
873
|
+
// The sort control is a real <button> inside the header cell. It used to be
|
|
874
|
+
// role="button" ON the <th>, which threw away the columnheader role and put
|
|
875
|
+
// aria-sort on a role that forbids it.
|
|
876
|
+
/* @__PURE__ */ jsx9(
|
|
877
|
+
"th",
|
|
878
|
+
{
|
|
879
|
+
scope: "col",
|
|
880
|
+
className: [c.num && "ui-table__num", c.sortable && "rx-sortable"].filter(Boolean).join(" "),
|
|
881
|
+
"aria-sort": sort.key === c.key ? sort.dir === 1 ? "ascending" : "descending" : c.sortable && sortIsKnown ? "none" : void 0,
|
|
882
|
+
children: c.sortable ? /* @__PURE__ */ jsxs7("button", { type: "button", className: "rx-sort", onClick: () => onSort(c.key), children: [
|
|
883
|
+
c.label,
|
|
884
|
+
/* @__PURE__ */ jsx9("span", { className: "rx-caret", "aria-hidden": "true", children: caret(c.key) })
|
|
885
|
+
] }) : c.label
|
|
886
|
+
},
|
|
887
|
+
c.key
|
|
888
|
+
)
|
|
889
|
+
))
|
|
890
|
+
] }) }),
|
|
891
|
+
/* @__PURE__ */ jsx9("tbody", { children: slice.map((r) => /* @__PURE__ */ jsxs7("tr", { children: [
|
|
892
|
+
selectable ? /* @__PURE__ */ jsx9("td", { children: /* @__PURE__ */ jsx9(
|
|
893
|
+
"input",
|
|
894
|
+
{
|
|
895
|
+
type: "checkbox",
|
|
896
|
+
checked: selected.has(r.name),
|
|
897
|
+
"aria-label": `Select ${r.name}`,
|
|
898
|
+
onChange: () => onToggle(r.name)
|
|
899
|
+
}
|
|
900
|
+
) }) : null,
|
|
901
|
+
columns.map((c) => /* @__PURE__ */ jsx9("td", { className: c.num ? "ui-table__num" : void 0, children: c.render ? c.render(r) : String(r[c.key]) }, c.key))
|
|
902
|
+
] }, r.name)) })
|
|
903
|
+
]
|
|
904
|
+
}
|
|
905
|
+
),
|
|
906
|
+
pager ? /* @__PURE__ */ jsx9(
|
|
907
|
+
Pagination,
|
|
908
|
+
{
|
|
909
|
+
page,
|
|
910
|
+
pageSize: size,
|
|
911
|
+
total: owned ? ordered.length : total ?? null,
|
|
912
|
+
hasMore,
|
|
913
|
+
pageSizes,
|
|
914
|
+
loading,
|
|
915
|
+
...pagerLabel === void 0 ? {} : { label: pagerLabel },
|
|
916
|
+
onPageChange: goTo,
|
|
917
|
+
onPageSizeChange: (s) => {
|
|
918
|
+
if (pageSize === void 0) setLocalSize(s);
|
|
919
|
+
onPageSizeChange?.(s);
|
|
920
|
+
if (owned) setLocalPage(1);
|
|
289
921
|
}
|
|
290
|
-
|
|
291
|
-
|
|
922
|
+
}
|
|
923
|
+
) : null
|
|
292
924
|
] });
|
|
293
925
|
}
|
|
294
926
|
|
|
927
|
+
// src/index.ts
|
|
928
|
+
import { PAGE_SIZES as KIT_PAGE_SIZES, DEFAULT_PAGE_SIZE as KIT_DEFAULT_PAGE_SIZE } from "@apliteni/apliteni-ui";
|
|
929
|
+
|
|
295
930
|
// src/Loading.tsx
|
|
296
|
-
import { jsx as
|
|
297
|
-
var
|
|
931
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
932
|
+
var cx4 = (...a) => a.filter(Boolean).join(" ");
|
|
298
933
|
function Skeleton({ lines = 3, width, height, radius, className }) {
|
|
299
934
|
const widths = Array.isArray(lines) ? lines : null;
|
|
300
935
|
const n = widths ? widths.length : Math.max(1, lines);
|
|
@@ -303,19 +938,19 @@ function Skeleton({ lines = 3, width, height, radius, className }) {
|
|
|
303
938
|
if (!w && !height && !radius) return void 0;
|
|
304
939
|
return { ...w && { width: w }, ...height && { height }, ...radius && { borderRadius: radius } };
|
|
305
940
|
};
|
|
306
|
-
return /* @__PURE__ */
|
|
941
|
+
return /* @__PURE__ */ jsx10("div", { className: cx4("ui-skel", className), "aria-hidden": "true", children: Array.from({ length: n }, (_, i) => /* @__PURE__ */ jsx10("span", { className: "ui-skel__bar m-skeleton", style: styleFor(i) }, i)) });
|
|
307
942
|
}
|
|
308
943
|
function SkeletonTable({ rows = 5, cols = 4, head = true }) {
|
|
309
|
-
const cells = Array.from({ length: Math.max(1, cols) }, (_, i) => /* @__PURE__ */
|
|
310
|
-
return /* @__PURE__ */
|
|
944
|
+
const cells = Array.from({ length: Math.max(1, cols) }, (_, i) => /* @__PURE__ */ jsx10("span", { className: "ui-skel__bar m-skeleton" }, i));
|
|
945
|
+
return /* @__PURE__ */ jsxs8(
|
|
311
946
|
"div",
|
|
312
947
|
{
|
|
313
948
|
className: "ui-skel ui-skel--table",
|
|
314
949
|
style: { "--skel-cols": Math.max(1, cols) },
|
|
315
950
|
"aria-hidden": "true",
|
|
316
951
|
children: [
|
|
317
|
-
head && /* @__PURE__ */
|
|
318
|
-
Array.from({ length: Math.max(1, rows) }, (_, i) => /* @__PURE__ */
|
|
952
|
+
head && /* @__PURE__ */ jsx10("div", { className: "ui-skel__row ui-skel__row--head", children: cells }),
|
|
953
|
+
Array.from({ length: Math.max(1, rows) }, (_, i) => /* @__PURE__ */ jsx10("div", { className: "ui-skel__row", children: cells }, i))
|
|
319
954
|
]
|
|
320
955
|
}
|
|
321
956
|
);
|
|
@@ -328,16 +963,16 @@ function BusyRegion({
|
|
|
328
963
|
className,
|
|
329
964
|
children
|
|
330
965
|
}) {
|
|
331
|
-
return /* @__PURE__ */
|
|
966
|
+
return /* @__PURE__ */ jsxs8(
|
|
332
967
|
"div",
|
|
333
968
|
{
|
|
334
|
-
className:
|
|
969
|
+
className: cx4("ui-busy", className),
|
|
335
970
|
role: "status",
|
|
336
971
|
"aria-live": "polite",
|
|
337
972
|
"aria-busy": busy,
|
|
338
973
|
children: [
|
|
339
|
-
/* @__PURE__ */
|
|
340
|
-
/* @__PURE__ */
|
|
974
|
+
/* @__PURE__ */ jsx10("span", { className: "ui-sr", children: busy ? label : message }),
|
|
975
|
+
/* @__PURE__ */ jsx10("div", { className: "ui-busy__body", children: busy ? placeholder ?? /* @__PURE__ */ jsx10(Skeleton, { lines: 3 }) : children })
|
|
341
976
|
]
|
|
342
977
|
}
|
|
343
978
|
);
|
|
@@ -346,30 +981,39 @@ function Denied({
|
|
|
346
981
|
title = "You don\u2019t have access",
|
|
347
982
|
sub,
|
|
348
983
|
need,
|
|
349
|
-
icon:
|
|
984
|
+
icon: icon3 = "lock",
|
|
350
985
|
className,
|
|
351
986
|
children
|
|
352
987
|
}) {
|
|
353
|
-
return /* @__PURE__ */
|
|
354
|
-
/* @__PURE__ */
|
|
355
|
-
/* @__PURE__ */
|
|
356
|
-
sub && /* @__PURE__ */
|
|
357
|
-
need && /* @__PURE__ */
|
|
988
|
+
return /* @__PURE__ */ jsxs8("div", { className: cx4("ui-denied", className), children: [
|
|
989
|
+
/* @__PURE__ */ jsx10("div", { className: "ui-denied__seal", children: /* @__PURE__ */ jsx10(Icon, { name: icon3 }) }),
|
|
990
|
+
/* @__PURE__ */ jsx10("div", { className: "ui-denied__title", children: title }),
|
|
991
|
+
sub && /* @__PURE__ */ jsx10("div", { className: "ui-denied__sub", children: sub }),
|
|
992
|
+
need && /* @__PURE__ */ jsxs8("div", { className: "ui-denied__need", children: [
|
|
358
993
|
"Needs ",
|
|
359
|
-
/* @__PURE__ */
|
|
994
|
+
/* @__PURE__ */ jsx10("code", { className: "ui-code", children: need })
|
|
360
995
|
] }),
|
|
361
|
-
children && /* @__PURE__ */
|
|
996
|
+
children && /* @__PURE__ */ jsx10("div", { className: "ui-denied__actions", children })
|
|
362
997
|
] });
|
|
363
998
|
}
|
|
999
|
+
|
|
1000
|
+
// src/index.ts
|
|
1001
|
+
var PAGE_SIZES = KIT_PAGE_SIZES;
|
|
1002
|
+
var DEFAULT_PAGE_SIZE3 = KIT_DEFAULT_PAGE_SIZE;
|
|
364
1003
|
export {
|
|
365
1004
|
Badge,
|
|
366
1005
|
BusyRegion,
|
|
367
1006
|
Button,
|
|
368
1007
|
Card,
|
|
1008
|
+
CommandPalette,
|
|
1009
|
+
DEFAULT_PAGE_SIZE3 as DEFAULT_PAGE_SIZE,
|
|
369
1010
|
DataTable,
|
|
370
1011
|
Denied,
|
|
1012
|
+
Drawer,
|
|
371
1013
|
Icon,
|
|
372
1014
|
Modal,
|
|
1015
|
+
PAGE_SIZES,
|
|
1016
|
+
Pagination,
|
|
373
1017
|
Skeleton,
|
|
374
1018
|
SkeletonTable,
|
|
375
1019
|
sortTableRows
|