@omnitron-dev/prism 0.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/bin/prism.js +13 -0
  4. package/dist/accessibility/index.d.ts +157 -0
  5. package/dist/accessibility/index.js +186 -0
  6. package/dist/accessibility/index.js.map +1 -0
  7. package/dist/blocks/index.d.ts +1239 -0
  8. package/dist/blocks/index.js +1712 -0
  9. package/dist/blocks/index.js.map +1 -0
  10. package/dist/chunk-77KIJLPP.js +37 -0
  11. package/dist/chunk-77KIJLPP.js.map +1 -0
  12. package/dist/chunk-BTIT7WYH.js +339 -0
  13. package/dist/chunk-BTIT7WYH.js.map +1 -0
  14. package/dist/chunk-BV32OJ2A.js +1409 -0
  15. package/dist/chunk-BV32OJ2A.js.map +1 -0
  16. package/dist/chunk-DDY7TLUI.js +139 -0
  17. package/dist/chunk-DDY7TLUI.js.map +1 -0
  18. package/dist/chunk-DXXZ3ITR.js +4227 -0
  19. package/dist/chunk-DXXZ3ITR.js.map +1 -0
  20. package/dist/chunk-E3XANPTO.js +2319 -0
  21. package/dist/chunk-E3XANPTO.js.map +1 -0
  22. package/dist/chunk-FU52GL2E.js +3 -0
  23. package/dist/chunk-FU52GL2E.js.map +1 -0
  24. package/dist/chunk-GYDT5EKX.js +16505 -0
  25. package/dist/chunk-GYDT5EKX.js.map +1 -0
  26. package/dist/chunk-HO2GKTWJ.js +28 -0
  27. package/dist/chunk-HO2GKTWJ.js.map +1 -0
  28. package/dist/chunk-JDTC2SBY.js +140 -0
  29. package/dist/chunk-JDTC2SBY.js.map +1 -0
  30. package/dist/chunk-JNU4QHJK.js +6 -0
  31. package/dist/chunk-JNU4QHJK.js.map +1 -0
  32. package/dist/chunk-LAEY5USO.js +2621 -0
  33. package/dist/chunk-LAEY5USO.js.map +1 -0
  34. package/dist/chunk-UR6X3W5I.js +530 -0
  35. package/dist/chunk-UR6X3W5I.js.map +1 -0
  36. package/dist/chunk-WC2WM2JD.js +883 -0
  37. package/dist/chunk-WC2WM2JD.js.map +1 -0
  38. package/dist/chunk-XWL6J6IO.js +40 -0
  39. package/dist/chunk-XWL6J6IO.js.map +1 -0
  40. package/dist/cli/index.js +2695 -0
  41. package/dist/cli/index.js.map +1 -0
  42. package/dist/config-BA6IeTq9.d.ts +100 -0
  43. package/dist/core/index.d.ts +454 -0
  44. package/dist/core/index.js +9 -0
  45. package/dist/core/index.js.map +1 -0
  46. package/dist/forms/index.d.ts +562 -0
  47. package/dist/forms/index.js +545 -0
  48. package/dist/forms/index.js.map +1 -0
  49. package/dist/hooks/index.d.ts +7 -0
  50. package/dist/hooks/index.js +10 -0
  51. package/dist/hooks/index.js.map +1 -0
  52. package/dist/http/index.d.ts +233 -0
  53. package/dist/http/index.js +282 -0
  54. package/dist/http/index.js.map +1 -0
  55. package/dist/index-odhPSv9I.d.ts +2491 -0
  56. package/dist/index.css +131 -0
  57. package/dist/index.css.map +1 -0
  58. package/dist/index.d.ts +9109 -0
  59. package/dist/index.js +13280 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/layouts/index.d.ts +854 -0
  62. package/dist/layouts/index.js +6 -0
  63. package/dist/layouts/index.js.map +1 -0
  64. package/dist/netron/index.d.ts +4 -0
  65. package/dist/netron/index.js +4 -0
  66. package/dist/netron/index.js.map +1 -0
  67. package/dist/registry/index.d.ts +352 -0
  68. package/dist/registry/index.js +4 -0
  69. package/dist/registry/index.js.map +1 -0
  70. package/dist/registry-BrDNftd5.d.ts +574 -0
  71. package/dist/settings-plpR26Xk.d.ts +455 -0
  72. package/dist/state/index.d.ts +981 -0
  73. package/dist/state/index.js +5 -0
  74. package/dist/state/index.js.map +1 -0
  75. package/dist/theme/index.d.ts +1049 -0
  76. package/dist/theme/index.js +5 -0
  77. package/dist/theme/index.js.map +1 -0
  78. package/dist/theme-CrXLfP1c.d.ts +389 -0
  79. package/dist/types/index.d.ts +146 -0
  80. package/dist/types/index.js +5 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/use-timeout-D7U3EAtH.d.ts +808 -0
  83. package/package.json +194 -0
