@jmruthers/pace-core 0.6.4 → 0.6.5

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 (101) hide show
  1. package/dist/{DataTable-E7YQZD7D.js → DataTable-AOVNCPTX.js} +8 -8
  2. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-QTFVrL-Z.d.ts} +65 -83
  3. package/dist/{UnifiedAuthProvider-QPXO24B4.js → UnifiedAuthProvider-4SBX4LU5.js} +4 -4
  4. package/dist/{api-6LVZTHDS.js → api-O6HTBX5Y.js} +3 -3
  5. package/dist/{chunk-I6DAQMWX.js → chunk-6COVEUS7.js} +130 -106
  6. package/dist/chunk-6COVEUS7.js.map +1 -0
  7. package/dist/{chunk-36LVWXB2.js → chunk-AFVQODI2.js} +37 -1
  8. package/dist/{chunk-36LVWXB2.js.map → chunk-AFVQODI2.js.map} +1 -1
  9. package/dist/{chunk-3LPHPB62.js → chunk-EFN2EIMK.js} +2 -2
  10. package/dist/{chunk-ATKZM7RX.js → chunk-G7QEZTYQ.js} +31 -31
  11. package/dist/{chunk-ATKZM7RX.js.map → chunk-G7QEZTYQ.js.map} +1 -1
  12. package/dist/{chunk-NN6WWZ5U.js → chunk-HU2C6SSC.js} +29 -18
  13. package/dist/chunk-HU2C6SSC.js.map +1 -0
  14. package/dist/{chunk-AVMLPIM7.js → chunk-IHB5DR3H.js} +102 -51
  15. package/dist/chunk-IHB5DR3H.js.map +1 -0
  16. package/dist/{chunk-7JPAB3T5.js → chunk-IVOFDYWT.js} +364 -208
  17. package/dist/chunk-IVOFDYWT.js.map +1 -0
  18. package/dist/{chunk-6SOIHG6Z.js → chunk-JGRYX5UX.js} +120 -20
  19. package/dist/chunk-JGRYX5UX.js.map +1 -0
  20. package/dist/{chunk-OEWDTMG7.js → chunk-NTM7ZSB6.js} +4 -4
  21. package/dist/chunk-NTM7ZSB6.js.map +1 -0
  22. package/dist/{chunk-5EC5MEWX.js → chunk-RGAWHO7N.js} +4 -4
  23. package/dist/chunk-RGAWHO7N.js.map +1 -0
  24. package/dist/{chunk-YKRAFF5K.js → chunk-UPPMRMYG.js} +3 -3
  25. package/dist/{chunk-YKRAFF5K.js.map → chunk-UPPMRMYG.js.map} +1 -1
  26. package/dist/components.d.ts +2 -3
  27. package/dist/components.js +24 -28
  28. package/dist/components.js.map +1 -1
  29. package/dist/{contextValidator-OOPCLPZW.js → contextValidator-5OGXSPKS.js} +2 -2
  30. package/dist/hooks.d.ts +3 -3
  31. package/dist/hooks.js +41 -139
  32. package/dist/hooks.js.map +1 -1
  33. package/dist/index.d.ts +27 -18
  34. package/dist/index.js +41 -50
  35. package/dist/index.js.map +1 -1
  36. package/dist/providers.js +3 -3
  37. package/dist/rbac/index.d.ts +16 -9
  38. package/dist/rbac/index.js +6 -6
  39. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-ClnV4tnv.d.ts} +8 -8
  40. package/dist/utils.js +1 -1
  41. package/docs/api/modules.md +210 -100
  42. package/package.json +1 -2
  43. package/scripts/validate-master.js +1 -1
  44. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  45. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  46. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  47. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  48. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  49. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  50. package/src/components/DateTimeField/DateTimeField.tsx +17 -19
  51. package/src/components/DateTimeField/README.md +5 -2
  52. package/src/components/Dialog/Dialog.test.tsx +248 -228
  53. package/src/components/Dialog/Dialog.tsx +455 -325
  54. package/src/components/Dialog/index.ts +3 -3
  55. package/src/components/FileDisplay/FileDisplay.test.tsx +41 -0
  56. package/src/components/FileDisplay/FileDisplay.tsx +5 -5
  57. package/src/components/Form/Form.test.tsx +3 -2
  58. package/src/components/Form/Form.tsx +4 -5
  59. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  60. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  61. package/src/components/LoginForm/LoginForm.tsx +2 -2
  62. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  63. package/src/components/PaceAppLayout/PaceAppLayout.tsx +32 -39
  64. package/src/components/PaceAppLayout/README.md +10 -9
  65. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  66. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  67. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  68. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  69. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  70. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  71. package/src/components/UserMenu/UserMenu.tsx +36 -34
  72. package/src/components/index.ts +3 -4
  73. package/src/hooks/useEventTheme.ts +4 -4
  74. package/src/hooks/useEvents.ts +11 -7
  75. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  76. package/src/hooks/useOrganisationPermissions.ts +4 -4
  77. package/src/hooks/useOrganisations.ts +13 -7
  78. package/src/index.ts +11 -1
  79. package/src/rbac/README.md +20 -20
  80. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  81. package/src/rbac/hooks/useRBAC.ts +4 -3
  82. package/src/rbac/hooks/useResourcePermissions.test.ts +125 -30
  83. package/src/rbac/hooks/useResourcePermissions.ts +57 -29
  84. package/src/rbac/permissions.ts +17 -17
  85. package/src/rbac/utils/contextValidator.ts +36 -0
  86. package/src/services/AuthService.ts +2 -5
  87. package/src/services/InactivityService.ts +139 -58
  88. package/src/styles/core.css +4 -0
  89. package/src/utils/formatting/formatTime.test.ts +3 -2
  90. package/dist/chunk-5EC5MEWX.js.map +0 -1
  91. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  92. package/dist/chunk-7JPAB3T5.js.map +0 -1
  93. package/dist/chunk-AVMLPIM7.js.map +0 -1
  94. package/dist/chunk-I6DAQMWX.js.map +0 -1
  95. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  96. package/dist/chunk-OEWDTMG7.js.map +0 -1
  97. /package/dist/{DataTable-E7YQZD7D.js.map → DataTable-AOVNCPTX.js.map} +0 -0
  98. /package/dist/{UnifiedAuthProvider-QPXO24B4.js.map → UnifiedAuthProvider-4SBX4LU5.js.map} +0 -0
  99. /package/dist/{api-6LVZTHDS.js.map → api-O6HTBX5Y.js.map} +0 -0
  100. /package/dist/{chunk-3LPHPB62.js.map → chunk-EFN2EIMK.js.map} +0 -0
  101. /package/dist/{contextValidator-OOPCLPZW.js.map → contextValidator-5OGXSPKS.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  export { a as UnifiedAuthContextType, d as UnifiedAuthProvider, c as UnifiedAuthProviderProps, u as useUnifiedAuth } from './UnifiedAuthProvider-CKvHP1MK.js';
2
- export { A as AddressField, k as AddressFieldProps, l as AddressFieldRef, o as Alert, q as AlertDescription, p as AlertTitle, r as Avatar, s as AvatarProps, t as Badge, u as BadgeProps, v as BadgeVariant, B as Button, a as ButtonProps, an as Calendar, ao as CalendarProps, C as Card, g as CardActions, i as CardActionsProps, f as CardContent, e as CardDescription, c as CardFooter, b as CardHeader, h as CardProps, d as CardTitle, w as Checkbox, aS as ContextSelector, aT as ContextSelectorProps, M as Dialog, W as DialogBody, R as DialogClose, U as DialogContent, a0 as DialogContentProps, Z as DialogDescription, a5 as DialogDescriptionProps, X as DialogFooter, a3 as DialogFooterProps, V as DialogHeader, a2 as DialogHeaderProps, O as DialogOverlay, a1 as DialogOverlayProps, N as DialogPortal, _ as DialogProps, a6 as DialogSize, Y as DialogTitle, a4 as DialogTitleProps, Q as DialogTrigger, $ as DialogTriggerProps, aV as ErrorBoundary, aX as ErrorBoundaryProps, aW as ErrorBoundaryProvider, aZ as ErrorBoundaryProviderProps, aY as ErrorBoundaryState, b4 as FileDisplay, b5 as FileDisplayProps, b2 as FileUpload, b3 as FileUploadProps, aL as Footer, aM as FooterProps, aE as Form, aF as FormField, aH as FormFieldProps, aG as FormProps, a_ as GlobalErrorHandler, aK as Header, I as Input, j as InputProps, L as Label, m as LabelProps, a$ as LoadingSpinner, aI as LoginForm, aJ as LoginFormProps, aR as NavigationItem, aP as NavigationMenu, aQ as NavigationMenuProps, bn as PaceAppLayout, bm as PaceAppLayoutProps, bp as PaceLoginPage, bo as PaceLoginPageProps, P as Progress, y as ProgressProps, aN as ProtectedRoute, aO as ProtectedRouteProps, bf as PublicPageFooter, bl as PublicPageFooterProps, be as PublicPageHeader, bk as PublicPageHeaderProps, bd as PublicPageLayout, bj as PublicPageLayoutProps, bg as PublicPageProvider, a7 as Select, ab as SelectContent, a8 as SelectGroup, ad as SelectItem, ac as SelectLabel, ae as SelectSeparator, aa as SelectTrigger, a9 as SelectValue, b0 as SessionRestorationLoader, b1 as SessionRestorationLoaderProps, S as Switch, x as SwitchProps, z as Table, E as TableBody, F as TableCaption, G as TableCell, H as TableFooter, J as TableHead, D as TableHeader, K as TableRow, af as Tabs, ai as TabsContent, am as TabsContentProps, ag as TabsList, ak as TabsListProps, aj as TabsProps, ah as TabsTrigger, al as TabsTriggerProps, T as Textarea, n as TextareaProps, ap as Toast, ar as ToastAction, ax as ToastActionElement, aw as ToastClose, av as ToastDescription, ay as ToastProps, as as ToastProvider, au as ToastTitle, at as ToastViewport, aq as Toaster, az as Tooltip, aB as TooltipContent, aC as TooltipProvider, aD as TooltipRoot, aA as TooltipTrigger, bc as UseFileReferenceForRecordReturn, ba as UseFileReferenceOptions, bb as UseFileReferenceReturn, aU as UserMenu, b6 as useFileReference, b8 as useFileReferenceById, b7 as useFileReferenceForRecord, b9 as useFilesByCategory, bi as useIsPublicPage, bh as usePublicPageContext } from './PublicPageProvider-DEMpysFR.js';
2
+ export { A as AddressField, k as AddressFieldProps, l as AddressFieldRef, o as Alert, q as AlertDescription, p as AlertTitle, r as Avatar, s as AvatarProps, t as Badge, u as BadgeProps, v as BadgeVariant, B as Button, a as ButtonProps, am as Calendar, an as CalendarProps, C as Card, g as CardActions, i as CardActionsProps, f as CardContent, e as CardDescription, c as CardFooter, b as CardHeader, h as CardProps, d as CardTitle, w as Checkbox, aR as ContextSelector, aS as ContextSelectorProps, M as Dialog, V as DialogBody, a4 as DialogBodyProps, Q as DialogClose, a1 as DialogCloseProps, R as DialogContent, $ as DialogContentProps, Y as DialogDescription, W as DialogFooter, a3 as DialogFooterProps, U as DialogHeader, a2 as DialogHeaderProps, N as DialogPortal, a0 as DialogPortalProps, Z as DialogProps, a5 as DialogSize, X as DialogTitle, O as DialogTrigger, _ as DialogTriggerProps, aU as ErrorBoundary, aW as ErrorBoundaryProps, aV as ErrorBoundaryProvider, aY as ErrorBoundaryProviderProps, aX as ErrorBoundaryState, b3 as FileDisplay, b4 as FileDisplayProps, b1 as FileUpload, b2 as FileUploadProps, aK as Footer, aL as FooterProps, aD as Form, aE as FormField, aG as FormFieldProps, aF as FormProps, aZ as GlobalErrorHandler, aJ as Header, I as Input, j as InputProps, L as Label, m as LabelProps, a_ as LoadingSpinner, aH as LoginForm, aI as LoginFormProps, aQ as NavigationItem, aO as NavigationMenu, aP as NavigationMenuProps, bm as PaceAppLayout, bl as PaceAppLayoutProps, bo as PaceLoginPage, bn as PaceLoginPageProps, P as Progress, y as ProgressProps, aM as ProtectedRoute, aN as ProtectedRouteProps, be as PublicPageFooter, bk as PublicPageFooterProps, bd as PublicPageHeader, bj as PublicPageHeaderProps, bc as PublicPageLayout, bi as PublicPageLayoutProps, bf as PublicPageProvider, a6 as Select, aa as SelectContent, a7 as SelectGroup, ac as SelectItem, ab as SelectLabel, ad as SelectSeparator, a9 as SelectTrigger, a8 as SelectValue, a$ as SessionRestorationLoader, b0 as SessionRestorationLoaderProps, S as Switch, x as SwitchProps, z as Table, E as TableBody, F as TableCaption, G as TableCell, H as TableFooter, J as TableHead, D as TableHeader, K as TableRow, ae as Tabs, ah as TabsContent, al as TabsContentProps, af as TabsList, aj as TabsListProps, ai as TabsProps, ag as TabsTrigger, ak as TabsTriggerProps, T as Textarea, n as TextareaProps, ao as Toast, aq as ToastAction, aw as ToastActionElement, av as ToastClose, au as ToastDescription, ax as ToastProps, ar as ToastProvider, at as ToastTitle, as as ToastViewport, ap as Toaster, ay as Tooltip, aA as TooltipContent, aB as TooltipProvider, aC as TooltipRoot, az as TooltipTrigger, bb as UseFileReferenceForRecordReturn, b9 as UseFileReferenceOptions, ba as UseFileReferenceReturn, aT as UserMenu, b5 as useFileReference, b7 as useFileReferenceById, b6 as useFileReferenceForRecord, b8 as useFilesByCategory, bh as useIsPublicPage, bg as usePublicPageContext } from './PublicPageProvider-QTFVrL-Z.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  export { u as useToast } from './useToast-AyaT-x7p.js';
5
5
  export { D as DataTable, a as DataTableProps } from './DataTable-BMRU8a1j.js';
@@ -13,7 +13,6 @@ import './auth-BZOJqrdd.js';
13
13
  import '@radix-ui/react-label';
14
14
  import '@radix-ui/react-checkbox';
15
15
  import '@radix-ui/react-switch';
16
- import '@radix-ui/react-dialog';
17
16
  import '@radix-ui/react-tabs';
18
17
  import 'react-day-picker';
19
18
  import '@radix-ui/react-toast';
@@ -35,7 +34,7 @@ import '@tanstack/react-table';
35
34
  * Features:
36
35
  * - Automatic UTC ↔ timezone conversion
37
36
  * - Prevents unwanted conversions during user editing
38
- * - Shows timezone information when not UTC
37
+ * - Shows timezone information below the input field when not UTC
39
38
  * - Supports both ISO string and Date object values
40
39
  * - Uses native datetime-local input type
41
40
  * - Accessible form field with proper labels
@@ -47,7 +47,7 @@ import {
47
47
  useFileReferenceById,
48
48
  useFileReferenceForRecord,
49
49
  useFilesByCategory
50
- } from "./chunk-I6DAQMWX.js";
50
+ } from "./chunk-6COVEUS7.js";
51
51
  import {
52
52
  Alert,
53
53
  AlertDescription,
@@ -69,7 +69,6 @@ import {
69
69
  DialogDescription,
70
70
  DialogFooter,
71
71
  DialogHeader,
72
- DialogOverlay,
73
72
  DialogPortal,
74
73
  DialogTitle,
75
74
  DialogTrigger,
@@ -88,27 +87,27 @@ import {
88
87
  TooltipProvider,
89
88
  TooltipRoot,
90
89
  TooltipTrigger
91
- } from "./chunk-7JPAB3T5.js";
92
- import "./chunk-NN6WWZ5U.js";
93
- import "./chunk-YKRAFF5K.js";
90
+ } from "./chunk-IVOFDYWT.js";
91
+ import "./chunk-HU2C6SSC.js";
92
+ import "./chunk-UPPMRMYG.js";
94
93
  import {
95
94
  useToast
96
- } from "./chunk-6SOIHG6Z.js";
95
+ } from "./chunk-JGRYX5UX.js";
97
96
  import {
98
97
  ErrorBoundary,
99
98
  ErrorBoundaryProvider,
100
99
  PublicPageProvider,
101
100
  useIsPublicPage,
102
101
  usePublicPageContext
103
- } from "./chunk-OEWDTMG7.js";
102
+ } from "./chunk-NTM7ZSB6.js";
104
103
  import "./chunk-KQCRWDSA.js";
