@caffeinebounce/ui 0.62.2
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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/FinancialStatementTable-BNUrdTU4.d.cts +249 -0
- package/dist/FinancialStatementTable-BNUrdTU4.d.ts +249 -0
- package/dist/NewsletterSignup-BPreFi5W.d.cts +37 -0
- package/dist/NewsletterSignup-BPreFi5W.d.ts +37 -0
- package/dist/TestimonialsSection-DtPu2OeR.d.ts +736 -0
- package/dist/TestimonialsSection-z-yotRfv.d.cts +736 -0
- package/dist/UnifiedTableControls-CG299y9h.d.ts +1233 -0
- package/dist/UnifiedTableControls-CIjRpNhy.d.cts +1233 -0
- package/dist/blog.d.cts +99 -0
- package/dist/blog.d.ts +99 -0
- package/dist/blog.js +292 -0
- package/dist/blog.mjs +279 -0
- package/dist/button-BHnoRUkF.d.cts +34 -0
- package/dist/button-BHnoRUkF.d.ts +34 -0
- package/dist/charts.d.cts +80 -0
- package/dist/charts.d.ts +80 -0
- package/dist/charts.js +19 -0
- package/dist/charts.mjs +2 -0
- package/dist/chunk-33JR5SYE.js +44 -0
- package/dist/chunk-3NDB4YPC.js +247 -0
- package/dist/chunk-5RW4PYZ6.js +1504 -0
- package/dist/chunk-5THF4YP6.mjs +155 -0
- package/dist/chunk-6BUBNZPG.mjs +164 -0
- package/dist/chunk-6DVWMJ3H.mjs +7029 -0
- package/dist/chunk-6TGV2DNP.js +120 -0
- package/dist/chunk-72JGQ7IJ.mjs +1498 -0
- package/dist/chunk-7DHKQODW.mjs +2932 -0
- package/dist/chunk-7IKHZKAC.js +160 -0
- package/dist/chunk-ADIDI7AJ.js +11 -0
- package/dist/chunk-BFWX5GJZ.mjs +940 -0
- package/dist/chunk-BMFQG6RA.mjs +5537 -0
- package/dist/chunk-C4UT5V3P.js +65 -0
- package/dist/chunk-CC4KUIKC.js +2004 -0
- package/dist/chunk-D3QXPL47.mjs +1814 -0
- package/dist/chunk-DQWHYBV2.js +36 -0
- package/dist/chunk-E42B4GSB.js +993 -0
- package/dist/chunk-ESZ7CBA2.js +1007 -0
- package/dist/chunk-EYJJQVV4.js +111 -0
- package/dist/chunk-FRRS2YZH.mjs +129 -0
- package/dist/chunk-G5TQWWQA.mjs +37 -0
- package/dist/chunk-GAIQJCAZ.js +5612 -0
- package/dist/chunk-GMBGWOCR.mjs +48 -0
- package/dist/chunk-GUSTCU2W.mjs +105 -0
- package/dist/chunk-HBLKVQIQ.mjs +23 -0
- package/dist/chunk-HMAMMC72.js +26 -0
- package/dist/chunk-IMKLN273.mjs +9 -0
- package/dist/chunk-J6OLBSZR.js +250 -0
- package/dist/chunk-JAE45W2T.js +28 -0
- package/dist/chunk-JORVSG52.js +606 -0
- package/dist/chunk-KB7UXIQZ.mjs +984 -0
- package/dist/chunk-KGGQ5NZV.js +186 -0
- package/dist/chunk-KHCC5UKW.mjs +22 -0
- package/dist/chunk-KRRIRS6A.mjs +1945 -0
- package/dist/chunk-LQCVRWVF.js +48 -0
- package/dist/chunk-MHZXUOGN.mjs +168 -0
- package/dist/chunk-MPZFPU4X.js +349 -0
- package/dist/chunk-MVYRNJA6.js +74 -0
- package/dist/chunk-N6AFNFZR.mjs +565 -0
- package/dist/chunk-OFQLWSUR.mjs +214 -0
- package/dist/chunk-OLAAXLXY.mjs +219 -0
- package/dist/chunk-OZZWDIOY.js +1859 -0
- package/dist/chunk-PZRI43EZ.js +111 -0
- package/dist/chunk-Q256HRYD.js +176 -0
- package/dist/chunk-Q52ZEL62.mjs +223 -0
- package/dist/chunk-R26Y7LGJ.js +142 -0
- package/dist/chunk-RBUYW6QQ.js +39 -0
- package/dist/chunk-RVEFPVZF.mjs +43 -0
- package/dist/chunk-SORWLKOK.js +96 -0
- package/dist/chunk-STEP6C4C.mjs +33 -0
- package/dist/chunk-T5R6HUDG.mjs +22 -0
- package/dist/chunk-T6ZBA6VJ.js +7109 -0
- package/dist/chunk-UM7WMXIU.js +2995 -0
- package/dist/chunk-VBD4Q5LL.mjs +117 -0
- package/dist/chunk-WOITB4JL.js +195 -0
- package/dist/chunk-YKZEKJMZ.mjs +71 -0
- package/dist/chunk-YL7RZRHM.mjs +103 -0
- package/dist/chunk-YSLD2HLP.mjs +346 -0
- package/dist/chunk-ZFLZA7UP.mjs +140 -0
- package/dist/chunk-ZKUIUE7W.mjs +26 -0
- package/dist/chunk-ZOA7B32D.js +248 -0
- package/dist/data-table.d.cts +46 -0
- package/dist/data-table.d.ts +46 -0
- package/dist/data-table.js +270 -0
- package/dist/data-table.mjs +13 -0
- package/dist/editor.d.cts +89 -0
- package/dist/editor.d.ts +89 -0
- package/dist/editor.js +10 -0
- package/dist/editor.mjs +1 -0
- package/dist/forms.d.cts +142 -0
- package/dist/forms.d.ts +142 -0
- package/dist/forms.js +24 -0
- package/dist/forms.mjs +11 -0
- package/dist/hooks-8ORd7T1A.d.cts +751 -0
- package/dist/hooks-B2jU1GVT.d.ts +751 -0
- package/dist/hooks.d.cts +6 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +99 -0
- package/dist/hooks.mjs +10 -0
- package/dist/index.d.cts +3141 -0
- package/dist/index.d.ts +3141 -0
- package/dist/index.js +7332 -0
- package/dist/index.mjs +5876 -0
- package/dist/layouts-DPfDDF53.d.cts +1001 -0
- package/dist/layouts-DPfDDF53.d.ts +1001 -0
- package/dist/layouts.d.cts +4 -0
- package/dist/layouts.d.ts +4 -0
- package/dist/layouts.js +100 -0
- package/dist/layouts.mjs +11 -0
- package/dist/marketing-3d.d.cts +51 -0
- package/dist/marketing-3d.d.ts +51 -0
- package/dist/marketing-3d.js +553 -0
- package/dist/marketing-3d.mjs +526 -0
- package/dist/marketing.d.cts +583 -0
- package/dist/marketing.d.ts +583 -0
- package/dist/marketing.js +299 -0
- package/dist/marketing.mjs +10 -0
- package/dist/media.d.cts +29 -0
- package/dist/media.d.ts +29 -0
- package/dist/media.js +189 -0
- package/dist/media.mjs +182 -0
- package/dist/navigation.d.cts +591 -0
- package/dist/navigation.d.ts +591 -0
- package/dist/navigation.js +108 -0
- package/dist/navigation.mjs +15 -0
- package/dist/portal.d.cts +58 -0
- package/dist/portal.d.ts +58 -0
- package/dist/portal.js +403 -0
- package/dist/portal.mjs +395 -0
- package/dist/primitives.d.cts +508 -0
- package/dist/primitives.d.ts +508 -0
- package/dist/primitives.js +295 -0
- package/dist/primitives.mjs +14 -0
- package/dist/settings.d.cts +216 -0
- package/dist/settings.d.ts +216 -0
- package/dist/settings.js +34 -0
- package/dist/settings.mjs +9 -0
- package/dist/shared-Dqn36QHZ.d.cts +4 -0
- package/dist/shared-Dqn36QHZ.d.ts +4 -0
- package/dist/styles.css +1213 -0
- package/package.json +189 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkADIDI7AJ_js = require('./chunk-ADIDI7AJ.js');
|
|
4
|
+
var SeparatorPrimitive = require('@radix-ui/react-separator');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
function _interopNamespace(e) {
|
|
8
|
+
if (e && e.__esModule) return e;
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
|
|
26
|
+
|
|
27
|
+
function Separator({
|
|
28
|
+
className,
|
|
29
|
+
orientation = "horizontal",
|
|
30
|
+
decorative = true,
|
|
31
|
+
...props
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
34
|
+
SeparatorPrimitive__namespace.Root,
|
|
35
|
+
{
|
|
36
|
+
"data-slot": "separator",
|
|
37
|
+
decorative,
|
|
38
|
+
orientation,
|
|
39
|
+
className: chunkADIDI7AJ_js.cn(
|
|
40
|
+
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
41
|
+
className
|
|
42
|
+
),
|
|
43
|
+
...props
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports.Separator = Separator;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { RefreshCcw, AlertTriangle, AlertCircle, Database, LoaderCircle } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
// src/utils/avatar-gradient.ts
|
|
4
|
+
var GRADIENT_PAIRS = [
|
|
5
|
+
// Vibrant contrasts
|
|
6
|
+
{ from: "#f97316", to: "#ec4899" },
|
|
7
|
+
// Orange → Pink
|
|
8
|
+
{ from: "#ef4444", to: "#a855f7" },
|
|
9
|
+
// Red → Purple
|
|
10
|
+
{ from: "#f59e0b", to: "#ef4444" },
|
|
11
|
+
// Amber → Red
|
|
12
|
+
{ from: "#ec4899", to: "#8b5cf6" },
|
|
13
|
+
// Pink → Violet
|
|
14
|
+
{ from: "#f43f5e", to: "#fb923c" },
|
|
15
|
+
// Rose → Orange
|
|
16
|
+
// Cool gradients
|
|
17
|
+
{ from: "#3b82f6", to: "#a855f7" },
|
|
18
|
+
// Blue → Purple
|
|
19
|
+
{ from: "#6366f1", to: "#ec4899" },
|
|
20
|
+
// Indigo → Pink
|
|
21
|
+
{ from: "#8b5cf6", to: "#06b6d4" },
|
|
22
|
+
// Violet → Cyan
|
|
23
|
+
{ from: "#a855f7", to: "#3b82f6" },
|
|
24
|
+
// Purple → Blue
|
|
25
|
+
{ from: "#06b6d4", to: "#10b981" },
|
|
26
|
+
// Cyan → Emerald
|
|
27
|
+
// Bold combos
|
|
28
|
+
{ from: "#10b981", to: "#3b82f6" },
|
|
29
|
+
// Emerald → Blue
|
|
30
|
+
{ from: "#14b8a6", to: "#8b5cf6" },
|
|
31
|
+
// Teal → Violet
|
|
32
|
+
{ from: "#22c55e", to: "#06b6d4" },
|
|
33
|
+
// Green → Cyan
|
|
34
|
+
{ from: "#0ea5e9", to: "#f43f5e" },
|
|
35
|
+
// Sky → Rose
|
|
36
|
+
{ from: "#eab308", to: "#22c55e" }
|
|
37
|
+
// Yellow → Green
|
|
38
|
+
];
|
|
39
|
+
function hashString(str) {
|
|
40
|
+
let hash = 0;
|
|
41
|
+
for (let i = 0; i < str.length; i++) {
|
|
42
|
+
const char = str.charCodeAt(i);
|
|
43
|
+
hash = (hash << 5) - hash + char;
|
|
44
|
+
hash = hash & hash;
|
|
45
|
+
}
|
|
46
|
+
return Math.abs(hash);
|
|
47
|
+
}
|
|
48
|
+
function getAvatarGradient(userId) {
|
|
49
|
+
const index = hashString(userId) % GRADIENT_PAIRS.length;
|
|
50
|
+
const gradient = GRADIENT_PAIRS[index];
|
|
51
|
+
return {
|
|
52
|
+
from: gradient.from,
|
|
53
|
+
to: gradient.to,
|
|
54
|
+
style: {
|
|
55
|
+
background: `linear-gradient(135deg, ${gradient.from} 0%, ${gradient.to} 100%)`
|
|
56
|
+
},
|
|
57
|
+
className: "text-white"
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function getGradientIndex(userId) {
|
|
61
|
+
return hashString(userId) % GRADIENT_PAIRS.length;
|
|
62
|
+
}
|
|
63
|
+
function getGradientPairs() {
|
|
64
|
+
return GRADIENT_PAIRS;
|
|
65
|
+
}
|
|
66
|
+
var DATA_STATE_COPY = {
|
|
67
|
+
loading: {
|
|
68
|
+
title: "Loading data",
|
|
69
|
+
description: "Please wait while we prepare your finance data."
|
|
70
|
+
},
|
|
71
|
+
empty: {
|
|
72
|
+
title: "No data yet",
|
|
73
|
+
description: "There\u2019s no data for this selection yet."
|
|
74
|
+
},
|
|
75
|
+
stale: {
|
|
76
|
+
title: "Showing older data",
|
|
77
|
+
description: "This view may be out of date. Refresh to see the latest values."
|
|
78
|
+
},
|
|
79
|
+
partial: {
|
|
80
|
+
title: "Some data is missing",
|
|
81
|
+
description: "We loaded what we could, but part of this view is unavailable."
|
|
82
|
+
},
|
|
83
|
+
error: {
|
|
84
|
+
title: "Something went wrong",
|
|
85
|
+
description: "We couldn\u2019t load this data right now. Please try again."
|
|
86
|
+
},
|
|
87
|
+
unauthorized: {
|
|
88
|
+
title: "Access needed",
|
|
89
|
+
description: "You don\u2019t currently have permission to view this data."
|
|
90
|
+
},
|
|
91
|
+
misconfigured: {
|
|
92
|
+
title: "Setup required",
|
|
93
|
+
description: "This view needs additional setup before data can be shown."
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function resolveDataState({
|
|
97
|
+
error,
|
|
98
|
+
data,
|
|
99
|
+
metadata,
|
|
100
|
+
hasData
|
|
101
|
+
}) {
|
|
102
|
+
const normalizedError = error;
|
|
103
|
+
const isUnauthorized = metadata?.isUnauthorized || normalizedError?.status === 401 || normalizedError?.status === 403 || normalizedError?.code === "unauthorized";
|
|
104
|
+
const isMisconfigured = metadata?.isMisconfigured || normalizedError?.status === 501 || normalizedError?.code === "misconfigured";
|
|
105
|
+
const computedHasData = hasData ? hasData(data) : metadata?.hasData ?? (Array.isArray(data) ? data.length > 0 : data != null && (typeof data !== "object" || Object.keys(data).length > 0));
|
|
106
|
+
if (metadata?.isLoading || metadata?.isFetching) {
|
|
107
|
+
return {
|
|
108
|
+
state: "loading",
|
|
109
|
+
retryable: false,
|
|
110
|
+
copy: DATA_STATE_COPY.loading
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (isUnauthorized) {
|
|
114
|
+
return {
|
|
115
|
+
state: "unauthorized",
|
|
116
|
+
retryable: false,
|
|
117
|
+
copy: DATA_STATE_COPY.unauthorized
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (isMisconfigured) {
|
|
121
|
+
return {
|
|
122
|
+
state: "misconfigured",
|
|
123
|
+
retryable: false,
|
|
124
|
+
copy: DATA_STATE_COPY.misconfigured
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (error) {
|
|
128
|
+
return { state: "error", retryable: true, copy: DATA_STATE_COPY.error };
|
|
129
|
+
}
|
|
130
|
+
if (metadata?.isPartial) {
|
|
131
|
+
return { state: "partial", retryable: true, copy: DATA_STATE_COPY.partial };
|
|
132
|
+
}
|
|
133
|
+
if (metadata?.isStale) {
|
|
134
|
+
return { state: "stale", retryable: true, copy: DATA_STATE_COPY.stale };
|
|
135
|
+
}
|
|
136
|
+
if (metadata?.isEmpty || !computedHasData) {
|
|
137
|
+
return { state: "empty", retryable: false, copy: DATA_STATE_COPY.empty };
|
|
138
|
+
}
|
|
139
|
+
return { state: null, retryable: false };
|
|
140
|
+
}
|
|
141
|
+
function getDataStateIcon(state) {
|
|
142
|
+
switch (state) {
|
|
143
|
+
case "loading":
|
|
144
|
+
return LoaderCircle;
|
|
145
|
+
case "empty":
|
|
146
|
+
return Database;
|
|
147
|
+
case "error":
|
|
148
|
+
case "unauthorized":
|
|
149
|
+
case "misconfigured":
|
|
150
|
+
return AlertCircle;
|
|
151
|
+
case "partial":
|
|
152
|
+
return AlertTriangle;
|
|
153
|
+
default:
|
|
154
|
+
return RefreshCcw;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function getDataStateIconClassName(state) {
|
|
158
|
+
switch (state) {
|
|
159
|
+
case "loading":
|
|
160
|
+
return "animate-spin";
|
|
161
|
+
case "empty":
|
|
162
|
+
return "animate-pulse";
|
|
163
|
+
default:
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { DATA_STATE_COPY, getAvatarGradient, getDataStateIcon, getDataStateIconClassName, getGradientIndex, getGradientPairs, resolveDataState };
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkESZ7CBA2_js = require('./chunk-ESZ7CBA2.js');
|
|
4
|
+
var chunkSORWLKOK_js = require('./chunk-SORWLKOK.js');
|
|
5
|
+
var chunkADIDI7AJ_js = require('./chunk-ADIDI7AJ.js');
|
|
6
|
+
var client = require('@caffeinebounce/logger/client');
|
|
7
|
+
var lucideReact = require('lucide-react');
|
|
8
|
+
var react = require('react');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
function FormWizard({
|
|
12
|
+
steps,
|
|
13
|
+
currentStep,
|
|
14
|
+
onStepChange,
|
|
15
|
+
getStepStatus,
|
|
16
|
+
getStepTooltip,
|
|
17
|
+
enableKeyboardNavigation = true,
|
|
18
|
+
scopeToDialog = true,
|
|
19
|
+
onCancel,
|
|
20
|
+
onSubmit,
|
|
21
|
+
onReset,
|
|
22
|
+
autoFocusSelector,
|
|
23
|
+
persistKey,
|
|
24
|
+
formData,
|
|
25
|
+
onDataRestored,
|
|
26
|
+
children,
|
|
27
|
+
className
|
|
28
|
+
}) {
|
|
29
|
+
const totalSteps = steps.length;
|
|
30
|
+
const isFirstStep = currentStep === 0;
|
|
31
|
+
const isLastStep = currentStep === totalSteps - 1;
|
|
32
|
+
const { logError } = client.useErrorLoggerSafe();
|
|
33
|
+
const [storedValue, setStoredValue, , isLoaded] = chunkESZ7CBA2_js.useLocalStorage(
|
|
34
|
+
persistKey,
|
|
35
|
+
null
|
|
36
|
+
);
|
|
37
|
+
const debouncedData = chunkESZ7CBA2_js.useDebounce(formData, 500);
|
|
38
|
+
const [hasRestored, setHasRestored] = react.useState(false);
|
|
39
|
+
const isRestoring = react.useRef(false);
|
|
40
|
+
const formDataRef = react.useRef(formData);
|
|
41
|
+
const restoredDataRef = react.useRef(null);
|
|
42
|
+
react.useEffect(() => {
|
|
43
|
+
formDataRef.current = formData;
|
|
44
|
+
}, [formData]);
|
|
45
|
+
const hasRestoredDataPropagated = react.useCallback(() => {
|
|
46
|
+
if (!restoredDataRef.current) return true;
|
|
47
|
+
const restored = restoredDataRef.current;
|
|
48
|
+
const current = debouncedData;
|
|
49
|
+
for (const key of Object.keys(restored)) {
|
|
50
|
+
const restoredVal = restored[key];
|
|
51
|
+
const currentVal = current?.[key];
|
|
52
|
+
if (!restoredVal || restoredVal === "") continue;
|
|
53
|
+
if (Array.isArray(restoredVal) && restoredVal.length === 0) continue;
|
|
54
|
+
const isObjectLike = typeof restoredVal === "object" && restoredVal !== null;
|
|
55
|
+
const valuesMatch = isObjectLike ? JSON.stringify(currentVal) === JSON.stringify(restoredVal) : currentVal === restoredVal;
|
|
56
|
+
if (!valuesMatch) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
restoredDataRef.current = null;
|
|
61
|
+
return true;
|
|
62
|
+
}, [debouncedData]);
|
|
63
|
+
react.useEffect(() => {
|
|
64
|
+
if (hasRestored && persistKey && debouncedData) {
|
|
65
|
+
if (isRestoring.current) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (restoredDataRef.current && !hasRestoredDataPropagated()) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
setStoredValue(debouncedData);
|
|
72
|
+
}
|
|
73
|
+
}, [
|
|
74
|
+
hasRestored,
|
|
75
|
+
persistKey,
|
|
76
|
+
debouncedData,
|
|
77
|
+
setStoredValue,
|
|
78
|
+
hasRestoredDataPropagated
|
|
79
|
+
]);
|
|
80
|
+
react.useEffect(() => {
|
|
81
|
+
return () => {
|
|
82
|
+
if (hasRestored && persistKey && formDataRef.current) {
|
|
83
|
+
if (isRestoring.current) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (restoredDataRef.current) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
window.localStorage.setItem(
|
|
91
|
+
persistKey,
|
|
92
|
+
JSON.stringify(formDataRef.current)
|
|
93
|
+
);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
logError(e, {
|
|
96
|
+
component: "FormWizard",
|
|
97
|
+
action: "saveOnUnmount",
|
|
98
|
+
metadata: { persistKey }
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}, [hasRestored, persistKey, logError]);
|
|
104
|
+
react.useEffect(() => {
|
|
105
|
+
if (!isLoaded) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (persistKey && storedValue && !hasRestored && onDataRestored) {
|
|
109
|
+
restoredDataRef.current = storedValue;
|
|
110
|
+
onDataRestored(storedValue);
|
|
111
|
+
isRestoring.current = true;
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
isRestoring.current = false;
|
|
114
|
+
}, 600);
|
|
115
|
+
setHasRestored(true);
|
|
116
|
+
} else if (persistKey && !storedValue && !hasRestored) {
|
|
117
|
+
setHasRestored(true);
|
|
118
|
+
}
|
|
119
|
+
}, [isLoaded, persistKey, storedValue, hasRestored, onDataRestored]);
|
|
120
|
+
react.useEffect(() => {
|
|
121
|
+
if (!autoFocusSelector) return;
|
|
122
|
+
const timeoutId = setTimeout(() => {
|
|
123
|
+
const element = document.querySelector(autoFocusSelector);
|
|
124
|
+
element?.focus();
|
|
125
|
+
}, 0);
|
|
126
|
+
return () => clearTimeout(timeoutId);
|
|
127
|
+
}, [autoFocusSelector]);
|
|
128
|
+
const stepStatuses = react.useMemo(() => {
|
|
129
|
+
return steps.map((_, index) => getStepStatus(index));
|
|
130
|
+
}, [steps, getStepStatus]);
|
|
131
|
+
const handleStepClick = react.useCallback(
|
|
132
|
+
(stepIndex) => {
|
|
133
|
+
onStepChange(stepIndex);
|
|
134
|
+
},
|
|
135
|
+
[onStepChange]
|
|
136
|
+
);
|
|
137
|
+
const handleNext = react.useCallback(() => {
|
|
138
|
+
if (!isLastStep) {
|
|
139
|
+
onStepChange(currentStep + 1);
|
|
140
|
+
}
|
|
141
|
+
}, [currentStep, isLastStep, onStepChange]);
|
|
142
|
+
const handleBack = react.useCallback(() => {
|
|
143
|
+
if (!isFirstStep) {
|
|
144
|
+
onStepChange(currentStep - 1);
|
|
145
|
+
}
|
|
146
|
+
}, [currentStep, isFirstStep, onStepChange]);
|
|
147
|
+
react.useEffect(() => {
|
|
148
|
+
if (!enableKeyboardNavigation) return;
|
|
149
|
+
const handleKeyDown = (e) => {
|
|
150
|
+
if (scopeToDialog) {
|
|
151
|
+
const target = e.target;
|
|
152
|
+
const isInDialog = target.closest('[role="dialog"]');
|
|
153
|
+
if (!isInDialog) return;
|
|
154
|
+
}
|
|
155
|
+
if (e.key === "Escape" && onCancel) {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
e.stopPropagation();
|
|
158
|
+
onCancel();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey) && onSubmit) {
|
|
162
|
+
e.preventDefault();
|
|
163
|
+
e.stopPropagation();
|
|
164
|
+
onSubmit();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if ((e.key === "r" || e.key === "\xAE" || e.code === "KeyR") && e.altKey && !e.shiftKey && !e.metaKey && !e.ctrlKey && onReset) {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
e.stopPropagation();
|
|
170
|
+
if (persistKey) {
|
|
171
|
+
try {
|
|
172
|
+
window.localStorage.removeItem(persistKey);
|
|
173
|
+
setStoredValue(null);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
logError(err, {
|
|
176
|
+
component: "FormWizard",
|
|
177
|
+
action: "clearStorageOnReset",
|
|
178
|
+
metadata: { persistKey }
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
onReset();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!e.altKey) return;
|
|
186
|
+
if (e.key === "ArrowLeft" && !isFirstStep) {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
e.stopPropagation();
|
|
189
|
+
handleBack();
|
|
190
|
+
} else if (e.key === "ArrowRight" && !isLastStep) {
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
e.stopPropagation();
|
|
193
|
+
handleNext();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
window.addEventListener("keydown", handleKeyDown, true);
|
|
197
|
+
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
198
|
+
}, [
|
|
199
|
+
enableKeyboardNavigation,
|
|
200
|
+
scopeToDialog,
|
|
201
|
+
isFirstStep,
|
|
202
|
+
isLastStep,
|
|
203
|
+
handleBack,
|
|
204
|
+
handleNext,
|
|
205
|
+
onCancel,
|
|
206
|
+
onSubmit,
|
|
207
|
+
onReset,
|
|
208
|
+
persistKey,
|
|
209
|
+
setStoredValue,
|
|
210
|
+
logError
|
|
211
|
+
]);
|
|
212
|
+
const getStatusStyles = react.useCallback(
|
|
213
|
+
(stepIndex) => {
|
|
214
|
+
const status = stepStatuses[stepIndex];
|
|
215
|
+
const isCurrent = stepIndex === currentStep;
|
|
216
|
+
const step = steps[stepIndex];
|
|
217
|
+
const Icon = step.icon;
|
|
218
|
+
const tooltip = getStepTooltip?.(stepIndex, status) ?? null;
|
|
219
|
+
switch (status) {
|
|
220
|
+
case "error":
|
|
221
|
+
return {
|
|
222
|
+
border: "border-destructive bg-destructive",
|
|
223
|
+
text: "text-destructive",
|
|
224
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5 text-white" }),
|
|
225
|
+
tooltip: tooltip || "This section has errors"
|
|
226
|
+
};
|
|
227
|
+
case "complete":
|
|
228
|
+
return {
|
|
229
|
+
border: "border-foreground bg-foreground text-background",
|
|
230
|
+
text: "text-foreground",
|
|
231
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-5 h-5" }),
|
|
232
|
+
tooltip: null
|
|
233
|
+
};
|
|
234
|
+
case "incomplete":
|
|
235
|
+
return {
|
|
236
|
+
border: "border-yellow-500 bg-yellow-500 text-white",
|
|
237
|
+
text: "text-yellow-600 dark:text-yellow-500",
|
|
238
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5" }),
|
|
239
|
+
tooltip: tooltip || "This section is incomplete"
|
|
240
|
+
};
|
|
241
|
+
case "in-progress":
|
|
242
|
+
return {
|
|
243
|
+
border: "border-primary bg-primary text-primary-foreground",
|
|
244
|
+
text: "text-primary",
|
|
245
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5" }),
|
|
246
|
+
tooltip: null
|
|
247
|
+
};
|
|
248
|
+
default:
|
|
249
|
+
return {
|
|
250
|
+
border: isCurrent ? "border-muted-foreground bg-muted-foreground text-background dark:border-muted dark:bg-muted dark:text-foreground" : "border-transparent bg-background",
|
|
251
|
+
text: isCurrent ? "text-foreground" : "text-muted-foreground",
|
|
252
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-5 h-5" }),
|
|
253
|
+
tooltip: null
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
[stepStatuses, currentStep, steps, getStepTooltip]
|
|
258
|
+
);
|
|
259
|
+
const progressPercentage = react.useMemo(() => {
|
|
260
|
+
if (totalSteps <= 1) return 0;
|
|
261
|
+
return currentStep / (totalSteps - 1) * 100;
|
|
262
|
+
}, [currentStep, totalSteps]);
|
|
263
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkADIDI7AJ_js.cn("space-y-8", className), children: [
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-between", children: [
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-5 left-5 right-5 h-[2px]", children: [
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-border/60 rounded-full" }),
|
|
267
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
268
|
+
"div",
|
|
269
|
+
{
|
|
270
|
+
className: "absolute inset-y-0 left-0 bg-foreground rounded-full transition-all duration-500 ease-out",
|
|
271
|
+
style: { width: `${progressPercentage}%` }
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
] }),
|
|
275
|
+
steps.map((step, index) => {
|
|
276
|
+
const styles = getStatusStyles(index);
|
|
277
|
+
const stepButton = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
278
|
+
"button",
|
|
279
|
+
{
|
|
280
|
+
type: "button",
|
|
281
|
+
onClick: () => handleStepClick(index),
|
|
282
|
+
"aria-label": `Step ${index + 1}: ${step.label}`,
|
|
283
|
+
"aria-current": index === currentStep ? "step" : void 0,
|
|
284
|
+
className: chunkADIDI7AJ_js.cn(
|
|
285
|
+
"relative z-10 flex flex-col items-center gap-2 transition-colors cursor-pointer",
|
|
286
|
+
styles.text
|
|
287
|
+
),
|
|
288
|
+
children: [
|
|
289
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
290
|
+
"div",
|
|
291
|
+
{
|
|
292
|
+
className: chunkADIDI7AJ_js.cn(
|
|
293
|
+
"w-10 h-10 rounded-full flex items-center justify-center border-2 transition-colors",
|
|
294
|
+
styles.border
|
|
295
|
+
),
|
|
296
|
+
children: styles.icon
|
|
297
|
+
}
|
|
298
|
+
),
|
|
299
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium hidden sm:block", children: step.label })
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
step.id
|
|
303
|
+
);
|
|
304
|
+
if (styles.tooltip) {
|
|
305
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(chunkSORWLKOK_js.Tooltip, { children: [
|
|
306
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipTrigger, { asChild: true, children: stepButton }),
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkSORWLKOK_js.TooltipContent, { className: "whitespace-pre-line", children: styles.tooltip })
|
|
308
|
+
] }, step.id);
|
|
309
|
+
}
|
|
310
|
+
return stepButton;
|
|
311
|
+
})
|
|
312
|
+
] }) }),
|
|
313
|
+
children
|
|
314
|
+
] }) });
|
|
315
|
+
}
|
|
316
|
+
function useFormWizardNavigation(currentStep, totalSteps, onStepChange) {
|
|
317
|
+
const isFirstStep = currentStep === 0;
|
|
318
|
+
const isLastStep = currentStep === totalSteps - 1;
|
|
319
|
+
const goNext = react.useCallback(() => {
|
|
320
|
+
if (!isLastStep) {
|
|
321
|
+
onStepChange(currentStep + 1);
|
|
322
|
+
}
|
|
323
|
+
}, [currentStep, isLastStep, onStepChange]);
|
|
324
|
+
const goBack = react.useCallback(() => {
|
|
325
|
+
if (!isFirstStep) {
|
|
326
|
+
onStepChange(currentStep - 1);
|
|
327
|
+
}
|
|
328
|
+
}, [currentStep, isFirstStep, onStepChange]);
|
|
329
|
+
const goToStep = react.useCallback(
|
|
330
|
+
(index) => {
|
|
331
|
+
if (index >= 0 && index < totalSteps) {
|
|
332
|
+
onStepChange(index);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
[totalSteps, onStepChange]
|
|
336
|
+
);
|
|
337
|
+
return {
|
|
338
|
+
goNext,
|
|
339
|
+
goBack,
|
|
340
|
+
goToStep,
|
|
341
|
+
isFirstStep,
|
|
342
|
+
isLastStep,
|
|
343
|
+
currentStep,
|
|
344
|
+
totalSteps
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
exports.FormWizard = FormWizard;
|
|
349
|
+
exports.useFormWizardNavigation = useFormWizardNavigation;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkADIDI7AJ_js = require('./chunk-ADIDI7AJ.js');
|
|
4
|
+
var TabsPrimitive = require('@radix-ui/react-tabs');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
|
+
|
|
29
|
+
var Tabs = TabsPrimitive__namespace.Root;
|
|
30
|
+
var TabsList = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
31
|
+
TabsPrimitive__namespace.List,
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
className: chunkADIDI7AJ_js.cn("inline-flex h-auto items-center gap-0.5", className),
|
|
35
|
+
...props
|
|
36
|
+
}
|
|
37
|
+
));
|
|
38
|
+
TabsList.displayName = TabsPrimitive__namespace.List.displayName;
|
|
39
|
+
var TabsTrigger = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
40
|
+
TabsPrimitive__namespace.Trigger,
|
|
41
|
+
{
|
|
42
|
+
ref,
|
|
43
|
+
className: chunkADIDI7AJ_js.cn(
|
|
44
|
+
"relative inline-flex items-center justify-center whitespace-nowrap px-2 py-1 text-sm transition-colors rounded-box",
|
|
45
|
+
"ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
46
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
47
|
+
"text-muted-foreground data-[state=inactive]:hover:text-foreground data-[state=inactive]:hover:bg-accent/50",
|
|
48
|
+
"data-[state=active]:text-foreground data-[state=active]:font-medium",
|
|
49
|
+
// Active indicator line
|
|
50
|
+
"after:absolute after:bottom-0 after:left-2 after:right-2 after:h-0.5 after:rounded-full",
|
|
51
|
+
"after:bg-transparent data-[state=active]:after:bg-foreground",
|
|
52
|
+
className
|
|
53
|
+
),
|
|
54
|
+
...props
|
|
55
|
+
}
|
|
56
|
+
));
|
|
57
|
+
TabsTrigger.displayName = TabsPrimitive__namespace.Trigger.displayName;
|
|
58
|
+
var TabsContent = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
59
|
+
TabsPrimitive__namespace.Content,
|
|
60
|
+
{
|
|
61
|
+
ref,
|
|
62
|
+
className: chunkADIDI7AJ_js.cn(
|
|
63
|
+
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
64
|
+
className
|
|
65
|
+
),
|
|
66
|
+
...props
|
|
67
|
+
}
|
|
68
|
+
));
|
|
69
|
+
TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
|
|
70
|
+
|
|
71
|
+
exports.Tabs = Tabs;
|
|
72
|
+
exports.TabsContent = TabsContent;
|
|
73
|
+
exports.TabsList = TabsList;
|
|
74
|
+
exports.TabsTrigger = TabsTrigger;
|