@@ -0,0 +1,1712 @@
1
+ import { Field, SearchInput } from '../chunk-LAEY5USO.js';
2
+ import { useBoolean } from '../chunk-HO2GKTWJ.js';
3
+ import '../chunk-77KIJLPP.js';
4
+ import { createContext, useContext, useCallback, useMemo, useState, useEffect, useRef } from 'react';
5
+ import Box2 from '@mui/material/Box';
6
+ import Paper from '@mui/material/Paper';
7
+ import Typography2 from '@mui/material/Typography';
8
+ import IconButton2 from '@mui/material/IconButton';
9
+ import Collapse from '@mui/material/Collapse';
10
+ import Divider from '@mui/material/Divider';
11
+ import Skeleton from '@mui/material/Skeleton';
12
+ import Button2 from '@mui/material/Button';
13
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
14
+ import { useForm, FormProvider } from 'react-hook-form';
15
+ import { zodResolver } from '@hookform/resolvers/zod';
16
+ import { z } from 'zod';
17
+ import Link from '@mui/material/Link';
18
+ import Alert from '@mui/material/Alert';
19
+ import CircularProgress from '@mui/material/CircularProgress';
20
+ import InputAdornment from '@mui/material/InputAdornment';
21
+ import Menu from '@mui/material/Menu';
22
+ import MenuItem from '@mui/material/MenuItem';
23
+ import ListItemIcon from '@mui/material/ListItemIcon';
24
+ import ListItemText from '@mui/material/ListItemText';
25
+ import Tooltip from '@mui/material/Tooltip';
26
+ import LinearProgress from '@mui/material/LinearProgress';
27
+ import { DataGrid, GridToolbarContainer, GridToolbarColumnsButton, GridToolbarDensitySelector, GridToolbarExport } from '@mui/x-data-grid';
28
+
29
+ var collapseNoop = () => {
30
+ };
31
+ var DashboardBlockContext = createContext(null);
32
+ function useDashboardBlockContext() {
33
+ const context = useContext(DashboardBlockContext);
34
+ if (!context) {
35
+ throw new Error("useDashboardBlockContext must be used within DashboardBlock");
36
+ }
37
+ return context;
38
+ }
39
+ var sizeConfig = {
40
+ small: {
41
+ headerPx: 2,
42
+ headerPy: 1.5,
43
+ contentPx: 2,
44
+ contentPy: 1.5,
45
+ titleVariant: "subtitle1",
46
+ subtitleVariant: "caption"
47
+ },
48
+ medium: {
49
+ headerPx: 2.5,
50
+ headerPy: 2,
51
+ contentPx: 2.5,
52
+ contentPy: 2,
53
+ titleVariant: "h6",
54
+ subtitleVariant: "body2"
55
+ },
56
+ large: {
57
+ headerPx: 3,
58
+ headerPy: 2.5,
59
+ contentPx: 3,
60
+ contentPy: 2.5,
61
+ titleVariant: "h5",
62
+ subtitleVariant: "body1"
63
+ }
64
+ };
65
+ function DashboardBlockHeader({ title, subtitle, icon, actions, sx }) {
66
+ const { collapsed, toggleCollapse, variant, size } = useDashboardBlockContext();
67
+ const config = sizeConfig[size];
68
+ return /* @__PURE__ */ jsxs(
69
+ Box2,
70
+ {
71
+ "data-testid": "prism-dashboard-block-header",
72
+ sx: [
73
+ {
74
+ display: "flex",
75
+ alignItems: "flex-start",
76
+ justifyContent: "space-between",
77
+ gap: 2,
78
+ px: config.headerPx,
79
+ py: config.headerPy
80
+ },
81
+ ...Array.isArray(sx) ? sx : [sx]
82
+ ],
83
+ children: [
84
+ /* @__PURE__ */ jsxs(Box2, { sx: { display: "flex", alignItems: "flex-start", gap: 1.5, flex: 1, minWidth: 0 }, children: [
85
+ icon && /* @__PURE__ */ jsx(
86
+ Box2,
87
+ {
88
+ sx: {
89
+ display: "flex",
90
+ alignItems: "center",
91
+ justifyContent: "center",
92
+ mt: 0.25,
93
+ color: "primary.main"
94
+ },
95
+ children: icon
96
+ }
97
+ ),
98
+ /* @__PURE__ */ jsxs(Box2, { sx: { flex: 1, minWidth: 0 }, children: [
99
+ /* @__PURE__ */ jsx(Typography2, { variant: config.titleVariant, component: "h3", sx: { fontWeight: 600, lineHeight: 1.4 }, noWrap: true, children: title }),
100
+ subtitle && /* @__PURE__ */ jsx(Typography2, { variant: config.subtitleVariant, color: "text.secondary", sx: { mt: 0.25 }, children: subtitle })
101
+ ] })
102
+ ] }),
103
+ /* @__PURE__ */ jsxs(Box2, { sx: { display: "flex", alignItems: "center", gap: 0.5, flexShrink: 0 }, children: [
104
+ actions,
105
+ collapsed !== void 0 && /* @__PURE__ */ jsx(
106
+ IconButton2,
107
+ {
108
+ size: "small",
109
+ onClick: toggleCollapse,
110
+ "aria-expanded": !collapsed,
111
+ "aria-label": collapsed ? "Expand block" : "Collapse block",
112
+ "data-testid": "prism-dashboard-block-collapse",
113
+ children: /* @__PURE__ */ jsx(ChevronIcon, { direction: collapsed ? "down" : "up" })
114
+ }
115
+ )
116
+ ] })
117
+ ]
118
+ }
119
+ );
120
+ }
121
+ function DashboardBlockContent({ children, disablePadding = false, sx }) {
122
+ const { collapsed, loading, error, size } = useDashboardBlockContext();
123
+ const config = sizeConfig[size];
124
+ return /* @__PURE__ */ jsx(Collapse, { in: !collapsed, timeout: "auto", children: /* @__PURE__ */ jsx(
125
+ Box2,
126
+ {
127
+ "data-testid": "prism-dashboard-block-content",
128
+ sx: [
129
+ {
130
+ ...!disablePadding && {
131
+ px: config.contentPx,
132
+ py: config.contentPy
133
+ }
134
+ },
135
+ ...Array.isArray(sx) ? sx : [sx]
136
+ ],
137
+ children
138
+ }
139
+ ) });
140
+ }
141
+ function DashboardBlockFooter({ children, divider = true, sx }) {
142
+ const { collapsed, size } = useDashboardBlockContext();
143
+ const config = sizeConfig[size];
144
+ if (collapsed) return null;
145
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
146
+ divider && /* @__PURE__ */ jsx(Divider, {}),
147
+ /* @__PURE__ */ jsx(
148
+ Box2,
149
+ {
150
+ "data-testid": "prism-dashboard-block-footer",
151
+ sx: [
152
+ {
153
+ px: config.contentPx,
154
+ py: 1.5
155
+ },
156
+ ...Array.isArray(sx) ? sx : [sx]
157
+ ],
158
+ children
159
+ }
160
+ )
161
+ ] });
162
+ }
163
+ function LoadingState({ rows = 3, size }) {
164
+ const config = sizeConfig[size];
165
+ return /* @__PURE__ */ jsx(Box2, { sx: { px: config.contentPx, py: config.contentPy }, children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { variant: "text", animation: "wave", sx: { height: 20, mb: 1 } }, i)) });
166
+ }
167
+ function ErrorState({ message = "Failed to load data", onRetry, size }) {
168
+ const config = sizeConfig[size];
169
+ return /* @__PURE__ */ jsxs(
170
+ Box2,
171
+ {
172
+ sx: {
173
+ px: config.contentPx,
174
+ py: config.contentPy,
175
+ textAlign: "center"
176
+ },
177
+ children: [
178
+ /* @__PURE__ */ jsx(Typography2, { color: "error", variant: "body2", sx: { mb: onRetry ? 1.5 : 0 }, children: message }),
179
+ onRetry && /* @__PURE__ */ jsx(Button2, { size: "small", onClick: onRetry, children: "Retry" })
180
+ ]
181
+ }
182
+ );
183
+ }
184
+ function DashboardBlock({
185
+ title,
186
+ subtitle,
187
+ icon,
188
+ actions,
189
+ children,
190
+ footer,
191
+ variant = "default",
192
+ size = "medium",
193
+ loading = false,
194
+ loadingConfig,
195
+ error = false,
196
+ errorConfig,
197
+ collapsible = false,
198
+ defaultCollapsed = false,
199
+ collapsed: controlledCollapsed,
200
+ onCollapseChange,
201
+ disablePadding = false,
202
+ footerDivider = true,
203
+ sx,
204
+ slotProps
205
+ }) {
206
+ const uncontrolledCollapse = useBoolean(defaultCollapsed);
207
+ const isControlled = controlledCollapsed !== void 0;
208
+ const collapsed = isControlled ? controlledCollapsed : uncontrolledCollapse.value;
209
+ const handleToggleCollapse = useCallback(() => {
210
+ if (isControlled) {
211
+ onCollapseChange?.(!controlledCollapsed);
212
+ } else {
213
+ uncontrolledCollapse.onToggle();
214
+ }
215
+ }, [isControlled, controlledCollapsed, onCollapseChange, uncontrolledCollapse]);
216
+ const handleSetCollapsed = useCallback(
217
+ (value) => {
218
+ if (isControlled) {
219
+ onCollapseChange?.(value);
220
+ } else {
221
+ uncontrolledCollapse.setValue(value);
222
+ }
223
+ },
224
+ [isControlled, onCollapseChange, uncontrolledCollapse]
225
+ );
226
+ const contextValue = useMemo(
227
+ () => ({
228
+ collapsed: collapsible ? collapsed : false,
229
+ toggleCollapse: collapsible ? handleToggleCollapse : collapseNoop,
230
+ setCollapsed: collapsible ? handleSetCollapsed : collapseNoop,
231
+ loading,
232
+ error,
233
+ variant,
234
+ size
235
+ }),
236
+ [collapsed, collapsible, handleToggleCollapse, handleSetCollapsed, loading, error, variant, size]
237
+ );
238
+ const paperVariant = variant === "outlined" ? "outlined" : "elevation";
239
+ const paperElevation = variant === "default" ? 1 : 0;
240
+ return /* @__PURE__ */ jsx(DashboardBlockContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
241
+ Paper,
242
+ {
243
+ "data-testid": "prism-dashboard-block",
244
+ variant: paperVariant,
245
+ elevation: paperElevation,
246
+ sx: [
247
+ {
248
+ overflow: "hidden",
249
+ ...variant === "filled" && {
250
+ bgcolor: "action.hover"
251
+ }
252
+ },
253
+ ...Array.isArray(sx) ? sx : [sx]
254
+ ],
255
+ children: [
256
+ title && /* @__PURE__ */ jsx(
257
+ DashboardBlockHeader,
258
+ {
259
+ title,
260
+ subtitle,
261
+ icon,
262
+ actions,
263
+ ...slotProps?.header
264
+ }
265
+ ),
266
+ title && /* @__PURE__ */ jsx(Divider, {}),
267
+ /* @__PURE__ */ jsx(Box2, { "aria-live": "polite", "aria-busy": loading, children: loading ? loadingConfig?.loadingComponent ?? /* @__PURE__ */ jsx(LoadingState, { rows: loadingConfig?.skeletonRows ?? 3, size }) : error ? errorConfig?.errorComponent ?? /* @__PURE__ */ jsx(ErrorState, { message: errorConfig?.message, onRetry: errorConfig?.onRetry, size }) : children ? /* @__PURE__ */ jsx(DashboardBlockContent, { disablePadding, ...slotProps?.content, children }) : null }),
268
+ footer && !loading && !error && /* @__PURE__ */ jsx(DashboardBlockFooter, { divider: footerDivider, ...slotProps?.footer, children: footer })
269
+ ]
270
+ }
271
+ ) });
272
+ }
273
+ function ChevronIcon({ direction }) {
274
+ return /* @__PURE__ */ jsx(
275
+ "svg",
276
+ {
277
+ width: "20",
278
+ height: "20",
279
+ viewBox: "0 0 24 24",
280
+ fill: "none",
281
+ stroke: "currentColor",
282
+ strokeWidth: 2,
283
+ strokeLinecap: "round",
284
+ strokeLinejoin: "round",
285
+ "aria-hidden": "true",
286
+ style: {
287
+ transform: direction === "up" ? "rotate(180deg)" : void 0,
288
+ transition: "transform 0.2s ease"
289
+ },
290
+ children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
291
+ }
292
+ );
293
+ }
294
+ function useDashboardBlock(options = {}) {
295
+ const { defaultCollapsed = false, defaultLoading = false, onRetry } = options;
296
+ const [state, setState] = useState({
297
+ collapsed: defaultCollapsed,
298
+ loading: defaultLoading,
299
+ error: false,
300
+ errorMessage: void 0
301
+ });
302
+ const toggleCollapse = useCallback(() => {
303
+ setState((prev) => ({ ...prev, collapsed: !prev.collapsed }));
304
+ }, []);
305
+ const setCollapsed = useCallback((collapsed) => {
306
+ setState((prev) => ({ ...prev, collapsed }));
307
+ }, []);
308
+ const expand = useCallback(() => {
309
+ setState((prev) => ({ ...prev, collapsed: false }));
310
+ }, []);
311
+ const collapse = useCallback(() => {
312
+ setState((prev) => ({ ...prev, collapsed: true }));
313
+ }, []);
314
+ const setLoading = useCallback((loading) => {
315
+ setState((prev) => ({ ...prev, loading }));
316
+ }, []);
317
+ const setError = useCallback((error, errorMessage) => {
318
+ setState((prev) => ({ ...prev, error, errorMessage, loading: false }));
319
+ }, []);
320
+ const clearError = useCallback(() => {
321
+ setState((prev) => ({ ...prev, error: false, errorMessage: void 0 }));
322
+ }, []);
323
+ const reset = useCallback(() => {
324
+ setState({
325
+ collapsed: defaultCollapsed,
326
+ loading: defaultLoading,
327
+ error: false,
328
+ errorMessage: void 0
329
+ });
330
+ }, [defaultCollapsed, defaultLoading]);
331
+ const actions = useMemo(
332
+ () => ({
333
+ toggleCollapse,
334
+ setCollapsed,
335
+ expand,
336
+ collapse,
337
+ setLoading,
338
+ setError,
339
+ clearError,
340
+ reset
341
+ }),
342
+ [toggleCollapse, setCollapsed, expand, collapse, setLoading, setError, clearError, reset]
343
+ );
344
+ const blockProps = useMemo(
345
+ () => ({
346
+ collapsed: state.collapsed,
347
+ onCollapseChange: setCollapsed,
348
+ loading: state.loading,
349
+ error: state.error,
350
+ errorConfig: state.error ? {
351
+ message: state.errorMessage,
352
+ onRetry
353
+ } : void 0
354
+ }),
355
+ [state.collapsed, state.loading, state.error, state.errorMessage, setCollapsed, onRetry]
356
+ );
357
+ return {
358
+ state,
359
+ actions,
360
+ blockProps
361
+ };
362
+ }
363
+ function EyeIcon() {
364
+ return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
365
+ /* @__PURE__ */ jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
366
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" })
367
+ ] });
368
+ }
369
+ function EyeOffIcon() {
370
+ return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
371
+ /* @__PURE__ */ jsx("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
372
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
373
+ ] });
374
+ }
375
+ var UNSAFE_ERROR_PATTERNS = [
376
+ /at\s+\w+\s*\(/i,
377
+ // stack trace frames
378
+ /\b(ECONNREFUSED|ETIMEDOUT|ENOTFOUND)\b/,
379
+ // Node.js system errors
380
+ /\b(SELECT|INSERT|UPDATE|DELETE)\b.*\bFROM\b/i,
381
+ // SQL fragments
382
+ /\/[a-z_-]+\/[a-z_-]+\//i,
383
+ // Unix file paths
384
+ /[A-Z]:\\[^\s]+/,
385
+ // Windows file paths
386
+ /password|secret|token|key/i
387
+ // sensitive keywords in error context
388
+ ];
389
+ var DEFAULT_AUTH_ERROR = "An error occurred. Please try again.";
390
+ function sanitizeErrorMessage(err, fallback = DEFAULT_AUTH_ERROR) {
391
+ if (!(err instanceof Error)) return fallback;
392
+ const message = err.message;
393
+ for (const pattern of UNSAFE_ERROR_PATTERNS) {
394
+ if (pattern.test(message)) return fallback;
395
+ }
396
+ if (message.length > 200) return fallback;
397
+ return message;
398
+ }
399
+ var defaultLoginSchema = z.object({
400
+ email: z.string().email("Please enter a valid email"),
401
+ password: z.string().min(1, "Password is required"),
402
+ rememberMe: z.boolean().optional()
403
+ });
404
+ var createRegisterSchema = (minPasswordLength = 8, requireTerms = true) => z.object({
405
+ email: z.string().email("Please enter a valid email"),
406
+ password: z.string().min(minPasswordLength, `Password must be at least ${minPasswordLength} characters`),
407
+ confirmPassword: z.string(),
408
+ firstName: z.string().optional(),
409
+ lastName: z.string().optional(),
410
+ acceptTerms: requireTerms ? z.boolean().refine((val) => val === true, { message: "You must accept the terms" }) : z.boolean().optional()
411
+ }).refine((data) => data.password === data.confirmPassword, {
412
+ message: "Passwords do not match",
413
+ path: ["confirmPassword"]
414
+ });
415
+ var defaultForgotPasswordSchema = z.object({
416
+ email: z.string().email("Please enter a valid email")
417
+ });
418
+ var createResetPasswordSchema = (minPasswordLength = 8) => z.object({
419
+ password: z.string().min(minPasswordLength, `Password must be at least ${minPasswordLength} characters`),
420
+ confirmPassword: z.string()
421
+ }).refine((data) => data.password === data.confirmPassword, {
422
+ message: "Passwords do not match",
423
+ path: ["confirmPassword"]
424
+ });
425
+ var createVerifyCodeSchema = (codeLength = 6) => z.object({
426
+ code: z.string().length(codeLength, `Code must be ${codeLength} digits`)
427
+ });
428
+ function LoginForm({
429
+ onSubmit,
430
+ loading = false,
431
+ disabled = false,
432
+ showRememberMe = true,
433
+ showForgotPassword = true,
434
+ onForgotPassword,
435
+ showSocialLogin = false,
436
+ socialProviders = [],
437
+ schema,
438
+ labels = {},
439
+ sx,
440
+ slotProps
441
+ }) {
442
+ const [showPassword, setShowPassword] = useState(false);
443
+ const [error, setError] = useState(null);
444
+ const methods = useForm({
445
+ resolver: zodResolver(schema ?? defaultLoginSchema),
446
+ defaultValues: {
447
+ email: "",
448
+ password: "",
449
+ rememberMe: false
450
+ }
451
+ });
452
+ const handleSubmit = methods.handleSubmit(async (data) => {
453
+ setError(null);
454
+ try {
455
+ await onSubmit(data);
456
+ } catch (err) {
457
+ setError(sanitizeErrorMessage(err));
458
+ }
459
+ });
460
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs(
461
+ Box2,
462
+ {
463
+ component: "form",
464
+ onSubmit: handleSubmit,
465
+ sx: [{ display: "flex", flexDirection: "column", gap: 2.5 }, ...Array.isArray(sx) ? sx : [sx]],
466
+ ...slotProps?.wrapper,
467
+ children: [
468
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setError(null), children: error }),
469
+ /* @__PURE__ */ jsx(
470
+ Field.Text,
471
+ {
472
+ name: "email",
473
+ label: labels.email ?? "Email",
474
+ type: "email",
475
+ autoComplete: "email",
476
+ disabled: disabled || loading,
477
+ ...slotProps?.textField
478
+ }
479
+ ),
480
+ /* @__PURE__ */ jsx(
481
+ Field.Text,
482
+ {
483
+ name: "password",
484
+ label: labels.password ?? "Password",
485
+ type: showPassword ? "text" : "password",
486
+ autoComplete: "current-password",
487
+ disabled: disabled || loading,
488
+ slotProps: {
489
+ input: {
490
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
491
+ IconButton2,
492
+ {
493
+ onClick: () => setShowPassword(!showPassword),
494
+ edge: "end",
495
+ "aria-label": showPassword ? "Hide password" : "Show password",
496
+ children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
497
+ }
498
+ ) })
499
+ }
500
+ },
501
+ ...slotProps?.textField
502
+ }
503
+ ),
504
+ (showRememberMe || showForgotPassword) && /* @__PURE__ */ jsxs(Box2, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
505
+ showRememberMe && /* @__PURE__ */ jsx(
506
+ Field.Checkbox,
507
+ {
508
+ name: "rememberMe",
509
+ label: labels.rememberMe ?? "Remember me",
510
+ disabled: disabled || loading
511
+ }
512
+ ),
513
+ showForgotPassword && /* @__PURE__ */ jsx(
514
+ Link,
515
+ {
516
+ component: "button",
517
+ type: "button",
518
+ variant: "body2",
519
+ onClick: onForgotPassword,
520
+ sx: { textDecoration: "none" },
521
+ children: labels.forgotPassword ?? "Forgot password?"
522
+ }
523
+ )
524
+ ] }),
525
+ /* @__PURE__ */ jsx(
526
+ Button2,
527
+ {
528
+ type: "submit",
529
+ variant: "contained",
530
+ size: "large",
531
+ fullWidth: true,
532
+ disabled: disabled || loading,
533
+ ...slotProps?.submitButton,
534
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: 24, color: "inherit" }) : labels.submit ?? "Sign In"
535
+ }
536
+ ),
537
+ showSocialLogin && socialProviders.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
538
+ /* @__PURE__ */ jsx(Divider, { children: /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", children: labels.socialDivider ?? "or continue with" }) }),
539
+ /* @__PURE__ */ jsx(Box2, { sx: { display: "flex", gap: 1.5, justifyContent: "center" }, children: socialProviders.map((provider) => /* @__PURE__ */ jsx(
540
+ IconButton2,
541
+ {
542
+ onClick: provider.onClick,
543
+ disabled: disabled || loading,
544
+ sx: {
545
+ border: 1,
546
+ borderColor: "divider",
547
+ borderRadius: 1,
548
+ p: 1
549
+ },
550
+ "aria-label": `Sign in with ${provider.name}`,
551
+ children: provider.icon
552
+ },
553
+ provider.id
554
+ )) })
555
+ ] })
556
+ ]
557
+ }
558
+ ) });
559
+ }
560
+ function RegisterForm({
561
+ onSubmit,
562
+ loading = false,
563
+ disabled = false,
564
+ showNameFields = false,
565
+ requireTerms = true,
566
+ onTermsClick,
567
+ onPrivacyClick,
568
+ minPasswordLength = 8,
569
+ schema,
570
+ labels = {},
571
+ sx,
572
+ slotProps
573
+ }) {
574
+ const [showPassword, setShowPassword] = useState(false);
575
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
576
+ const [error, setError] = useState(null);
577
+ const methods = useForm({
578
+ resolver: zodResolver(
579
+ schema ?? createRegisterSchema(minPasswordLength, requireTerms)
580
+ ),
581
+ defaultValues: {
582
+ email: "",
583
+ password: "",
584
+ confirmPassword: "",
585
+ firstName: "",
586
+ lastName: "",
587
+ acceptTerms: false
588
+ }
589
+ });
590
+ const handleSubmit = methods.handleSubmit(async (data) => {
591
+ setError(null);
592
+ try {
593
+ await onSubmit(data);
594
+ } catch (err) {
595
+ setError(sanitizeErrorMessage(err));
596
+ }
597
+ });
598
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs(
599
+ Box2,
600
+ {
601
+ component: "form",
602
+ onSubmit: handleSubmit,
603
+ sx: [{ display: "flex", flexDirection: "column", gap: 2.5 }, ...Array.isArray(sx) ? sx : [sx]],
604
+ ...slotProps?.wrapper,
605
+ children: [
606
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setError(null), children: error }),
607
+ showNameFields && /* @__PURE__ */ jsxs(Box2, { sx: { display: "flex", gap: 2 }, children: [
608
+ /* @__PURE__ */ jsx(
609
+ Field.Text,
610
+ {
611
+ name: "firstName",
612
+ label: labels.firstName ?? "First Name",
613
+ autoComplete: "given-name",
614
+ disabled: disabled || loading,
615
+ ...slotProps?.textField
616
+ }
617
+ ),
618
+ /* @__PURE__ */ jsx(
619
+ Field.Text,
620
+ {
621
+ name: "lastName",
622
+ label: labels.lastName ?? "Last Name",
623
+ autoComplete: "family-name",
624
+ disabled: disabled || loading,
625
+ ...slotProps?.textField
626
+ }
627
+ )
628
+ ] }),
629
+ /* @__PURE__ */ jsx(
630
+ Field.Text,
631
+ {
632
+ name: "email",
633
+ label: labels.email ?? "Email",
634
+ type: "email",
635
+ autoComplete: "email",
636
+ disabled: disabled || loading,
637
+ ...slotProps?.textField
638
+ }
639
+ ),
640
+ /* @__PURE__ */ jsx(
641
+ Field.Text,
642
+ {
643
+ name: "password",
644
+ label: labels.password ?? "Password",
645
+ type: showPassword ? "text" : "password",
646
+ autoComplete: "new-password",
647
+ disabled: disabled || loading,
648
+ helperText: `At least ${minPasswordLength} characters`,
649
+ slotProps: {
650
+ input: {
651
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
652
+ IconButton2,
653
+ {
654
+ onClick: () => setShowPassword(!showPassword),
655
+ edge: "end",
656
+ "aria-label": showPassword ? "Hide password" : "Show password",
657
+ children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
658
+ }
659
+ ) })
660
+ }
661
+ },
662
+ ...slotProps?.textField
663
+ }
664
+ ),
665
+ /* @__PURE__ */ jsx(
666
+ Field.Text,
667
+ {
668
+ name: "confirmPassword",
669
+ label: labels.confirmPassword ?? "Confirm Password",
670
+ type: showConfirmPassword ? "text" : "password",
671
+ autoComplete: "new-password",
672
+ disabled: disabled || loading,
673
+ slotProps: {
674
+ input: {
675
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
676
+ IconButton2,
677
+ {
678
+ onClick: () => setShowConfirmPassword(!showConfirmPassword),
679
+ edge: "end",
680
+ "aria-label": showConfirmPassword ? "Hide password" : "Show password",
681
+ children: showConfirmPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
682
+ }
683
+ ) })
684
+ }
685
+ },
686
+ ...slotProps?.textField
687
+ }
688
+ ),
689
+ requireTerms && /* @__PURE__ */ jsx(
690
+ Field.Checkbox,
691
+ {
692
+ name: "acceptTerms",
693
+ disabled: disabled || loading,
694
+ label: /* @__PURE__ */ jsxs(Typography2, { variant: "body2", component: "span", children: [
695
+ labels.acceptTerms ?? "I agree to the ",
696
+ /* @__PURE__ */ jsx(Link, { component: "button", type: "button", onClick: onTermsClick, children: labels.termsLink ?? "Terms of Service" }),
697
+ " and ",
698
+ /* @__PURE__ */ jsx(Link, { component: "button", type: "button", onClick: onPrivacyClick, children: labels.privacyLink ?? "Privacy Policy" })
699
+ ] })
700
+ }
701
+ ),
702
+ /* @__PURE__ */ jsx(
703
+ Button2,
704
+ {
705
+ type: "submit",
706
+ variant: "contained",
707
+ size: "large",
708
+ fullWidth: true,
709
+ disabled: disabled || loading,
710
+ ...slotProps?.submitButton,
711
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: 24, color: "inherit" }) : labels.submit ?? "Create Account"
712
+ }
713
+ )
714
+ ]
715
+ }
716
+ ) });
717
+ }
718
+ function ForgotPasswordForm({
719
+ onSubmit,
720
+ loading = false,
721
+ disabled = false,
722
+ onBackToLogin,
723
+ schema,
724
+ labels = {},
725
+ sx,
726
+ slotProps
727
+ }) {
728
+ const [error, setError] = useState(null);
729
+ const [success, setSuccess] = useState(false);
730
+ const methods = useForm({
731
+ resolver: zodResolver(schema ?? defaultForgotPasswordSchema),
732
+ defaultValues: {
733
+ email: ""
734
+ }
735
+ });
736
+ const handleSubmit = methods.handleSubmit(async (data) => {
737
+ setError(null);
738
+ try {
739
+ await onSubmit(data);
740
+ setSuccess(true);
741
+ } catch (err) {
742
+ setError(sanitizeErrorMessage(err));
743
+ }
744
+ });
745
+ if (success) {
746
+ return /* @__PURE__ */ jsxs(Box2, { sx: { textAlign: "center" }, children: [
747
+ /* @__PURE__ */ jsx(Typography2, { variant: "h6", gutterBottom: true, children: "Check your email" }),
748
+ /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", sx: { mb: 3 }, children: "We sent a password reset link to your email address." }),
749
+ onBackToLogin && /* @__PURE__ */ jsx(Button2, { variant: "text", onClick: onBackToLogin, children: labels.backToLogin ?? "Back to login" })
750
+ ] });
751
+ }
752
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs(
753
+ Box2,
754
+ {
755
+ component: "form",
756
+ onSubmit: handleSubmit,
757
+ sx: [{ display: "flex", flexDirection: "column", gap: 2.5 }, ...Array.isArray(sx) ? sx : [sx]],
758
+ ...slotProps?.wrapper,
759
+ children: [
760
+ /* @__PURE__ */ jsxs(Box2, { sx: { textAlign: "center", mb: 1 }, children: [
761
+ /* @__PURE__ */ jsx(Typography2, { variant: "h6", gutterBottom: true, children: labels.title ?? "Forgot password?" }),
762
+ /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", children: labels.description ?? "Enter your email and we'll send you a reset link." })
763
+ ] }),
764
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setError(null), children: error }),
765
+ /* @__PURE__ */ jsx(
766
+ Field.Text,
767
+ {
768
+ name: "email",
769
+ label: labels.email ?? "Email",
770
+ type: "email",
771
+ autoComplete: "email",
772
+ disabled: disabled || loading,
773
+ ...slotProps?.textField
774
+ }
775
+ ),
776
+ /* @__PURE__ */ jsx(
777
+ Button2,
778
+ {
779
+ type: "submit",
780
+ variant: "contained",
781
+ size: "large",
782
+ fullWidth: true,
783
+ disabled: disabled || loading,
784
+ ...slotProps?.submitButton,
785
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: 24, color: "inherit" }) : labels.submit ?? "Send Reset Link"
786
+ }
787
+ ),
788
+ onBackToLogin && /* @__PURE__ */ jsx(Button2, { variant: "text", onClick: onBackToLogin, disabled: loading, children: labels.backToLogin ?? "Back to login" })
789
+ ]
790
+ }
791
+ ) });
792
+ }
793
+ function ResetPasswordForm({
794
+ onSubmit,
795
+ loading = false,
796
+ disabled = false,
797
+ minPasswordLength = 8,
798
+ schema,
799
+ labels = {},
800
+ sx,
801
+ slotProps
802
+ }) {
803
+ const [showPassword, setShowPassword] = useState(false);
804
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
805
+ const [error, setError] = useState(null);
806
+ const methods = useForm({
807
+ resolver: zodResolver(
808
+ schema ?? createResetPasswordSchema(minPasswordLength)
809
+ ),
810
+ defaultValues: {
811
+ password: "",
812
+ confirmPassword: ""
813
+ }
814
+ });
815
+ const handleSubmit = methods.handleSubmit(async (data) => {
816
+ setError(null);
817
+ try {
818
+ await onSubmit(data);
819
+ } catch (err) {
820
+ setError(sanitizeErrorMessage(err));
821
+ }
822
+ });
823
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs(
824
+ Box2,
825
+ {
826
+ component: "form",
827
+ onSubmit: handleSubmit,
828
+ sx: [{ display: "flex", flexDirection: "column", gap: 2.5 }, ...Array.isArray(sx) ? sx : [sx]],
829
+ ...slotProps?.wrapper,
830
+ children: [
831
+ /* @__PURE__ */ jsxs(Box2, { sx: { textAlign: "center", mb: 1 }, children: [
832
+ /* @__PURE__ */ jsx(Typography2, { variant: "h6", gutterBottom: true, children: labels.title ?? "Set new password" }),
833
+ /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", children: labels.description ?? "Create a new password for your account." })
834
+ ] }),
835
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setError(null), children: error }),
836
+ /* @__PURE__ */ jsx(
837
+ Field.Text,
838
+ {
839
+ name: "password",
840
+ label: labels.password ?? "New Password",
841
+ type: showPassword ? "text" : "password",
842
+ autoComplete: "new-password",
843
+ disabled: disabled || loading,
844
+ helperText: `At least ${minPasswordLength} characters`,
845
+ slotProps: {
846
+ input: {
847
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
848
+ IconButton2,
849
+ {
850
+ onClick: () => setShowPassword(!showPassword),
851
+ edge: "end",
852
+ "aria-label": showPassword ? "Hide password" : "Show password",
853
+ children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
854
+ }
855
+ ) })
856
+ }
857
+ },
858
+ ...slotProps?.textField
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsx(
862
+ Field.Text,
863
+ {
864
+ name: "confirmPassword",
865
+ label: labels.confirmPassword ?? "Confirm Password",
866
+ type: showConfirmPassword ? "text" : "password",
867
+ autoComplete: "new-password",
868
+ disabled: disabled || loading,
869
+ slotProps: {
870
+ input: {
871
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
872
+ IconButton2,
873
+ {
874
+ onClick: () => setShowConfirmPassword(!showConfirmPassword),
875
+ edge: "end",
876
+ "aria-label": showConfirmPassword ? "Hide password" : "Show password",
877
+ children: showConfirmPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
878
+ }
879
+ ) })
880
+ }
881
+ },
882
+ ...slotProps?.textField
883
+ }
884
+ ),
885
+ /* @__PURE__ */ jsx(
886
+ Button2,
887
+ {
888
+ type: "submit",
889
+ variant: "contained",
890
+ size: "large",
891
+ fullWidth: true,
892
+ disabled: disabled || loading,
893
+ ...slotProps?.submitButton,
894
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: 24, color: "inherit" }) : labels.submit ?? "Reset Password"
895
+ }
896
+ )
897
+ ]
898
+ }
899
+ ) });
900
+ }
901
+ function VerifyCodeForm({
902
+ onSubmit,
903
+ loading = false,
904
+ disabled = false,
905
+ codeLength = 6,
906
+ onResendCode,
907
+ resendCooldown = 60,
908
+ schema,
909
+ labels = {},
910
+ sx,
911
+ slotProps
912
+ }) {
913
+ const [error, setError] = useState(null);
914
+ const [cooldown, setCooldown] = useState(0);
915
+ const methods = useForm({
916
+ resolver: zodResolver(schema ?? createVerifyCodeSchema(codeLength)),
917
+ defaultValues: {
918
+ code: ""
919
+ }
920
+ });
921
+ useEffect(() => {
922
+ if (cooldown > 0) {
923
+ const timer = setTimeout(() => setCooldown(cooldown - 1), 1e3);
924
+ return () => clearTimeout(timer);
925
+ }
926
+ return void 0;
927
+ }, [cooldown]);
928
+ const handleResendCode = useCallback(async () => {
929
+ if (cooldown > 0 || !onResendCode) return;
930
+ try {
931
+ await onResendCode();
932
+ setCooldown(resendCooldown);
933
+ } catch (err) {
934
+ setError(sanitizeErrorMessage(err, "Failed to resend code"));
935
+ }
936
+ }, [cooldown, onResendCode, resendCooldown]);
937
+ const handleSubmit = methods.handleSubmit(async (data) => {
938
+ setError(null);
939
+ try {
940
+ await onSubmit(data);
941
+ } catch (err) {
942
+ setError(sanitizeErrorMessage(err));
943
+ }
944
+ });
945
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs(
946
+ Box2,
947
+ {
948
+ component: "form",
949
+ onSubmit: handleSubmit,
950
+ sx: [
951
+ { display: "flex", flexDirection: "column", gap: 2.5, alignItems: "center" },
952
+ ...Array.isArray(sx) ? sx : [sx]
953
+ ],
954
+ ...slotProps?.wrapper,
955
+ children: [
956
+ /* @__PURE__ */ jsxs(Box2, { sx: { textAlign: "center", mb: 1 }, children: [
957
+ /* @__PURE__ */ jsx(Typography2, { variant: "h6", gutterBottom: true, children: labels.title ?? "Enter verification code" }),
958
+ /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", children: labels.description ?? "We sent a verification code to your email." })
959
+ ] }),
960
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setError(null), sx: { width: "100%" }, children: error }),
961
+ /* @__PURE__ */ jsx(Field.Code, { name: "code", length: codeLength, autoFocus: true, disabled: disabled || loading }),
962
+ /* @__PURE__ */ jsx(
963
+ Button2,
964
+ {
965
+ type: "submit",
966
+ variant: "contained",
967
+ size: "large",
968
+ fullWidth: true,
969
+ disabled: disabled || loading,
970
+ ...slotProps?.submitButton,
971
+ children: loading ? /* @__PURE__ */ jsx(CircularProgress, { size: 24, color: "inherit" }) : labels.submit ?? "Verify"
972
+ }
973
+ ),
974
+ onResendCode && /* @__PURE__ */ jsx(Box2, { sx: { textAlign: "center" }, children: cooldown > 0 ? /* @__PURE__ */ jsxs(Typography2, { variant: "body2", color: "text.secondary", children: [
975
+ labels.resendIn ?? "Resend code in",
976
+ " ",
977
+ cooldown,
978
+ "s"
979
+ ] }) : /* @__PURE__ */ jsx(Link, { component: "button", type: "button", variant: "body2", onClick: handleResendCode, disabled: loading, children: labels.resendCode ?? "Didn't receive the code? Resend" }) })
980
+ ]
981
+ }
982
+ ) });
983
+ }
984
+ var AuthBlock = {
985
+ Login: LoginForm,
986
+ Register: RegisterForm,
987
+ ForgotPassword: ForgotPasswordForm,
988
+ ResetPassword: ResetPasswordForm,
989
+ VerifyCode: VerifyCodeForm
990
+ };
991
+ function AuthGuard({
992
+ children,
993
+ useAuth,
994
+ loadingComponent = null,
995
+ onUnauthenticated,
996
+ unauthenticatedComponent = null
997
+ }) {
998
+ const { isAuthenticated, isLoading } = useAuth();
999
+ const [checked, setChecked] = useState(false);
1000
+ useEffect(() => {
1001
+ if (!isLoading) {
1002
+ if (!isAuthenticated) {
1003
+ onUnauthenticated?.();
1004
+ }
1005
+ setChecked(true);
1006
+ }
1007
+ }, [isAuthenticated, isLoading, onUnauthenticated]);
1008
+ if (isLoading || !checked) {
1009
+ return loadingComponent;
1010
+ }
1011
+ if (!isAuthenticated) {
1012
+ return unauthenticatedComponent;
1013
+ }
1014
+ return children;
1015
+ }
1016
+ function GuestGuard({
1017
+ children,
1018
+ useAuth,
1019
+ loadingComponent = null,
1020
+ onAuthenticated,
1021
+ authenticatedComponent = null
1022
+ }) {
1023
+ const { isAuthenticated, isLoading } = useAuth();
1024
+ const [checked, setChecked] = useState(false);
1025
+ useEffect(() => {
1026
+ if (!isLoading) {
1027
+ if (isAuthenticated) {
1028
+ onAuthenticated?.();
1029
+ }
1030
+ setChecked(true);
1031
+ }
1032
+ }, [isAuthenticated, isLoading, onAuthenticated]);
1033
+ if (isLoading || !checked) {
1034
+ return loadingComponent;
1035
+ }
1036
+ if (isAuthenticated) {
1037
+ return authenticatedComponent;
1038
+ }
1039
+ return children;
1040
+ }
1041
+ function RoleBasedGuard({
1042
+ children,
1043
+ useAuth,
1044
+ roles = [],
1045
+ permissions = [],
1046
+ requireEmailVerified = false,
1047
+ roleMatchStrategy = "any",
1048
+ loadingComponent = null,
1049
+ onAccessDenied,
1050
+ accessDeniedComponent = null
1051
+ }) {
1052
+ const { isAuthenticated, isLoading, user } = useAuth();
1053
+ const [checked, setChecked] = useState(false);
1054
+ const [accessGranted, setAccessGranted] = useState(false);
1055
+ useEffect(() => {
1056
+ if (!isLoading) {
1057
+ if (!isAuthenticated || !user) {
1058
+ onAccessDenied?.("not_authenticated");
1059
+ setAccessGranted(false);
1060
+ setChecked(true);
1061
+ return;
1062
+ }
1063
+ if (requireEmailVerified && !user.emailVerified) {
1064
+ onAccessDenied?.("email_not_verified");
1065
+ setAccessGranted(false);
1066
+ setChecked(true);
1067
+ return;
1068
+ }
1069
+ if (roles.length > 0) {
1070
+ const userRoles = user.roles ?? [];
1071
+ const hasRequiredRole = roleMatchStrategy === "all" ? roles.every((role) => userRoles.includes(role)) : roles.some((role) => userRoles.includes(role));
1072
+ if (!hasRequiredRole) {
1073
+ onAccessDenied?.("missing_role");
1074
+ setAccessGranted(false);
1075
+ setChecked(true);
1076
+ return;
1077
+ }
1078
+ }
1079
+ if (permissions.length > 0) {
1080
+ const userPermissions = user.permissions ?? [];
1081
+ const hasAllPermissions = permissions.every((perm) => userPermissions.includes(perm));
1082
+ if (!hasAllPermissions) {
1083
+ onAccessDenied?.("missing_permission");
1084
+ setAccessGranted(false);
1085
+ setChecked(true);
1086
+ return;
1087
+ }
1088
+ }
1089
+ setAccessGranted(true);
1090
+ setChecked(true);
1091
+ }
1092
+ }, [isAuthenticated, isLoading, user, roles, permissions, requireEmailVerified, roleMatchStrategy, onAccessDenied]);
1093
+ if (isLoading || !checked) {
1094
+ return loadingComponent;
1095
+ }
1096
+ if (!accessGranted) {
1097
+ return accessDeniedComponent;
1098
+ }
1099
+ return children;
1100
+ }
1101
+ function hasRole(user, role, strategy = "any") {
1102
+ if (!user?.roles?.length) return false;
1103
+ const roles = Array.isArray(role) ? role : [role];
1104
+ return strategy === "all" ? roles.every((r) => user.roles.includes(r)) : roles.some((r) => user.roles.includes(r));
1105
+ }
1106
+ function hasPermission(user, permission, strategy = "all") {
1107
+ if (!user?.permissions?.length) return false;
1108
+ const permissions = Array.isArray(permission) ? permission : [permission];
1109
+ return strategy === "all" ? permissions.every((p) => user.permissions.includes(p)) : permissions.some((p) => user.permissions.includes(p));
1110
+ }
1111
+ function createConditionalRender(user) {
1112
+ return {
1113
+ canRender: (options) => {
1114
+ const { roles = [], permissions = [], roleMatchStrategy = "any" } = options;
1115
+ if (roles.length > 0 && !hasRole(user, roles, roleMatchStrategy)) {
1116
+ return false;
1117
+ }
1118
+ if (permissions.length > 0 && !hasPermission(user, permissions, "all")) {
1119
+ return false;
1120
+ }
1121
+ return true;
1122
+ }
1123
+ };
1124
+ }
1125
+ var DataGridBlockContext = createContext(null);
1126
+ function useDataGridBlockContext() {
1127
+ const context = useContext(DataGridBlockContext);
1128
+ if (!context) {
1129
+ throw new Error("useDataGridBlockContext must be used within DataGridBlock");
1130
+ }
1131
+ return context;
1132
+ }
1133
+ function MoreVertIcon() {
1134
+ return /* @__PURE__ */ jsxs(
1135
+ "svg",
1136
+ {
1137
+ width: "20",
1138
+ height: "20",
1139
+ viewBox: "0 0 24 24",
1140
+ fill: "none",
1141
+ stroke: "currentColor",
1142
+ strokeWidth: 2,
1143
+ strokeLinecap: "round",
1144
+ strokeLinejoin: "round",
1145
+ "aria-hidden": "true",
1146
+ children: [
1147
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1" }),
1148
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1" }),
1149
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1" })
1150
+ ]
1151
+ }
1152
+ );
1153
+ }
1154
+ function EmptyIcon() {
1155
+ return /* @__PURE__ */ jsxs(
1156
+ "svg",
1157
+ {
1158
+ width: "64",
1159
+ height: "64",
1160
+ viewBox: "0 0 24 24",
1161
+ fill: "none",
1162
+ stroke: "currentColor",
1163
+ strokeWidth: 1.5,
1164
+ strokeLinecap: "round",
1165
+ strokeLinejoin: "round",
1166
+ "aria-hidden": "true",
1167
+ style: { opacity: 0.4 },
1168
+ children: [
1169
+ /* @__PURE__ */ jsx("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
1170
+ /* @__PURE__ */ jsx("polyline", { points: "13 2 13 9 20 9" }),
1171
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "12", x2: "10", y2: "18" }),
1172
+ /* @__PURE__ */ jsx("line", { x1: "14", y1: "12", x2: "14", y2: "18" }),
1173
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "15", x2: "14", y2: "15" })
1174
+ ]
1175
+ }
1176
+ );
1177
+ }
1178
+ function CustomToolbar({
1179
+ quickFilter,
1180
+ exportConfig,
1181
+ showColumnSelector = true,
1182
+ showDensitySelector = true,
1183
+ startContent,
1184
+ endContent,
1185
+ actions,
1186
+ onQuickFilterChange
1187
+ }) {
1188
+ const [searchValue, setSearchValue] = useState("");
1189
+ const debounceRef = useRef(null);
1190
+ useEffect(
1191
+ () => () => {
1192
+ if (debounceRef.current) clearTimeout(debounceRef.current);
1193
+ },
1194
+ []
1195
+ );
1196
+ const handleSearchChange = useCallback(
1197
+ (value) => {
1198
+ setSearchValue(value);
1199
+ if (debounceRef.current) {
1200
+ clearTimeout(debounceRef.current);
1201
+ }
1202
+ debounceRef.current = setTimeout(() => {
1203
+ onQuickFilterChange?.(value);
1204
+ }, quickFilter?.debounceMs ?? 300);
1205
+ },
1206
+ [onQuickFilterChange, quickFilter?.debounceMs]
1207
+ );
1208
+ return /* @__PURE__ */ jsxs(
1209
+ GridToolbarContainer,
1210
+ {
1211
+ sx: {
1212
+ gap: 1.5,
1213
+ p: 2,
1214
+ borderBottom: 1,
1215
+ borderColor: "divider"
1216
+ },
1217
+ children: [
1218
+ startContent,
1219
+ quickFilter?.enabled !== false && /* @__PURE__ */ jsx(
1220
+ SearchInput,
1221
+ {
1222
+ value: searchValue,
1223
+ onChange: handleSearchChange,
1224
+ placeholder: quickFilter?.placeholder ?? "Search...",
1225
+ fullWidth: false,
1226
+ minWidth: 200
1227
+ }
1228
+ ),
1229
+ /* @__PURE__ */ jsx(Box2, { sx: { flex: 1 } }),
1230
+ showColumnSelector && /* @__PURE__ */ jsx(GridToolbarColumnsButton, {}),
1231
+ showDensitySelector && /* @__PURE__ */ jsx(GridToolbarDensitySelector, {}),
1232
+ (exportConfig?.csv !== false || exportConfig?.print !== false) && /* @__PURE__ */ jsx(
1233
+ GridToolbarExport,
1234
+ {
1235
+ printOptions: exportConfig?.print === false ? { disableToolbarButton: true } : void 0,
1236
+ csvOptions: exportConfig?.csv === false ? { disableToolbarButton: true } : void 0
1237
+ }
1238
+ ),
1239
+ actions,
1240
+ endContent
1241
+ ]
1242
+ }
1243
+ );
1244
+ }
1245
+ function RowActionsCell({ row, actions }) {
1246
+ const [anchorEl, setAnchorEl] = useState(null);
1247
+ const open = Boolean(anchorEl);
1248
+ const handleClick = useCallback((event) => {
1249
+ event.stopPropagation();
1250
+ setAnchorEl(event.currentTarget);
1251
+ }, []);
1252
+ const handleClose = useCallback(() => {
1253
+ setAnchorEl(null);
1254
+ }, []);
1255
+ const handleAction = useCallback(
1256
+ (action, event) => {
1257
+ setAnchorEl(null);
1258
+ action.onClick(row, event);
1259
+ },
1260
+ [row]
1261
+ );
1262
+ const visibleActions = actions.filter((action) => {
1263
+ if (typeof action.hidden === "function") {
1264
+ return !action.hidden(row);
1265
+ }
1266
+ return !action.hidden;
1267
+ });
1268
+ if (visibleActions.length === 0) {
1269
+ return null;
1270
+ }
1271
+ if (visibleActions.length <= 2) {
1272
+ return /* @__PURE__ */ jsx(Box2, { sx: { display: "flex", gap: 0.5 }, children: visibleActions.map((action) => {
1273
+ const isDisabled = typeof action.disabled === "function" ? action.disabled(row) : action.disabled;
1274
+ return /* @__PURE__ */ jsx(Tooltip, { title: action.label, children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
1275
+ IconButton2,
1276
+ {
1277
+ size: "small",
1278
+ color: action.color ?? "default",
1279
+ disabled: isDisabled,
1280
+ onClick: (e) => handleAction(action, e),
1281
+ "aria-label": action.label,
1282
+ children: action.icon ?? action.label.charAt(0)
1283
+ }
1284
+ ) }) }, action.key);
1285
+ }) });
1286
+ }
1287
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1288
+ /* @__PURE__ */ jsx(
1289
+ IconButton2,
1290
+ {
1291
+ size: "small",
1292
+ onClick: handleClick,
1293
+ "aria-label": "Row actions",
1294
+ "aria-controls": open ? "row-actions-menu" : void 0,
1295
+ "aria-haspopup": "true",
1296
+ "aria-expanded": open ? "true" : void 0,
1297
+ children: /* @__PURE__ */ jsx(MoreVertIcon, {})
1298
+ }
1299
+ ),
1300
+ /* @__PURE__ */ jsx(
1301
+ Menu,
1302
+ {
1303
+ id: "row-actions-menu",
1304
+ anchorEl,
1305
+ open,
1306
+ onClose: handleClose,
1307
+ onClick: (e) => e.stopPropagation(),
1308
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
1309
+ transformOrigin: { vertical: "top", horizontal: "right" },
1310
+ children: visibleActions.map((action, index) => {
1311
+ const isDisabled = typeof action.disabled === "function" ? action.disabled(row) : action.disabled;
1312
+ return [
1313
+ /* @__PURE__ */ jsxs(MenuItem, { disabled: isDisabled, onClick: (e) => handleAction(action, e), children: [
1314
+ action.icon && /* @__PURE__ */ jsx(ListItemIcon, { children: action.icon }),
1315
+ /* @__PURE__ */ jsx(ListItemText, { primary: action.label, sx: { color: action.color ? `${action.color}.main` : void 0 } })
1316
+ ] }, action.key),
1317
+ action.divider && index < visibleActions.length - 1 && /* @__PURE__ */ jsx(Divider, {}, `${action.key}-divider`)
1318
+ ];
1319
+ })
1320
+ }
1321
+ )
1322
+ ] });
1323
+ }
1324
+ function EmptyState({
1325
+ icon,
1326
+ title = "No data",
1327
+ description = "No records to display.",
1328
+ action,
1329
+ component
1330
+ }) {
1331
+ if (component) {
1332
+ return /* @__PURE__ */ jsx(Fragment, { children: component });
1333
+ }
1334
+ return /* @__PURE__ */ jsxs(
1335
+ Box2,
1336
+ {
1337
+ sx: {
1338
+ display: "flex",
1339
+ flexDirection: "column",
1340
+ alignItems: "center",
1341
+ justifyContent: "center",
1342
+ py: 8,
1343
+ px: 3,
1344
+ textAlign: "center"
1345
+ },
1346
+ children: [
1347
+ /* @__PURE__ */ jsx(Box2, { sx: { mb: 2, color: "text.disabled" }, children: icon ?? /* @__PURE__ */ jsx(EmptyIcon, {}) }),
1348
+ /* @__PURE__ */ jsx(Typography2, { variant: "h6", gutterBottom: true, children: title }),
1349
+ /* @__PURE__ */ jsx(Typography2, { variant: "body2", color: "text.secondary", sx: { mb: action ? 2 : 0 }, children: description }),
1350
+ action && /* @__PURE__ */ jsx(Button2, { variant: "contained", size: "small", onClick: action.onClick, children: action.label })
1351
+ ]
1352
+ }
1353
+ );
1354
+ }
1355
+ function ErrorState2({ message = "Failed to load data", onRetry }) {
1356
+ return /* @__PURE__ */ jsxs(
1357
+ Box2,
1358
+ {
1359
+ sx: {
1360
+ display: "flex",
1361
+ flexDirection: "column",
1362
+ alignItems: "center",
1363
+ justifyContent: "center",
1364
+ py: 8,
1365
+ px: 3,
1366
+ textAlign: "center"
1367
+ },
1368
+ children: [
1369
+ /* @__PURE__ */ jsx(Typography2, { color: "error", variant: "body1", gutterBottom: true, children: message }),
1370
+ onRetry && /* @__PURE__ */ jsx(Button2, { variant: "outlined", size: "small", onClick: onRetry, sx: { mt: 1 }, children: "Retry" })
1371
+ ]
1372
+ }
1373
+ );
1374
+ }
1375
+ function DataGridBlock({
1376
+ columns,
1377
+ rows,
1378
+ loading = false,
1379
+ error = false,
1380
+ errorMessage,
1381
+ onRetry,
1382
+ rowActions,
1383
+ rowActionsWidth = 80,
1384
+ toolbar,
1385
+ pagination,
1386
+ selection,
1387
+ empty,
1388
+ density: defaultDensity = "standard",
1389
+ autoHeight = false,
1390
+ height = 500,
1391
+ hideFooter = false,
1392
+ rowHeight,
1393
+ getRowId,
1394
+ onRowClick,
1395
+ onRowDoubleClick,
1396
+ onSelectionChange,
1397
+ onPaginationChange,
1398
+ onSortChange,
1399
+ onFilterChange,
1400
+ paginationModel: controlledPaginationModel,
1401
+ sortModel: controlledSortModel,
1402
+ filterModel: controlledFilterModel,
1403
+ selectionModel: controlledSelectionModel,
1404
+ columnVisibilityModel,
1405
+ onColumnVisibilityChange,
1406
+ slots,
1407
+ slotProps,
1408
+ disableColumnMenu = false,
1409
+ disableColumnFilter = false,
1410
+ disableColumnSelector = false,
1411
+ disableRowSelectionOnClick = true,
1412
+ disableVirtualization = false,
1413
+ sx
1414
+ }) {
1415
+ const [density, setDensity] = useState(defaultDensity);
1416
+ const [internalPaginationModel, setInternalPaginationModel] = useState({
1417
+ page: 0,
1418
+ pageSize: pagination?.defaultPageSize ?? 25
1419
+ });
1420
+ const [internalSortModel, setInternalSortModel] = useState([]);
1421
+ const [internalFilterModel, setInternalFilterModel] = useState({ items: [] });
1422
+ const [internalSelectionModel, setInternalSelectionModel] = useState({
1423
+ type: "include",
1424
+ ids: /* @__PURE__ */ new Set()
1425
+ });
1426
+ const [quickFilterValue, setQuickFilterValue] = useState("");
1427
+ const paginationModel = controlledPaginationModel ?? internalPaginationModel;
1428
+ const sortModel = controlledSortModel ?? internalSortModel;
1429
+ const filterModel = controlledFilterModel ?? internalFilterModel;
1430
+ const selectionModelValue = controlledSelectionModel ?? internalSelectionModel;
1431
+ const finalColumns = useMemo(() => {
1432
+ if (!rowActions || rowActions.length === 0) {
1433
+ return columns;
1434
+ }
1435
+ const actionsColumn = {
1436
+ field: "__actions__",
1437
+ headerName: "",
1438
+ width: rowActionsWidth,
1439
+ sortable: false,
1440
+ filterable: false,
1441
+ disableColumnMenu: true,
1442
+ disableReorder: true,
1443
+ renderCell: (params) => /* @__PURE__ */ jsx(RowActionsCell, { row: params.row, actions: rowActions })
1444
+ };
1445
+ return [...columns, actionsColumn];
1446
+ }, [columns, rowActions, rowActionsWidth]);
1447
+ const handlePaginationChange = useCallback(
1448
+ (model, details) => {
1449
+ if (!controlledPaginationModel) {
1450
+ setInternalPaginationModel(model);
1451
+ }
1452
+ onPaginationChange?.(model);
1453
+ },
1454
+ [controlledPaginationModel, onPaginationChange]
1455
+ );
1456
+ const handleSortChange = useCallback(
1457
+ (model, details) => {
1458
+ if (!controlledSortModel) {
1459
+ setInternalSortModel(model);
1460
+ }
1461
+ onSortChange?.(model);
1462
+ },
1463
+ [controlledSortModel, onSortChange]
1464
+ );
1465
+ const handleFilterChange = useCallback(
1466
+ (model, details) => {
1467
+ if (!controlledFilterModel) {
1468
+ setInternalFilterModel(model);
1469
+ }
1470
+ onFilterChange?.(model);
1471
+ },
1472
+ [controlledFilterModel, onFilterChange]
1473
+ );
1474
+ const handleSelectionChange = useCallback(
1475
+ (model, details) => {
1476
+ if (!controlledSelectionModel) {
1477
+ setInternalSelectionModel(model);
1478
+ }
1479
+ onSelectionChange?.(model);
1480
+ },
1481
+ [controlledSelectionModel, onSelectionChange]
1482
+ );
1483
+ const contextValue = useMemo(
1484
+ () => ({
1485
+ loading,
1486
+ error,
1487
+ density,
1488
+ setDensity,
1489
+ rowCount: rows.length,
1490
+ selectedCount: selectionModelValue.ids.size,
1491
+ refresh: onRetry
1492
+ }),
1493
+ [loading, error, density, rows.length, selectionModelValue, onRetry]
1494
+ );
1495
+ const rowCount = pagination?.mode === "server" ? pagination.rowCount ?? 0 : rows.length;
1496
+ const toolbarSlot = useMemo(() => {
1497
+ if (toolbar?.show === false) {
1498
+ return void 0;
1499
+ }
1500
+ return () => /* @__PURE__ */ jsx(
1501
+ CustomToolbar,
1502
+ {
1503
+ quickFilter: toolbar?.quickFilter,
1504
+ exportConfig: toolbar?.export,
1505
+ showColumnSelector: toolbar?.columnVisibility?.enabled !== false,
1506
+ showDensitySelector: toolbar?.densitySelector !== false,
1507
+ startContent: toolbar?.startContent,
1508
+ endContent: toolbar?.endContent,
1509
+ actions: toolbar?.actions,
1510
+ onQuickFilterChange: setQuickFilterValue
1511
+ }
1512
+ );
1513
+ }, [toolbar]);
1514
+ const noRowsOverlay = useMemo(() => {
1515
+ if (error) {
1516
+ return () => /* @__PURE__ */ jsx(ErrorState2, { message: errorMessage, onRetry });
1517
+ }
1518
+ return () => /* @__PURE__ */ jsx(
1519
+ EmptyState,
1520
+ {
1521
+ icon: empty?.icon,
1522
+ title: empty?.title,
1523
+ description: empty?.description,
1524
+ action: empty?.action,
1525
+ component: empty?.component
1526
+ }
1527
+ );
1528
+ }, [error, errorMessage, onRetry, empty]);
1529
+ return /* @__PURE__ */ jsx(DataGridBlockContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
1530
+ Paper,
1531
+ {
1532
+ "data-testid": "prism-data-grid-block",
1533
+ variant: "outlined",
1534
+ sx: [
1535
+ {
1536
+ width: "100%",
1537
+ overflow: "hidden"
1538
+ },
1539
+ ...Array.isArray(sx) ? sx : [sx]
1540
+ ],
1541
+ children: /* @__PURE__ */ jsx(Box2, { sx: { width: "100%", height: autoHeight ? "auto" : height }, children: /* @__PURE__ */ jsx(
1542
+ DataGrid,
1543
+ {
1544
+ rows,
1545
+ columns: finalColumns,
1546
+ loading,
1547
+ density,
1548
+ autoHeight,
1549
+ rowHeight,
1550
+ getRowId,
1551
+ onRowClick,
1552
+ onRowDoubleClick,
1553
+ paginationMode: pagination?.mode ?? "client",
1554
+ paginationModel,
1555
+ onPaginationModelChange: handlePaginationChange,
1556
+ pageSizeOptions: pagination?.pageSizeOptions ?? [10, 25, 50, 100],
1557
+ rowCount,
1558
+ sortingMode: pagination?.mode === "server" ? "server" : "client",
1559
+ sortModel,
1560
+ onSortModelChange: handleSortChange,
1561
+ filterMode: pagination?.mode === "server" ? "server" : "client",
1562
+ filterModel,
1563
+ onFilterModelChange: handleFilterChange,
1564
+ checkboxSelection: selection?.checkboxSelection ?? false,
1565
+ rowSelectionModel: selectionModelValue,
1566
+ onRowSelectionModelChange: handleSelectionChange,
1567
+ disableRowSelectionOnClick: selection?.disableSelectionOnClick ?? disableRowSelectionOnClick,
1568
+ disableMultipleRowSelection: selection?.mode === "single",
1569
+ keepNonExistentRowsSelected: selection?.keepNonExistentRowsSelected,
1570
+ columnVisibilityModel,
1571
+ onColumnVisibilityModelChange: onColumnVisibilityChange,
1572
+ disableColumnMenu,
1573
+ disableColumnFilter,
1574
+ disableColumnSelector,
1575
+ disableVirtualization,
1576
+ hideFooter: hideFooter || pagination?.hide,
1577
+ slots: {
1578
+ toolbar: toolbarSlot,
1579
+ noRowsOverlay,
1580
+ loadingOverlay: () => /* @__PURE__ */ jsx(LinearProgress, { sx: { position: "absolute", top: 0, left: 0, right: 0 } }),
1581
+ ...slots
1582
+ },
1583
+ slotProps,
1584
+ sx: {
1585
+ border: 0,
1586
+ "& .MuiDataGrid-columnHeaders": {
1587
+ bgcolor: "action.hover"
1588
+ },
1589
+ "& .MuiDataGrid-cell:focus": {
1590
+ outline: "none"
1591
+ },
1592
+ "& .MuiDataGrid-row:hover": {
1593
+ bgcolor: "action.hover"
1594
+ }
1595
+ }
1596
+ }
1597
+ ) })
1598
+ }
1599
+ ) });
1600
+ }
1601
+ function useDataGridBlock(options) {
1602
+ const {
1603
+ fetcher,
1604
+ initialPageSize = 25,
1605
+ initialSortModel = [],
1606
+ initialFilterModel = { items: [] },
1607
+ autoFetch = true,
1608
+ keepPreviousData = true
1609
+ } = options;
1610
+ const [rows, setRows] = useState([]);
1611
+ const [loading, setLoading] = useState(false);
1612
+ const [error, setError] = useState(null);
1613
+ const [total, setTotal] = useState(0);
1614
+ const [paginationModel, setPaginationModel] = useState({
1615
+ page: 0,
1616
+ pageSize: initialPageSize
1617
+ });
1618
+ const [sortModel, setSortModel] = useState(initialSortModel);
1619
+ const [filterModel, setFilterModel] = useState(initialFilterModel);
1620
+ const isMountedRef = useRef(true);
1621
+ const abortControllerRef = useRef(null);
1622
+ const fetchData = useCallback(
1623
+ async (params) => {
1624
+ if (abortControllerRef.current) {
1625
+ abortControllerRef.current.abort();
1626
+ }
1627
+ abortControllerRef.current = new AbortController();
1628
+ setLoading(true);
1629
+ setError(null);
1630
+ try {
1631
+ const result = await fetcher(params);
1632
+ if (isMountedRef.current) {
1633
+ setRows(result.rows);
1634
+ setTotal(result.total);
1635
+ }
1636
+ } catch (err) {
1637
+ if (isMountedRef.current && err instanceof Error && err.name !== "AbortError") {
1638
+ setError(err);
1639
+ if (!keepPreviousData) {
1640
+ setRows([]);
1641
+ }
1642
+ }
1643
+ } finally {
1644
+ if (isMountedRef.current) {
1645
+ setLoading(false);
1646
+ }
1647
+ }
1648
+ },
1649
+ [fetcher, keepPreviousData]
1650
+ );
1651
+ const refresh = useCallback(() => {
1652
+ fetchData({
1653
+ page: paginationModel.page,
1654
+ pageSize: paginationModel.pageSize,
1655
+ sortModel,
1656
+ filterModel
1657
+ });
1658
+ }, [fetchData, paginationModel, sortModel, filterModel]);
1659
+ const reset = useCallback(() => {
1660
+ setPaginationModel({ page: 0, pageSize: initialPageSize });
1661
+ setSortModel(initialSortModel);
1662
+ setFilterModel(initialFilterModel);
1663
+ }, [initialPageSize, initialSortModel, initialFilterModel]);
1664
+ useEffect(() => {
1665
+ if (autoFetch) {
1666
+ fetchData({
1667
+ page: paginationModel.page,
1668
+ pageSize: paginationModel.pageSize,
1669
+ sortModel,
1670
+ filterModel
1671
+ });
1672
+ }
1673
+ }, [fetchData, paginationModel, sortModel, filterModel, autoFetch]);
1674
+ useEffect(
1675
+ () => () => {
1676
+ isMountedRef.current = false;
1677
+ if (abortControllerRef.current) {
1678
+ abortControllerRef.current.abort();
1679
+ }
1680
+ },
1681
+ []
1682
+ );
1683
+ const handlePaginationChange = useCallback((model, _details) => {
1684
+ setPaginationModel(model);
1685
+ }, []);
1686
+ const handleSortChange = useCallback((model, _details) => {
1687
+ setSortModel(model);
1688
+ setPaginationModel((prev) => ({ ...prev, page: 0 }));
1689
+ }, []);
1690
+ const handleFilterChange = useCallback((model, _details) => {
1691
+ setFilterModel(model);
1692
+ setPaginationModel((prev) => ({ ...prev, page: 0 }));
1693
+ }, []);
1694
+ return {
1695
+ rows,
1696
+ loading,
1697
+ error,
1698
+ total,
1699
+ paginationModel,
1700
+ sortModel,
1701
+ filterModel,
1702
+ onPaginationChange: handlePaginationChange,
1703
+ onSortChange: handleSortChange,
1704
+ onFilterChange: handleFilterChange,
1705
+ refresh,
1706
+ reset
1707
+ };
1708
+ }
1709
+
1710
+ export { AuthBlock, AuthGuard, DashboardBlock, DashboardBlockContent, DashboardBlockFooter, DashboardBlockHeader, DataGridBlock, ForgotPasswordForm, GuestGuard, LoginForm, RegisterForm, ResetPasswordForm, RoleBasedGuard, VerifyCodeForm, createConditionalRender, hasPermission, hasRole, useDashboardBlock, useDashboardBlockContext, useDataGridBlock, useDataGridBlockContext };
1711
+ //# sourceMappingURL=index.js.map
1712
+ //# sourceMappingURL=index.js.map