105
104
  import {
106
105
  UnifiedAuthProvider,
107
106
  useUnifiedAuth
108
- } from "./chunk-AVMLPIM7.js";
109
- import "./chunk-3LPHPB62.js";
107
+ } from "./chunk-IHB5DR3H.js";
108
+ import "./chunk-EFN2EIMK.js";
110
109
  import "./chunk-63FOKYGO.js";
111
- import "./chunk-36LVWXB2.js";
110
+ import "./chunk-AFVQODI2.js";
112
111
  import {
113
112
  FileCategory
114
113
  } from "./chunk-ZSAAAMVR.js";
@@ -209,23 +208,21 @@ function DateTimeField({
209
208
  const timezoneDisplay = getTimezoneDisplay();
210
209
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
211
210
  /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, required, helperText, error, children: label }),
212
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
213
- /* @__PURE__ */ jsx(
214
- Input,
215
- {
216
- ref: inputRef,
217
- id: fieldId,
218
- type: "datetime-local",
219
- value: displayValue,
220
- onChange: handleChange,
221
- onBlur: handleBlur,
222
- required,
223
- error: !!error,
224
- className: "w-full"
225
- }
226
- ),
227
- timezoneDisplay && /* @__PURE__ */ jsx("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground pointer-events-none", children: timezoneDisplay })
228
- ] })
211
+ /* @__PURE__ */ jsx(
212
+ Input,
213
+ {
214
+ ref: inputRef,
215
+ id: fieldId,
216
+ type: "datetime-local",
217
+ value: displayValue,
218
+ onChange: handleChange,
219
+ onBlur: handleBlur,
220
+ required,
221
+ error: !!error,
222
+ className: "w-full"
223
+ }
224
+ ),
225
+ timezoneDisplay && !error && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: timezoneDisplay })
229
226
  ] });
