@eifi1/ui-kit 0.6.0 → 0.7.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 +69 -33
- package/dist/chart.d.ts +1 -0
- package/dist/components/account-settings.js +3 -2
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +3 -0
- package/dist/components/amount-input.js +6 -4
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +36 -7
- package/dist/components/autocomplete.js +68 -22
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/calculator.d.ts +3 -0
- package/dist/components/calculator.js +2 -1
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-zoom.js +2 -1
- package/dist/components/chart-zoom.js.map +1 -1
- package/dist/components/chart.d.ts +33 -2
- package/dist/components/chart.js +20 -8
- package/dist/components/chart.js.map +1 -1
- package/dist/components/checkbox.d.ts +9 -0
- package/dist/components/checkbox.js +7 -2
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +34 -14
- package/dist/components/chip.js +63 -28
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +18 -1
- package/dist/components/choice-card.js +21 -8
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.d.ts +61 -2
- package/dist/components/combobox-core.js +68 -17
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +11 -7
- package/dist/components/combobox.js +51 -28
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/currency-select.js +3 -3
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +30 -6
- package/dist/components/danger-confirm.js +51 -32
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-pagination.d.ts +6 -3
- package/dist/components/data-table-pagination.js +6 -5
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +332 -248
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +17 -7
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +28 -3
- package/dist/components/dialog-frame.js +47 -11
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/disclosure.d.ts +22 -2
- package/dist/components/disclosure.js +41 -8
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/dropdown.d.ts +7 -3
- package/dist/components/dropdown.js +6 -2
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +17 -8
- package/dist/components/entity-combobox.js +7 -5
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/file-button.d.ts +36 -5
- package/dist/components/file-button.js +42 -3
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +9 -5
- package/dist/components/file-dropzone.js +14 -19
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/grouped-picker.js +2 -2
- package/dist/components/grouped-picker.js.map +1 -1
- package/dist/components/hover-menu.d.ts +8 -3
- package/dist/components/hover-menu.js +88 -4
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-picker.d.ts +10 -1
- package/dist/components/icon-picker.js +5 -1
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/measured-grid.d.ts +165 -0
- package/dist/components/measured-grid.js +559 -0
- package/dist/components/measured-grid.js.map +1 -0
- package/dist/components/mini-calendar.js +7 -8
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/month-picker.js +13 -9
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +9 -1
- package/dist/components/multi-select.js +22 -8
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +3 -0
- package/dist/components/number-input.d.ts +3 -0
- package/dist/components/number-input.js +3 -3
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +3 -0
- package/dist/components/numpad-sheet.js +3 -3
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/picker-sheet.js +1 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/popover.js +11 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/series-chart-ticks.d.ts +13 -0
- package/dist/components/series-chart-ticks.js +29 -0
- package/dist/components/series-chart-ticks.js.map +1 -0
- package/dist/components/series-chart.js +33 -27
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/swatch-picker.d.ts +10 -1
- package/dist/components/swatch-picker.js +2 -0
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/swipeable-row.d.ts +11 -2
- package/dist/components/swipeable-row.js +5 -3
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/switch.d.ts +9 -0
- package/dist/components/switch.js +7 -2
- package/dist/components/switch.js.map +1 -1
- package/dist/components/tile-radio.js +5 -7
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/toggle-group.d.ts +13 -3
- package/dist/components/toggle-group.js +21 -1
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.js +1 -2
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/treemap.d.ts +6 -1
- package/dist/components/treemap.js +16 -6
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/ui.d.ts +31 -7
- package/dist/components/ui.js +26 -18
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-anchor-dir.d.ts +15 -0
- package/dist/components/use-anchor-dir.js +14 -0
- package/dist/components/use-anchor-dir.js.map +1 -0
- package/dist/components/use-mobile-reveal.d.ts +8 -1
- package/dist/components/use-mobile-reveal.js +3 -2
- package/dist/components/use-mobile-reveal.js.map +1 -1
- package/dist/components/use-table-state.d.ts +4 -4
- package/dist/components/use-table-state.js +12 -5
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/{data-table-filters-DM1auUfH.d.ts → data-table-filters-noy0Abvi.d.ts} +40 -7
- package/dist/data-table.d.ts +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +22 -3
- package/dist/feedback/feedback-attachment.js +15 -7
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +3 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback.d.ts +1 -1
- package/dist/hooks/use-windowed-rows.d.ts +29 -0
- package/dist/hooks/use-windowed-rows.js +31 -0
- package/dist/hooks/use-windowed-rows.js.map +1 -0
- package/dist/i18n/defaults.d.ts +3 -0
- package/dist/i18n/defaults.js +5 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +5 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH.d.ts +43 -0
- package/dist/i18n/locales/de-CH.js +21 -0
- package/dist/i18n/locales/de-CH.js.map +1 -0
- package/dist/i18n/locales/de.d.ts +43 -0
- package/dist/i18n/locales/de.js +344 -0
- package/dist/i18n/locales/de.js.map +1 -0
- package/dist/i18n/locales/es.d.ts +43 -0
- package/dist/i18n/locales/es.js +339 -0
- package/dist/i18n/locales/es.js.map +1 -0
- package/dist/i18n/locales/fr.d.ts +43 -0
- package/dist/i18n/locales/fr.js +344 -0
- package/dist/i18n/locales/fr.js.map +1 -0
- package/dist/i18n/locales/hu.d.ts +43 -0
- package/dist/i18n/locales/hu.js +343 -0
- package/dist/i18n/locales/hu.js.map +1 -0
- package/dist/i18n/locales/it.d.ts +43 -0
- package/dist/i18n/locales/it.js +342 -0
- package/dist/i18n/locales/it.js.map +1 -0
- package/dist/i18n/locales/zh.d.ts +43 -0
- package/dist/i18n/locales/zh.js +338 -0
- package/dist/i18n/locales/zh.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/direction.d.ts +24 -0
- package/dist/lib/direction.js +19 -0
- package/dist/lib/direction.js.map +1 -0
- package/dist/rhf/form.js.map +1 -1
- package/dist/search/command-palette.d.ts +5 -0
- package/dist/search/command-palette.js +80 -50
- package/dist/search/command-palette.js.map +1 -1
- package/dist/shell/app-shell.d.ts +13 -1
- package/dist/shell/app-shell.js +133 -84
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/topbar-action-menu.js +1 -1
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +7 -3
- package/dist/shell/topbar-controls.js +38 -31
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +7 -1
- package/dist/theme/chart-palette.js +2 -1
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/tour/tour.d.ts +11 -5
- package/dist/tour/tour.js +124 -58
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/use-wizard.js +30 -13
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-summary.js +1 -1
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/package.json +12 -2
- package/src/components/account-settings.tsx +6 -2
- package/src/components/amount-input.tsx +10 -8
- package/src/components/autocomplete.tsx +123 -33
- package/src/components/calculator.tsx +5 -1
- package/src/components/chart-zoom.tsx +8 -1
- package/src/components/chart.tsx +68 -7
- package/src/components/checkbox.tsx +16 -0
- package/src/components/chip.tsx +131 -49
- package/src/components/choice-card.tsx +77 -36
- package/src/components/combobox-core.tsx +147 -20
- package/src/components/combobox.tsx +100 -44
- package/src/components/currency-select.tsx +6 -6
- package/src/components/danger-confirm.tsx +90 -36
- package/src/components/data-table-pagination.tsx +32 -19
- package/src/components/data-table.tsx +198 -36
- package/src/components/date-picker.tsx +24 -7
- package/src/components/dialog-frame.tsx +97 -22
- package/src/components/disclosure.tsx +75 -13
- package/src/components/dropdown.tsx +17 -5
- package/src/components/entity-combobox.tsx +26 -13
- package/src/components/file-button.tsx +102 -6
- package/src/components/file-dropzone.tsx +44 -35
- package/src/components/grouped-picker.tsx +2 -2
- package/src/components/hover-menu.tsx +139 -10
- package/src/components/icon-picker.tsx +14 -1
- package/src/components/measured-grid.tsx +852 -0
- package/src/components/mini-calendar.tsx +11 -8
- package/src/components/month-picker.tsx +18 -11
- package/src/components/multi-entity-combobox.tsx +2 -2
- package/src/components/multi-select.tsx +34 -7
- package/src/components/number-input.tsx +4 -4
- package/src/components/numpad-sheet.tsx +5 -3
- package/src/components/picker-sheet.tsx +1 -1
- package/src/components/popover.tsx +18 -3
- package/src/components/series-chart-ticks.ts +52 -0
- package/src/components/series-chart.tsx +39 -31
- package/src/components/swatch-picker.tsx +11 -0
- package/src/components/swipeable-row.tsx +21 -6
- package/src/components/switch.tsx +16 -0
- package/src/components/tile-radio.tsx +5 -7
- package/src/components/toggle-group.tsx +39 -3
- package/src/components/toggle-legend.tsx +5 -2
- package/src/components/treemap.tsx +28 -5
- package/src/components/ui.tsx +74 -30
- package/src/components/use-anchor-dir.ts +20 -0
- package/src/components/use-mobile-reveal.ts +10 -2
- package/src/components/use-table-state.ts +44 -7
- package/src/data-table.ts +1 -0
- package/src/feedback/feedback-attachment.tsx +36 -9
- package/src/feedback/feedback-dialog.tsx +3 -2
- package/src/hooks/use-windowed-rows.ts +69 -0
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/kit-labels.tsx +4 -0
- package/src/i18n/locales/de-CH.ts +30 -0
- package/src/i18n/locales/de.ts +365 -0
- package/src/i18n/locales/es.ts +358 -0
- package/src/i18n/locales/fr.ts +371 -0
- package/src/i18n/locales/hu.ts +359 -0
- package/src/i18n/locales/it.ts +360 -0
- package/src/i18n/locales/zh.ts +348 -0
- package/src/index.ts +10 -1
- package/src/lib/direction.ts +37 -0
- package/src/rhf/form.tsx +21 -0
- package/src/search/command-palette.tsx +77 -19
- package/src/shell/app-shell.tsx +200 -129
- package/src/shell/topbar-action-menu.tsx +1 -1
- package/src/shell/topbar-controls.tsx +19 -8
- package/src/theme/chart-palette.ts +9 -2
- package/src/tour/tour.tsx +119 -18
- package/src/wizard/use-wizard.ts +55 -17
- package/src/wizard/wizard-summary.tsx +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useEffect, useId, useRef, useState } from "react";
|
|
2
|
-
import type { ComponentPropsWithoutRef, FormEvent, ReactNode } from "react";
|
|
2
|
+
import type { ChangeEvent, ComponentPropsWithoutRef, FormEvent, ReactNode } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
4
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
5
|
-
import { Button, Input, Spinner } from "./ui";
|
|
5
|
+
import { Button, Input, Label, Spinner } from "./ui";
|
|
6
|
+
import { Tooltip } from "./tooltip";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Every string the tile renders — the `dangerConfirm` namespace of
|
|
@@ -20,20 +21,30 @@ export interface DangerConfirmLabels {
|
|
|
20
21
|
prompt: string;
|
|
21
22
|
/** Label of the password field (`requirePassword`). */
|
|
22
23
|
password: string;
|
|
23
|
-
/** Label of the type-to-confirm field
|
|
24
|
+
/** Label of the type-to-confirm field. A FUNCTION of the phrase by default, like
|
|
24
25
|
* every message that carries a value: where the phrase sits in the sentence moves
|
|
25
|
-
* with the language.
|
|
26
|
-
|
|
26
|
+
* with the language. A plain STRING is taken as the finished label — for an app
|
|
27
|
+
* whose catalogue already words it ("Type DELETE to confirm") and would otherwise
|
|
28
|
+
* wrap it as `() => label`. */
|
|
29
|
+
phrase: string | ((phrase: string) => string);
|
|
30
|
+
/** Placeholder of the type-to-confirm field — a string, or a function of the
|
|
31
|
+
* phrase (`(p) => p` echoes it). Optional and unset by default: the field keeps its
|
|
32
|
+
* floating label, as before. Given, the label moves ABOVE the field (a floating
|
|
33
|
+
* label occupies the empty field, which is exactly where a placeholder shows) and
|
|
34
|
+
* the placeholder fills the field. An empty string means none. */
|
|
35
|
+
phrasePlaceholder?: string | ((phrase: string) => string);
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
/** `satisfies` rather than a type annotation, so `DEFAULT_DANGER_CONFIRM_LABELS.phrase`
|
|
39
|
+
* stays callable for a caller that composes its own label from it. */
|
|
40
|
+
export const DEFAULT_DANGER_CONFIRM_LABELS = {
|
|
30
41
|
arm: "Delete…",
|
|
31
42
|
confirm: "Delete",
|
|
32
43
|
cancel: "Cancel",
|
|
33
44
|
prompt: "This cannot be undone.",
|
|
34
45
|
password: "Password",
|
|
35
|
-
phrase: (phrase) => `Type “${phrase}” to confirm`,
|
|
36
|
-
};
|
|
46
|
+
phrase: (phrase: string) => `Type “${phrase}” to confirm`,
|
|
47
|
+
} satisfies DangerConfirmLabels;
|
|
37
48
|
|
|
38
49
|
export interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
|
|
39
50
|
/**
|
|
@@ -48,8 +59,15 @@ export interface DangerConfirmProps extends Omit<ComponentPropsWithoutRef<"div">
|
|
|
48
59
|
/** Show a password field; confirm stays disabled until it is filled. */
|
|
49
60
|
requirePassword?: boolean;
|
|
50
61
|
/** Show a "type <phrase> to confirm" field; confirm stays disabled until the field
|
|
51
|
-
* matches
|
|
62
|
+
* matches (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
|
|
52
63
|
phrase?: string;
|
|
64
|
+
/**
|
|
65
|
+
* How the typed text is compared with `phrase`. `"trim"` (default) ignores spaces
|
|
66
|
+
* around it — a phone keyboard's autocomplete likes to add one. `"exact"` compares
|
|
67
|
+
* character for character, spaces included, for an app whose contract is "type
|
|
68
|
+
* exactly this".
|
|
69
|
+
*/
|
|
70
|
+
phraseMatch?: "trim" | "exact";
|
|
53
71
|
/** The warning above the fields. Defaults to `labels.prompt`. */
|
|
54
72
|
prompt?: ReactNode;
|
|
55
73
|
/** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
|
|
@@ -103,6 +121,7 @@ export function DangerConfirm({
|
|
|
103
121
|
onConfirm,
|
|
104
122
|
requirePassword,
|
|
105
123
|
phrase,
|
|
124
|
+
phraseMatch = "trim",
|
|
106
125
|
prompt,
|
|
107
126
|
tone = "danger",
|
|
108
127
|
armLabel,
|
|
@@ -127,6 +146,7 @@ export function DangerConfirm({
|
|
|
127
146
|
// that has focus (Enter was pressed in it) drops focus to <body>.
|
|
128
147
|
const promptId = useId();
|
|
129
148
|
const reasonId = useId();
|
|
149
|
+
const phraseFieldId = useId();
|
|
130
150
|
|
|
131
151
|
// The kit's Button takes no ref, so the two buttons focus is moved to are found by id.
|
|
132
152
|
const armId = useId();
|
|
@@ -180,7 +200,7 @@ export function DangerConfirm({
|
|
|
180
200
|
|
|
181
201
|
const locked = lockedReason !== undefined && lockedReason !== null && lockedReason !== false && lockedReason !== "";
|
|
182
202
|
const passwordOk = !requirePassword || password !== "";
|
|
183
|
-
const phraseOk = phrase === undefined || typed.trim() === phrase;
|
|
203
|
+
const phraseOk = phrase === undefined || (phraseMatch === "exact" ? typed : typed.trim()) === phrase;
|
|
184
204
|
const canConfirm = passwordOk && phraseOk && !busy;
|
|
185
205
|
|
|
186
206
|
const submit = (e: FormEvent) => {
|
|
@@ -202,25 +222,61 @@ export function DangerConfirm({
|
|
|
202
222
|
);
|
|
203
223
|
};
|
|
204
224
|
|
|
225
|
+
const phrasePlaceholder =
|
|
226
|
+
phrase === undefined || labels.phrasePlaceholder === undefined
|
|
227
|
+
? undefined
|
|
228
|
+
: typeof labels.phrasePlaceholder === "function"
|
|
229
|
+
? labels.phrasePlaceholder(phrase)
|
|
230
|
+
: labels.phrasePlaceholder;
|
|
231
|
+
|
|
232
|
+
const phraseLabel =
|
|
233
|
+
phrase === undefined ? "" : typeof labels.phrase === "function" ? labels.phrase(phrase) : labels.phrase;
|
|
234
|
+
const phraseFieldProps = {
|
|
235
|
+
ref: firstFieldRef,
|
|
236
|
+
value: typed,
|
|
237
|
+
autoComplete: "off",
|
|
238
|
+
autoCapitalize: "off",
|
|
239
|
+
spellCheck: false,
|
|
240
|
+
readOnly: busy,
|
|
241
|
+
onChange: (e: ChangeEvent<HTMLInputElement>) => setTyped(e.target.value),
|
|
242
|
+
};
|
|
243
|
+
|
|
205
244
|
const toneText = tone === "warning" ? "text-[var(--warning)]" : "text-[var(--danger)]";
|
|
206
245
|
|
|
207
246
|
if (!armed) {
|
|
247
|
+
const arm = (
|
|
248
|
+
<Button
|
|
249
|
+
id={armId}
|
|
250
|
+
type="button"
|
|
251
|
+
variant={tone === "warning" ? "secondary" : "danger"}
|
|
252
|
+
disabled={disabled}
|
|
253
|
+
aria-disabled={locked || undefined}
|
|
254
|
+
aria-describedby={locked ? reasonId : undefined}
|
|
255
|
+
onClick={() => {
|
|
256
|
+
if (!locked) setArmed(true);
|
|
257
|
+
}}
|
|
258
|
+
className="aria-disabled:cursor-not-allowed aria-disabled:opacity-50"
|
|
259
|
+
>
|
|
260
|
+
{armLabel ?? labels.arm}
|
|
261
|
+
</Button>
|
|
262
|
+
);
|
|
208
263
|
return (
|
|
209
264
|
<div {...rest} className={cn("space-y-1", className)}>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
aria-describedby
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
265
|
+
{locked ? (
|
|
266
|
+
// The reason on the button itself too, where the pointer that tried it is —
|
|
267
|
+
// the line below can sit out of view in a long settings card. Portalled, so
|
|
268
|
+
// a card that scrolls neither clips it nor grows by it.
|
|
269
|
+
//
|
|
270
|
+
// The button in a FRAGMENT on purpose: Tooltip clones an element child to
|
|
271
|
+
// add the bubble to its `aria-describedby`, and the button is already
|
|
272
|
+
// described by the visible line below — the same sentence twice, read out
|
|
273
|
+
// on every focus. A fragment is left as it is, so the bubble stays visual.
|
|
274
|
+
<Tooltip label={lockedReason} portal>
|
|
275
|
+
<>{arm}</>
|
|
276
|
+
</Tooltip>
|
|
277
|
+
) : (
|
|
278
|
+
arm
|
|
279
|
+
)}
|
|
224
280
|
{locked && (
|
|
225
281
|
<p id={reasonId} className="text-xs text-[var(--text-muted)]">
|
|
226
282
|
{lockedReason}
|
|
@@ -242,18 +298,16 @@ export function DangerConfirm({
|
|
|
242
298
|
<p id={promptId} className={cn("text-xs font-medium", toneText)}>
|
|
243
299
|
{prompt ?? labels.prompt}
|
|
244
300
|
</p>
|
|
245
|
-
{phrase !== undefined &&
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
/>
|
|
256
|
-
)}
|
|
301
|
+
{phrase !== undefined &&
|
|
302
|
+
(phrasePlaceholder ? (
|
|
303
|
+
// A static label above, so the placeholder has the empty field to itself.
|
|
304
|
+
<div className="space-y-1.5">
|
|
305
|
+
<Label htmlFor={phraseFieldId}>{phraseLabel}</Label>
|
|
306
|
+
<Input id={phraseFieldId} placeholder={phrasePlaceholder} {...phraseFieldProps} />
|
|
307
|
+
</div>
|
|
308
|
+
) : (
|
|
309
|
+
<Input label={phraseLabel} {...phraseFieldProps} />
|
|
310
|
+
))}
|
|
257
311
|
{requirePassword && (
|
|
258
312
|
<Input
|
|
259
313
|
// The phrase field takes the ref when both are there — it comes first.
|
|
@@ -2,7 +2,7 @@ import { useMemo } from "react";
|
|
|
2
2
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
4
|
import { DEFAULT_DATA_TABLE_LABELS, type DataTableLabels } from "./data-table-labels";
|
|
5
|
-
import { useKitLocale } from "../i18n/kit-labels";
|
|
5
|
+
import { useKitLabels, useKitLocale } from "../i18n/kit-labels";
|
|
6
6
|
|
|
7
7
|
export const PAGE_SIZE_OPTIONS = [10, 25, 50, 100, 200] as const;
|
|
8
8
|
|
|
@@ -12,8 +12,11 @@ interface PaginationProps {
|
|
|
12
12
|
pageSize: number;
|
|
13
13
|
total: number;
|
|
14
14
|
onPage: (p: number) => void;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/** Omit when the page size is not the user's to change (a server that fixes it):
|
|
16
|
+
* the select is then not rendered at all, rather than rendered and inert. */
|
|
17
|
+
onPageSize?: (n: number) => void;
|
|
18
|
+
/** Over `dataTable` from `<UiKitProvider labels>`, over the English defaults. */
|
|
19
|
+
labels?: Partial<DataTableLabels>;
|
|
17
20
|
/** For the page numbers and page-size options; falls back to the provider's. */
|
|
18
21
|
locale?: string;
|
|
19
22
|
}
|
|
@@ -27,9 +30,14 @@ export function Pagination({
|
|
|
27
30
|
total,
|
|
28
31
|
onPage,
|
|
29
32
|
onPageSize,
|
|
30
|
-
labels
|
|
33
|
+
labels: labelsProp,
|
|
31
34
|
locale: localeProp,
|
|
32
35
|
}: PaginationProps) {
|
|
36
|
+
// prop > provider > English, like every other kit component. This defaulted straight
|
|
37
|
+
// to the English object, so a standalone pager under a translated provider still
|
|
38
|
+
// said "Rows per page" — only the pager INSIDE a DataTable was translated, because
|
|
39
|
+
// the table resolved the provider's labels and handed them down.
|
|
40
|
+
const labels = useKitLabels("dataTable", DEFAULT_DATA_TABLE_LABELS, labelsProp);
|
|
33
41
|
const locale = useKitLocale(localeProp);
|
|
34
42
|
// The bare numbers on the strip and in the select are text too: `String(n)` is
|
|
35
43
|
// always ASCII digits, which is wrong for a locale that writes its own. The range
|
|
@@ -60,19 +68,23 @@ export function Pagination({
|
|
|
60
68
|
? labels.rowCount(total)
|
|
61
69
|
: labels.pageRange(page * pageSize + 1, Math.min(total, (page + 1) * pageSize), total)}
|
|
62
70
|
</span>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
{onPageSize && (
|
|
72
|
+
<select
|
|
73
|
+
value={pageSize === Infinity ? "all" : pageSize}
|
|
74
|
+
onChange={(e) =>
|
|
75
|
+
onPageSize(e.target.value === "all" ? Infinity : Number(e.target.value))
|
|
76
|
+
}
|
|
77
|
+
className="rounded border border-[var(--border)] bg-[var(--bg-surface)] px-1 py-0.5 text-xs"
|
|
78
|
+
aria-label={labels.pageSize}
|
|
79
|
+
>
|
|
80
|
+
{PAGE_SIZE_OPTIONS.map((n) => (
|
|
81
|
+
<option key={n} value={n}>
|
|
82
|
+
{num.format(n)}
|
|
83
|
+
</option>
|
|
84
|
+
))}
|
|
85
|
+
<option value="all">{labels.pageSizeAll}</option>
|
|
86
|
+
</select>
|
|
87
|
+
)}
|
|
76
88
|
</div>
|
|
77
89
|
{pageSize !== Infinity && totalPages > 1 && (
|
|
78
90
|
<div className="flex items-center gap-1">
|
|
@@ -83,7 +95,8 @@ export function Pagination({
|
|
|
83
95
|
className="rounded p-1 hover:bg-[var(--bg-hover)] disabled:opacity-40"
|
|
84
96
|
aria-label={labels.prevPage}
|
|
85
97
|
>
|
|
86
|
-
|
|
98
|
+
{/* "Previous" points back along the line — left in LTR, right in RTL. */}
|
|
99
|
+
<ChevronLeft className="size-4 rtl:-scale-x-100" />
|
|
87
100
|
</button>
|
|
88
101
|
{items.map((it, i) =>
|
|
89
102
|
it === "ellipsis" ? (
|
|
@@ -117,7 +130,7 @@ export function Pagination({
|
|
|
117
130
|
className="rounded p-1 hover:bg-[var(--bg-hover)] disabled:opacity-40"
|
|
118
131
|
aria-label={labels.nextPage}
|
|
119
132
|
>
|
|
120
|
-
<ChevronRight className="size-4" />
|
|
133
|
+
<ChevronRight className="size-4 rtl:-scale-x-100" />
|
|
121
134
|
</button>
|
|
122
135
|
</div>
|
|
123
136
|
)}
|