@akira-io/ui 1.0.0 → 1.1.1
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 +15 -10
- package/dist/blocks.d.ts +162 -9
- package/dist/blocks.js +1410 -36
- package/dist/blocks.js.map +1 -1
- package/dist/button-Bj6My68b.d.ts +17 -0
- package/dist/chunk-2WIIRDHT.js +83 -0
- package/dist/chunk-2WIIRDHT.js.map +1 -0
- package/dist/{chunk-A2SIZOEA.js → chunk-4SOQAVUP.js} +125 -45
- package/dist/chunk-4SOQAVUP.js.map +1 -0
- package/dist/chunk-5AJFQ6C4.js +35 -0
- package/dist/chunk-5AJFQ6C4.js.map +1 -0
- package/dist/chunk-CFDDAFPJ.js +1243 -0
- package/dist/chunk-CFDDAFPJ.js.map +1 -0
- package/dist/chunk-FWQFB37J.js +45 -0
- package/dist/chunk-FWQFB37J.js.map +1 -0
- package/dist/chunk-IQMRJXEO.js +59 -0
- package/dist/chunk-IQMRJXEO.js.map +1 -0
- package/dist/chunk-L2H5GIF7.js +22 -0
- package/dist/chunk-L2H5GIF7.js.map +1 -0
- package/dist/chunk-ODYCBCKS.js +290 -0
- package/dist/chunk-ODYCBCKS.js.map +1 -0
- package/dist/{chunk-5MQWJVM2.js → chunk-QHZWW55M.js} +383 -326
- package/dist/chunk-QHZWW55M.js.map +1 -0
- package/dist/chunk-RPCL7VFQ.js +123 -0
- package/dist/chunk-RPCL7VFQ.js.map +1 -0
- package/dist/chunk-T2INZOCM.js +165 -0
- package/dist/chunk-T2INZOCM.js.map +1 -0
- package/dist/chunk-TGF54WAO.js +29 -0
- package/dist/chunk-TGF54WAO.js.map +1 -0
- package/dist/chunk-XZCC6MTE.js +26 -0
- package/dist/chunk-XZCC6MTE.js.map +1 -0
- package/dist/{chunk-UXL33CZ4.js → chunk-YOVY3KT6.js} +13 -11
- package/dist/chunk-YOVY3KT6.js.map +1 -0
- package/dist/code.d.ts +9 -0
- package/dist/code.js +650 -0
- package/dist/code.js.map +1 -0
- package/dist/context-YWbxMH0C.d.ts +383 -0
- package/dist/editor.d.ts +128 -0
- package/dist/editor.js +450 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.d.ts +298 -222
- package/dist/index.js +1300 -670
- package/dist/index.js.map +1 -1
- package/dist/inertia.d.ts +47 -2
- package/dist/inertia.js +138 -7
- package/dist/inertia.js.map +1 -1
- package/dist/input-Dpi7pXeR.d.ts +6 -0
- package/dist/json-viewer-BARA2RCW.d.ts +51 -0
- package/dist/{language-Bft6rBBt.d.ts → language-Dgjr9bm3.d.ts} +1 -1
- package/dist/locales/pt.d.ts +26 -4
- package/dist/locales/pt.js +127 -1
- package/dist/locales/pt.js.map +1 -1
- package/dist/password-input-DcXX7SG9.d.ts +51 -0
- package/dist/shells.d.ts +45 -7
- package/dist/shells.js +96 -60
- package/dist/shells.js.map +1 -1
- package/dist/sidebar-DqkFRUxQ.d.ts +81 -0
- package/dist/types-B-eGPoFD.d.ts +111 -0
- package/dist/types-cmBL8zOc.d.ts +51 -0
- package/package.json +170 -130
- package/theme.css +20 -0
- package/themes/nosferry.css +4 -0
- package/dist/chunk-42BJBH56.js +0 -786
- package/dist/chunk-42BJBH56.js.map +0 -1
- package/dist/chunk-5MQWJVM2.js.map +0 -1
- package/dist/chunk-A2SIZOEA.js.map +0 -1
- package/dist/chunk-POE7OYET.js +0 -96
- package/dist/chunk-POE7OYET.js.map +0 -1
- package/dist/chunk-UXL33CZ4.js.map +0 -1
- package/dist/date-range-filter-QEa8fhUM.d.ts +0 -149
- package/dist/sidebar-BDhG9SUU.d.ts +0 -88
- package/dist/types-Cno1_Ijx.d.ts +0 -40
- package/dist/types-cOieac8G.d.ts +0 -77
package/dist/blocks.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Popover, PopoverTrigger, PopoverContent, Tabs, TabsList, TabsTrigger, TabsContent,
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, ConfirmDialog, Popover, PopoverTrigger, PopoverContent, FloatingSheet, FloatingSheetBody, FloatingSheetFooter, Tabs, TabsList, TabsTrigger, TabsContent, Textarea, Switch, FieldError, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, InputOTP, InputOTPGroup, InputOTPSlot, Alert, AlertDescription, Calendar } from './chunk-CFDDAFPJ.js';
|
|
2
|
+
import { CopyButton } from './chunk-2WIIRDHT.js';
|
|
3
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Label } from './chunk-T2INZOCM.js';
|
|
4
|
+
import { Card } from './chunk-RPCL7VFQ.js';
|
|
5
|
+
export { DEFAULT_TOUR_LABELS, TourProvider, resolveSteps, shouldStartTour, stepsForBreakpoint, useTour, useTourController } from './chunk-YOVY3KT6.js';
|
|
6
|
+
import { useUiLabels, useUiLocale } from './chunk-5AJFQ6C4.js';
|
|
7
|
+
export { UiLocaleProvider, useUiLabels, useUiLocale } from './chunk-5AJFQ6C4.js';
|
|
8
|
+
import { resolveLink } from './chunk-L2H5GIF7.js';
|
|
9
|
+
import { Input } from './chunk-XZCC6MTE.js';
|
|
10
|
+
import { Button, cn, elevatedSurface, nestedSurfaceReset, recessedSurface, compactRadius, controlRadius, Spinner } from './chunk-ODYCBCKS.js';
|
|
11
|
+
import { createContext, useState, useCallback, useEffect, useContext, useId, useRef } from 'react';
|
|
5
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
import { CalendarDays, ChevronLeft, ArrowLeftToLine, X, ArrowRight, ArrowUpRight, ArrowDownRight } from 'lucide-react';
|
|
13
|
+
import { TriangleAlert, CalendarDays, ArrowLeft, ChevronRight, AlertCircle, ShieldOff, EyeOff, Eye, RefreshCw, ChevronLeft, ArrowLeftToLine, X, ArrowRight, ArrowUpRight, ArrowDownRight } from 'lucide-react';
|
|
7
14
|
import { subYears, subQuarters, subMonths, subWeeks, subDays, endOfYear, endOfQuarter, endOfMonth, endOfDay, startOfYear, startOfQuarter, startOfMonth, startOfDay, isSameYear, format, endOfWeek, startOfWeek } from 'date-fns';
|
|
8
15
|
import { pt } from 'date-fns/locale';
|
|
9
16
|
|
|
17
|
+
var commandPaletteDefaultLabels = {
|
|
18
|
+
placeholder: "Search...",
|
|
19
|
+
noResultsLabel: "No results found"
|
|
20
|
+
};
|
|
10
21
|
function CommandPalette({
|
|
11
22
|
open,
|
|
12
23
|
onOpenChange,
|
|
@@ -14,12 +25,16 @@ function CommandPalette({
|
|
|
14
25
|
onSelect,
|
|
15
26
|
query,
|
|
16
27
|
onQueryChange,
|
|
17
|
-
placeholder
|
|
18
|
-
noResultsLabel
|
|
28
|
+
placeholder,
|
|
29
|
+
noResultsLabel,
|
|
19
30
|
emptyState,
|
|
20
31
|
className
|
|
21
32
|
}) {
|
|
22
|
-
const
|
|
33
|
+
const labels = useUiLabels("commandPalette", commandPaletteDefaultLabels, {
|
|
34
|
+
placeholder,
|
|
35
|
+
noResultsLabel
|
|
36
|
+
});
|
|
37
|
+
const resolvedEmptyState = emptyState ?? labels.noResultsLabel;
|
|
23
38
|
return /* @__PURE__ */ jsxs(
|
|
24
39
|
CommandDialog,
|
|
25
40
|
{
|
|
@@ -30,7 +45,7 @@ function CommandPalette({
|
|
|
30
45
|
/* @__PURE__ */ jsx(
|
|
31
46
|
CommandInput,
|
|
32
47
|
{
|
|
33
|
-
placeholder,
|
|
48
|
+
placeholder: labels.placeholder,
|
|
34
49
|
value: query,
|
|
35
50
|
onValueChange: onQueryChange
|
|
36
51
|
}
|
|
@@ -70,6 +85,98 @@ function useCommandPalette(initialOpen = false) {
|
|
|
70
85
|
}, [toggle]);
|
|
71
86
|
return { open, setOpen, toggle };
|
|
72
87
|
}
|
|
88
|
+
var dangerZoneLabels = {
|
|
89
|
+
title: "Danger zone",
|
|
90
|
+
description: "These actions are permanent and cannot be undone.",
|
|
91
|
+
actionLabel: "Delete",
|
|
92
|
+
confirmTitle: "Confirm Action",
|
|
93
|
+
confirmDescription: "Are you sure you want to continue? This action cannot be undone.",
|
|
94
|
+
confirmText: "Confirm",
|
|
95
|
+
cancelText: "Cancel",
|
|
96
|
+
requiredValueLabel: "Type {{value}} to confirm"
|
|
97
|
+
};
|
|
98
|
+
function DangerZone({
|
|
99
|
+
title,
|
|
100
|
+
description,
|
|
101
|
+
actions,
|
|
102
|
+
processing = false,
|
|
103
|
+
labels,
|
|
104
|
+
footer,
|
|
105
|
+
className,
|
|
106
|
+
slotName = "danger-zone"
|
|
107
|
+
}) {
|
|
108
|
+
const copy = { ...dangerZoneLabels, ...labels };
|
|
109
|
+
const [activeId, setActiveId] = useState(null);
|
|
110
|
+
const active = actions.find((action) => action.id === activeId) ?? null;
|
|
111
|
+
return /* @__PURE__ */ jsxs(
|
|
112
|
+
"section",
|
|
113
|
+
{
|
|
114
|
+
className: cn(
|
|
115
|
+
elevatedSurface,
|
|
116
|
+
nestedSurfaceReset,
|
|
117
|
+
"gap-6 p-6 flex flex-col bg-destructive/5 ring-destructive/30",
|
|
118
|
+
className
|
|
119
|
+
),
|
|
120
|
+
"data-slot": slotName,
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "danger-zone-header", className: "gap-3 flex", children: [
|
|
123
|
+
/* @__PURE__ */ jsx("span", { className: "size-11 rounded-2xl flex shrink-0 items-center justify-center bg-destructive/10 text-destructive", children: /* @__PURE__ */ jsx(TriangleAlert, { className: "size-5" }) }),
|
|
124
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
125
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-destructive", children: title ?? copy.title }),
|
|
126
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: description ?? copy.description })
|
|
127
|
+
] })
|
|
128
|
+
] }),
|
|
129
|
+
/* @__PURE__ */ jsx("ul", { "data-slot": "danger-zone-actions", className: "gap-4 flex flex-col", children: actions.map((action) => /* @__PURE__ */ jsxs(
|
|
130
|
+
"li",
|
|
131
|
+
{
|
|
132
|
+
"data-slot": "danger-zone-action",
|
|
133
|
+
"data-action-id": action.id,
|
|
134
|
+
className: "gap-4 sm:flex-row sm:items-center sm:justify-between flex flex-col",
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
137
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: action.title }),
|
|
138
|
+
action.description && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: action.description })
|
|
139
|
+
] }),
|
|
140
|
+
/* @__PURE__ */ jsx(
|
|
141
|
+
Button,
|
|
142
|
+
{
|
|
143
|
+
type: "button",
|
|
144
|
+
variant: "destructive",
|
|
145
|
+
disabled: processing || action.disabled,
|
|
146
|
+
onClick: () => setActiveId(action.id),
|
|
147
|
+
className: "sm:w-auto w-full",
|
|
148
|
+
children: action.actionLabel ?? copy.actionLabel
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
action.id
|
|
154
|
+
)) }),
|
|
155
|
+
footer,
|
|
156
|
+
/* @__PURE__ */ jsx(
|
|
157
|
+
ConfirmDialog,
|
|
158
|
+
{
|
|
159
|
+
open: active !== null,
|
|
160
|
+
onOpenChange: (open) => {
|
|
161
|
+
if (!open) {
|
|
162
|
+
setActiveId(null);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
variant: "destructive",
|
|
166
|
+
processing,
|
|
167
|
+
title: active?.confirmTitle ?? copy.confirmTitle,
|
|
168
|
+
description: active?.confirmDescription ?? copy.confirmDescription,
|
|
169
|
+
confirmText: active?.confirmText ?? copy.confirmText,
|
|
170
|
+
cancelText: active?.cancelText ?? copy.cancelText,
|
|
171
|
+
requiredValue: active?.requiredValue,
|
|
172
|
+
requiredValueLabel: active?.requiredValueLabel ?? copy.requiredValueLabel,
|
|
173
|
+
onConfirm: () => active?.onConfirm()
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
73
180
|
var DateFilterContext = createContext(null);
|
|
74
181
|
var DateFilterProvider = DateFilterContext.Provider;
|
|
75
182
|
function useDateFilter() {
|
|
@@ -407,22 +514,24 @@ var DEFAULT_LABELS = {
|
|
|
407
514
|
function DateFilter({
|
|
408
515
|
value,
|
|
409
516
|
onChange,
|
|
410
|
-
presets
|
|
411
|
-
operators
|
|
412
|
-
units
|
|
517
|
+
presets,
|
|
518
|
+
operators,
|
|
519
|
+
units,
|
|
413
520
|
labels,
|
|
414
521
|
children
|
|
415
522
|
}) {
|
|
523
|
+
const locale = useUiLocale();
|
|
524
|
+
const resolvedLabels = useUiLabels("dateFilter", DEFAULT_LABELS, labels);
|
|
416
525
|
const [open, setOpen] = useState(false);
|
|
417
526
|
const [panel, setPanel] = useState("root");
|
|
418
527
|
const [draft, setDraft] = useState(value);
|
|
419
528
|
const context = {
|
|
420
529
|
value,
|
|
421
530
|
draft,
|
|
422
|
-
labels:
|
|
423
|
-
presets,
|
|
424
|
-
operators,
|
|
425
|
-
units,
|
|
531
|
+
labels: resolvedLabels,
|
|
532
|
+
presets: presets ?? locale.dateFilterPresets ?? DEFAULT_PRESETS,
|
|
533
|
+
operators: operators ?? locale.dateFilterOperators ?? DEFAULT_OPERATORS,
|
|
534
|
+
units: units ?? locale.dateFilterUnits ?? DEFAULT_UNITS,
|
|
426
535
|
panel,
|
|
427
536
|
setDraft,
|
|
428
537
|
openPanel: (next, seed) => {
|
|
@@ -572,9 +681,87 @@ function DateFilterRelative({ children }) {
|
|
|
572
681
|
);
|
|
573
682
|
}
|
|
574
683
|
|
|
575
|
-
// src/blocks/date-filter/
|
|
684
|
+
// src/blocks/date-filter/decode.ts
|
|
576
685
|
var RANGE_SEPARATOR = "~";
|
|
577
686
|
var RELATIVE_PREFIX = "previous";
|
|
687
|
+
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
688
|
+
var UNITS = ["day", "week", "month", "quarter", "year"];
|
|
689
|
+
var ALL = { mode: "all" };
|
|
690
|
+
function decodeDateFilter(encoded) {
|
|
691
|
+
if (!encoded) {
|
|
692
|
+
return ALL;
|
|
693
|
+
}
|
|
694
|
+
if (encoded.startsWith(`${RELATIVE_PREFIX}:`)) {
|
|
695
|
+
return decodeRelative(encoded);
|
|
696
|
+
}
|
|
697
|
+
if (encoded.includes(RANGE_SEPARATOR)) {
|
|
698
|
+
return decodeFixedRange(encoded);
|
|
699
|
+
}
|
|
700
|
+
if (ISO_DATE.test(encoded)) {
|
|
701
|
+
return isDate(encoded) ? { mode: "fixed", operator: "on", start: encoded } : ALL;
|
|
702
|
+
}
|
|
703
|
+
return { mode: "preset", preset: encoded };
|
|
704
|
+
}
|
|
705
|
+
function decodeFixedRange(encoded) {
|
|
706
|
+
const parts = encoded.split(RANGE_SEPARATOR);
|
|
707
|
+
if (parts.length !== 2) {
|
|
708
|
+
return ALL;
|
|
709
|
+
}
|
|
710
|
+
const [start, end] = parts;
|
|
711
|
+
if (start && end) {
|
|
712
|
+
return isDate(start) && isDate(end) ? { mode: "fixed", operator: "between", start, end } : ALL;
|
|
713
|
+
}
|
|
714
|
+
if (start) {
|
|
715
|
+
return isDate(start) ? { mode: "fixed", operator: "after", start } : ALL;
|
|
716
|
+
}
|
|
717
|
+
if (end) {
|
|
718
|
+
return isDate(end) ? { mode: "fixed", operator: "before", start: end } : ALL;
|
|
719
|
+
}
|
|
720
|
+
return ALL;
|
|
721
|
+
}
|
|
722
|
+
function decodeRelative(encoded) {
|
|
723
|
+
const [, rawAmount, rawUnit, ...rest] = encoded.split(":");
|
|
724
|
+
const amount = Number(rawAmount);
|
|
725
|
+
const unit = toUnit(rawUnit);
|
|
726
|
+
if (!unit || !Number.isInteger(amount) || amount < 1) {
|
|
727
|
+
return ALL;
|
|
728
|
+
}
|
|
729
|
+
const value = { mode: "relative", amount, unit };
|
|
730
|
+
const tail = [...rest];
|
|
731
|
+
if (tail[0] === "current") {
|
|
732
|
+
value.include_current = true;
|
|
733
|
+
tail.shift();
|
|
734
|
+
}
|
|
735
|
+
if (tail.length === 0) {
|
|
736
|
+
return value;
|
|
737
|
+
}
|
|
738
|
+
if (tail.length !== 3 || tail[0] !== "offset") {
|
|
739
|
+
return ALL;
|
|
740
|
+
}
|
|
741
|
+
const offsetAmount = Number(tail[1]);
|
|
742
|
+
const offsetUnit = toUnit(tail[2]);
|
|
743
|
+
if (!offsetUnit || !Number.isInteger(offsetAmount) || offsetAmount < 1) {
|
|
744
|
+
return ALL;
|
|
745
|
+
}
|
|
746
|
+
value.offset_amount = offsetAmount;
|
|
747
|
+
value.offset_unit = offsetUnit;
|
|
748
|
+
return value;
|
|
749
|
+
}
|
|
750
|
+
function toUnit(value) {
|
|
751
|
+
return UNITS.find((unit) => unit === value) ?? null;
|
|
752
|
+
}
|
|
753
|
+
function isDate(value) {
|
|
754
|
+
if (!ISO_DATE.test(value)) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
758
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
759
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/blocks/date-filter/encode.ts
|
|
763
|
+
var RANGE_SEPARATOR2 = "~";
|
|
764
|
+
var RELATIVE_PREFIX2 = "previous";
|
|
578
765
|
function encodeDateFilter(filter) {
|
|
579
766
|
if (filter.mode === "preset") {
|
|
580
767
|
return filter.preset ?? null;
|
|
@@ -592,21 +779,21 @@ function encodeFixed(filter) {
|
|
|
592
779
|
return null;
|
|
593
780
|
}
|
|
594
781
|
if (filter.operator === "before") {
|
|
595
|
-
return `${
|
|
782
|
+
return `${RANGE_SEPARATOR2}${filter.start}`;
|
|
596
783
|
}
|
|
597
784
|
if (filter.operator === "after") {
|
|
598
|
-
return `${filter.start}${
|
|
785
|
+
return `${filter.start}${RANGE_SEPARATOR2}`;
|
|
599
786
|
}
|
|
600
787
|
if (filter.operator === "on") {
|
|
601
788
|
return filter.start;
|
|
602
789
|
}
|
|
603
|
-
return filter.end ? `${filter.start}${
|
|
790
|
+
return filter.end ? `${filter.start}${RANGE_SEPARATOR2}${filter.end}` : null;
|
|
604
791
|
}
|
|
605
792
|
function encodeRelative(filter) {
|
|
606
793
|
if (!filter.unit || !filter.amount || filter.amount < 1) {
|
|
607
794
|
return null;
|
|
608
795
|
}
|
|
609
|
-
let value = `${
|
|
796
|
+
let value = `${RELATIVE_PREFIX2}:${filter.amount}:${filter.unit}`;
|
|
610
797
|
if (filter.include_current) {
|
|
611
798
|
value += ":current";
|
|
612
799
|
}
|
|
@@ -615,20 +802,263 @@ function encodeRelative(filter) {
|
|
|
615
802
|
}
|
|
616
803
|
return value;
|
|
617
804
|
}
|
|
805
|
+
var formOverlayDefaultLabels = {
|
|
806
|
+
cancelLabel: "Cancel",
|
|
807
|
+
saveLabel: "Save",
|
|
808
|
+
savingLabel: "Saving..."
|
|
809
|
+
};
|
|
810
|
+
function FormOverlayActions({
|
|
811
|
+
labels = formOverlayDefaultLabels,
|
|
812
|
+
processing = false,
|
|
813
|
+
intent = "default",
|
|
814
|
+
submit = false,
|
|
815
|
+
className,
|
|
816
|
+
onCancel,
|
|
817
|
+
onSave,
|
|
818
|
+
slotName = "form-overlay-actions"
|
|
819
|
+
}) {
|
|
820
|
+
return /* @__PURE__ */ jsxs(
|
|
821
|
+
"div",
|
|
822
|
+
{
|
|
823
|
+
className: cn("gap-2 flex items-center justify-end", className),
|
|
824
|
+
"data-slot": slotName,
|
|
825
|
+
children: [
|
|
826
|
+
/* @__PURE__ */ jsx(
|
|
827
|
+
Button,
|
|
828
|
+
{
|
|
829
|
+
type: "button",
|
|
830
|
+
variant: "ghost",
|
|
831
|
+
disabled: processing,
|
|
832
|
+
onClick: onCancel,
|
|
833
|
+
children: labels.cancelLabel
|
|
834
|
+
}
|
|
835
|
+
),
|
|
836
|
+
/* @__PURE__ */ jsx(
|
|
837
|
+
Button,
|
|
838
|
+
{
|
|
839
|
+
type: submit ? "submit" : "button",
|
|
840
|
+
"aria-label": processing ? labels.savingLabel : void 0,
|
|
841
|
+
variant: intent,
|
|
842
|
+
loading: processing,
|
|
843
|
+
loadingLabel: labels.savingLabel,
|
|
844
|
+
onClick: onSave,
|
|
845
|
+
children: processing ? labels.savingLabel : labels.saveLabel
|
|
846
|
+
}
|
|
847
|
+
)
|
|
848
|
+
]
|
|
849
|
+
}
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
function DetailEditSheet({
|
|
853
|
+
open,
|
|
854
|
+
onOpenChange,
|
|
855
|
+
title,
|
|
856
|
+
description,
|
|
857
|
+
processing = false,
|
|
858
|
+
intent,
|
|
859
|
+
labels,
|
|
860
|
+
className,
|
|
861
|
+
children,
|
|
862
|
+
onSave,
|
|
863
|
+
onCancel,
|
|
864
|
+
slotName = "detail-edit-sheet"
|
|
865
|
+
}) {
|
|
866
|
+
const handleSubmit = (event) => {
|
|
867
|
+
event.preventDefault();
|
|
868
|
+
if (processing) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
onSave();
|
|
872
|
+
};
|
|
873
|
+
const handleCancel = () => {
|
|
874
|
+
if (processing) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
onCancel?.();
|
|
878
|
+
onOpenChange(false);
|
|
879
|
+
};
|
|
880
|
+
return /* @__PURE__ */ jsx(
|
|
881
|
+
FloatingSheet,
|
|
882
|
+
{
|
|
883
|
+
open,
|
|
884
|
+
onOpenChange,
|
|
885
|
+
title,
|
|
886
|
+
description,
|
|
887
|
+
persistent: true,
|
|
888
|
+
className,
|
|
889
|
+
children: /* @__PURE__ */ jsxs(
|
|
890
|
+
"form",
|
|
891
|
+
{
|
|
892
|
+
onSubmit: handleSubmit,
|
|
893
|
+
className: "min-h-0 flex flex-1 flex-col",
|
|
894
|
+
"data-slot": slotName,
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ jsx(FloatingSheetBody, { children }),
|
|
897
|
+
/* @__PURE__ */ jsx(FloatingSheetFooter, { children: /* @__PURE__ */ jsx(
|
|
898
|
+
FormOverlayActions,
|
|
899
|
+
{
|
|
900
|
+
submit: true,
|
|
901
|
+
labels,
|
|
902
|
+
processing,
|
|
903
|
+
intent,
|
|
904
|
+
onCancel: handleCancel
|
|
905
|
+
}
|
|
906
|
+
) })
|
|
907
|
+
]
|
|
908
|
+
}
|
|
909
|
+
)
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
function FormDialog({
|
|
914
|
+
open,
|
|
915
|
+
onOpenChange,
|
|
916
|
+
title,
|
|
917
|
+
description,
|
|
918
|
+
processing = false,
|
|
919
|
+
intent,
|
|
920
|
+
labels,
|
|
921
|
+
className,
|
|
922
|
+
children,
|
|
923
|
+
onSave,
|
|
924
|
+
onCancel,
|
|
925
|
+
slotName = "form-dialog"
|
|
926
|
+
}) {
|
|
927
|
+
const handleSubmit = (event) => {
|
|
928
|
+
event.preventDefault();
|
|
929
|
+
if (processing) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
onSave();
|
|
933
|
+
};
|
|
934
|
+
const handleCancel = () => {
|
|
935
|
+
if (processing) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
onCancel?.();
|
|
939
|
+
onOpenChange(false);
|
|
940
|
+
};
|
|
941
|
+
const blockWhileProcessing = (event) => {
|
|
942
|
+
if (processing) {
|
|
943
|
+
event.preventDefault();
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
return /* @__PURE__ */ jsx(
|
|
947
|
+
Dialog,
|
|
948
|
+
{
|
|
949
|
+
open,
|
|
950
|
+
onOpenChange: (next) => {
|
|
951
|
+
if (processing && !next) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
onOpenChange(next);
|
|
955
|
+
},
|
|
956
|
+
children: /* @__PURE__ */ jsx(
|
|
957
|
+
DialogContent,
|
|
958
|
+
{
|
|
959
|
+
...description ? {} : { "aria-describedby": void 0 },
|
|
960
|
+
className: cn("gap-0 p-0", className),
|
|
961
|
+
onEscapeKeyDown: blockWhileProcessing,
|
|
962
|
+
onInteractOutside: blockWhileProcessing,
|
|
963
|
+
slotName,
|
|
964
|
+
children: /* @__PURE__ */ jsxs(
|
|
965
|
+
"form",
|
|
966
|
+
{
|
|
967
|
+
"data-slot": "form-dialog-form",
|
|
968
|
+
onSubmit: handleSubmit,
|
|
969
|
+
className: "grid max-h-[calc(100dvh-8rem)] grid-rows-[auto_minmax(0,1fr)_auto]",
|
|
970
|
+
children: [
|
|
971
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "text-left", children: [
|
|
972
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: title }),
|
|
973
|
+
description ? /* @__PURE__ */ jsx(DialogDescription, { children: description }) : null
|
|
974
|
+
] }),
|
|
975
|
+
/* @__PURE__ */ jsx(
|
|
976
|
+
"div",
|
|
977
|
+
{
|
|
978
|
+
"data-slot": "form-dialog-body",
|
|
979
|
+
className: "gap-4 px-6 pb-6 md:px-8 flex flex-col overflow-y-auto",
|
|
980
|
+
children
|
|
981
|
+
}
|
|
982
|
+
),
|
|
983
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(
|
|
984
|
+
FormOverlayActions,
|
|
985
|
+
{
|
|
986
|
+
submit: true,
|
|
987
|
+
labels,
|
|
988
|
+
processing,
|
|
989
|
+
intent,
|
|
990
|
+
onCancel: handleCancel,
|
|
991
|
+
className: "w-full"
|
|
992
|
+
}
|
|
993
|
+
) })
|
|
994
|
+
]
|
|
995
|
+
}
|
|
996
|
+
)
|
|
997
|
+
}
|
|
998
|
+
)
|
|
999
|
+
}
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
function copyableText(value, copyValue) {
|
|
1003
|
+
if (copyValue !== void 0) {
|
|
1004
|
+
return copyValue.trim();
|
|
1005
|
+
}
|
|
1006
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1007
|
+
return String(value).trim();
|
|
1008
|
+
}
|
|
1009
|
+
return "";
|
|
1010
|
+
}
|
|
618
1011
|
function InfoField({
|
|
619
1012
|
icon: Icon,
|
|
620
1013
|
label,
|
|
621
1014
|
value,
|
|
1015
|
+
copyable = false,
|
|
1016
|
+
copyValue,
|
|
1017
|
+
copyLabel,
|
|
1018
|
+
copiedLabel,
|
|
622
1019
|
iconClassName,
|
|
623
|
-
className
|
|
1020
|
+
className,
|
|
1021
|
+
slotName = "info-field"
|
|
624
1022
|
}) {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
1023
|
+
const text = copyableText(value, copyValue);
|
|
1024
|
+
return /* @__PURE__ */ jsxs(
|
|
1025
|
+
"div",
|
|
1026
|
+
{
|
|
1027
|
+
className: cn("gap-3 flex items-center", className),
|
|
1028
|
+
"data-slot": slotName,
|
|
1029
|
+
children: [
|
|
1030
|
+
/* @__PURE__ */ jsx("div", { className: cn("p-2 rounded-xl bg-muted", iconClassName), children: /* @__PURE__ */ jsx(Icon, { className: "size-5 text-muted-foreground" }) }),
|
|
1031
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1032
|
+
/* @__PURE__ */ jsx(
|
|
1033
|
+
"p",
|
|
1034
|
+
{
|
|
1035
|
+
"data-slot": "info-field-label",
|
|
1036
|
+
className: "text-xs font-medium tracking-wider text-muted-foreground uppercase",
|
|
1037
|
+
children: label
|
|
1038
|
+
}
|
|
1039
|
+
),
|
|
1040
|
+
/* @__PURE__ */ jsxs(
|
|
1041
|
+
"p",
|
|
1042
|
+
{
|
|
1043
|
+
"data-slot": "info-field-value",
|
|
1044
|
+
className: "gap-1 font-semibold flex items-center",
|
|
1045
|
+
children: [
|
|
1046
|
+
value,
|
|
1047
|
+
copyable && text !== "" && /* @__PURE__ */ jsx(
|
|
1048
|
+
CopyButton,
|
|
1049
|
+
{
|
|
1050
|
+
value: text,
|
|
1051
|
+
copyLabel,
|
|
1052
|
+
copiedLabel
|
|
1053
|
+
}
|
|
1054
|
+
)
|
|
1055
|
+
]
|
|
1056
|
+
}
|
|
1057
|
+
)
|
|
1058
|
+
] })
|
|
1059
|
+
]
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
632
1062
|
}
|
|
633
1063
|
function InfoFieldGroup({ children, className }) {
|
|
634
1064
|
return /* @__PURE__ */ jsx("div", { className: cn("space-y-4", className), children });
|
|
@@ -730,12 +1160,12 @@ function SettingsCard({
|
|
|
730
1160
|
control,
|
|
731
1161
|
children,
|
|
732
1162
|
inset = false,
|
|
733
|
-
className
|
|
1163
|
+
className,
|
|
1164
|
+
slotName = "settings-card"
|
|
734
1165
|
}) {
|
|
735
1166
|
return /* @__PURE__ */ jsxs(
|
|
736
1167
|
"section",
|
|
737
1168
|
{
|
|
738
|
-
"data-slot": "settings-card",
|
|
739
1169
|
"data-inset": inset || void 0,
|
|
740
1170
|
className: cn(
|
|
741
1171
|
elevatedSurface,
|
|
@@ -743,6 +1173,7 @@ function SettingsCard({
|
|
|
743
1173
|
inset && recessedSurface,
|
|
744
1174
|
className
|
|
745
1175
|
),
|
|
1176
|
+
"data-slot": slotName,
|
|
746
1177
|
children: [
|
|
747
1178
|
/* @__PURE__ */ jsxs("div", { className: "gap-4 sm:flex-row sm:items-center sm:justify-between flex flex-col", children: [
|
|
748
1179
|
/* @__PURE__ */ jsxs("div", { className: "gap-3 flex items-center", children: [
|
|
@@ -773,12 +1204,12 @@ function SettingsPanel({
|
|
|
773
1204
|
description,
|
|
774
1205
|
children,
|
|
775
1206
|
inset = true,
|
|
776
|
-
className
|
|
1207
|
+
className,
|
|
1208
|
+
slotName = "settings-panel"
|
|
777
1209
|
}) {
|
|
778
1210
|
return /* @__PURE__ */ jsxs(
|
|
779
1211
|
"div",
|
|
780
1212
|
{
|
|
781
|
-
"data-slot": "settings-panel",
|
|
782
1213
|
"data-inset": inset || void 0,
|
|
783
1214
|
className: cn(
|
|
784
1215
|
elevatedSurface,
|
|
@@ -786,6 +1217,7 @@ function SettingsPanel({
|
|
|
786
1217
|
inset && recessedSurface,
|
|
787
1218
|
className
|
|
788
1219
|
),
|
|
1220
|
+
"data-slot": slotName,
|
|
789
1221
|
children: [
|
|
790
1222
|
(title || description) && /* @__PURE__ */ jsxs("div", { children: [
|
|
791
1223
|
title && /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
@@ -827,6 +1259,346 @@ function ToggleRow({
|
|
|
827
1259
|
)
|
|
828
1260
|
] });
|
|
829
1261
|
}
|
|
1262
|
+
function SettingsField({
|
|
1263
|
+
id,
|
|
1264
|
+
label,
|
|
1265
|
+
description,
|
|
1266
|
+
error,
|
|
1267
|
+
required,
|
|
1268
|
+
className,
|
|
1269
|
+
children,
|
|
1270
|
+
slotName = "settings-field"
|
|
1271
|
+
}) {
|
|
1272
|
+
const generated = useId();
|
|
1273
|
+
const fieldId = id ?? generated;
|
|
1274
|
+
return /* @__PURE__ */ jsxs(
|
|
1275
|
+
"div",
|
|
1276
|
+
{
|
|
1277
|
+
"data-invalid": error ? true : void 0,
|
|
1278
|
+
className: cn("space-y-2 py-1", className),
|
|
1279
|
+
"data-slot": slotName,
|
|
1280
|
+
children: [
|
|
1281
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: fieldId, children: [
|
|
1282
|
+
label,
|
|
1283
|
+
required && /* @__PURE__ */ jsx(
|
|
1284
|
+
"span",
|
|
1285
|
+
{
|
|
1286
|
+
"data-slot": "settings-field-required",
|
|
1287
|
+
"aria-hidden": "true",
|
|
1288
|
+
className: "text-destructive",
|
|
1289
|
+
children: "*"
|
|
1290
|
+
}
|
|
1291
|
+
)
|
|
1292
|
+
] }),
|
|
1293
|
+
children(fieldId),
|
|
1294
|
+
description && /* @__PURE__ */ jsx(
|
|
1295
|
+
"p",
|
|
1296
|
+
{
|
|
1297
|
+
"data-slot": "settings-field-description",
|
|
1298
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
1299
|
+
children: description
|
|
1300
|
+
}
|
|
1301
|
+
),
|
|
1302
|
+
/* @__PURE__ */ jsx(FieldError, { message: error })
|
|
1303
|
+
]
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
function TextField({
|
|
1308
|
+
type = "text",
|
|
1309
|
+
value,
|
|
1310
|
+
onChange,
|
|
1311
|
+
disabled,
|
|
1312
|
+
placeholder,
|
|
1313
|
+
slotName = "text-field",
|
|
1314
|
+
...field
|
|
1315
|
+
}) {
|
|
1316
|
+
return /* @__PURE__ */ jsx(SettingsField, { ...field, children: (fieldId) => /* @__PURE__ */ jsx(
|
|
1317
|
+
Input,
|
|
1318
|
+
{
|
|
1319
|
+
id: fieldId,
|
|
1320
|
+
type,
|
|
1321
|
+
value,
|
|
1322
|
+
disabled,
|
|
1323
|
+
placeholder,
|
|
1324
|
+
"aria-invalid": field.error ? true : void 0,
|
|
1325
|
+
slotName,
|
|
1326
|
+
onChange: (event) => onChange(event.target.value)
|
|
1327
|
+
}
|
|
1328
|
+
) });
|
|
1329
|
+
}
|
|
1330
|
+
function NumberField({
|
|
1331
|
+
value,
|
|
1332
|
+
onChange,
|
|
1333
|
+
disabled,
|
|
1334
|
+
placeholder,
|
|
1335
|
+
min,
|
|
1336
|
+
max,
|
|
1337
|
+
step,
|
|
1338
|
+
slotName = "number-field",
|
|
1339
|
+
...field
|
|
1340
|
+
}) {
|
|
1341
|
+
return /* @__PURE__ */ jsx(SettingsField, { ...field, children: (fieldId) => /* @__PURE__ */ jsx(
|
|
1342
|
+
Input,
|
|
1343
|
+
{
|
|
1344
|
+
id: fieldId,
|
|
1345
|
+
type: "number",
|
|
1346
|
+
inputMode: "decimal",
|
|
1347
|
+
value: value === "" ? "" : String(value),
|
|
1348
|
+
min,
|
|
1349
|
+
max,
|
|
1350
|
+
step,
|
|
1351
|
+
disabled,
|
|
1352
|
+
placeholder,
|
|
1353
|
+
"aria-invalid": field.error ? true : void 0,
|
|
1354
|
+
slotName,
|
|
1355
|
+
onChange: (event) => onChange(
|
|
1356
|
+
event.target.value === "" ? "" : event.target.valueAsNumber
|
|
1357
|
+
)
|
|
1358
|
+
}
|
|
1359
|
+
) });
|
|
1360
|
+
}
|
|
1361
|
+
function DateField({
|
|
1362
|
+
value,
|
|
1363
|
+
onChange,
|
|
1364
|
+
disabled,
|
|
1365
|
+
min,
|
|
1366
|
+
max,
|
|
1367
|
+
slotName = "date-field",
|
|
1368
|
+
...field
|
|
1369
|
+
}) {
|
|
1370
|
+
return /* @__PURE__ */ jsx(SettingsField, { ...field, children: (fieldId) => /* @__PURE__ */ jsx(
|
|
1371
|
+
Input,
|
|
1372
|
+
{
|
|
1373
|
+
id: fieldId,
|
|
1374
|
+
type: "date",
|
|
1375
|
+
value,
|
|
1376
|
+
min,
|
|
1377
|
+
max,
|
|
1378
|
+
disabled,
|
|
1379
|
+
"aria-invalid": field.error ? true : void 0,
|
|
1380
|
+
slotName,
|
|
1381
|
+
onChange: (event) => onChange(event.target.value)
|
|
1382
|
+
}
|
|
1383
|
+
) });
|
|
1384
|
+
}
|
|
1385
|
+
function SelectField({
|
|
1386
|
+
value,
|
|
1387
|
+
onChange,
|
|
1388
|
+
options,
|
|
1389
|
+
disabled,
|
|
1390
|
+
placeholder,
|
|
1391
|
+
slotName = "select-field",
|
|
1392
|
+
...field
|
|
1393
|
+
}) {
|
|
1394
|
+
return /* @__PURE__ */ jsx(SettingsField, { ...field, children: (fieldId) => /* @__PURE__ */ jsxs(
|
|
1395
|
+
Select,
|
|
1396
|
+
{
|
|
1397
|
+
value,
|
|
1398
|
+
onValueChange: onChange,
|
|
1399
|
+
disabled,
|
|
1400
|
+
children: [
|
|
1401
|
+
/* @__PURE__ */ jsx(
|
|
1402
|
+
SelectTrigger,
|
|
1403
|
+
{
|
|
1404
|
+
id: fieldId,
|
|
1405
|
+
slotName,
|
|
1406
|
+
"aria-invalid": field.error ? true : void 0,
|
|
1407
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
|
|
1408
|
+
}
|
|
1409
|
+
),
|
|
1410
|
+
/* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(
|
|
1411
|
+
SelectItem,
|
|
1412
|
+
{
|
|
1413
|
+
value: option.value,
|
|
1414
|
+
disabled: option.disabled,
|
|
1415
|
+
children: option.label
|
|
1416
|
+
},
|
|
1417
|
+
option.value
|
|
1418
|
+
)) })
|
|
1419
|
+
]
|
|
1420
|
+
}
|
|
1421
|
+
) });
|
|
1422
|
+
}
|
|
1423
|
+
var SettingsLinkContext = createContext(void 0);
|
|
1424
|
+
function SettingsPage({
|
|
1425
|
+
title,
|
|
1426
|
+
description,
|
|
1427
|
+
control,
|
|
1428
|
+
linkComponent,
|
|
1429
|
+
children,
|
|
1430
|
+
className,
|
|
1431
|
+
slotName = "settings-page"
|
|
1432
|
+
}) {
|
|
1433
|
+
return /* @__PURE__ */ jsx(SettingsLinkContext.Provider, { value: linkComponent, children: /* @__PURE__ */ jsxs(
|
|
1434
|
+
"div",
|
|
1435
|
+
{
|
|
1436
|
+
className: cn(
|
|
1437
|
+
"gap-8 max-w-4xl mx-auto flex w-full flex-col",
|
|
1438
|
+
className
|
|
1439
|
+
),
|
|
1440
|
+
"data-slot": slotName,
|
|
1441
|
+
children: [
|
|
1442
|
+
title && /* @__PURE__ */ jsx(
|
|
1443
|
+
SectionHeader,
|
|
1444
|
+
{
|
|
1445
|
+
title,
|
|
1446
|
+
description,
|
|
1447
|
+
control
|
|
1448
|
+
}
|
|
1449
|
+
),
|
|
1450
|
+
children
|
|
1451
|
+
]
|
|
1452
|
+
}
|
|
1453
|
+
) });
|
|
1454
|
+
}
|
|
1455
|
+
var settingsLabels = {
|
|
1456
|
+
back: "Back"
|
|
1457
|
+
};
|
|
1458
|
+
function SettingsSection({
|
|
1459
|
+
title,
|
|
1460
|
+
description,
|
|
1461
|
+
control,
|
|
1462
|
+
backHref = "/settings",
|
|
1463
|
+
backLabel,
|
|
1464
|
+
wide = false,
|
|
1465
|
+
linkComponent,
|
|
1466
|
+
children,
|
|
1467
|
+
className,
|
|
1468
|
+
slotName = "settings-section"
|
|
1469
|
+
}) {
|
|
1470
|
+
const labels = useUiLabels("settings", settingsLabels, {
|
|
1471
|
+
back: backLabel
|
|
1472
|
+
});
|
|
1473
|
+
const contextLink = useContext(SettingsLinkContext);
|
|
1474
|
+
const Link = resolveLink(linkComponent ?? contextLink);
|
|
1475
|
+
return /* @__PURE__ */ jsxs(
|
|
1476
|
+
"section",
|
|
1477
|
+
{
|
|
1478
|
+
className: cn(
|
|
1479
|
+
"gap-6 mx-auto flex w-full flex-col",
|
|
1480
|
+
wide ? "max-w-4xl" : "max-w-2xl",
|
|
1481
|
+
className
|
|
1482
|
+
),
|
|
1483
|
+
"data-slot": slotName,
|
|
1484
|
+
children: [
|
|
1485
|
+
backHref && /* @__PURE__ */ jsxs(
|
|
1486
|
+
Link,
|
|
1487
|
+
{
|
|
1488
|
+
"data-slot": "settings-section-back",
|
|
1489
|
+
href: backHref,
|
|
1490
|
+
className: "gap-2 text-sm font-medium inline-flex w-fit items-center text-muted-foreground transition-colors hover:text-foreground",
|
|
1491
|
+
children: [
|
|
1492
|
+
/* @__PURE__ */ jsx(ArrowLeft, { className: "size-4" }),
|
|
1493
|
+
labels.back
|
|
1494
|
+
]
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
1497
|
+
title && /* @__PURE__ */ jsx(
|
|
1498
|
+
SectionHeader,
|
|
1499
|
+
{
|
|
1500
|
+
title,
|
|
1501
|
+
description,
|
|
1502
|
+
control
|
|
1503
|
+
}
|
|
1504
|
+
),
|
|
1505
|
+
children
|
|
1506
|
+
]
|
|
1507
|
+
}
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
function SettingsGroup({
|
|
1511
|
+
label,
|
|
1512
|
+
columns = 2,
|
|
1513
|
+
children,
|
|
1514
|
+
className,
|
|
1515
|
+
slotName = "settings-group"
|
|
1516
|
+
}) {
|
|
1517
|
+
return /* @__PURE__ */ jsxs(
|
|
1518
|
+
"div",
|
|
1519
|
+
{
|
|
1520
|
+
className: cn("gap-3 flex flex-col", className),
|
|
1521
|
+
"data-slot": slotName,
|
|
1522
|
+
children: [
|
|
1523
|
+
label && /* @__PURE__ */ jsx("p", { className: "font-bold tracking-widest text-[11px] text-muted-foreground uppercase", children: label }),
|
|
1524
|
+
/* @__PURE__ */ jsx(
|
|
1525
|
+
"div",
|
|
1526
|
+
{
|
|
1527
|
+
"data-slot": "settings-group-grid",
|
|
1528
|
+
className: cn(
|
|
1529
|
+
"gap-4 grid grid-cols-1",
|
|
1530
|
+
columns === 2 && "md:grid-cols-2"
|
|
1531
|
+
),
|
|
1532
|
+
children
|
|
1533
|
+
}
|
|
1534
|
+
)
|
|
1535
|
+
]
|
|
1536
|
+
}
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
function SettingsEntry({
|
|
1540
|
+
icon: Icon,
|
|
1541
|
+
iconClassName,
|
|
1542
|
+
title,
|
|
1543
|
+
description,
|
|
1544
|
+
href,
|
|
1545
|
+
badge,
|
|
1546
|
+
disabled = false,
|
|
1547
|
+
linkComponent,
|
|
1548
|
+
className,
|
|
1549
|
+
slotName = "settings-entry"
|
|
1550
|
+
}) {
|
|
1551
|
+
const contextLink = useContext(SettingsLinkContext);
|
|
1552
|
+
const Link = resolveLink(linkComponent ?? contextLink);
|
|
1553
|
+
const card = /* @__PURE__ */ jsxs(
|
|
1554
|
+
Card,
|
|
1555
|
+
{
|
|
1556
|
+
interactive: !disabled,
|
|
1557
|
+
padding: "none",
|
|
1558
|
+
"data-disabled": disabled || void 0,
|
|
1559
|
+
className: cn(
|
|
1560
|
+
"gap-4 p-5 flex h-full flex-row items-center",
|
|
1561
|
+
disabled && "opacity-60",
|
|
1562
|
+
className
|
|
1563
|
+
),
|
|
1564
|
+
children: [
|
|
1565
|
+
/* @__PURE__ */ jsx(
|
|
1566
|
+
"span",
|
|
1567
|
+
{
|
|
1568
|
+
className: cn(
|
|
1569
|
+
"size-11 flex shrink-0 items-center justify-center rounded-full",
|
|
1570
|
+
iconClassName ?? "bg-primary/10 text-primary"
|
|
1571
|
+
),
|
|
1572
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-5" })
|
|
1573
|
+
}
|
|
1574
|
+
),
|
|
1575
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex flex-1 flex-col", children: [
|
|
1576
|
+
/* @__PURE__ */ jsxs("span", { className: "gap-2 flex items-center", children: [
|
|
1577
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold text-foreground", children: title }),
|
|
1578
|
+
badge
|
|
1579
|
+
] }),
|
|
1580
|
+
description && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-muted-foreground", children: description })
|
|
1581
|
+
] }),
|
|
1582
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "size-4 shrink-0 text-muted-foreground" })
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
if (disabled) {
|
|
1587
|
+
return /* @__PURE__ */ jsx("div", { "data-disabled": "true", "aria-disabled": "true", "data-slot": slotName, children: card });
|
|
1588
|
+
}
|
|
1589
|
+
return /* @__PURE__ */ jsx(
|
|
1590
|
+
Link,
|
|
1591
|
+
{
|
|
1592
|
+
href,
|
|
1593
|
+
className: cn(
|
|
1594
|
+
compactRadius,
|
|
1595
|
+
"outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
1596
|
+
),
|
|
1597
|
+
"data-slot": slotName,
|
|
1598
|
+
children: card
|
|
1599
|
+
}
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
830
1602
|
function resolveTrend(trend) {
|
|
831
1603
|
if (trend === null || trend === void 0 || Number.isNaN(trend)) {
|
|
832
1604
|
return null;
|
|
@@ -861,13 +1633,13 @@ function StatCard({
|
|
|
861
1633
|
trend,
|
|
862
1634
|
comparisonLabel,
|
|
863
1635
|
inset = false,
|
|
864
|
-
className
|
|
1636
|
+
className,
|
|
1637
|
+
slotName = "stat-card"
|
|
865
1638
|
}) {
|
|
866
1639
|
const resolvedTrend = resolveTrend(trend);
|
|
867
1640
|
return /* @__PURE__ */ jsxs(
|
|
868
1641
|
"div",
|
|
869
1642
|
{
|
|
870
|
-
"data-slot": "stat-card",
|
|
871
1643
|
"data-inset": inset || void 0,
|
|
872
1644
|
className: cn(
|
|
873
1645
|
elevatedSurface,
|
|
@@ -875,6 +1647,7 @@ function StatCard({
|
|
|
875
1647
|
inset && recessedSurface,
|
|
876
1648
|
className
|
|
877
1649
|
),
|
|
1650
|
+
"data-slot": slotName,
|
|
878
1651
|
children: [
|
|
879
1652
|
/* @__PURE__ */ jsxs("div", { className: "mb-4 gap-4 flex items-start justify-between", children: [
|
|
880
1653
|
/* @__PURE__ */ jsx("div", { className: cn("rounded-2xl p-3 shrink-0", iconClassName), children: /* @__PURE__ */ jsx(Icon, { className: "size-6" }) }),
|
|
@@ -916,6 +1689,607 @@ function StatsGrid({ children, className }) {
|
|
|
916
1689
|
);
|
|
917
1690
|
}
|
|
918
1691
|
|
|
919
|
-
|
|
1692
|
+
// src/blocks/two-factor/types.ts
|
|
1693
|
+
var twoFactorLabels = {
|
|
1694
|
+
setupTitle: "Two-factor authentication",
|
|
1695
|
+
setupDescription: "Add a second step to your sign in with an authenticator app.",
|
|
1696
|
+
pendingLabel: "Preparing your setup key",
|
|
1697
|
+
scanTitle: "Scan the code",
|
|
1698
|
+
scanDescription: "Open your authenticator app and scan the code below to add this account.",
|
|
1699
|
+
qrFallbackLabel: "The QR code is not available yet.",
|
|
1700
|
+
manualKeyLabel: "Setup key",
|
|
1701
|
+
manualKeyDescription: "Enter this key by hand if your app cannot scan the code.",
|
|
1702
|
+
manualKeyRevealLabel: "Show setup key",
|
|
1703
|
+
manualKeyHideLabel: "Hide setup key",
|
|
1704
|
+
continueLabel: "Continue",
|
|
1705
|
+
confirmTitle: "Confirm the code",
|
|
1706
|
+
confirmDescription: "Enter the six digit code your authenticator app is showing.",
|
|
1707
|
+
codeLabel: "Authentication code",
|
|
1708
|
+
recoveryCodeLabel: "Recovery code",
|
|
1709
|
+
recoveryCodePlaceholder: "Enter a recovery code",
|
|
1710
|
+
useRecoveryCodeLabel: "Use a recovery code",
|
|
1711
|
+
useCodeLabel: "Use an authentication code",
|
|
1712
|
+
verifyLabel: "Verify",
|
|
1713
|
+
verifyingLabel: "Verifying",
|
|
1714
|
+
errorFallbackLabel: "That did not work. Try again.",
|
|
1715
|
+
cancelLabel: "Cancel",
|
|
1716
|
+
challengeTitle: "Two-factor confirmation",
|
|
1717
|
+
challengeDescription: "Confirm access to your account with the code from your authenticator app.",
|
|
1718
|
+
recoveryTitle: "Recovery codes",
|
|
1719
|
+
recoveryDescription: "Store these codes somewhere safe. Each one signs you in once if you lose your device.",
|
|
1720
|
+
recoveryWarning: "They are shown once and cannot be read again afterwards.",
|
|
1721
|
+
revealLabel: "Show codes",
|
|
1722
|
+
hideLabel: "Hide codes",
|
|
1723
|
+
copyLabel: "Copy",
|
|
1724
|
+
copiedLabel: "Copied",
|
|
1725
|
+
copyFailedLabel: "Copying is unavailable here. Select the codes manually.",
|
|
1726
|
+
regenerateLabel: "Regenerate codes",
|
|
1727
|
+
doneLabel: "Done",
|
|
1728
|
+
disableLabel: "Disable two-factor authentication",
|
|
1729
|
+
disableTitle: "Disable two-factor authentication",
|
|
1730
|
+
disableDescription: "Your account will be protected by your password alone. Recovery codes stop working.",
|
|
1731
|
+
disableConfirmLabel: "Disable",
|
|
1732
|
+
disableCancelLabel: "Keep it on"
|
|
1733
|
+
};
|
|
1734
|
+
function resolveLabels(labels) {
|
|
1735
|
+
return labels ? { ...twoFactorLabels, ...labels } : twoFactorLabels;
|
|
1736
|
+
}
|
|
1737
|
+
function messageList(errors) {
|
|
1738
|
+
if (!errors) {
|
|
1739
|
+
return [];
|
|
1740
|
+
}
|
|
1741
|
+
return (Array.isArray(errors) ? errors : [errors]).filter(
|
|
1742
|
+
(message) => message.length > 0
|
|
1743
|
+
);
|
|
1744
|
+
}
|
|
1745
|
+
function errorMessage(reason, fallback) {
|
|
1746
|
+
return reason instanceof Error && reason.message ? reason.message : fallback;
|
|
1747
|
+
}
|
|
1748
|
+
function TwoFactorVerifyForm({
|
|
1749
|
+
onSubmit,
|
|
1750
|
+
errors,
|
|
1751
|
+
allowRecoveryCode = false,
|
|
1752
|
+
length = 6,
|
|
1753
|
+
autoFocus = false,
|
|
1754
|
+
submitLabel,
|
|
1755
|
+
footer,
|
|
1756
|
+
labels,
|
|
1757
|
+
className,
|
|
1758
|
+
slotName = "two-factor-verify-form"
|
|
1759
|
+
}) {
|
|
1760
|
+
const text = resolveLabels(labels);
|
|
1761
|
+
const fieldId = useId();
|
|
1762
|
+
const [mode, setMode] = useState("code");
|
|
1763
|
+
const [value, setValue] = useState("");
|
|
1764
|
+
const [pending, setPending] = useState(false);
|
|
1765
|
+
const [failure, setFailure] = useState(null);
|
|
1766
|
+
const messages = [...messageList(errors), ...messageList(failure)];
|
|
1767
|
+
const complete = mode === "code" ? value.length === length : value.length > 0;
|
|
1768
|
+
const handleSubmit = async (event) => {
|
|
1769
|
+
event.preventDefault();
|
|
1770
|
+
if (pending || !complete) {
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
setFailure(null);
|
|
1774
|
+
setPending(true);
|
|
1775
|
+
try {
|
|
1776
|
+
await onSubmit(value, mode);
|
|
1777
|
+
} catch (reason) {
|
|
1778
|
+
setFailure(errorMessage(reason, text.errorFallbackLabel));
|
|
1779
|
+
} finally {
|
|
1780
|
+
setPending(false);
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
const switchMode = () => {
|
|
1784
|
+
setMode(mode === "code" ? "recovery" : "code");
|
|
1785
|
+
setValue("");
|
|
1786
|
+
setFailure(null);
|
|
1787
|
+
};
|
|
1788
|
+
return /* @__PURE__ */ jsxs(
|
|
1789
|
+
"form",
|
|
1790
|
+
{
|
|
1791
|
+
"data-mode": mode,
|
|
1792
|
+
"data-pending": pending || void 0,
|
|
1793
|
+
onSubmit: handleSubmit,
|
|
1794
|
+
className: cn("gap-5 flex w-full flex-col", className),
|
|
1795
|
+
"data-slot": slotName,
|
|
1796
|
+
children: [
|
|
1797
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-2 flex flex-col", children: [
|
|
1798
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: mode === "code" ? text.codeLabel : text.recoveryCodeLabel }),
|
|
1799
|
+
mode === "code" ? /* @__PURE__ */ jsx(
|
|
1800
|
+
InputOTP,
|
|
1801
|
+
{
|
|
1802
|
+
id: fieldId,
|
|
1803
|
+
"data-slot": "two-factor-code-input",
|
|
1804
|
+
maxLength: length,
|
|
1805
|
+
value,
|
|
1806
|
+
autoFocus,
|
|
1807
|
+
disabled: pending,
|
|
1808
|
+
onChange: setValue,
|
|
1809
|
+
"aria-label": text.codeLabel,
|
|
1810
|
+
children: /* @__PURE__ */ jsx(InputOTPGroup, { children: Array.from({ length }, (_, index) => /* @__PURE__ */ jsx(InputOTPSlot, { index }, index)) })
|
|
1811
|
+
}
|
|
1812
|
+
) : /* @__PURE__ */ jsx(
|
|
1813
|
+
Input,
|
|
1814
|
+
{
|
|
1815
|
+
id: fieldId,
|
|
1816
|
+
slotName: "two-factor-recovery-input",
|
|
1817
|
+
value,
|
|
1818
|
+
autoComplete: "one-time-code",
|
|
1819
|
+
spellCheck: false,
|
|
1820
|
+
disabled: pending,
|
|
1821
|
+
placeholder: text.recoveryCodePlaceholder,
|
|
1822
|
+
"aria-label": text.recoveryCodeLabel,
|
|
1823
|
+
onChange: (event) => setValue(event.target.value)
|
|
1824
|
+
}
|
|
1825
|
+
)
|
|
1826
|
+
] }),
|
|
1827
|
+
messages.length > 0 && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", slotName: "two-factor-error", children: [
|
|
1828
|
+
/* @__PURE__ */ jsx(AlertCircle, {}),
|
|
1829
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: messages.map((message) => /* @__PURE__ */ jsx("p", { children: message }, message)) })
|
|
1830
|
+
] }),
|
|
1831
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-3 flex flex-col", children: [
|
|
1832
|
+
/* @__PURE__ */ jsx(
|
|
1833
|
+
Button,
|
|
1834
|
+
{
|
|
1835
|
+
type: "submit",
|
|
1836
|
+
loading: pending,
|
|
1837
|
+
loadingLabel: text.verifyingLabel,
|
|
1838
|
+
disabled: !complete,
|
|
1839
|
+
children: submitLabel ?? text.verifyLabel
|
|
1840
|
+
}
|
|
1841
|
+
),
|
|
1842
|
+
allowRecoveryCode && /* @__PURE__ */ jsx(
|
|
1843
|
+
Button,
|
|
1844
|
+
{
|
|
1845
|
+
type: "button",
|
|
1846
|
+
variant: "ghost",
|
|
1847
|
+
size: "sm",
|
|
1848
|
+
disabled: pending,
|
|
1849
|
+
onClick: switchMode,
|
|
1850
|
+
children: mode === "code" ? text.useRecoveryCodeLabel : text.useCodeLabel
|
|
1851
|
+
}
|
|
1852
|
+
),
|
|
1853
|
+
footer
|
|
1854
|
+
] })
|
|
1855
|
+
]
|
|
1856
|
+
}
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
function TwoFactorChallenge({
|
|
1860
|
+
onSubmit,
|
|
1861
|
+
errors,
|
|
1862
|
+
allowRecoveryCode = true,
|
|
1863
|
+
title,
|
|
1864
|
+
description,
|
|
1865
|
+
footer,
|
|
1866
|
+
labels,
|
|
1867
|
+
className,
|
|
1868
|
+
slotName = "two-factor-challenge"
|
|
1869
|
+
}) {
|
|
1870
|
+
const text = resolveLabels(labels);
|
|
1871
|
+
return /* @__PURE__ */ jsxs(
|
|
1872
|
+
"section",
|
|
1873
|
+
{
|
|
1874
|
+
className: cn("gap-6 flex w-full flex-col", className),
|
|
1875
|
+
"data-slot": slotName,
|
|
1876
|
+
children: [
|
|
1877
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-2 flex flex-col", children: [
|
|
1878
|
+
/* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold tracking-tight text-foreground", children: title ?? text.challengeTitle }),
|
|
1879
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: description ?? text.challengeDescription })
|
|
1880
|
+
] }),
|
|
1881
|
+
/* @__PURE__ */ jsx(
|
|
1882
|
+
TwoFactorVerifyForm,
|
|
1883
|
+
{
|
|
1884
|
+
autoFocus: true,
|
|
1885
|
+
allowRecoveryCode,
|
|
1886
|
+
errors,
|
|
1887
|
+
labels,
|
|
1888
|
+
footer,
|
|
1889
|
+
onSubmit
|
|
1890
|
+
}
|
|
1891
|
+
)
|
|
1892
|
+
]
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
function TwoFactorDisableButton({
|
|
1897
|
+
onDisable,
|
|
1898
|
+
disabled = false,
|
|
1899
|
+
variant = "destructive",
|
|
1900
|
+
size = "default",
|
|
1901
|
+
labels,
|
|
1902
|
+
className,
|
|
1903
|
+
slotName = "two-factor-disable"
|
|
1904
|
+
}) {
|
|
1905
|
+
const text = resolveLabels(labels);
|
|
1906
|
+
const [open, setOpen] = useState(false);
|
|
1907
|
+
const [processing, setProcessing] = useState(false);
|
|
1908
|
+
const handleConfirm = async () => {
|
|
1909
|
+
setProcessing(true);
|
|
1910
|
+
try {
|
|
1911
|
+
await onDisable();
|
|
1912
|
+
} finally {
|
|
1913
|
+
setProcessing(false);
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
return /* @__PURE__ */ jsxs(
|
|
1917
|
+
"span",
|
|
1918
|
+
{
|
|
1919
|
+
"data-open": open || void 0,
|
|
1920
|
+
className: cn("inline-flex", className),
|
|
1921
|
+
"data-slot": slotName,
|
|
1922
|
+
children: [
|
|
1923
|
+
/* @__PURE__ */ jsxs(
|
|
1924
|
+
Button,
|
|
1925
|
+
{
|
|
1926
|
+
type: "button",
|
|
1927
|
+
variant,
|
|
1928
|
+
size,
|
|
1929
|
+
disabled: disabled || processing,
|
|
1930
|
+
onClick: () => setOpen(true),
|
|
1931
|
+
children: [
|
|
1932
|
+
/* @__PURE__ */ jsx(ShieldOff, {}),
|
|
1933
|
+
text.disableLabel
|
|
1934
|
+
]
|
|
1935
|
+
}
|
|
1936
|
+
),
|
|
1937
|
+
/* @__PURE__ */ jsx(
|
|
1938
|
+
ConfirmDialog,
|
|
1939
|
+
{
|
|
1940
|
+
open,
|
|
1941
|
+
onOpenChange: setOpen,
|
|
1942
|
+
title: text.disableTitle,
|
|
1943
|
+
description: text.disableDescription,
|
|
1944
|
+
confirmText: text.disableConfirmLabel,
|
|
1945
|
+
cancelText: text.disableCancelLabel,
|
|
1946
|
+
processing,
|
|
1947
|
+
onConfirm: handleConfirm
|
|
1948
|
+
}
|
|
1949
|
+
)
|
|
1950
|
+
]
|
|
1951
|
+
}
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
function TwoFactorRecoveryCodes({
|
|
1955
|
+
codes,
|
|
1956
|
+
defaultRevealed = false,
|
|
1957
|
+
onRegenerate,
|
|
1958
|
+
showHeading = true,
|
|
1959
|
+
labels,
|
|
1960
|
+
className,
|
|
1961
|
+
slotName = "two-factor-recovery-codes"
|
|
1962
|
+
}) {
|
|
1963
|
+
const text = resolveLabels(labels);
|
|
1964
|
+
const [revealed, setRevealed] = useState(defaultRevealed);
|
|
1965
|
+
const [copyFailed, setCopyFailed] = useState(false);
|
|
1966
|
+
const [regenerating, setRegenerating] = useState(false);
|
|
1967
|
+
const handleRegenerate = async () => {
|
|
1968
|
+
if (!onRegenerate || regenerating) {
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
setRegenerating(true);
|
|
1972
|
+
try {
|
|
1973
|
+
await onRegenerate();
|
|
1974
|
+
} finally {
|
|
1975
|
+
setRegenerating(false);
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1978
|
+
return /* @__PURE__ */ jsxs(
|
|
1979
|
+
"div",
|
|
1980
|
+
{
|
|
1981
|
+
"data-revealed": revealed || void 0,
|
|
1982
|
+
className: cn("gap-4 flex w-full flex-col", className),
|
|
1983
|
+
"data-slot": slotName,
|
|
1984
|
+
children: [
|
|
1985
|
+
showHeading && /* @__PURE__ */ jsxs("div", { className: "gap-1 flex flex-col", children: [
|
|
1986
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: text.recoveryTitle }),
|
|
1987
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: [
|
|
1988
|
+
text.recoveryDescription,
|
|
1989
|
+
" ",
|
|
1990
|
+
text.recoveryWarning
|
|
1991
|
+
] })
|
|
1992
|
+
] }),
|
|
1993
|
+
revealed && /* @__PURE__ */ jsx(
|
|
1994
|
+
"ul",
|
|
1995
|
+
{
|
|
1996
|
+
"data-slot": "two-factor-recovery-list",
|
|
1997
|
+
className: cn(
|
|
1998
|
+
recessedSurface,
|
|
1999
|
+
"gap-2 p-4 sm:grid-cols-2 grid"
|
|
2000
|
+
),
|
|
2001
|
+
children: codes.map((code) => /* @__PURE__ */ jsx(
|
|
2002
|
+
"li",
|
|
2003
|
+
{
|
|
2004
|
+
"data-slot": "two-factor-recovery-code",
|
|
2005
|
+
className: cn(
|
|
2006
|
+
compactRadius,
|
|
2007
|
+
"px-2 py-1 text-sm font-medium font-mono break-all text-foreground"
|
|
2008
|
+
),
|
|
2009
|
+
children: code
|
|
2010
|
+
},
|
|
2011
|
+
code
|
|
2012
|
+
))
|
|
2013
|
+
}
|
|
2014
|
+
),
|
|
2015
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-2 flex flex-wrap items-center", children: [
|
|
2016
|
+
/* @__PURE__ */ jsxs(
|
|
2017
|
+
Button,
|
|
2018
|
+
{
|
|
2019
|
+
type: "button",
|
|
2020
|
+
variant: "ghost",
|
|
2021
|
+
size: "sm",
|
|
2022
|
+
"aria-pressed": revealed,
|
|
2023
|
+
onClick: () => setRevealed(!revealed),
|
|
2024
|
+
children: [
|
|
2025
|
+
revealed ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {}),
|
|
2026
|
+
revealed ? text.hideLabel : text.revealLabel
|
|
2027
|
+
]
|
|
2028
|
+
}
|
|
2029
|
+
),
|
|
2030
|
+
/* @__PURE__ */ jsx(
|
|
2031
|
+
CopyButton,
|
|
2032
|
+
{
|
|
2033
|
+
value: codes.join("\n"),
|
|
2034
|
+
copyLabel: text.copyLabel,
|
|
2035
|
+
copiedLabel: text.copiedLabel,
|
|
2036
|
+
onCopied: () => setCopyFailed(false),
|
|
2037
|
+
onCopyFailed: () => setCopyFailed(true)
|
|
2038
|
+
}
|
|
2039
|
+
),
|
|
2040
|
+
onRegenerate && /* @__PURE__ */ jsxs(
|
|
2041
|
+
Button,
|
|
2042
|
+
{
|
|
2043
|
+
type: "button",
|
|
2044
|
+
variant: "outline",
|
|
2045
|
+
size: "sm",
|
|
2046
|
+
loading: regenerating,
|
|
2047
|
+
loadingLabel: text.regenerateLabel,
|
|
2048
|
+
onClick: handleRegenerate,
|
|
2049
|
+
children: [
|
|
2050
|
+
/* @__PURE__ */ jsx(RefreshCw, {}),
|
|
2051
|
+
text.regenerateLabel
|
|
2052
|
+
]
|
|
2053
|
+
}
|
|
2054
|
+
)
|
|
2055
|
+
] }),
|
|
2056
|
+
copyFailed && /* @__PURE__ */ jsx(
|
|
2057
|
+
"p",
|
|
2058
|
+
{
|
|
2059
|
+
"data-slot": "two-factor-copy-failed",
|
|
2060
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
2061
|
+
children: text.copyFailedLabel
|
|
2062
|
+
}
|
|
2063
|
+
)
|
|
2064
|
+
]
|
|
2065
|
+
}
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
function TwoFactorScanStep({
|
|
2069
|
+
qrCode,
|
|
2070
|
+
qrCodeSvg,
|
|
2071
|
+
manualSetupKey,
|
|
2072
|
+
labels,
|
|
2073
|
+
className,
|
|
2074
|
+
slotName = "two-factor-scan-step"
|
|
2075
|
+
}) {
|
|
2076
|
+
const text = resolveLabels(labels);
|
|
2077
|
+
const [revealed, setRevealed] = useState(false);
|
|
2078
|
+
return /* @__PURE__ */ jsxs(
|
|
2079
|
+
"div",
|
|
2080
|
+
{
|
|
2081
|
+
className: cn("gap-5 flex w-full flex-col", className),
|
|
2082
|
+
"data-slot": slotName,
|
|
2083
|
+
children: [
|
|
2084
|
+
/* @__PURE__ */ jsx(
|
|
2085
|
+
"div",
|
|
2086
|
+
{
|
|
2087
|
+
"data-slot": "two-factor-qr",
|
|
2088
|
+
className: cn(
|
|
2089
|
+
recessedSurface,
|
|
2090
|
+
"p-4 flex items-center justify-center [&_svg]:size-full [&_svg]:h-auto"
|
|
2091
|
+
),
|
|
2092
|
+
children: qrCode ?? (qrCodeSvg ? /* @__PURE__ */ jsx(
|
|
2093
|
+
"div",
|
|
2094
|
+
{
|
|
2095
|
+
"data-slot": "two-factor-qr-markup",
|
|
2096
|
+
className: cn(controlRadius, "p-3 bg-card"),
|
|
2097
|
+
dangerouslySetInnerHTML: { __html: qrCodeSvg }
|
|
2098
|
+
}
|
|
2099
|
+
) : /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: text.qrFallbackLabel }))
|
|
2100
|
+
}
|
|
2101
|
+
),
|
|
2102
|
+
manualSetupKey && /* @__PURE__ */ jsxs(
|
|
2103
|
+
"div",
|
|
2104
|
+
{
|
|
2105
|
+
"data-slot": "two-factor-setup-key",
|
|
2106
|
+
className: "gap-2 flex flex-col",
|
|
2107
|
+
children: [
|
|
2108
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: text.manualKeyLabel }),
|
|
2109
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: text.manualKeyDescription }),
|
|
2110
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-2 flex flex-wrap items-center", children: [
|
|
2111
|
+
/* @__PURE__ */ jsx(
|
|
2112
|
+
"code",
|
|
2113
|
+
{
|
|
2114
|
+
"data-slot": "two-factor-setup-key-value",
|
|
2115
|
+
className: cn(
|
|
2116
|
+
compactRadius,
|
|
2117
|
+
"px-3 py-2 text-sm font-medium font-mono bg-muted break-all text-foreground"
|
|
2118
|
+
),
|
|
2119
|
+
children: revealed ? manualSetupKey : "\u2022".repeat(manualSetupKey.length)
|
|
2120
|
+
}
|
|
2121
|
+
),
|
|
2122
|
+
/* @__PURE__ */ jsxs(
|
|
2123
|
+
Button,
|
|
2124
|
+
{
|
|
2125
|
+
type: "button",
|
|
2126
|
+
variant: "ghost",
|
|
2127
|
+
size: "sm",
|
|
2128
|
+
"aria-pressed": revealed,
|
|
2129
|
+
onClick: () => setRevealed(!revealed),
|
|
2130
|
+
children: [
|
|
2131
|
+
revealed ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {}),
|
|
2132
|
+
revealed ? text.manualKeyHideLabel : text.manualKeyRevealLabel
|
|
2133
|
+
]
|
|
2134
|
+
}
|
|
2135
|
+
),
|
|
2136
|
+
/* @__PURE__ */ jsx(
|
|
2137
|
+
CopyButton,
|
|
2138
|
+
{
|
|
2139
|
+
value: manualSetupKey,
|
|
2140
|
+
copyLabel: text.copyLabel,
|
|
2141
|
+
copiedLabel: text.copiedLabel
|
|
2142
|
+
}
|
|
2143
|
+
)
|
|
2144
|
+
] })
|
|
2145
|
+
]
|
|
2146
|
+
}
|
|
2147
|
+
)
|
|
2148
|
+
]
|
|
2149
|
+
}
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
function TwoFactorSetupDialog({
|
|
2153
|
+
open,
|
|
2154
|
+
onOpenChange,
|
|
2155
|
+
enabled = false,
|
|
2156
|
+
qrCode,
|
|
2157
|
+
qrCodeSvg,
|
|
2158
|
+
manualSetupKey,
|
|
2159
|
+
recoveryCodes,
|
|
2160
|
+
errors,
|
|
2161
|
+
onConfirm,
|
|
2162
|
+
onRequestSetupData,
|
|
2163
|
+
onRegenerateRecoveryCodes,
|
|
2164
|
+
onCompleted,
|
|
2165
|
+
labels,
|
|
2166
|
+
className,
|
|
2167
|
+
slotName = "two-factor-setup-dialog"
|
|
2168
|
+
}) {
|
|
2169
|
+
const text = resolveLabels(labels);
|
|
2170
|
+
const [step, setStep] = useState(
|
|
2171
|
+
enabled ? "recovery" : "scan"
|
|
2172
|
+
);
|
|
2173
|
+
const requestSetupData = useRef(onRequestSetupData);
|
|
2174
|
+
const openedBefore = useRef(false);
|
|
2175
|
+
useEffect(() => {
|
|
2176
|
+
requestSetupData.current = onRequestSetupData;
|
|
2177
|
+
}, [onRequestSetupData]);
|
|
2178
|
+
useEffect(() => {
|
|
2179
|
+
if (!open) {
|
|
2180
|
+
openedBefore.current = false;
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
if (openedBefore.current) {
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
openedBefore.current = true;
|
|
2187
|
+
setStep(enabled ? "recovery" : "scan");
|
|
2188
|
+
if (!enabled) {
|
|
2189
|
+
void requestSetupData.current?.();
|
|
2190
|
+
}
|
|
2191
|
+
}, [open, enabled]);
|
|
2192
|
+
const ready = Boolean(qrCode || qrCodeSvg || manualSetupKey);
|
|
2193
|
+
const codes = recoveryCodes ?? [];
|
|
2194
|
+
const handleConfirm = async (code) => {
|
|
2195
|
+
await onConfirm(code);
|
|
2196
|
+
setStep("recovery");
|
|
2197
|
+
};
|
|
2198
|
+
const finish = () => {
|
|
2199
|
+
onOpenChange(false);
|
|
2200
|
+
onCompleted?.();
|
|
2201
|
+
};
|
|
2202
|
+
const heading = {
|
|
2203
|
+
pending: text.setupTitle,
|
|
2204
|
+
scan: text.scanTitle,
|
|
2205
|
+
confirm: text.confirmTitle,
|
|
2206
|
+
recovery: text.recoveryTitle
|
|
2207
|
+
}[step];
|
|
2208
|
+
const description = {
|
|
2209
|
+
pending: text.setupDescription,
|
|
2210
|
+
scan: text.scanDescription,
|
|
2211
|
+
confirm: text.confirmDescription,
|
|
2212
|
+
recovery: `${text.recoveryDescription} ${text.recoveryWarning}`
|
|
2213
|
+
}[step];
|
|
2214
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
2215
|
+
DialogContent,
|
|
2216
|
+
{
|
|
2217
|
+
"data-step": step,
|
|
2218
|
+
className: cn("max-w-md p-0", className),
|
|
2219
|
+
slotName,
|
|
2220
|
+
children: [
|
|
2221
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "p-6 md:p-8", children: [
|
|
2222
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: heading }),
|
|
2223
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: description })
|
|
2224
|
+
] }),
|
|
2225
|
+
/* @__PURE__ */ jsxs("div", { className: "gap-5 p-6 md:p-8 pt-0 md:pt-0 flex flex-col", children: [
|
|
2226
|
+
step === "scan" && (ready ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2227
|
+
/* @__PURE__ */ jsx(
|
|
2228
|
+
TwoFactorScanStep,
|
|
2229
|
+
{
|
|
2230
|
+
qrCode,
|
|
2231
|
+
qrCodeSvg,
|
|
2232
|
+
manualSetupKey,
|
|
2233
|
+
labels
|
|
2234
|
+
}
|
|
2235
|
+
),
|
|
2236
|
+
/* @__PURE__ */ jsx(
|
|
2237
|
+
Button,
|
|
2238
|
+
{
|
|
2239
|
+
type: "button",
|
|
2240
|
+
onClick: () => setStep("confirm"),
|
|
2241
|
+
children: text.continueLabel
|
|
2242
|
+
}
|
|
2243
|
+
)
|
|
2244
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
2245
|
+
"div",
|
|
2246
|
+
{
|
|
2247
|
+
"data-slot": "two-factor-pending",
|
|
2248
|
+
className: "gap-3 py-6 text-sm font-medium flex items-center justify-center text-muted-foreground",
|
|
2249
|
+
children: [
|
|
2250
|
+
/* @__PURE__ */ jsx(Spinner, { label: text.pendingLabel }),
|
|
2251
|
+
text.pendingLabel
|
|
2252
|
+
]
|
|
2253
|
+
}
|
|
2254
|
+
)),
|
|
2255
|
+
step === "confirm" && /* @__PURE__ */ jsx(
|
|
2256
|
+
TwoFactorVerifyForm,
|
|
2257
|
+
{
|
|
2258
|
+
autoFocus: true,
|
|
2259
|
+
errors,
|
|
2260
|
+
labels,
|
|
2261
|
+
onSubmit: handleConfirm,
|
|
2262
|
+
footer: /* @__PURE__ */ jsx(
|
|
2263
|
+
Button,
|
|
2264
|
+
{
|
|
2265
|
+
type: "button",
|
|
2266
|
+
variant: "ghost",
|
|
2267
|
+
size: "sm",
|
|
2268
|
+
onClick: () => setStep("scan"),
|
|
2269
|
+
children: text.cancelLabel
|
|
2270
|
+
}
|
|
2271
|
+
)
|
|
2272
|
+
}
|
|
2273
|
+
),
|
|
2274
|
+
step === "recovery" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2275
|
+
/* @__PURE__ */ jsx(
|
|
2276
|
+
TwoFactorRecoveryCodes,
|
|
2277
|
+
{
|
|
2278
|
+
codes,
|
|
2279
|
+
defaultRevealed: true,
|
|
2280
|
+
showHeading: false,
|
|
2281
|
+
labels,
|
|
2282
|
+
onRegenerate: onRegenerateRecoveryCodes
|
|
2283
|
+
}
|
|
2284
|
+
),
|
|
2285
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: finish, children: text.doneLabel })
|
|
2286
|
+
] })
|
|
2287
|
+
] })
|
|
2288
|
+
]
|
|
2289
|
+
}
|
|
2290
|
+
) });
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
export { CommandPalette, DEFAULT_LABELS as DATE_FILTER_LABELS, DEFAULT_OPERATORS as DATE_FILTER_OPERATORS, DEFAULT_PRESETS as DATE_FILTER_PRESETS, DEFAULT_UNITS as DATE_FILTER_UNITS, DangerZone, DateField, DateFilter, DateFilterAll, DateFilterContent, DateFilterFixed, DateFilterItem, DateFilterPresets, DateFilterRelative, DateFilterSeparator, DateFilterTrigger, DetailEditSheet, FormDialog, FormOverlayActions, InfoField, InfoFieldGroup, LocalizedFields, NumberField, SectionHeader, SelectField, SettingsCard, SettingsEntry, SettingsField, SettingsGroup, SettingsPage, SettingsPanel, SettingsSection, StatCard, StatsGrid, TextField, ToggleRow, TwoFactorChallenge, TwoFactorDisableButton, TwoFactorRecoveryCodes, TwoFactorScanStep, TwoFactorSetupDialog, TwoFactorVerifyForm, dangerZoneLabels, decodeDateFilter, encodeDateFilter, formOverlayDefaultLabels, formatRangePreview, resolveRelativeRange, settingsLabels, summariseDateFilter, twoFactorLabels, useCommandPalette, useDateFilter };
|
|
920
2294
|
//# sourceMappingURL=blocks.js.map
|
|
921
2295
|
//# sourceMappingURL=blocks.js.map
|