230
227
  }
231
228
 
@@ -296,7 +293,6 @@ export {
296
293
  DialogDescription,
297
294
  DialogFooter,
298
295
  DialogHeader,
299
- DialogOverlay,
300
296
  DialogPortal,
301
297
  DialogTitle,
302
298
  DialogTrigger,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/DateTimeField/DateTimeField.tsx","../src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx"],"sourcesContent":["/**\n * @file DateTimeField Component\n * @package @jmruthers/pace-core\n * @module Components/DateTimeField\n * @since 0.1.0\n *\n * Form input component for datetime values with timezone support.\n * Handles UTC ↔ timezone conversion automatically.\n *\n * Features:\n * - Automatic UTC ↔ timezone conversion\n * - Prevents unwanted conversions during user editing\n * - Shows timezone information when not UTC\n * - Supports both ISO string and Date object values\n * - Uses native datetime-local input type\n * - Accessible form field with proper labels\n *\n * @example\n * ```tsx\n * import { DateTimeField } from '@jmruthers/pace-core/components';\n * import { useState } from 'react';\n *\n * function EventForm() {\n * const [startTime, setStartTime] = useState<string>();\n *\n * return (\n * <DateTimeField\n * label=\"Start Time\"\n * value={startTime}\n * onChange={setStartTime}\n * timezone=\"America/New_York\"\n * required\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - Proper label association with htmlFor\n * - Required field indicators\n * - Screen reader friendly\n * - Keyboard navigation support\n * - Focus management\n */\n\nimport * as React from 'react';\nimport { format, parse } from 'date-fns';\nimport { Label } from '../Label';\nimport { Input } from '../Input';\nimport { cn } from '../../utils/core/cn';\nimport { toZonedTime, fromZonedTime, getUserTimeZone } from '../../utils/timezone';\n\n/**\n * Props for the DateTimeField component\n */\nexport interface DateTimeFieldProps {\n /**\n * Field label\n */\n label: string;\n /**\n * UTC date value (ISO string, Date object, or undefined)\n */\n value: string | Date | undefined;\n /**\n * Change handler that receives UTC value (ISO string or Date object)\n */\n onChange: (value: string | Date | undefined) => void;\n /**\n * Target timezone for display (default: 'UTC')\n */\n timezone?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Additional CSS classes\n */\n className?: string;\n /**\n * If true, onChange returns Date object instead of ISO string\n */\n returnAsDate?: boolean;\n /**\n * Input id (auto-generated if not provided)\n */\n id?: string;\n /**\n * Helper text to display below the label\n */\n helperText?: string;\n /**\n * Error message to display\n */\n error?: string;\n}\n\n/**\n * DateTimeField component\n * Form input for datetime values with automatic timezone conversion\n *\n * @param props - DateTimeField configuration\n * @returns JSX.Element - The rendered datetime field\n */\nexport function DateTimeField({\n label,\n value,\n onChange,\n timezone = 'UTC',\n required = false,\n className,\n returnAsDate = false,\n id,\n helperText,\n error\n}: DateTimeFieldProps) {\n const [isEditing, setIsEditing] = React.useState(false);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const fieldId = id || `datetime-field-${React.useId()}`;\n\n // Convert UTC value to timezone for display\n const getDisplayValue = React.useCallback((): string => {\n if (!value) {\n return '';\n }\n\n try {\n let dateObj: Date;\n if (typeof value === 'string') {\n dateObj = new Date(value);\n } else {\n dateObj = value;\n }\n\n if (!dateObj || isNaN(dateObj.getTime())) {\n return '';\n }\n\n // Convert UTC to timezone\n const zonedDate = toZonedTime(dateObj, timezone);\n\n // Format for datetime-local input (YYYY-MM-DDTHH:mm)\n return format(zonedDate, \"yyyy-MM-dd'T'HH:mm\");\n } catch {\n return '';\n }\n }, [value, timezone]);\n\n const displayValue = isEditing ? undefined : getDisplayValue();\n\n // Handle input change\n const handleChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n setIsEditing(true);\n const inputValue = e.target.value;\n\n if (!inputValue) {\n onChange(undefined);\n return;\n }\n\n try {\n // Parse the datetime-local value (in timezone)\n const localDate = parse(inputValue, \"yyyy-MM-dd'T'HH:mm\", new Date());\n\n if (isNaN(localDate.getTime())) {\n onChange(undefined);\n return;\n }\n\n // Convert from timezone to UTC\n const utcDate = fromZonedTime(localDate, timezone);\n\n // Return as ISO string or Date object\n if (returnAsDate) {\n onChange(utcDate);\n } else {\n onChange(utcDate.toISOString());\n }\n } catch {\n onChange(undefined);\n }\n }, [timezone, returnAsDate, onChange]);\n\n // Handle blur to stop editing mode\n const handleBlur = React.useCallback(() => {\n setIsEditing(false);\n }, []);\n\n // Get timezone display text\n const getTimezoneDisplay = React.useCallback((): string => {\n if (timezone === 'UTC') {\n return '';\n }\n\n const userTz = getUserTimeZone();\n if (timezone === userTz) {\n return 'Local';\n }\n\n return timezone;\n }, [timezone]);\n\n const timezoneDisplay = getTimezoneDisplay();\n\n return (\n <div className={cn('space-y-2', className)}>\n <Label htmlFor={fieldId} required={required} helperText={helperText} error={error}>\n {label}\n </Label>\n <div className=\"relative\">\n <Input\n ref={inputRef}\n id={fieldId}\n type=\"datetime-local\"\n value={displayValue}\n onChange={handleChange}\n onBlur={handleBlur}\n required={required}\n error={!!error}\n className=\"w-full\"\n />\n {timezoneDisplay && (\n <span className=\"absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground pointer-events-none\">\n {timezoneDisplay}\n </span>\n )}\n </div>\n </div>\n );\n}\n\n","/**\n * @file DatePickerWithTimezone Component\n * @package @jmruthers/pace-core\n * @module Components/DatePickerWithTimezone\n * @since 0.1.0\n *\n * Date picker component that displays timezone information alongside the calendar.\n * Provides a calendar interface with timezone context for date selection.\n *\n * Features:\n * - Calendar date selection\n * - Timezone display (shows \"Local\" when matches user timezone)\n * - Optional \"Done\" button\n * - Accessible date selection\n * - Keyboard navigation support\n *\n * @example\n * ```tsx\n * import { DatePickerWithTimezone } from '@jmruthers/pace-core/components';\n * import { useState } from 'react';\n *\n * function DateSelector() {\n * const [date, setDate] = useState<Date>();\n *\n * return (\n * <DatePickerWithTimezone\n * selected={date}\n * onSelect={setDate}\n * timezone=\"America/New_York\"\n * onDone={() => console.log('Date selected')}\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - Proper ARIA attributes\n */\n\nimport * as React from 'react';\nimport { Calendar } from '../Calendar';\nimport { Button } from '../Button';\nimport { Clock } from 'lucide-react';\nimport { getUserTimeZone } from '../../utils/timezone';\nimport { cn } from '../../utils/core/cn';\n\n/**\n * Props for the DatePickerWithTimezone component\n */\nexport interface DatePickerWithTimezoneProps {\n /**\n * Currently selected date\n */\n selected?: Date;\n /**\n * Date selection handler\n */\n onSelect: (date: Date | undefined) => void;\n /**\n * Optional callback when \"Done\" button is clicked\n */\n onDone?: () => void;\n /**\n * Timezone to display (defaults to user's timezone)\n */\n timezone?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * DatePickerWithTimezone component\n * Date picker with timezone information display\n *\n * @param props - DatePickerWithTimezone configuration\n * @returns JSX.Element - The rendered date picker with timezone\n */\nexport function DatePickerWithTimezone({\n selected,\n onSelect,\n onDone,\n timezone,\n className\n}: DatePickerWithTimezoneProps) {\n const userTimezone = getUserTimeZone();\n const displayTimezone = timezone || userTimezone;\n const timezoneDisplay = displayTimezone === userTimezone ? 'Local' : displayTimezone;\n\n return (\n <div className={cn('flex flex-col', className)}>\n <div className=\"p-3\">\n <Calendar\n mode=\"single\"\n selected={selected}\n onSelect={onSelect}\n initialFocus\n captionLayout=\"dropdown\"\n startMonth={new Date(1900, 0)}\n endMonth={new Date(2100, 11)}\n className=\"p-0\"\n />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Clock className=\"size-4\" aria-hidden=\"true\" />\n <span>\n Timezone: <span aria-label={`Timezone ${timezoneDisplay}`}>{timezoneDisplay}</span>\n </span>\n </div>\n {onDone && (\n <Button onClick={onDone} size=\"sm\" className=\"h-8\">\n Done\n </Button>\n )}\n </div>\n </div>\n );\n}\n\n"],"mappings":"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","names":["jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/components/DateTimeField/DateTimeField.tsx","../src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx"],"sourcesContent":["/**\n * @file DateTimeField Component\n * @package @jmruthers/pace-core\n * @module Components/DateTimeField\n * @since 0.1.0\n *\n * Form input component for datetime values with timezone support.\n * Handles UTC ↔ timezone conversion automatically.\n *\n * Features:\n * - Automatic UTC ↔ timezone conversion\n * - Prevents unwanted conversions during user editing\n * - Shows timezone information below the input field when not UTC\n * - Supports both ISO string and Date object values\n * - Uses native datetime-local input type\n * - Accessible form field with proper labels\n *\n * @example\n * ```tsx\n * import { DateTimeField } from '@jmruthers/pace-core/components';\n * import { useState } from 'react';\n *\n * function EventForm() {\n * const [startTime, setStartTime] = useState<string>();\n *\n * return (\n * <DateTimeField\n * label=\"Start Time\"\n * value={startTime}\n * onChange={setStartTime}\n * timezone=\"America/New_York\"\n * required\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - Proper label association with htmlFor\n * - Required field indicators\n * - Screen reader friendly\n * - Keyboard navigation support\n * - Focus management\n */\n\nimport * as React from 'react';\nimport { format, parse } from 'date-fns';\nimport { Label } from '../Label';\nimport { Input } from '../Input';\nimport { cn } from '../../utils/core/cn';\nimport { toZonedTime, fromZonedTime, getUserTimeZone } from '../../utils/timezone';\n\n/**\n * Props for the DateTimeField component\n */\nexport interface DateTimeFieldProps {\n /**\n * Field label\n */\n label: string;\n /**\n * UTC date value (ISO string, Date object, or undefined)\n */\n value: string | Date | undefined;\n /**\n * Change handler that receives UTC value (ISO string or Date object)\n */\n onChange: (value: string | Date | undefined) => void;\n /**\n * Target timezone for display (default: 'UTC')\n */\n timezone?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Additional CSS classes\n */\n className?: string;\n /**\n * If true, onChange returns Date object instead of ISO string\n */\n returnAsDate?: boolean;\n /**\n * Input id (auto-generated if not provided)\n */\n id?: string;\n /**\n * Helper text to display below the label\n */\n helperText?: string;\n /**\n * Error message to display\n */\n error?: string;\n}\n\n/**\n * DateTimeField component\n * Form input for datetime values with automatic timezone conversion\n *\n * @param props - DateTimeField configuration\n * @returns JSX.Element - The rendered datetime field\n */\nexport function DateTimeField({\n label,\n value,\n onChange,\n timezone = 'UTC',\n required = false,\n className,\n returnAsDate = false,\n id,\n helperText,\n error\n}: DateTimeFieldProps) {\n const [isEditing, setIsEditing] = React.useState(false);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const fieldId = id || `datetime-field-${React.useId()}`;\n\n // Convert UTC value to timezone for display\n const getDisplayValue = React.useCallback((): string => {\n if (!value) {\n return '';\n }\n\n try {\n let dateObj: Date;\n if (typeof value === 'string') {\n dateObj = new Date(value);\n } else {\n dateObj = value;\n }\n\n if (!dateObj || isNaN(dateObj.getTime())) {\n return '';\n }\n\n // Convert UTC to timezone\n const zonedDate = toZonedTime(dateObj, timezone);\n\n // Format for datetime-local input (YYYY-MM-DDTHH:mm)\n return format(zonedDate, \"yyyy-MM-dd'T'HH:mm\");\n } catch {\n return '';\n }\n }, [value, timezone]);\n\n const displayValue = isEditing ? undefined : getDisplayValue();\n\n // Handle input change\n const handleChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n setIsEditing(true);\n const inputValue = e.target.value;\n\n if (!inputValue) {\n onChange(undefined);\n return;\n }\n\n try {\n // Parse the datetime-local value (in timezone)\n const localDate = parse(inputValue, \"yyyy-MM-dd'T'HH:mm\", new Date());\n\n if (isNaN(localDate.getTime())) {\n onChange(undefined);\n return;\n }\n\n // Convert from timezone to UTC\n const utcDate = fromZonedTime(localDate, timezone);\n\n // Return as ISO string or Date object\n if (returnAsDate) {\n onChange(utcDate);\n } else {\n onChange(utcDate.toISOString());\n }\n } catch {\n onChange(undefined);\n }\n }, [timezone, returnAsDate, onChange]);\n\n // Handle blur to stop editing mode\n const handleBlur = React.useCallback(() => {\n setIsEditing(false);\n }, []);\n\n // Get timezone display text\n const getTimezoneDisplay = React.useCallback((): string => {\n if (timezone === 'UTC') {\n return '';\n }\n\n const userTz = getUserTimeZone();\n if (timezone === userTz) {\n return 'Local';\n }\n\n return timezone;\n }, [timezone]);\n\n const timezoneDisplay = getTimezoneDisplay();\n\n return (\n <div className={cn('space-y-2', className)}>\n <Label htmlFor={fieldId} required={required} helperText={helperText} error={error}>\n {label}\n </Label>\n <Input\n ref={inputRef}\n id={fieldId}\n type=\"datetime-local\"\n value={displayValue}\n onChange={handleChange}\n onBlur={handleBlur}\n required={required}\n error={!!error}\n className=\"w-full\"\n />\n {timezoneDisplay && !error && (\n <p className=\"text-sm text-muted-foreground\">\n {timezoneDisplay}\n </p>\n )}\n </div>\n );\n}\n\n","/**\n * @file DatePickerWithTimezone Component\n * @package @jmruthers/pace-core\n * @module Components/DatePickerWithTimezone\n * @since 0.1.0\n *\n * Date picker component that displays timezone information alongside the calendar.\n * Provides a calendar interface with timezone context for date selection.\n *\n * Features:\n * - Calendar date selection\n * - Timezone display (shows \"Local\" when matches user timezone)\n * - Optional \"Done\" button\n * - Accessible date selection\n * - Keyboard navigation support\n *\n * @example\n * ```tsx\n * import { DatePickerWithTimezone } from '@jmruthers/pace-core/components';\n * import { useState } from 'react';\n *\n * function DateSelector() {\n * const [date, setDate] = useState<Date>();\n *\n * return (\n * <DatePickerWithTimezone\n * selected={date}\n * onSelect={setDate}\n * timezone=\"America/New_York\"\n * onDone={() => console.log('Date selected')}\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - Proper ARIA attributes\n */\n\nimport * as React from 'react';\nimport { Calendar } from '../Calendar';\nimport { Button } from '../Button';\nimport { Clock } from 'lucide-react';\nimport { getUserTimeZone } from '../../utils/timezone';\nimport { cn } from '../../utils/core/cn';\n\n/**\n * Props for the DatePickerWithTimezone component\n */\nexport interface DatePickerWithTimezoneProps {\n /**\n * Currently selected date\n */\n selected?: Date;\n /**\n * Date selection handler\n */\n onSelect: (date: Date | undefined) => void;\n /**\n * Optional callback when \"Done\" button is clicked\n */\n onDone?: () => void;\n /**\n * Timezone to display (defaults to user's timezone)\n */\n timezone?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * DatePickerWithTimezone component\n * Date picker with timezone information display\n *\n * @param props - DatePickerWithTimezone configuration\n * @returns JSX.Element - The rendered date picker with timezone\n */\nexport function DatePickerWithTimezone({\n selected,\n onSelect,\n onDone,\n timezone,\n className\n}: DatePickerWithTimezoneProps) {\n const userTimezone = getUserTimeZone();\n const displayTimezone = timezone || userTimezone;\n const timezoneDisplay = displayTimezone === userTimezone ? 'Local' : displayTimezone;\n\n return (\n <div className={cn('flex flex-col', className)}>\n <div className=\"p-3\">\n <Calendar\n mode=\"single\"\n selected={selected}\n onSelect={onSelect}\n initialFocus\n captionLayout=\"dropdown\"\n startMonth={new Date(1900, 0)}\n endMonth={new Date(2100, 11)}\n className=\"p-0\"\n />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Clock className=\"size-4\" aria-hidden=\"true\" />\n <span>\n Timezone: <span aria-label={`Timezone ${timezoneDisplay}`}>{timezoneDisplay}</span>\n </span>\n </div>\n {onDone && (\n <Button onClick={onDone} size=\"sm\" className=\"h-8\">\n Done\n </Button>\n )}\n </div>\n </div>\n );\n}\n\n"],"mappings":"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","names":["jsx","jsxs"]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ContextValidator
3
- } from "./chunk-36LVWXB2.js";
3
+ } from "./chunk-AFVQODI2.js";
4
4
  import "./chunk-PWLANIRT.js";
