@blakesteve/roster 5.4.0 → 5.6.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 +170 -1
- package/dist/components/atoms/Button/Button.cjs +1 -1
- package/dist/components/atoms/Button/Button.d.ts +11 -0
- package/dist/components/atoms/Button/Button.js +42 -32
- package/dist/components/atoms/Button/button-variants.cjs +1 -1
- package/dist/components/atoms/Button/button-variants.js +3 -1
- package/dist/components/molecules/FileUpload/FileUpload.cjs +1 -0
- package/dist/components/molecules/FileUpload/FileUpload.d.ts +111 -0
- package/dist/components/molecules/FileUpload/FileUpload.js +403 -0
- package/dist/components/molecules/FileUpload/file-rules.cjs +1 -0
- package/dist/components/molecules/FileUpload/file-rules.d.ts +22 -0
- package/dist/components/molecules/FileUpload/file-rules.js +43 -0
- package/dist/components/molecules/Pagination/Pagination.cjs +1 -0
- package/dist/components/molecules/Pagination/Pagination.d.ts +116 -0
- package/dist/components/molecules/Pagination/Pagination.js +247 -0
- package/dist/components/molecules/Pagination/page-items.cjs +1 -0
- package/dist/components/molecules/Pagination/page-items.d.ts +13 -0
- package/dist/components/molecules/Pagination/page-items.js +11 -0
- package/dist/components/organisms/DataTable/DataTable.cjs +1 -1
- package/dist/components/organisms/DataTable/DataTable.d.ts +8 -1
- package/dist/components/organisms/DataTable/DataTable.js +61 -98
- package/dist/components/organisms/ModerationQueue/ModerationQueue.cjs +1 -1
- package/dist/components/organisms/ModerationQueue/ModerationQueue.js +190 -192
- package/dist/components/organisms/Navbar/Navbar.cjs +1 -1
- package/dist/components/organisms/Navbar/Navbar.d.ts +2 -0
- package/dist/components/organisms/Navbar/Navbar.js +49 -49
- package/dist/index.d.ts +2 -0
- package/dist/meta.json +3 -3
- package/dist/node_modules/@fortawesome/free-solid-svg-icons/index.cjs +1 -1
- package/dist/node_modules/@fortawesome/free-solid-svg-icons/index.js +30 -50
- package/dist/roster.cjs +1 -1
- package/dist/roster.css +1 -1
- package/dist/roster.js +102 -98
- package/package.json +4 -3
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as g, jsx as n } from "react/jsx-runtime";
|
|
3
|
+
import { useId as vr, useState as L, useRef as p, useCallback as U, useLayoutEffect as Y, useEffect as xr } from "react";
|
|
4
|
+
import { cn as f } from "../../../lib/utils.js";
|
|
5
|
+
import { Button as G } from "../../atoms/Button/Button.js";
|
|
6
|
+
import { formatBytes as Z, acceptList as yr, sameFile as br, matchesType as kr } from "./file-rules.js";
|
|
7
|
+
const Nr = {
|
|
8
|
+
choose: "Choose photos",
|
|
9
|
+
dropHint: "or drag them here",
|
|
10
|
+
dropHere: "Drop to add them",
|
|
11
|
+
queued: "Waiting",
|
|
12
|
+
uploading: (s) => s === null ? "Uploading" : `Uploading, ${s}%`,
|
|
13
|
+
processing: "Finishing up",
|
|
14
|
+
done: "Uploaded",
|
|
15
|
+
failed: "Didn't upload.",
|
|
16
|
+
rejected: "Not added.",
|
|
17
|
+
remove: (s) => `Remove ${s}`,
|
|
18
|
+
retry: (s) => `Try ${s} again`,
|
|
19
|
+
wrongType: () => "That type of file isn't accepted.",
|
|
20
|
+
tooLarge: (s, d) => `It's over ${Z(d)}.`,
|
|
21
|
+
tooMany: (s) => `Only ${s} can be added.`,
|
|
22
|
+
duplicate: () => "It's already added.",
|
|
23
|
+
uploadError: (s) => s instanceof Error && s.message ? s.message : "Something went wrong.",
|
|
24
|
+
size: Z,
|
|
25
|
+
added: (s) => `${s} ${s === 1 ? "photo" : "photos"} added.`,
|
|
26
|
+
progress: (s, d) => `${s} of ${d} uploaded.`,
|
|
27
|
+
failedNotice: (s, d) => `${s} didn't upload. ${d}`,
|
|
28
|
+
rejectedNotice: (s, d) => `${s} wasn't added. ${d}`,
|
|
29
|
+
removed: (s) => `${s} removed.`
|
|
30
|
+
};
|
|
31
|
+
function wr({ file: s, status: d }) {
|
|
32
|
+
const [T, D] = L(!1), B = !T && (s.type.startsWith("image/") || /\.(jpe?g|png|gif|webp|avif|heic|heif)$/i.test(s.name)), $ = U(
|
|
33
|
+
(q) => {
|
|
34
|
+
if (!q) return;
|
|
35
|
+
const j = URL.createObjectURL(s);
|
|
36
|
+
return q.src = j, () => URL.revokeObjectURL(j);
|
|
37
|
+
},
|
|
38
|
+
[s]
|
|
39
|
+
), v = "rst:h-14 rst:w-14 rst:shrink-0 rst:rounded-md rst:border rst:border-[var(--roster-card-border)]";
|
|
40
|
+
return B ? /* @__PURE__ */ n(
|
|
41
|
+
"img",
|
|
42
|
+
{
|
|
43
|
+
ref: $,
|
|
44
|
+
alt: "",
|
|
45
|
+
onError: () => D(!0),
|
|
46
|
+
className: f(v, "rst:object-cover", d === "rejected" && "rst:opacity-50"),
|
|
47
|
+
"data-file-thumb": "image"
|
|
48
|
+
}
|
|
49
|
+
) : /* @__PURE__ */ n(
|
|
50
|
+
"span",
|
|
51
|
+
{
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
className: f(v, "rst:flex rst:items-center rst:justify-center rst:text-gray-500 rst:dark:text-gray-400"),
|
|
54
|
+
"data-file-thumb": "placeholder",
|
|
55
|
+
children: /* @__PURE__ */ g("svg", { viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
56
|
+
/* @__PURE__ */ n("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
|
|
57
|
+
/* @__PURE__ */ n("circle", { cx: "9", cy: "10", r: "1.6" }),
|
|
58
|
+
/* @__PURE__ */ n("path", { d: "m21 15-4.2-4.2a1.6 1.6 0 0 0-2.3 0L7 18" })
|
|
59
|
+
] })
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const V = "rst:cursor-not-allowed rst:opacity-50", I = { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" };
|
|
64
|
+
function Dr({
|
|
65
|
+
label: s,
|
|
66
|
+
upload: d,
|
|
67
|
+
onChange: T,
|
|
68
|
+
accept: D = "image/*",
|
|
69
|
+
types: B,
|
|
70
|
+
maxSize: $,
|
|
71
|
+
maxFiles: v,
|
|
72
|
+
validate: q,
|
|
73
|
+
concurrency: j = 3,
|
|
74
|
+
helperText: S,
|
|
75
|
+
errorMessage: R,
|
|
76
|
+
disabled: c = !1,
|
|
77
|
+
strings: rr,
|
|
78
|
+
className: tr
|
|
79
|
+
}) {
|
|
80
|
+
const o = { ...Nr, ...rr }, C = vr(), F = `${C}-label`, X = `${C}-help`, _ = `${C}-error`, [z, er] = L([]), l = p(z), sr = p(0), x = p(/* @__PURE__ */ new Map()), O = p(null), J = p(null), h = p({ upload: d, onChange: T, concurrency: j, t: o, pump: () => {
|
|
81
|
+
} }), [A, nr] = L({ text: "", n: 0 }), y = p([]), b = p(null), M = U((r, e = !1) => {
|
|
82
|
+
e && (y.current = y.current.filter((t) => !t.count)), y.current.push({ text: r, count: e }), !b.current && (b.current = setTimeout(() => {
|
|
83
|
+
b.current = null;
|
|
84
|
+
const t = y.current.map((i) => i.text).join(" ");
|
|
85
|
+
y.current = [], nr((i) => ({ text: t, n: i.n + 1 }));
|
|
86
|
+
}, 0));
|
|
87
|
+
}, []), H = p(null), [ar, or] = L(0), K = (r) => {
|
|
88
|
+
H.current = r, or((e) => e + 1);
|
|
89
|
+
};
|
|
90
|
+
Y(() => {
|
|
91
|
+
const r = H.current;
|
|
92
|
+
if (!r) return;
|
|
93
|
+
H.current = null, (O.current?.querySelector(r) ?? O.current?.querySelector("[data-file-choose]"))?.focus();
|
|
94
|
+
}, [ar]);
|
|
95
|
+
const k = U((r) => {
|
|
96
|
+
l.current = r, er(r), h.current.onChange?.(r);
|
|
97
|
+
}, []), N = U(
|
|
98
|
+
(r, e) => {
|
|
99
|
+
l.current.some((t) => t.id === r) && k(l.current.map((t) => t.id === r ? { ...t, ...e } : t));
|
|
100
|
+
},
|
|
101
|
+
[k]
|
|
102
|
+
);
|
|
103
|
+
function w() {
|
|
104
|
+
const { concurrency: r } = h.current, e = l.current.filter((i) => i.status === "uploading" || i.status === "processing").length, t = l.current.filter((i) => i.status === "queued").slice(0, Math.max(0, Math.max(1, r) - e));
|
|
105
|
+
for (const i of t) ir(i);
|
|
106
|
+
}
|
|
107
|
+
function ir(r) {
|
|
108
|
+
const e = new AbortController();
|
|
109
|
+
x.current.set(r.id, e), N(r.id, { status: "uploading", progress: null, reason: void 0 });
|
|
110
|
+
const t = () => !e.signal.aborted && x.current.get(r.id) === e, i = {
|
|
111
|
+
onProgress: (a) => {
|
|
112
|
+
if (!t()) return;
|
|
113
|
+
const u = Math.round(Math.min(1, Math.max(0, Number.isFinite(a) ? a : 0)) * 100) / 100, m = l.current.find((mr) => mr.id === r.id);
|
|
114
|
+
m?.status === "uploading" && m.progress !== u && N(r.id, { progress: u });
|
|
115
|
+
},
|
|
116
|
+
onProcessing: () => {
|
|
117
|
+
t() && N(r.id, { status: "processing" });
|
|
118
|
+
},
|
|
119
|
+
signal: e.signal
|
|
120
|
+
};
|
|
121
|
+
new Promise((a) => a(h.current.upload(r.file, i))).then(
|
|
122
|
+
(a) => {
|
|
123
|
+
if (!t()) return;
|
|
124
|
+
x.current.delete(r.id), N(r.id, { status: "done", progress: 1, result: a });
|
|
125
|
+
const u = l.current.filter((m) => m.status !== "rejected");
|
|
126
|
+
M(h.current.t.progress(u.filter((m) => m.status === "done").length, u.length), !0), w();
|
|
127
|
+
},
|
|
128
|
+
(a) => {
|
|
129
|
+
if (!t()) return;
|
|
130
|
+
x.current.delete(r.id);
|
|
131
|
+
const u = h.current.t.uploadError(a);
|
|
132
|
+
N(r.id, { status: "failed", reason: u }), M(h.current.t.failedNotice(r.file.name, u)), w();
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
Y(() => {
|
|
137
|
+
h.current = { upload: d, onChange: T, concurrency: j, t: o, pump: w };
|
|
138
|
+
}), xr(() => {
|
|
139
|
+
const r = x.current;
|
|
140
|
+
return l.current.some((t) => (t.status === "uploading" || t.status === "processing") && !r.has(t.id)) && (k(
|
|
141
|
+
l.current.map(
|
|
142
|
+
(t) => (t.status === "uploading" || t.status === "processing") && !r.has(t.id) ? { ...t, status: "queued", progress: null } : t
|
|
143
|
+
)
|
|
144
|
+
), h.current.pump()), () => {
|
|
145
|
+
for (const t of r.values()) t.abort();
|
|
146
|
+
r.clear(), b.current && clearTimeout(b.current), b.current = null, y.current = [];
|
|
147
|
+
};
|
|
148
|
+
}, [k]);
|
|
149
|
+
const cr = B ?? yr(D), dr = (r, e) => {
|
|
150
|
+
if (e.some((i) => br(i.file, r))) return o.duplicate(r);
|
|
151
|
+
const t = q?.(r);
|
|
152
|
+
if (t) return t;
|
|
153
|
+
if (!kr(r, cr)) return o.wrongType(r);
|
|
154
|
+
if ($ !== void 0 && r.size > $) return o.tooLarge(r, $);
|
|
155
|
+
if (v !== void 0 && e.length >= v) return o.tooMany(v);
|
|
156
|
+
}, Q = (r) => {
|
|
157
|
+
if (c || r.length === 0) return;
|
|
158
|
+
const e = l.current.filter((a) => a.status !== "rejected"), t = [];
|
|
159
|
+
for (const a of r) {
|
|
160
|
+
const u = dr(a, [...e, ...t.filter((m) => m.status !== "rejected")]);
|
|
161
|
+
t.push({ id: `${C}-file-${sr.current++}`, file: a, status: u ? "rejected" : "queued", progress: null, reason: u });
|
|
162
|
+
}
|
|
163
|
+
k([...l.current, ...t]);
|
|
164
|
+
const i = t.filter((a) => a.status === "queued").length;
|
|
165
|
+
i && M(o.added(i));
|
|
166
|
+
for (const a of t) a.reason && M(o.rejectedNotice(a.file.name, a.reason));
|
|
167
|
+
w();
|
|
168
|
+
}, lr = (r) => {
|
|
169
|
+
if (c) return;
|
|
170
|
+
const e = l.current, t = e.findIndex((a) => a.id === r);
|
|
171
|
+
if (t < 0) return;
|
|
172
|
+
x.current.get(r)?.abort(), x.current.delete(r);
|
|
173
|
+
const i = e[t + 1] ?? e[t - 1];
|
|
174
|
+
k(e.filter((a) => a.id !== r)), M(o.removed(e[t].file.name)), K(i ? `[data-file-remove="${i.id}"]` : "[data-file-choose]"), w();
|
|
175
|
+
}, ur = (r) => {
|
|
176
|
+
c || (N(r, { status: "queued", progress: null, reason: void 0 }), K(`[data-file-remove="${r}"]`), w());
|
|
177
|
+
}, [fr, W] = L(0), E = (r) => Array.from(r.dataTransfer?.types ?? []).includes("Files"), pr = {
|
|
178
|
+
onDragEnter: (r) => {
|
|
179
|
+
E(r) && (r.preventDefault(), W((e) => e + 1));
|
|
180
|
+
},
|
|
181
|
+
onDragOver: (r) => {
|
|
182
|
+
E(r) && (r.preventDefault(), r.dataTransfer.dropEffect = c ? "none" : "copy");
|
|
183
|
+
},
|
|
184
|
+
onDragLeave: (r) => {
|
|
185
|
+
E(r) && W((e) => Math.max(0, e - 1));
|
|
186
|
+
},
|
|
187
|
+
onDrop: (r) => {
|
|
188
|
+
E(r) && (r.preventDefault(), W(0), Q(Array.from(r.dataTransfer.files)));
|
|
189
|
+
}
|
|
190
|
+
}, P = fr > 0 && !c, gr = (r) => {
|
|
191
|
+
switch (r.status) {
|
|
192
|
+
case "queued":
|
|
193
|
+
return o.queued;
|
|
194
|
+
case "uploading":
|
|
195
|
+
return o.uploading(r.progress === null ? null : Math.round(r.progress * 100));
|
|
196
|
+
case "processing":
|
|
197
|
+
return o.processing;
|
|
198
|
+
case "done":
|
|
199
|
+
return o.done;
|
|
200
|
+
case "failed":
|
|
201
|
+
return `${o.failed} ${r.reason ?? ""}`.trim();
|
|
202
|
+
case "rejected":
|
|
203
|
+
return `${o.rejected} ${r.reason ?? ""}`.trim();
|
|
204
|
+
}
|
|
205
|
+
}, hr = [S ? X : null, R ? _ : null].filter(Boolean).join(" ") || void 0;
|
|
206
|
+
return /* @__PURE__ */ g(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
ref: O,
|
|
210
|
+
role: "group",
|
|
211
|
+
"aria-labelledby": F,
|
|
212
|
+
className: f("rst:font-ui rst:w-full", tr),
|
|
213
|
+
"data-file-upload": "",
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ n(
|
|
216
|
+
"p",
|
|
217
|
+
{
|
|
218
|
+
id: F,
|
|
219
|
+
className: f(
|
|
220
|
+
"rst:mb-1.5 rst:text-left rst:text-sm rst:font-medium rst:leading-none rst:text-[var(--roster-control-text)]",
|
|
221
|
+
c && "rst:opacity-70"
|
|
222
|
+
),
|
|
223
|
+
children: s
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
/* @__PURE__ */ g(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
...pr,
|
|
230
|
+
"data-file-drop": "",
|
|
231
|
+
"data-dragging": P ? "" : void 0,
|
|
232
|
+
className: f(
|
|
233
|
+
"rst:flex rst:flex-col rst:items-center rst:justify-center rst:gap-2 rst:rounded-lg rst:border-2 rst:border-dashed rst:px-4 rst:py-6 rst:text-center rst:transition-colors rst:motion-reduce:transition-none",
|
|
234
|
+
P ? "rst:border-primary-500 rst:bg-primary-500/10" : R ? "rst:border-error-500 rst:dark:border-error-400" : "rst:border-gray-300 rst:dark:border-gray-600"
|
|
235
|
+
),
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ n(
|
|
238
|
+
G,
|
|
239
|
+
{
|
|
240
|
+
type: "button",
|
|
241
|
+
variant: "outline",
|
|
242
|
+
colorScheme: "neutral",
|
|
243
|
+
size: "lg",
|
|
244
|
+
className: f("rst:px-5", c && V),
|
|
245
|
+
"aria-disabled": c || void 0,
|
|
246
|
+
"aria-describedby": hr,
|
|
247
|
+
onClick: () => J.current?.click(),
|
|
248
|
+
"data-file-choose": "",
|
|
249
|
+
startIcon: /* @__PURE__ */ n("svg", { ...I, "aria-hidden": "true", children: /* @__PURE__ */ n("path", { d: "M12 16V4M7 9l5-5 5 5M5 20h14" }) }),
|
|
250
|
+
children: o.choose
|
|
251
|
+
}
|
|
252
|
+
),
|
|
253
|
+
/* @__PURE__ */ n(
|
|
254
|
+
"p",
|
|
255
|
+
{
|
|
256
|
+
className: "rst:hidden rst:text-xs rst:text-gray-600 rst:pointer-fine:block rst:dark:text-gray-400",
|
|
257
|
+
"data-file-drop-hint": "",
|
|
258
|
+
children: P ? o.dropHere : o.dropHint
|
|
259
|
+
}
|
|
260
|
+
),
|
|
261
|
+
/* @__PURE__ */ n(
|
|
262
|
+
"input",
|
|
263
|
+
{
|
|
264
|
+
ref: J,
|
|
265
|
+
type: "file",
|
|
266
|
+
hidden: !0,
|
|
267
|
+
tabIndex: -1,
|
|
268
|
+
accept: D,
|
|
269
|
+
multiple: v !== 1,
|
|
270
|
+
disabled: c,
|
|
271
|
+
onChange: (r) => {
|
|
272
|
+
Q(Array.from(r.currentTarget.files ?? [])), r.currentTarget.value = "";
|
|
273
|
+
},
|
|
274
|
+
"data-file-input": ""
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
S && /* @__PURE__ */ n("p", { id: X, className: "rst:mt-1.5 rst:text-left rst:text-xs rst:text-gray-500 rst:dark:text-gray-400", children: S }),
|
|
281
|
+
R && /* @__PURE__ */ n("p", { id: _, className: "rst:mt-1.5 rst:text-left rst:text-xs rst:font-medium rst:text-error-600 rst:dark:text-error-400", children: R }),
|
|
282
|
+
z.length > 0 && /* @__PURE__ */ n("ul", { className: "rst:mt-3 rst:flex rst:flex-col rst:gap-2", "aria-labelledby": F, children: z.map((r) => {
|
|
283
|
+
const e = r.status === "failed" || r.status === "rejected", t = r.status === "uploading" || r.status === "processing" || r.status === "queued";
|
|
284
|
+
return /* @__PURE__ */ g(
|
|
285
|
+
"li",
|
|
286
|
+
{
|
|
287
|
+
"data-file-item": r.id,
|
|
288
|
+
"data-status": r.status,
|
|
289
|
+
className: "rst:flex rst:items-center rst:gap-3 rst:rounded-md rst:border rst:border-[var(--roster-card-border)] rst:p-2",
|
|
290
|
+
children: [
|
|
291
|
+
/* @__PURE__ */ n(wr, { file: r.file, status: r.status }),
|
|
292
|
+
/* @__PURE__ */ g("div", { className: "rst:min-w-0 rst:flex-1 rst:text-left", children: [
|
|
293
|
+
/* @__PURE__ */ n("p", { className: "rst:truncate rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]", title: r.file.name, children: r.file.name }),
|
|
294
|
+
/* @__PURE__ */ g(
|
|
295
|
+
"p",
|
|
296
|
+
{
|
|
297
|
+
className: f(
|
|
298
|
+
"rst:mt-0.5 rst:flex rst:items-start rst:gap-1 rst:text-xs",
|
|
299
|
+
e ? "rst:text-error-600 rst:dark:text-error-400" : "rst:text-gray-600 rst:dark:text-gray-400"
|
|
300
|
+
),
|
|
301
|
+
"data-file-status": "",
|
|
302
|
+
children: [
|
|
303
|
+
r.status === "done" && /* @__PURE__ */ n("svg", { ...I, width: 14, height: 14, "aria-hidden": "true", className: "rst:mt-px rst:shrink-0 rst:text-success-600 rst:dark:text-success-400", children: /* @__PURE__ */ n("path", { d: "M20 6 9 17l-5-5" }) }),
|
|
304
|
+
/* @__PURE__ */ g("span", { children: [
|
|
305
|
+
/* @__PURE__ */ n("span", { className: "rst:tabular-nums", children: o.size(r.file.size) }),
|
|
306
|
+
/* @__PURE__ */ n("span", { "aria-hidden": "true", children: " · " }),
|
|
307
|
+
gr(r)
|
|
308
|
+
] })
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
t && /* @__PURE__ */ n(
|
|
313
|
+
"div",
|
|
314
|
+
{
|
|
315
|
+
role: "progressbar",
|
|
316
|
+
"aria-label": r.file.name,
|
|
317
|
+
"aria-valuemin": 0,
|
|
318
|
+
"aria-valuemax": 100,
|
|
319
|
+
"aria-valuenow": r.status === "uploading" && r.progress !== null ? Math.round(r.progress * 100) : void 0,
|
|
320
|
+
className: f(
|
|
321
|
+
"rst:mt-1.5 rst:h-1.5 rst:overflow-hidden rst:rounded-full rst:bg-gray-200 rst:dark:bg-gray-700",
|
|
322
|
+
/* Under way with no figure yet: the track pulses and the
|
|
323
|
+
fill waits at zero, so the first figure grows it
|
|
324
|
+
rather than shrinking a full bar. */
|
|
325
|
+
r.status === "uploading" && r.progress === null && "rst:animate-pulse rst:motion-reduce:animate-none"
|
|
326
|
+
),
|
|
327
|
+
"data-file-progress": "",
|
|
328
|
+
children: /* @__PURE__ */ n(
|
|
329
|
+
"div",
|
|
330
|
+
{
|
|
331
|
+
className: f(
|
|
332
|
+
"rst:h-full rst:origin-left rst:rounded-full rst:bg-primary-600 rst:transition-transform rst:motion-reduce:transition-none rst:dark:bg-primary-400",
|
|
333
|
+
/* On the server: full, and pulsing, since there's no figure to give. */
|
|
334
|
+
r.status === "processing" && "rst:animate-pulse rst:motion-reduce:animate-none"
|
|
335
|
+
),
|
|
336
|
+
style: {
|
|
337
|
+
transform: `scaleX(${r.status === "processing" ? 1 : r.status === "uploading" ? r.progress ?? 0 : 0})`
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
] }),
|
|
344
|
+
r.status === "failed" && /* @__PURE__ */ n(
|
|
345
|
+
G,
|
|
346
|
+
{
|
|
347
|
+
type: "button",
|
|
348
|
+
variant: "ghost",
|
|
349
|
+
colorScheme: "neutral",
|
|
350
|
+
size: "icon",
|
|
351
|
+
className: f("rst:h-11 rst:w-11", c && V),
|
|
352
|
+
"aria-disabled": c || void 0,
|
|
353
|
+
"aria-label": o.retry(r.file.name),
|
|
354
|
+
onClick: () => ur(r.id),
|
|
355
|
+
"data-file-retry": r.id,
|
|
356
|
+
children: /* @__PURE__ */ g("svg", { ...I, "aria-hidden": "true", children: [
|
|
357
|
+
/* @__PURE__ */ n("path", { d: "M3 12a9 9 0 1 0 3-6.7L3 8" }),
|
|
358
|
+
/* @__PURE__ */ n("path", { d: "M3 3v5h5" })
|
|
359
|
+
] })
|
|
360
|
+
}
|
|
361
|
+
),
|
|
362
|
+
/* @__PURE__ */ n(
|
|
363
|
+
G,
|
|
364
|
+
{
|
|
365
|
+
type: "button",
|
|
366
|
+
variant: "ghost",
|
|
367
|
+
colorScheme: "neutral",
|
|
368
|
+
size: "icon",
|
|
369
|
+
className: f("rst:h-11 rst:w-11", c && V),
|
|
370
|
+
"aria-disabled": c || void 0,
|
|
371
|
+
"aria-label": o.remove(r.file.name),
|
|
372
|
+
onClick: () => lr(r.id),
|
|
373
|
+
"data-file-remove": r.id,
|
|
374
|
+
children: /* @__PURE__ */ n("svg", { ...I, "aria-hidden": "true", children: /* @__PURE__ */ n("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
375
|
+
}
|
|
376
|
+
)
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
r.id
|
|
380
|
+
);
|
|
381
|
+
}) }),
|
|
382
|
+
/* @__PURE__ */ g(
|
|
383
|
+
"div",
|
|
384
|
+
{
|
|
385
|
+
role: "status",
|
|
386
|
+
"aria-live": "polite",
|
|
387
|
+
"aria-atomic": "true",
|
|
388
|
+
className: "rst:sr-only",
|
|
389
|
+
"data-file-live": "",
|
|
390
|
+
"data-file-live-n": A.n,
|
|
391
|
+
children: [
|
|
392
|
+
A.text,
|
|
393
|
+
A.n % 2 ? " " : ""
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
)
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
export {
|
|
402
|
+
Dr as FileUpload
|
|
403
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={jpg:"image/jpeg",jpeg:"image/jpeg",jfif:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",avif:"image/avif",heic:"image/heic",heif:"image/heif",bmp:"image/bmp",tif:"image/tiff",tiff:"image/tiff",pdf:"application/pdf"},r=e=>{const t=e.lastIndexOf(".");return t>0?e.slice(t+1).toLowerCase():""};function a(e){return(e.type||s[r(e.name)]||"").toLowerCase()}function m(e,t){if(t.length===0)return!0;const n=a(e),f=r(e.name);return t.some(o=>{const i=o.trim().toLowerCase();return i?i.startsWith(".")?f===i.slice(1):i.endsWith("/*")?n.startsWith(i.slice(0,-1)):n===i:!1})}const p=e=>e.split(",").map(t=>t.trim()).filter(Boolean),c=(e,t)=>e.name===t.name&&e.size===t.size&&e.lastModified===t.lastModified;function g(e){if(e<1024)return`${e} B`;if(e<1024*1024)return`${Math.round(e/1024)} KB`;const t=e/(1024*1024);return`${t<9.95?t.toFixed(1).replace(/\.0$/,""):Math.round(t)} MB`}exports.acceptList=p;exports.formatBytes=g;exports.matchesType=m;exports.sameFile=c;exports.typeOf=a;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rules FileUpload checks a picked or dropped file against, kept apart
|
|
3
|
+
* from the component so they can be tested on their own.
|
|
4
|
+
*/
|
|
5
|
+
/** The file's type as reported, or as its extension implies when none is. */
|
|
6
|
+
export declare function typeOf(file: Pick<File, "name" | "type">): string;
|
|
7
|
+
/**
|
|
8
|
+
* Whether `file` matches one of `accepted`, written the way an `accept`
|
|
9
|
+
* attribute is: a type (`image/png`), a family (`image/*`) or an extension
|
|
10
|
+
* (`.png`). An empty list accepts anything.
|
|
11
|
+
*/
|
|
12
|
+
export declare function matchesType(file: Pick<File, "name" | "type">, accepted: readonly string[]): boolean;
|
|
13
|
+
/** An `accept` attribute's value, as a list. */
|
|
14
|
+
export declare const acceptList: (accept: string) => string[];
|
|
15
|
+
/** The same file picked twice: same name, size and modified time. */
|
|
16
|
+
export declare const sameFile: (a: File, b: File) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* A byte count as a short size: "820 KB", "2.4 MB". In units of 1,024, the way
|
|
19
|
+
* a limit is usually written (`15 * 1024 * 1024`), so that limit reads back as
|
|
20
|
+
* "15 MB" rather than "15.7 MB".
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatBytes(bytes: number): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const o = {
|
|
2
|
+
jpg: "image/jpeg",
|
|
3
|
+
jpeg: "image/jpeg",
|
|
4
|
+
jfif: "image/jpeg",
|
|
5
|
+
png: "image/png",
|
|
6
|
+
gif: "image/gif",
|
|
7
|
+
webp: "image/webp",
|
|
8
|
+
avif: "image/avif",
|
|
9
|
+
heic: "image/heic",
|
|
10
|
+
heif: "image/heif",
|
|
11
|
+
bmp: "image/bmp",
|
|
12
|
+
tif: "image/tiff",
|
|
13
|
+
tiff: "image/tiff",
|
|
14
|
+
pdf: "application/pdf"
|
|
15
|
+
}, r = (e) => {
|
|
16
|
+
const t = e.lastIndexOf(".");
|
|
17
|
+
return t > 0 ? e.slice(t + 1).toLowerCase() : "";
|
|
18
|
+
};
|
|
19
|
+
function s(e) {
|
|
20
|
+
return (e.type || o[r(e.name)] || "").toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
function m(e, t) {
|
|
23
|
+
if (t.length === 0) return !0;
|
|
24
|
+
const n = s(e), a = r(e.name);
|
|
25
|
+
return t.some((f) => {
|
|
26
|
+
const i = f.trim().toLowerCase();
|
|
27
|
+
return i ? i.startsWith(".") ? a === i.slice(1) : i.endsWith("/*") ? n.startsWith(i.slice(0, -1)) : n === i : !1;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const p = (e) => e.split(",").map((t) => t.trim()).filter(Boolean), g = (e, t) => e.name === t.name && e.size === t.size && e.lastModified === t.lastModified;
|
|
31
|
+
function c(e) {
|
|
32
|
+
if (e < 1024) return `${e} B`;
|
|
33
|
+
if (e < 1024 * 1024) return `${Math.round(e / 1024)} KB`;
|
|
34
|
+
const t = e / (1024 * 1024);
|
|
35
|
+
return `${t < 9.95 ? t.toFixed(1).replace(/\.0$/, "") : Math.round(t)} MB`;
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
p as acceptList,
|
|
39
|
+
c as formatBytes,
|
|
40
|
+
m as matchesType,
|
|
41
|
+
g as sameFile,
|
|
42
|
+
s as typeOf
|
|
43
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),w=require("react"),v=require("../../../lib/utils.cjs"),ee=require("../../atoms/Button/Button.cjs"),te=require("../../atoms/Button/button-variants.cjs"),se=require("../../atoms/Select/select-variants.cjs"),Q=require("./page-items.cjs"),re={nav:"Pagination",page:t=>`Page ${t}`,number:t=>String(t),previous:"Previous",next:"Next",previousPage:t=>t===null?"Previous page":`Previous page (${t})`,nextPage:t=>t===null?"Next page":`Next page (${t})`,firstPage:t=>t===null?"First page":`First page (${t})`,lastPage:t=>t===null?"Last page":`Last page (${t})`,gap:"…",picker:"Page",of:t=>`of ${t}`,status:(t,i)=>`Page ${t} of ${i}`};function ae({href:t,className:i,children:c,onClick:o,...d}){return e.jsx("a",{href:t,className:i,onClick:o,"aria-label":d["aria-label"],"aria-current":d["aria-current"],"aria-disabled":d["aria-disabled"],children:c})}const ne="rst:h-11 rst:min-w-11 rst:px-2",ie="rst:cursor-not-allowed rst:opacity-50",le="rst:forced-colors:border-2 rst:forced-colors:underline rst:forced-colors:decoration-2 rst:forced-colors:underline-offset-4",X={width:18,height:18,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0},F=({dir:t,double:i=!1})=>e.jsx("svg",{...X,className:"rst:shrink-0",children:t==="left"?i?e.jsx("path",{d:"m11 17-5-5 5-5M18 17l-5-5 5-5"}):e.jsx("path",{d:"m15 18-6-6 6-6"}):i?e.jsx("path",{d:"m13 17 5-5-5-5M6 17l5-5-5-5"}):e.jsx("path",{d:"m9 18 6-6-6-6"})});function oe({id:t,describedBy:i,page:c,pageCount:o,number:d,onCommit:k}){const[u,j]=w.useState(null),p=w.useRef(!1),x=u&&u.page===c?u.value:null,b=l=>{j(null),l!==c&&k(l)},P=w.useMemo(()=>Array.from({length:o},(l,f)=>e.jsx("option",{value:f+1,children:d(f+1)},f+1)),[o,d]);return e.jsx("select",{id:t,value:x??c,"aria-describedby":i,disabled:o<1,onKeyDown:l=>{if(l.key==="Enter"){x!==null&&(l.preventDefault(),b(x));return}if(l.key==="Escape"){j(null);return}p.current=!0,setTimeout(()=>{p.current=!1},0)},onChange:l=>{const f=Number(l.currentTarget.value);p.current?j({page:c,value:f}):b(f)},onBlur:()=>{x!==null&&b(x)},className:v.cn(se.selectTriggerVariants({variant:"outline"}),"rst:h-11 rst:w-auto rst:min-w-16 rst:appearance-none rst:pl-3 rst:pr-8 rst:text-base rst:tabular-nums"),"data-pagination-picker":"",children:P})}function ce({page:t,pageCount:i,onPageChange:c,getPageHref:o,linkComponent:d,navigate:k,layout:u="auto",siblings:j=1,edges:p=!0,align:x="center",variant:b="ghost",announce:P=!0,labels:l,className:f}){const a={...re,...l},m=Number.isFinite(i)?Math.max(0,Math.floor(i)):0,n=Q.clampPage(t,m),C=w.useId(),Y=d??ae,[E,Z]=w.useState({page:n,text:""});E.page!==n&&Z({page:n,text:P?a.status(n,m):""});const L=s=>{s!==Math.floor(t)&&c?.(s)},y=(s,r,N,A)=>{const h=s==="page"&&r===n,$=r===null,U=v.cn(ne,$&&ie,h&&le,A.className),W=s==="page"?`page-${r}`:s;if(o){const J=o(r??n);return e.jsx(Y,{href:J,to:J,className:v.cn(te.buttonVariants({variant:h?"solid":b,colorScheme:h?"primary":"neutral"}),U),"aria-label":A.label,"aria-current":h?"page":void 0,"aria-disabled":$?!0:void 0,onClick:g=>{if($){g.preventDefault();return}!g.defaultPrevented&&g.button===0&&!g.metaKey&&!g.ctrlKey&&!g.shiftKey&&!g.altKey&&r!==null&&L(r)},children:N},W)}return e.jsx(ee.Button,{type:"button",variant:h?"solid":b,colorScheme:h?"primary":"neutral",className:U,"aria-label":A.label,"aria-current":h?"page":void 0,"aria-disabled":$||void 0,onClick:()=>{r!==null&&L(r)},children:N},W)},I=n>1?n-1:null,R=n<m?n+1:null,T=n>1?1:null,B=n<m?m:null,M=s=>y("previous",I,e.jsxs(e.Fragment,{children:[e.jsx(F,{dir:"left"}),s&&e.jsx("span",{className:"rst:hidden rst:pr-1 rst:@[36rem]:inline",children:a.previous})]}),{label:a.previousPage(I)}),S=s=>y("next",R,e.jsxs(e.Fragment,{children:[s&&e.jsx("span",{className:"rst:hidden rst:pl-1 rst:@[36rem]:inline",children:a.next}),e.jsx(F,{dir:"right"})]}),{label:a.nextPage(R)}),K=s=>y("first",T,e.jsx(F,{dir:"left",double:!0}),{label:a.firstPage(T),className:s?"rst:hidden rst:@[24rem]:inline-flex":void 0}),V=s=>y("last",B,e.jsx(F,{dir:"right",double:!0}),{label:a.lastPage(B),className:s?"rst:hidden rst:@[24rem]:inline-flex":void 0}),D="rst:flex rst:flex-wrap rst:items-center rst:gap-1",q={start:"rst:justify-start",center:"rst:justify-center",end:"rst:justify-end"}[x],O=s=>e.jsxs("div",{className:v.cn(D,q,s),"data-pagination-layout":"pages",children:[M(!0),Q.pageItems(n,m,j).map(r=>typeof r=="number"?y("page",r,a.number(r),{label:a.page(r)}):e.jsx("span",{"aria-hidden":"true",className:"rst:inline-flex rst:h-11 rst:w-11 rst:items-center rst:justify-center rst:text-sm rst:text-gray-500 rst:dark:text-gray-400",children:a.gap},r)),S(!0)]}),_=`${C}-picker`,z=`${C}-of`,G=s=>e.jsxs("div",{className:v.cn(D,q,s),"data-pagination-layout":"compact",children:[p&&K(!0),M(!1),e.jsxs("div",{className:"rst:flex rst:items-center rst:gap-2 rst:px-1 rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]",children:[e.jsx("label",{htmlFor:_,children:a.picker}),e.jsxs("span",{className:"rst:relative rst:inline-flex",children:[e.jsx(oe,{id:_,describedBy:z,page:n,pageCount:m,number:a.number,onCommit:r=>{if(o){c?.(r);const N=o(r);k?k(N):window.location.assign(N)}else L(r)}}),e.jsx("svg",{...X,width:16,height:16,className:"rst:pointer-events-none rst:absolute rst:right-2.5 rst:top-1/2 rst:-translate-y-1/2 rst:text-gray-500 rst:dark:text-gray-400",children:e.jsx("path",{d:"m6 9 6 6 6-6"})})]}),e.jsx("span",{id:z,className:"rst:tabular-nums",children:a.of(m)})]}),S(!1),p&&V(!0)]}),H=e.jsxs("div",{className:v.cn(D,q),"data-pagination-layout":"arrows",children:[p&&K(!1),M(!1),S(!1),p&&V(!1)]});return e.jsxs("nav",{"aria-label":a.nav,className:v.cn("rst:font-ui",u==="arrows"?"rst:w-fit":"rst:@container rst:w-full rst:[contain-intrinsic-inline-size:18rem]",f),"data-pagination":"",children:[u==="pages"&&O(),u==="compact"&&G(),u==="arrows"&&H,u==="auto"&&e.jsxs(e.Fragment,{children:[O("rst:hidden rst:@[28rem]:flex"),G("rst:@[28rem]:hidden")]}),P&&e.jsx("div",{role:"status","aria-live":"polite","aria-atomic":"true",className:"rst:sr-only","data-pagination-live":"",children:E.text})]})}exports.Pagination=ce;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ComponentType, MouseEvent, ReactNode } from 'react';
|
|
2
|
+
/** Every word Pagination shows or says. Pass any of them in `labels` to replace it. */
|
|
3
|
+
export interface PaginationLabels {
|
|
4
|
+
/** The landmark's name. A page with two pagers needs each named. */
|
|
5
|
+
nav: string;
|
|
6
|
+
/** A page number's accessible name: "Page 40". */
|
|
7
|
+
page: (page: number) => string;
|
|
8
|
+
/** A page number as shown. */
|
|
9
|
+
number: (page: number) => string;
|
|
10
|
+
/** Shown beside the arrows where there's room. */
|
|
11
|
+
previous: string;
|
|
12
|
+
next: string;
|
|
13
|
+
/** Each arrow's accessible name, given the page it goes to, or `null` at the end it can't pass. */
|
|
14
|
+
previousPage: (target: number | null) => string;
|
|
15
|
+
nextPage: (target: number | null) => string;
|
|
16
|
+
firstPage: (target: number | null) => string;
|
|
17
|
+
lastPage: (target: number | null) => string;
|
|
18
|
+
/** Where pages are skipped. Hidden from screen readers, which hear the numbers either side. */
|
|
19
|
+
gap: string;
|
|
20
|
+
/** The page picker's label in the compact form: "Page". */
|
|
21
|
+
picker: string;
|
|
22
|
+
/** After the picker: "of 79". */
|
|
23
|
+
of: (pageCount: number) => string;
|
|
24
|
+
/** Said politely when the page changes: "Page 41 of 79". */
|
|
25
|
+
status: (page: number, pageCount: number) => string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The props every link is rendered with, in link mode.
|
|
29
|
+
*
|
|
30
|
+
* `href` and `to` carry the same value, so `next/link`, React Router's `Link`
|
|
31
|
+
* and a plain `<a>` all work without a wrapper.
|
|
32
|
+
*/
|
|
33
|
+
export interface PaginationLinkProps {
|
|
34
|
+
href: string;
|
|
35
|
+
to: string;
|
|
36
|
+
className: string;
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
"aria-label": string;
|
|
39
|
+
"aria-current"?: "page";
|
|
40
|
+
"aria-disabled"?: true;
|
|
41
|
+
onClick: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface PaginationProps {
|
|
44
|
+
/** The current page, from 1. */
|
|
45
|
+
page: number;
|
|
46
|
+
/** How many pages there are. */
|
|
47
|
+
pageCount: number;
|
|
48
|
+
/**
|
|
49
|
+
* Called with the page a control goes to.
|
|
50
|
+
*
|
|
51
|
+
* Without `getPageHref`, every control is a button and this is the only
|
|
52
|
+
* thing that changes the page: page in your own state.
|
|
53
|
+
*
|
|
54
|
+
* With `getPageHref`, the controls are links and navigate themselves; this
|
|
55
|
+
* is called first, on a plain left click (not one that opens a new tab),
|
|
56
|
+
* for an app that wants to do something as it goes.
|
|
57
|
+
*/
|
|
58
|
+
onPageChange?: (page: number) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Makes every control a real link to `getPageHref(page)`: crawlable,
|
|
61
|
+
* shareable, and openable in a new tab. Use it when your pages are URLs.
|
|
62
|
+
*/
|
|
63
|
+
getPageHref?: (page: number) => string;
|
|
64
|
+
/**
|
|
65
|
+
* Renders each link in link mode. Defaults to a plain `<a>`, which is right
|
|
66
|
+
* for a static site and wrong inside a router, where every hop becomes a
|
|
67
|
+
* full page load.
|
|
68
|
+
*
|
|
69
|
+
* **Pass it from a client component.** Functions can not cross the React
|
|
70
|
+
* Server Component boundary. Bind it in a small `"use client"` wrapper.
|
|
71
|
+
*/
|
|
72
|
+
linkComponent?: ComponentType<PaginationLinkProps>;
|
|
73
|
+
/**
|
|
74
|
+
* How the compact form's page picker goes to a page in link mode, where
|
|
75
|
+
* there's no link to follow. Defaults to a full page load
|
|
76
|
+
* (`location.assign`); pass your router's push to stay client-side.
|
|
77
|
+
*/
|
|
78
|
+
navigate?: (href: string) => void;
|
|
79
|
+
/**
|
|
80
|
+
* - `"pages"`: previous, page numbers with gaps, next.
|
|
81
|
+
* - `"compact"`: previous, a page picker ("Page 40 of 79"), next, and the
|
|
82
|
+
* first and last pages where there's room. Any page is two taps away.
|
|
83
|
+
* - `"arrows"`: first, previous, next, last, for a pager that shows its
|
|
84
|
+
* own position.
|
|
85
|
+
* - `"auto"` (the default): `"pages"` where the pager has room, `"compact"`
|
|
86
|
+
* where it doesn't. Decided by the pager's own width, not the screen's.
|
|
87
|
+
*/
|
|
88
|
+
layout?: "auto" | "pages" | "compact" | "arrows";
|
|
89
|
+
/** Page numbers shown either side of the current one. */
|
|
90
|
+
siblings?: number;
|
|
91
|
+
/** Whether the compact and arrow forms offer the first and last pages. */
|
|
92
|
+
edges?: boolean;
|
|
93
|
+
/** Where the controls sit in the pager's width. */
|
|
94
|
+
align?: "start" | "center" | "end";
|
|
95
|
+
/** How the controls other than the current page are drawn. */
|
|
96
|
+
variant?: "ghost" | "outline";
|
|
97
|
+
/** Say the new page in a polite live region when it changes. */
|
|
98
|
+
announce?: boolean;
|
|
99
|
+
labels?: Partial<PaginationLabels>;
|
|
100
|
+
className?: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Moves through pages of a list.
|
|
104
|
+
*
|
|
105
|
+
* Controlled: you hold `page`, and the pager says which page a control goes
|
|
106
|
+
* to. Its controls are buttons that call `onPageChange`, or, with
|
|
107
|
+
* `getPageHref`, real links.
|
|
108
|
+
*
|
|
109
|
+
* **Focus.** A control keeps focus after the page changes: the number you
|
|
110
|
+
* pressed is the same element afterwards, and an arrow that reaches the end
|
|
111
|
+
* stays focusable, `aria-disabled`. Nothing moves focus for you. To take a
|
|
112
|
+
* reader to the top of the new page, focus your list's heading in
|
|
113
|
+
* `onPageChange`.
|
|
114
|
+
*/
|
|
115
|
+
declare function Pagination({ page: rawPage, pageCount: rawCount, onPageChange, getPageHref, linkComponent, navigate, layout, siblings, edges, align, variant, announce, labels: overrides, className, }: PaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
116
|
+
export { Pagination };
|