5
5
  import "./chunk-DGUM43GV.js";
6
6
  export {
7
7
  ContextValidator
8
8
  };
9
- //# sourceMappingURL=contextValidator-OOPCLPZW.js.map
9
+ //# sourceMappingURL=contextValidator-5OGXSPKS.js.map
package/dist/hooks.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { u as useToast } from './useToast-AyaT-x7p.js';
2
- import { S as StorageUploadOptions, a as StorageUploadResult, b as StorageListOptions, c as StorageListResult, d as StorageFileInfo } from './usePublicRouteParams-i3qtoBgg.js';
3
- export { O as OrganisationSecurityHook, l as UseAppConfigReturn, i as UseFormDialogOptions, j as UseFormDialogReturn, U as UseOrganisationPermissionsReturn, F as UsePublicEventLogoOptions, E as UsePublicEventLogoReturn, B as UsePublicEventOptions, A as UsePublicEventReturn, D as UsePublicFileDisplayOptions, C as UsePublicFileDisplayReturn, G as UsePublicRouteParamsReturn, n as clearPublicEventCache, q as clearPublicFileDisplayCache, t as clearPublicLogoCache, z as extractEventCodeFromPath, y as generatePublicRoutePath, o as getPublicEventCacheStats, r as getPublicFileDisplayCacheStats, v as getPublicLogoCacheStats, k as useAppConfig, u as useEventTheme, h as useFormDialog, e as useOrganisationPermissions, f as useOrganisationSecurity, m as usePublicEvent, x as usePublicEventCode, s as usePublicEventLogo, p as usePublicFileDisplay, w as usePublicRouteParams, g as useZodForm } from './usePublicRouteParams-i3qtoBgg.js';
2
+ import { S as StorageUploadOptions, a as StorageUploadResult, b as StorageListOptions, c as StorageListResult, d as StorageFileInfo } from './usePublicRouteParams-ClnV4tnv.js';
3
+ export { O as OrganisationSecurityHook, l as UseAppConfigReturn, i as UseFormDialogOptions, j as UseFormDialogReturn, U as UseOrganisationPermissionsReturn, F as UsePublicEventLogoOptions, E as UsePublicEventLogoReturn, B as UsePublicEventOptions, A as UsePublicEventReturn, D as UsePublicFileDisplayOptions, C as UsePublicFileDisplayReturn, G as UsePublicRouteParamsReturn, n as clearPublicEventCache, q as clearPublicFileDisplayCache, t as clearPublicLogoCache, z as extractEventCodeFromPath, y as generatePublicRoutePath, o as getPublicEventCacheStats, r as getPublicFileDisplayCacheStats, v as getPublicLogoCacheStats, k as useAppConfig, u as useEventTheme, h as useFormDialog, e as useOrganisationPermissions, f as useOrganisationSecurity, m as usePublicEvent, x as usePublicEventCode, s as usePublicEventLogo, p as usePublicFileDisplay, w as usePublicRouteParams, g as useZodForm } from './usePublicRouteParams-ClnV4tnv.js';
4
4
  import * as React$1 from 'react';
5
5
  import { SortingState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table';
6
6
  import { d as DataRecord, g as PerformanceConfig, S as ServerSideConfig, C as ChunkingConfig, i as SearchIndexConfig, h as PaginationMode, k as ServerSideParams, l as ServerSideResponse, A as AutocompleteOptions, m as GooglePlaceAutocompletePrediction, P as ParsedAddress } from './types-CkbwOr4Y.js';
@@ -198,7 +198,7 @@ interface KeyboardShortcutsOptions {
198
198
  *
199
199
  * useKeyboardShortcuts(shortcuts);
200
200
  *
201
- * return <div>Content</div>;
201
+ * return <main>Content</main>;
202
202
  * }
203
203
  * ```
204
204
  */
package/dist/hooks.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  usePublicEventLogo,
13
13
  usePublicRouteParams,
14
14
  useZodForm
15
- } from "./chunk-5EC5MEWX.js";
15
+ } from "./chunk-RGAWHO7N.js";
16
16
  import {
17
17
  archiveFile,
18
18
  cleanupQueryCache,
@@ -34,20 +34,21 @@ import {
34
34
  usePreventTabReload,
35
35
  usePublicFileDisplay,
36
36
  useQueryCache
37
- } from "./chunk-YKRAFF5K.js";
37
+ } from "./chunk-UPPMRMYG.js";
38
38
  import {
39
39
  useDataTablePerformance,
40
+ useFocusTrap,
40
41
  useToast
41
- } from "./chunk-6SOIHG6Z.js";
42
+ } from "./chunk-JGRYX5UX.js";
42
43
  import {
43
44
  useAppConfig,
44
45
  useOrganisationSecurity
45
- } from "./chunk-OEWDTMG7.js";
46
+ } from "./chunk-NTM7ZSB6.js";
46
47
  import "./chunk-KQCRWDSA.js";
47
- import "./chunk-AVMLPIM7.js";
48
- import "./chunk-3LPHPB62.js";
48
+ import "./chunk-IHB5DR3H.js";
49
+ import "./chunk-EFN2EIMK.js";
49
50
  import "./chunk-63FOKYGO.js";
50
- import "./chunk-36LVWXB2.js";
51
+ import "./chunk-AFVQODI2.js";
51
52
  import "./chunk-ZSAAAMVR.js";
52
53
  import "./chunk-QXHPKYJV.js";
53
54
  import {
@@ -180,107 +181,8 @@ function useFocusManagement(options = {}) {
180
181
  };
181
182
  }
182
183
 
183
- // src/hooks/useFocusTrap.ts
184
- import { useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
185
- var DEFAULT_FOCUSABLE_SELECTOR = [
186
- "button:not([disabled])",
187
- "[href]",
188
- "input:not([disabled])",
189
- "select:not([disabled])",
190
- "textarea:not([disabled])",
191
- '[tabindex]:not([tabindex="-1"])',
192
- '[contenteditable="true"]'
193
- ].join(", ");
194
- function useFocusTrap(options = {}) {
195
- const {
196
- isActive = false,
197
- autoFocus = false,
198
- restoreFocus = false,
199
- onEscape,
200
- focusableSelector = DEFAULT_FOCUSABLE_SELECTOR
201
- } = options;
202
- const containerRef = useRef2(null);
203
- const previouslyFocusedElement = useRef2(null);
204
- const getFocusableElements = useCallback2(() => {
205
- if (!containerRef.current) return [];
206
- return Array.from(
207
- containerRef.current.querySelectorAll(focusableSelector)
208
- ).filter((element) => {
209
- return (
210
- // visible check
211
- !element.hasAttribute("disabled") && !element.hasAttribute("hidden") && element.offsetParent !== null
212
- );
213
- });
214
- }, [focusableSelector]);
215
- const focusFirst = useCallback2(() => {
216
- const elements = getFocusableElements();
217
- if (elements.length > 0) {
218
- elements[0].focus();
219
- }
220
- }, [getFocusableElements]);
221
- const focusLast = useCallback2(() => {
222
- const elements = getFocusableElements();
223
- if (elements.length > 0) {
224
- elements[elements.length - 1].focus();
225
- }
226
- }, [getFocusableElements]);
227
- useEffect2(() => {
228
- if (!isActive || !containerRef.current) return;
229
- const handleKeyDown = (event) => {
230
- if (event.key === "Escape" && onEscape) {
231
- onEscape();
232
- return;
233
- }
234
- if (event.key === "Tab") {
235
- const focusableElements = getFocusableElements();
236
- if (focusableElements.length === 0) return;
237
- const firstElement = focusableElements[0];
238
- const lastElement = focusableElements[focusableElements.length - 1];
239
- if (event.shiftKey) {
240
- if (document.activeElement === firstElement) {
241
- event.preventDefault();
242
- lastElement.focus();
243
- }
244
- } else {
245
- if (document.activeElement === lastElement) {
246
- event.preventDefault();
247
- firstElement.focus();
248
- }
249
- }
250
- }
251
- };
252
- const container = containerRef.current;
253
- container.addEventListener("keydown", handleKeyDown);
254
- return () => {
255
- container.removeEventListener("keydown", handleKeyDown);
256
- };
257
- }, [isActive, onEscape, getFocusableElements]);
258
- useEffect2(() => {
259
- if (!isActive) return;
260
- if (restoreFocus) {
261
- previouslyFocusedElement.current = document.activeElement;
262
- }
263
- if (autoFocus) {
264
- const timer = setTimeout(focusFirst, 0);
265
- return () => clearTimeout(timer);
266
- }
267
- return () => {
268
- if (restoreFocus && previouslyFocusedElement.current) {
269
- previouslyFocusedElement.current.focus();
270
- previouslyFocusedElement.current = null;
271
- }
272
- };
273
- }, [isActive, autoFocus, restoreFocus, focusFirst]);
274
- return {
275
- containerRef,
276
- focusFirst,
277
- focusLast,
278
- getFocusableElements
279
- };
280
- }
281
-
282
184
  // src/hooks/useKeyboardShortcuts.ts
283
- import { useEffect as useEffect3, useCallback as useCallback3 } from "react";
185
+ import { useEffect as useEffect2, useCallback as useCallback2 } from "react";
284
186
  function parseKeyCombo(combo) {
285
187
  const parts = combo.toLowerCase().split("+");
286
188
  const key = parts.pop();
@@ -303,7 +205,7 @@ function matchesKeyCombo(event, combo) {
303
205
  }
304
206
  function useKeyboardShortcuts(shortcuts, options = {}) {
305
207
  const { element = document, enabled = true } = options;
306
- const handleKeyDown = useCallback3((event) => {
208
+ const handleKeyDown = useCallback2((event) => {
307
209
  if (!enabled) return;
308
210
  for (const shortcut of shortcuts) {
309
211
  if (shortcut.enabled === false) continue;
@@ -319,7 +221,7 @@ function useKeyboardShortcuts(shortcuts, options = {}) {
319
221
  }
320
222
  }
321
223
  }, [shortcuts, enabled]);
322
- useEffect3(() => {
224
+ useEffect2(() => {
323
225
  if (!enabled) return;
324
226
  element.addEventListener("keydown", handleKeyDown);
325
227
  return () => element.removeEventListener("keydown", handleKeyDown);
@@ -327,11 +229,11 @@ function useKeyboardShortcuts(shortcuts, options = {}) {
327
229
  }
328
230
 
329
231
  // src/hooks/useIsMobile.ts
330
- import { useState, useEffect as useEffect4 } from "react";
232
+ import { useState, useEffect as useEffect3 } from "react";
331
233
  var MOBILE_BREAKPOINT = 768;
332
234
  function useIsMobile() {
333
235
  const [isMobile, setIsMobile] = useState(void 0);
334
- useEffect4(() => {
236
+ useEffect3(() => {
335
237
  if (typeof window === "undefined") {
336
238
  setIsMobile(false);
337
239
  return;
@@ -348,7 +250,7 @@ function useIsMobile() {
348
250
  }
349
251
 
350
252
  // src/hooks/useDataTableState.ts
351
- import { useState as useState2, useCallback as useCallback4 } from "react";
253
+ import { useState as useState2, useCallback as useCallback3 } from "react";
352
254
  function useDataTableState(options) {
353
255
  const { initialPageSize = 10, data } = options;
354
256
  const [sorting, setSorting] = useState2([]);
@@ -357,7 +259,7 @@ function useDataTableState(options) {
357
259
  const [pageSize, setPageSize] = useState2(initialPageSize);
358
260
  const [pageIndex, setPageIndex] = useState2(0);
359
261
  const [selectedRows, setSelectedRows] = useState2([]);
360
- const resetState = useCallback4(() => {
262
+ const resetState = useCallback3(() => {
361
263
  setSorting([]);
362
264
  setColumnFilters([]);
363
265
  setExpanded({});
@@ -399,16 +301,16 @@ function useDataTableState(options) {
399
301
  }
400
302
 
401
303
  // src/hooks/usePerformanceMonitor.ts
402
- import { useEffect as useEffect5, useRef as useRef3, useCallback as useCallback5 } from "react";
304
+ import { useEffect as useEffect4, useRef as useRef2, useCallback as useCallback4 } from "react";
403
305
  var log = createLogger("usePerformanceMonitor");
404
306
  function usePerformanceMonitor(componentName, enabled = import.meta.env.MODE === "development", budgetName = "COMPONENT_RENDER") {
405
- const renderStartTime = useRef3(0);
406
- const metrics = useRef3([]);
407
- const startMeasurement = useCallback5(() => {
307
+ const renderStartTime = useRef2(0);
308
+ const metrics = useRef2([]);
309
+ const startMeasurement = useCallback4(() => {
408
310
  if (!enabled) return;
409
311
  renderStartTime.current = performance.now();
410
312
  }, [enabled]);
411
- const endMeasurement = useCallback5(() => {
313
+ const endMeasurement = useCallback4(() => {
412
314
  if (!enabled || renderStartTime.current === 0) return;
413
315
  const renderTime = performance.now() - renderStartTime.current;
414
316
  const metric = {
@@ -431,15 +333,15 @@ function usePerformanceMonitor(componentName, enabled = import.meta.env.MODE ===
431
333
  }
432
334
  renderStartTime.current = 0;
433
335
  }, [enabled, componentName, budgetName]);
434
- const getMetrics = useCallback5(() => {
336
+ const getMetrics = useCallback4(() => {
435
337
  return metrics.current.slice();
436
338
  }, []);
437
- const getAverageRenderTime = useCallback5(() => {
339
+ const getAverageRenderTime = useCallback4(() => {
438
340
  if (metrics.current.length === 0) return 0;
439
341
  const total = metrics.current.reduce((sum, metric) => sum + metric.renderTime, 0);
440
342
  return total / metrics.current.length;
441
343
  }, []);
442
- const getBudgetStatus = useCallback5(() => {
344
+ const getBudgetStatus = useCallback4(() => {
443
345
  const budget = PERFORMANCE_BUDGETS[budgetName];
444
346
  if (!budget) return null;
445
347
  const averageTime = getAverageRenderTime();
@@ -450,7 +352,7 @@ function usePerformanceMonitor(componentName, enabled = import.meta.env.MODE ===
450
352
  efficiency: budget.threshold > 0 ? (budget.threshold - averageTime) / budget.threshold : 0
451
353
  };
452
354
  }, [budgetName, getAverageRenderTime]);
453
- useEffect5(() => {
355
+ useEffect4(() => {
454
356
  startMeasurement();
455
357
  return endMeasurement;
456
358
  });
@@ -464,7 +366,7 @@ function usePerformanceMonitor(componentName, enabled = import.meta.env.MODE ===
464
366
  }
465
367
 
466
368
  // src/hooks/useFileUrlCache.ts
467
- import { useRef as useRef4, useCallback as useCallback6 } from "react";
369
+ import { useRef as useRef3, useCallback as useCallback5 } from "react";
468
370
  var globalUrlCache = /* @__PURE__ */ new Map();
469
371
  var MAX_CACHE_SIZE = 500;
470
372
  var DEFAULT_TTL_MS = 3600 * 1e3;
@@ -488,13 +390,13 @@ function cleanupCache() {
488
390
  }
489
391
  }
490
392
  function useFileUrlCache() {
491
- const cleanupIntervalRef = useRef4(null);
393
+ const cleanupIntervalRef = useRef3(null);
492
394
  if (cleanupIntervalRef.current === null && typeof window !== "undefined") {
493
395
  cleanupIntervalRef.current = window.setInterval(() => {
494
396
  cleanupCache();
495
397
  }, 5 * 60 * 1e3);
496
398
  }
497
- const getUrl = useCallback6(async (fileReference, supabase, organisationId, ttl = DEFAULT_TTL_MS) => {
399
+ const getUrl = useCallback5(async (fileReference, supabase, organisationId, ttl = DEFAULT_TTL_MS) => {
498
400
  const cacheKey = getCacheKey(fileReference);
499
401
  const cached = globalUrlCache.get(cacheKey);
500
402
  const now = Date.now();
@@ -527,7 +429,7 @@ function useFileUrlCache() {
527
429
  return null;
528
430
  }
529
431
  }, []);
530
- const setUrl = useCallback6((fileReference, url, ttl = DEFAULT_TTL_MS) => {
432
+ const setUrl = useCallback5((fileReference, url, ttl = DEFAULT_TTL_MS) => {
531
433
  const cacheKey = getCacheKey(fileReference);
532
434
  globalUrlCache.set(cacheKey, {
533
435
  url,
@@ -535,7 +437,7 @@ function useFileUrlCache() {
535
437
  });
536
438
  cleanupCache();
537
439
  }, []);
538
- const getCachedUrl = useCallback6((fileReference) => {
440
+ const getCachedUrl = useCallback5((fileReference) => {
539
441
  const cacheKey = getCacheKey(fileReference);
540
442
  const cached = globalUrlCache.get(cacheKey);
541
443
  const now = Date.now();
@@ -544,14 +446,14 @@ function useFileUrlCache() {
544
446
  }
545
447
  return null;
546
448
  }, []);
547
- const clearFile = useCallback6((fileReference) => {
449
+ const clearFile = useCallback5((fileReference) => {
548
450
  const cacheKey = getCacheKey(fileReference);
549
451
  globalUrlCache.delete(cacheKey);
550
452
  }, []);
551
- const clearCache = useCallback6(() => {
453
+ const clearCache = useCallback5(() => {
552
454
  globalUrlCache.clear();
553
455
  }, []);
554
- const getCacheStats = useCallback6(() => {
456
+ const getCacheStats = useCallback5(() => {
555
457
  return {
556
458
  size: globalUrlCache.size,
557
459
  maxSize: MAX_CACHE_SIZE
@@ -568,7 +470,7 @@ function useFileUrlCache() {
568
470
  }
569
471
 
570
472
  // src/hooks/useStorage.ts
571
- import { useState as useState3, useCallback as useCallback7 } from "react";
473
+ import { useState as useState3, useCallback as useCallback6 } from "react";
572
474
  var log2 = createLogger("useStorage");
573
475
  function useStorage({ supabase, appName, orgId }) {
574
476
  const [isUploading, setIsUploading] = useState3(false);
@@ -576,7 +478,7 @@ function useStorage({ supabase, appName, orgId }) {
576
478
  const [isListing, setIsListing] = useState3(false);
577
479
  const [listError, setListError] = useState3(null);
578
480
  const [files, setFiles] = useState3([]);
579
- const handleUploadFile = useCallback7(async (file, options = {}) => {
481
+ const handleUploadFile = useCallback6(async (file, options = {}) => {
580
482
  setIsUploading(true);
581
483
  setUploadError(null);
582
484
  try {
@@ -604,10 +506,10 @@ function useStorage({ supabase, appName, orgId }) {
604
506
  setIsUploading(false);
605
507
  }
606
508
  }, [supabase, appName, orgId]);
607
- const handleGetPublicUrl = useCallback7((path) => {
509
+ const handleGetPublicUrl = useCallback6((path) => {
608
510
  return getPublicUrl(supabase, path);
609
511
  }, [supabase]);
610
- const handleGetSignedUrl = useCallback7(async (path, expiresIn) => {
512
+ const handleGetSignedUrl = useCallback6(async (path, expiresIn) => {
611
513
  try {
612
514
  const result = await getSignedUrl(supabase, path, {
613
515
  appName,
@@ -620,7 +522,7 @@ function useStorage({ supabase, appName, orgId }) {
620
522
  return null;
621
523
  }
622
524
  }, [supabase, appName, orgId]);
623
- const handleDeleteFile = useCallback7(async (path) => {
525
+ const handleDeleteFile = useCallback6(async (path) => {
624
526
  try {
625
527
  const result = await deleteFile(supabase, path);
626
528
  if (result.success) {
@@ -634,7 +536,7 @@ function useStorage({ supabase, appName, orgId }) {
634
536
  };
635
537
  }
636
538
  }, [supabase]);
637
- const handleArchiveFile = useCallback7(async (path) => {
539
+ const handleArchiveFile = useCallback6(async (path) => {
638
540
  try {
639
541
  const result = await archiveFile(supabase, path, { appName, orgId });
640
542
  if (result.success) {
@@ -648,7 +550,7 @@ function useStorage({ supabase, appName, orgId }) {
648
550
  };
649
551
  }
650
552
  }, [supabase, appName, orgId]);
651
- const handleListFiles = useCallback7(async (options = {}) => {
553
+ const handleListFiles = useCallback6(async (options = {}) => {
652
554
  setIsListing(true);
653
555
  setListError(null);
654
556
  try {
@@ -668,7 +570,7 @@ function useStorage({ supabase, appName, orgId }) {
668
570
  setIsListing(false);
669
571
  }
670
572
  }, [supabase, appName, orgId]);
671
- const refreshFiles = useCallback7(async () => {
573
+ const refreshFiles = useCallback6(async () => {
672
574
  await handleListFiles();
673
575
  }, [handleListFiles]);
674
576
  return {
@@ -701,7 +603,7 @@ function useFileUpload({ supabase, appName, orgId }) {
701
603
  const [uploadProgress, setUploadProgress] = useState3(0);
702
604
  const [isUploading, setIsUploading] = useState3(false);
703
605
  const [uploadError, setUploadError] = useState3(null);
704
- const uploadWithProgress = useCallback7(async (file, options = {}) => {
606
+ const uploadWithProgress = useCallback6(async (file, options = {}) => {
705
607
  setIsUploading(true);
706
608
  setUploadProgress(0);
707
609
  setUploadError(null);