@jmruthers/pace-core 0.6.6 → 0.6.7

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 (246) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +255 -0
  4. package/audit-tool/audits/03-architecture.cjs +196 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +291 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +241 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-7PMH7XN7.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
  28. package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
  29. package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
  30. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  31. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  32. package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
  33. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  34. package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
  35. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  36. package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
  37. package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
  38. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  39. package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
  40. package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
  41. package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
  42. package/dist/components.d.ts +5 -4
  43. package/dist/components.js +27 -32
  44. package/dist/eslint-rules/index.cjs +22 -9
  45. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  46. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  47. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  48. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +26 -10
  49. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  50. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  51. package/dist/hooks.d.ts +5 -5
  52. package/dist/hooks.js +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +18 -17
  55. package/dist/rbac/index.js +6 -6
  56. package/dist/theming/runtime.d.ts +14 -1
  57. package/dist/theming/runtime.js +1 -1
  58. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  59. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  60. package/dist/utils.d.ts +2 -2
  61. package/dist/utils.js +8 -8
  62. package/docs/README.md +1 -1
  63. package/docs/api/modules.md +47 -31
  64. package/docs/api-reference/components.md +18 -20
  65. package/docs/api-reference/hooks.md +80 -80
  66. package/docs/api-reference/types.md +1 -1
  67. package/docs/api-reference/utilities.md +1 -1
  68. package/docs/architecture/README.md +1 -1
  69. package/docs/core-concepts/events.md +3 -3
  70. package/docs/core-concepts/organisations.md +6 -6
  71. package/docs/core-concepts/permissions.md +6 -6
  72. package/docs/documentation-index.md +12 -18
  73. package/docs/getting-started/documentation-index.md +1 -1
  74. package/docs/getting-started/examples/README.md +4 -4
  75. package/docs/getting-started/examples/full-featured-app.md +1 -1
  76. package/docs/getting-started/faq.md +2 -2
  77. package/docs/getting-started/quick-reference.md +4 -4
  78. package/docs/implementation-guides/authentication.md +15 -15
  79. package/docs/implementation-guides/component-styling.md +1 -1
  80. package/docs/implementation-guides/data-tables.md +126 -33
  81. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  82. package/docs/implementation-guides/dynamic-colors.md +3 -3
  83. package/docs/implementation-guides/file-upload-storage.md +2 -2
  84. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  85. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  86. package/docs/implementation-guides/large-datasets.md +3 -2
  87. package/docs/implementation-guides/organisation-security.md +2 -2
  88. package/docs/implementation-guides/performance.md +2 -2
  89. package/docs/implementation-guides/permission-enforcement.md +1 -1
  90. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  91. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  92. package/docs/rbac/README.md +5 -5
  93. package/docs/rbac/advanced-patterns.md +6 -6
  94. package/docs/rbac/api-reference.md +20 -20
  95. package/docs/rbac/event-based-apps.md +3 -3
  96. package/docs/rbac/examples.md +41 -41
  97. package/docs/rbac/getting-started.md +37 -37
  98. package/docs/rbac/performance.md +1 -1
  99. package/docs/rbac/quick-start.md +52 -52
  100. package/docs/rbac/secure-client-protection.md +1 -1
  101. package/docs/rbac/troubleshooting.md +1 -1
  102. package/docs/security/README.md +5 -5
  103. package/docs/standards/0-standards-overview.md +220 -0
  104. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +204 -185
  105. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  106. package/docs/standards/3-architecture-standards.md +606 -0
  107. package/docs/standards/4-code-quality-standards.md +728 -0
  108. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  109. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  110. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  111. package/docs/standards/8-testing-documentation-standards.md +401 -0
  112. package/docs/standards/9-operations-standards.md +1102 -0
  113. package/docs/standards/README.md +203 -104
  114. package/docs/troubleshooting/README.md +4 -4
  115. package/docs/troubleshooting/common-issues.md +2 -2
  116. package/docs/troubleshooting/debugging.md +9 -9
  117. package/docs/troubleshooting/migration.md +4 -4
  118. package/eslint-config-pace-core.cjs +21 -10
  119. package/package.json +6 -5
  120. package/scripts/install-cursor-rules.cjs +11 -243
  121. package/scripts/install-eslint-config.cjs +284 -0
  122. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  123. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  124. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +10 -10
  125. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  126. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  127. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  128. package/src/__tests__/templates/component.test.template.tsx +18 -15
  129. package/src/components/Calendar/Calendar.tsx +201 -47
  130. package/src/components/ContextSelector/ContextSelector.tsx +137 -153
  131. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  132. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  133. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  134. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  135. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  136. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  137. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  138. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  139. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  140. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  141. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  142. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  143. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  144. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  145. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  146. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  147. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  148. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  149. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  150. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  151. package/src/components/DataTable/components/index.ts +2 -1
  152. package/src/components/DataTable/types.ts +0 -18
  153. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  154. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  155. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  156. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  157. package/src/components/Dialog/Dialog.test.tsx +1 -0
  158. package/src/components/Dialog/Dialog.tsx +25 -8
  159. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  160. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  161. package/src/components/FileUpload/FileUpload.tsx +112 -130
  162. package/src/components/Progress/Progress.tsx +2 -4
  163. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  164. package/src/components/Select/Select.tsx +86 -77
  165. package/src/components/Select/types.ts +3 -0
  166. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  167. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  168. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  169. package/src/hooks/public/usePublicEvent.ts +5 -5
  170. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  171. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  172. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  173. package/src/hooks/useAppConfig.ts +2 -2
  174. package/src/hooks/useEventTheme.test.ts +7 -7
  175. package/src/hooks/useEventTheme.ts +1 -4
  176. package/src/hooks/useFileDisplay.ts +2 -2
  177. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  178. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  179. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  180. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  181. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  182. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  183. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  184. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  185. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  186. package/src/styles/core.css +7 -0
  187. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  188. package/src/theming/parseEventColours.ts +22 -10
  189. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  190. package/src/utils/storage/README.md +1 -1
  191. package/cursor-rules/01-standards-compliance.mdc +0 -285
  192. package/cursor-rules/04-testing-standards.mdc +0 -270
  193. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  194. package/cursor-rules/06-code-quality.mdc +0 -311
  195. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  196. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  197. package/cursor-rules/11-performance-optimization.mdc +0 -169
  198. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  199. package/dist/DataTable-LRJL4IRV.js +0 -15
  200. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  201. package/dist/eslint-rules/rules/components.cjs +0 -113
  202. package/dist/eslint-rules/rules/imports.cjs +0 -102
  203. package/docs/best-practices/README.md +0 -472
  204. package/docs/best-practices/accessibility.md +0 -604
  205. package/docs/best-practices/common-patterns.md +0 -516
  206. package/docs/best-practices/deployment.md +0 -1103
  207. package/docs/best-practices/performance.md +0 -1328
  208. package/docs/best-practices/security.md +0 -940
  209. package/docs/best-practices/testing.md +0 -1034
  210. package/docs/rbac/compliance/compliance-guide.md +0 -544
  211. package/docs/standards/01-standards-compliance.md +0 -188
  212. package/docs/standards/03-solid-principles.md +0 -39
  213. package/docs/standards/04-testing-standards.md +0 -36
  214. package/docs/standards/05-bug-reports-and-features.md +0 -27
  215. package/docs/standards/06-code-quality.md +0 -34
  216. package/docs/standards/07-tech-stack-compliance.md +0 -30
  217. package/docs/standards/10-error-handling-patterns.md +0 -401
  218. package/docs/standards/11-performance-optimization.md +0 -348
  219. package/docs/standards/12-ci-cd-integration.md +0 -370
  220. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  221. package/scripts/audit/audit-compliance.cjs +0 -1295
  222. package/scripts/audit/audit-components.cjs +0 -260
  223. package/scripts/audit/audit-rbac.cjs +0 -954
  224. package/scripts/audit/audit-standards.cjs +0 -1268
  225. package/scripts/audit/index.cjs +0 -1927
  226. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  227. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  228. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  229. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  230. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  231. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  232. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  233. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  234. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  235. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  236. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  237. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  238. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  239. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  240. package/src/components/DataTable/utils/debugTools.ts +0 -514
  241. package/src/eslint-rules/index.cjs +0 -22
  242. package/src/eslint-rules/rules/components.cjs +0 -113
  243. package/src/eslint-rules/rules/imports.cjs +0 -102
  244. package/src/eslint-rules/rules/rbac.cjs +0 -790
  245. package/src/eslint-rules/utils/helpers.cjs +0 -42
  246. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -0,0 +1,365 @@
1
+ ---
2
+ description: Enforce error handling patterns, performance optimization, and CI/CD integration patterns
3
+ globs: ["src/**/*.{ts,tsx,js,jsx}", "supabase/migrations/**/*.sql", ".github/workflows/**/*.{yml,yaml}", "package.json"]
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
+ ---
8
+ # Operations Standards Guide
9
+
10
+ **📚 Human-Readable Standard**: See [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md) for complete documentation.
11
+
12
+ This guide enforces error handling patterns, performance optimization strategies, and CI/CD integration patterns.
13
+
14
+ ## AI Agent Instructions
15
+
16
+ **When writing or modifying code, ALWAYS:**
17
+ 1. **Use type-safe errors** - Never use `any` for errors, always use type guards or Result types
18
+ 2. **Never expose internals** - User-facing errors must be friendly, never show SQL, stack traces, or file paths
19
+ 3. **Log with context** - Always log errors with context, but never log sensitive data (passwords, tokens, PII)
20
+ 4. **Memoize expensive operations** - Use `useMemo` for expensive computations, `useCallback` for stable references
21
+ 5. **Avoid new objects in render** - Never create new objects/arrays in render, memoize them with `useMemo`
22
+ 6. **Use helper functions in RLS** - Always use STABLE SECURITY DEFINER helper functions, never subqueries
23
+ 7. **Provide recovery paths** - When possible, provide retry logic or fallback values
24
+
25
+ **Decision Tree: Error Handling**
26
+ ```
27
+ 1. What type of error is this?
28
+ ├─ API Error → Use ApiResult shape, user-friendly message
29
+ ├─ Validation Error → Use Zod errors, field-specific messages
30
+ ├─ Network Error → Retry logic, connection message
31
+ └─ Unknown Error → Generic user message, detailed log
32
+
33
+ 2. Should user see this error?
34
+ ├─ YES → User-friendly message (no internals)
35
+ └─ NO → Log only, show generic message
36
+
37
+ 3. Can we recover?
38
+ ├─ YES → Retry logic or fallback value
39
+ └─ NO → Show error, allow user to retry
40
+ ```
41
+
42
+ **Decision Tree: Performance**
43
+ ```
44
+ 1. Is this expensive computation?
45
+ ├─ YES → Use useMemo
46
+ └─ NO → Don't memoize (overhead not worth it)
47
+
48
+ 2. Is this function passed as prop?
49
+ ├─ YES → Use useCallback
50
+ └─ NO → Regular function is fine
51
+
52
+ 3. Is this creating new object/array in render?
53
+ ├─ YES → Memoize with useMemo
54
+ └─ NO → Continue
55
+ ```
56
+
57
+ ## Error Handling Patterns
58
+
59
+ ### MUST: Use Type-Safe Error Handling
60
+
61
+ **MUST use type guards or Result types, NEVER use `any`:**
62
+
63
+ ```tsx
64
+ // ❌ WRONG: Using any
65
+ catch (error: any) {
66
+ console.log(error.message);
67
+ }
68
+
69
+ // ✅ CORRECT: Type guard
70
+ function isApiError(error: unknown): error is ApiError {
71
+ return typeof error === 'object' && error !== null && 'ok' in error && (error as ApiError).ok === false;
72
+ }
73
+ catch (error) {
74
+ if (isApiError(error)) {
75
+ handleApiError(error);
76
+ } else {
77
+ handleUnknownError(error);
78
+ }
79
+ }
80
+
81
+ // ✅ CORRECT: Result type
82
+ type Result<T> = { ok: true; data: T } | { ok: false; error: ApiError };
83
+ const result = await fetchData();
84
+ if (result.ok) {
85
+ useData(result.data);
86
+ } else {
87
+ showError(result.error.message);
88
+ }
89
+ ```
90
+
91
+ ### MUST: Never Expose Internal Details
92
+
93
+ **MUST NOT expose SQL, stack traces, file paths, or internal errors to users:**
94
+
95
+ ```tsx
96
+ // ❌ WRONG: Exposing internal details
97
+ toast.error(error.message); // May contain SQL, stack traces
98
+
99
+ // ✅ CORRECT: User-friendly message
100
+ toast.error('Unable to save changes. Please try again.');
101
+ logger.error('Save failed', { error: error.message, context: 'saveUser' });
102
+ ```
103
+
104
+ ### MUST: Use Consistent Error Shapes
105
+
106
+ **MUST use ApiResult shape for API errors:**
107
+
108
+ ```tsx
109
+ // ✅ CORRECT: Consistent error shape
110
+ type ApiError = {
111
+ ok: false;
112
+ error: {
113
+ code: string;
114
+ message: string; // User-friendly
115
+ details?: object; // Non-sensitive context
116
+ };
117
+ };
118
+ ```
119
+
120
+ ### MUST: Log Errors with Context
121
+
122
+ **MUST log errors with context, but NEVER log sensitive data:**
123
+
124
+ ```tsx
125
+ // ✅ CORRECT: Log with context, no sensitive data
126
+ logger.error('Failed to save user', {
127
+ userId: user.id,
128
+ operation: 'updateUser',
129
+ errorCode: error.code,
130
+ });
131
+
132
+ // ❌ WRONG: Logging sensitive data
133
+ logger.error('Failed to save user', {
134
+ password: user.password, // NEVER
135
+ token: authToken, // NEVER
136
+ });
137
+ ```
138
+
139
+ ### SHOULD: Provide Recovery Paths
140
+
141
+ **SHOULD provide retry logic or fallback values when appropriate:**
142
+
143
+ ```tsx
144
+ // ✅ CORRECT: Retry with exponential backoff
145
+ async function fetchWithRetry<T>(fn: () => Promise<Result<T>>, maxRetries = 3): Promise<Result<T>> {
146
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
147
+ const result = await fn();
148
+ if (result.ok) return result;
149
+ if (result.error.code?.startsWith('4')) return result; // Don't retry 4xx
150
+ await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
151
+ }
152
+ return { ok: false, error: { code: 'MAX_RETRIES', message: 'Operation failed after retries' } };
153
+ }
154
+ ```
155
+
156
+ ## Performance Optimization Patterns
157
+
158
+ ### MUST: Optimize React Re-renders
159
+
160
+ **MUST use memoization for expensive computations and stable references:**
161
+
162
+ ```tsx
163
+ // ✅ CORRECT - Memoize expensive computation
164
+ const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
165
+
166
+ // ✅ CORRECT - Stable callback reference
167
+ const handleClick = useCallback(() => doSomething(id), [id]);
168
+
169
+ // ✅ CORRECT - Memoize component
170
+ const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
171
+ ```
172
+
173
+ ### MUST: Avoid Creating New Objects in Render
174
+
175
+ **MUST NOT create new objects/arrays in render:**
176
+
177
+ ```tsx
178
+ // ❌ WRONG - New object on every render
179
+ function Component({ items }) {
180
+ const config = { items, enabled: true };
181
+ return <Child config={config} />;
182
+ }
183
+
184
+ // ✅ CORRECT - Memoize object
185
+ function Component({ items }) {
186
+ const config = useMemo(() => ({ items, enabled: true }), [items]);
187
+ return <Child config={config} />;
188
+ }
189
+ ```
190
+
191
+ ### MUST: Use Helper Functions in RLS Policies
192
+
193
+ **MUST use STABLE SECURITY DEFINER helper functions (never subqueries):**
194
+
195
+ ```sql
196
+ -- ✅ CORRECT - Helper function (evaluated once)
197
+ CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
198
+ check_user_organisation_access(organisation_id)
199
+ );
200
+
201
+ -- ❌ WRONG - Subquery (N+1 performance issue)
202
+ CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
203
+ organisation_id IN (SELECT organisation_id FROM organisation_memberships WHERE user_id = auth.uid())
204
+ );
205
+ ```
206
+
207
+ ### SHOULD: Lazy Load Heavy Components
208
+
209
+ **SHOULD lazy load heavy components:**
210
+
211
+ ```tsx
212
+ // ✅ CORRECT - Lazy load
213
+ import { lazy, Suspense } from 'react';
214
+ const HeavyComponent = lazy(() => import('./HeavyComponent'));
215
+ <Suspense fallback={<Loading />}><HeavyComponent /></Suspense>
216
+ ```
217
+
218
+ ### SHOULD: Configure TanStack Query Cache
219
+
220
+ **SHOULD configure appropriate cache times:**
221
+
222
+ ```tsx
223
+ // ✅ CORRECT - Configure cache
224
+ const queryClient = new QueryClient({
225
+ defaultOptions: {
226
+ queries: {
227
+ staleTime: 5 * 60 * 1000,
228
+ cacheTime: 10 * 60 * 1000,
229
+ retry: 1,
230
+ refetchOnWindowFocus: false,
231
+ },
232
+ },
233
+ });
234
+ ```
235
+
236
+ ## CI/CD Integration Patterns
237
+
238
+ ### MUST: Include Required CI Checks
239
+
240
+ **MUST run these checks in every CI pipeline:**
241
+
242
+ ```yaml
243
+ # ✅ CORRECT - Required checks
244
+ jobs:
245
+ quality-checks:
246
+ steps:
247
+ - name: Lint
248
+ run: npm run lint
249
+ - name: Type check
250
+ run: npx tsc --noEmit
251
+ - name: Run tests
252
+ run: npm run test
253
+ - name: Build
254
+ run: npm run build
255
+ ```
256
+
257
+ ### MUST: Have Required Scripts
258
+
259
+ **MUST have these scripts in package.json:**
260
+
261
+ ```json
262
+ // ✅ CORRECT - Required scripts
263
+ {
264
+ "scripts": {
265
+ "lint": "eslint .",
266
+ "type-check": "tsc --noEmit",
267
+ "test": "vitest run",
268
+ "build": "vite build"
269
+ }
270
+ }
271
+ ```
272
+
273
+ ### MUST: Use Secrets for Sensitive Data
274
+
275
+ **MUST NOT commit secrets to repository:**
276
+
277
+ ```yaml
278
+ # ✅ CORRECT - Use secrets
279
+ env:
280
+ SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
281
+ VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
282
+
283
+ # ❌ WRONG - Hardcoded secrets
284
+ env:
285
+ SUPABASE_URL: "https://hardcoded-url.supabase.co"
286
+ ```
287
+
288
+ ### SHOULD: Deploy to Staging First
289
+
290
+ **SHOULD deploy to staging before production:**
291
+
292
+ ```yaml
293
+ # ✅ CORRECT - Staging first
294
+ deploy-staging:
295
+ if: github.ref == 'refs/heads/develop'
296
+ environment: staging
297
+
298
+ deploy-production:
299
+ needs: deploy-staging
300
+ if: github.ref == 'refs/heads/main'
301
+ environment: production
302
+ ```
303
+
304
+ ## Common Mistakes to Avoid
305
+
306
+ **When writing code, NEVER:**
307
+ 1. **Use `any` for errors** - Always use type guards or Result types
308
+ ```tsx
309
+ // ❌ WRONG
310
+ catch (error: any) {
311
+ toast.error(error.message);
312
+ }
313
+
314
+ // ✅ CORRECT
315
+ catch (error: unknown) {
316
+ if (isApiError(error)) {
317
+ toast.error(error.error.message);
318
+ } else {
319
+ toast.error('An unexpected error occurred');
320
+ }
321
+ }
322
+ ```
323
+
324
+ 2. **Expose internal details in errors** - Always use user-friendly messages
325
+ 3. **Create new objects in render** - Always memoize with useMemo
326
+ 4. **Skip memoization for expensive operations** - Always use useMemo/useCallback
327
+ 5. **Use subqueries in RLS policies** - Always use STABLE SECURITY DEFINER helper functions
328
+ 6. **Log sensitive data** - Never log passwords, tokens, or PII
329
+
330
+ ## Operations Checklist
331
+
332
+ Before committing, verify:
333
+
334
+ **Error Handling:**
335
+ - [ ] Type-safe error handling (no `any`)
336
+ - [ ] User-friendly error messages (no internals)
337
+ - [ ] Errors logged with context (no sensitive data)
338
+ - [ ] Recovery paths provided when possible
339
+ - [ ] Consistent error shapes used
340
+
341
+ **Performance:**
342
+ - [ ] Expensive computations memoized
343
+ - [ ] Callbacks stable with useCallback
344
+ - [ ] Components memoized when appropriate
345
+ - [ ] No new objects/arrays in render
346
+ - [ ] Heavy components lazy loaded
347
+ - [ ] RLS policies use helper functions
348
+ - [ ] TanStack Query configured properly
349
+
350
+ **CI/CD:**
351
+ - [ ] Lint check configured
352
+ - [ ] Type check configured
353
+ - [ ] Tests run in CI
354
+ - [ ] Build succeeds in CI
355
+ - [ ] Environment variables set as secrets
356
+ - [ ] Staging deployment configured
357
+ - [ ] Production deployment configured
358
+
359
+ ## Reference
360
+
361
+ **Note**: CI/CD configuration validation and performance metric thresholds are handled by CI/audit tool. See [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md) for complete enforcement details.
362
+
363
+ - Error Handling: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#error-handling-patterns)
364
+ - Performance: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#performance-optimization)
365
+ - CI/CD: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#cicd-integration)
@@ -0,0 +1,15 @@
1
+ export { ActionButtons, BulkOperationsDropdown, ColumnFactory, ColumnVisibilityDropdown, DataTable, DataTableCore, DataTableErrorBoundary, DataTableModals, DataTableToolbar, EditableRow, EmptyState, EnhancedPaginationControls, GroupingDropdown, ImportModal, LoadingState, PaginationControls, SortIndicator, UnifiedTableBody, announce, announceBulkOperation, announceFilterChange, announceLoadingState, announcePaginationChange, announceSearchResults, announceSelectionChange, announceSortChange, average, calculateAllDepths, calculateAllIndentation, calculateIndentation, calculateOptimalPageSize, cleanupLiveRegion, count, createHierarchicalStructure, defaultDataTableFeatures, exportToCSV, exportToCSVWithTableRows, generateCSVContent, getAriaSortState, getAriaSortValue, getCellRenderer, getColumnHeaderText, getHierarchicalSortConfig, getPageSizeOptions, getPaginationBinding, getRowDepth, getRowDescription, getRowIdSafe, getSortButtonLabel, groupHierarchicalData, hasValidRowId, initializeLiveRegion, isHierarchicalSortableColumn, max, min, normalizeDataTableFeatures, shouldShowColumnForRow, sortHierarchicalDataByStructure, sortHierarchicalDataWithSorting, sum, validateHierarchicalData, validatePaginationConfig } from './chunk-Q7Q7V5NV.js';
2
+ import './chunk-BM4CQ5P3.js';
3
+ export { CircuitBreaker, DEFAULT_FALLBACK_CONFIG, DataChunkManager, DataTableError, DataTableErrorType, ErrorRecoveryManager, MemoryMonitor, SearchIndex, VisibilityTracker, chunkData, debounce, determinePaginationMode, getOptimalPageSizeOptions, safeExecute, throttle, useDataTablePerformance } from './chunk-S7DKJPLT.js';
4
+ import './chunk-VBCS3DUA.js';
5
+ import './chunk-C7NSAPTL.js';
6
+ import './chunk-FTCRZOG2.js';
7
+ import './chunk-ZFYPMX46.js';
8
+ import './chunk-AHU7G2R5.js';
9
+ import './chunk-4SXLQIZO.js';
10
+ import './chunk-A3W6LW53.js';
11
+ import './chunk-OJ4SKRSV.js';
12
+ import './chunk-7ILTDCL2.js';
13
+ import './chunk-HF6O3O37.js';
14
+ import './chunk-TTRFSOKR.js';
15
+ import './chunk-3RG5ZIWI.js';
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { d as DataRecord, D as DataTableColumn, e as DataTableRBACConfig, f as DataTableFeatureConfig, H as HierarchicalConfig, g as PerformanceConfig, S as ServerSideConfig, h as PaginationMode, C as ChunkingConfig, i as SearchIndexConfig, j as ExportOptions, G as GetRowId, E as EmptyStateConfig, c as AggregateConfig, a as DataTableAction } from './types-B-K_5VnO.js';
2
+ import { d as DataRecord, D as DataTableColumn, e as DataTableRBACConfig, f as DataTableFeatureConfig, H as HierarchicalConfig, g as PerformanceConfig, S as ServerSideConfig, h as PaginationMode, C as ChunkingConfig, i as SearchIndexConfig, j as ExportOptions, G as GetRowId, E as EmptyStateConfig, c as AggregateConfig, a as DataTableAction } from './types-DXstZpNI.js';
3
3
  import React__default from 'react';
4
4
 
5
5
  /**
@@ -1,7 +1,7 @@
1
1
  import * as React$1 from 'react';
2
2
  import React__default, { ReactNode, Component } from 'react';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { P as ParsedAddress, A as AutocompleteOptions } from './types-B-K_5VnO.js';
4
+ import { P as ParsedAddress, A as AutocompleteOptions } from './types-DXstZpNI.js';
5
5
  import * as LabelPrimitive from '@radix-ui/react-label';
6
6
  import { F as FileCategory, e as FileUploadResult, U as UploadProgress, c as FileUploadOptions, a as FileReference } from './file-reference-BavO2eQj.js';
7
7
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
@@ -912,9 +912,9 @@ interface DialogContentProps extends React$1.HTMLAttributes<HTMLDialogElement> {
912
912
  minHeight?: string;
913
913
  /** Minimum width in CSS units */
914
914
  minWidth?: string;
915
- /** Dialog title for accessibility (sets native title attribute) */
915
+ /** Dialog title - sets native title attribute and aria-labelledby */
916
916
  title?: string;
917
- /** Dialog description for accessibility (sets aria-description attribute) */
917
+ /** Dialog description - sets native aria-description attribute */
918
918
  description?: string;
919
919
  /** Whether to persist open state across tab switches */
920
920
  persistOpenState?: boolean;
@@ -926,12 +926,6 @@ interface DialogContentProps extends React$1.HTMLAttributes<HTMLDialogElement> {
926
926
  interface DialogPortalProps {
927
927
  children: React$1.ReactNode;
928
928
  }
929
- /**
930
- * Props for the DialogClose component
931
- * @public
932
- */
933
- interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
934
- }
935
929
  /**
936
930
  * Props for the DialogHeader component (semantic header element)
937
931
  * @public
@@ -1008,6 +1002,20 @@ declare const DialogPortal: React$1.FC<DialogPortalProps>;
1008
1002
  * @returns JSX.Element - The semantic dialog content with overlay and optional close button
1009
1003
  */
1010
1004
  declare const DialogContent: React$1.ForwardRefExoticComponent<DialogContentProps & React$1.RefAttributes<HTMLDialogElement>>;
1005
+ /**
1006
+ * Props for the DialogClose component
1007
+ * @public
1008
+ */
1009
+ interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
1010
+ }
1011
+ /**
1012
+ * Props for the DialogClose component
1013
+ * @public
1014
+ */
1015
+ interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
1016
+ /** Whether to merge props with child element instead of rendering a button */
1017
+ asChild?: boolean;
1018
+ }
1011
1019
  /**
1012
1020
  * DialogClose component
1013
1021
  * Button to close the dialog
@@ -1073,6 +1081,7 @@ interface SelectProps extends Omit<React$1.HTMLAttributes<HTMLFieldSetElement>,
1073
1081
  children: React$1.ReactNode;
1074
1082
  className?: string;
1075
1083
  direction?: SelectDirection;
1084
+ showCheckmark?: boolean;
1076
1085
  }
1077
1086
  /**
1078
1087
  * Props for the SelectTrigger component.
@@ -1108,6 +1117,7 @@ interface SelectItemProps {
1108
1117
  disabled?: boolean;
1109
1118
  className?: string;
1110
1119
  onClick?: (e: React$1.MouseEvent) => void;
1120
+ showCheckmark?: boolean;
1111
1121
  }
1112
1122
 
1113
1123
  /**
@@ -1171,39 +1181,39 @@ declare const SelectContent: React$1.ForwardRefExoticComponent<SelectContentProp
1171
1181
  declare const SelectItem: React$1.ForwardRefExoticComponent<SelectItemProps & React$1.RefAttributes<HTMLLIElement>>;
1172
1182
  /**
1173
1183
  * Select group component.
1174
- * Groups related select items together.
1184
+ * Groups related select items together using a nested list structure.
1175
1185
  *
1176
1186
  * @param props - Select group configuration
1177
- * @param ref - Forwarded ref to the div element
1187
+ * @param ref - Forwarded ref to the ul element
1178
1188
  * @returns The rendered select group
1179
1189
  */
1180
1190
  declare const SelectGroup: React$1.ForwardRefExoticComponent<{
1181
1191
  children: React$1.ReactNode;
1182
1192
  className?: string;
1183
- } & React$1.RefAttributes<HTMLDivElement>>;
1193
+ } & React$1.RefAttributes<HTMLUListElement>>;
1184
1194
  /**
1185
1195
  * Select label component.
1186
1196
  * Provides a label for a group of select items.
1187
1197
  *
1188
1198
  * @param props - Select label configuration
1189
- * @param ref - Forwarded ref to the div element
1199
+ * @param ref - Forwarded ref to the li element
1190
1200
  * @returns The rendered select label
1191
1201
  */
1192
1202
  declare const SelectLabel: React$1.ForwardRefExoticComponent<{
1193
1203
  children: React$1.ReactNode;
1194
1204
  className?: string;
1195
- } & React$1.RefAttributes<HTMLDivElement>>;
1205
+ } & React$1.RefAttributes<HTMLLIElement>>;
1196
1206
  /**
1197
1207
  * Select separator component.
1198
1208
  * Provides visual separation between groups of select items.
1199
1209
  *
1200
1210
  * @param props - Select separator configuration
1201
- * @param ref - Forwarded ref to the div element
1211
+ * @param ref - Forwarded ref to the hr element
1202
1212
  * @returns The rendered select separator
1203
1213
  */
1204
1214
  declare const SelectSeparator: React$1.ForwardRefExoticComponent<{
1205
1215
  className?: string;
1206
- } & React$1.RefAttributes<HTMLDivElement>>;
1216
+ } & React$1.RefAttributes<HTMLHRElement>>;
1207
1217
 
1208
1218
  /**
1209
1219
  * @file Tabs Component System
@@ -1,4 +1,4 @@
1
- import { clearPalette, parseAndNormalizeEventColours, applyPalette } from './chunk-BVP2BCJF.js';
1
+ import { clearPalette, parseAndNormalizeEventColours, applyPalette } from './chunk-ZKAWKYT4.js';
2
2
  import { EventServiceContext } from './chunk-FTCRZOG2.js';
3
3
  import { assertAppId } from './chunk-4SXLQIZO.js';
4
4
  import { fetchPlaceDetails, createAddressFromPlaceResult, getAddressByPlaceId, fetchPlaceAutocomplete, setOrganisationContext } from './chunk-FYHN4DD5.js';
@@ -2087,7 +2087,6 @@ function invalidateFileDisplayCache(table_name, record_id, organisation_id, cate
2087
2087
  authenticatedFileCache.delete(allCategoryKey);
2088
2088
  }
2089
2089
  }
2090
- var log4 = createLogger("useEventTheme");
2091
2090
  function useEventTheme(event) {
2092
2091
  const location = useLocation();
2093
2092
  const eventServiceContext = useContext(EventServiceContext);
@@ -2112,7 +2111,6 @@ function useEventTheme(event) {
2112
2111
  try {
2113
2112
  applyPalette(normalized);
2114
2113
  } catch (error) {
2115
- log4.error("Failed to apply event palette:", error);
2116
2114
  }
2117
2115
  return () => {
2118
2116
  };
@@ -1,4 +1,4 @@
1
- import { Button } from './chunk-7TYHROIV.js';
1
+ import { Button } from './chunk-BM4CQ5P3.js';
2
2
  import { ShieldX } from 'lucide-react';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
 
@@ -1,3 +1,11 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ // src/utils/core/cn.ts
5
+ function cn(...inputs) {
6
+ return twMerge(clsx(inputs));
7
+ }
8
+
1
9
  // src/utils/performance/performanceBudgets.ts
2
10
  var PERFORMANCE_BUDGETS = {
3
11
  COMPONENT_RENDER: { threshold: 50 },
@@ -69,4 +77,4 @@ performanceBudgetMonitor.setBudget("CHUNK_COUNT", 10, "warning");
69
77
  performanceBudgetMonitor.setBudget("TREESHAKING_SCORE", 70, "warning");
70
78
  performanceBudgetMonitor.setBudget("ERROR_BOUNDARY_TRIGGER", 5, "error");
71
79
 
72
- export { PERFORMANCE_BUDGETS, performanceBudgetMonitor };
80
+ export { PERFORMANCE_BUDGETS, cn, performanceBudgetMonitor };
@@ -1,3 +1,5 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+
1
3
  // src/utils/validation/htmlSanitization.ts
2
4
  function sanitizeHtml(html) {
3
5
  if (!html || typeof html !== "string") {
@@ -51,5 +53,18 @@ function renderSafeHtml(html, options = {}) {
51
53
  warnings: validation.warnings
52
54
  };
53
55
  }
56
+ var LoadingSpinner = ({
57
+ size = "md",
58
+ className = ""
59
+ }) => {
60
+ const sizeClasses = {
61
+ sm: "size-4",
62
+ md: "size-6",
63
+ lg: "size-8"
64
+ };
65
+ const validSize = size && size in sizeClasses ? size : "md";
66
+ const sizeClass = sizeClasses[validSize];
67
+ return /* @__PURE__ */ jsx("canvas", { className: `inline-block animate-spin rounded-full border-2 border-solid border-current border-r-transparent motion-reduce:animate-[spin_1.5s_linear_infinite] ${sizeClass} ${className}`.trim(), role: "status", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading..." }) });
68
+ };
54
69
 
55
- export { renderSafeHtml, sanitizeHtml, validateHtml };
70
+ export { LoadingSpinner, renderSafeHtml, sanitizeHtml, validateHtml };
@@ -1,9 +1,10 @@
1
- import { useAppConfig, useOrganisationSecurity } from './chunk-3O3WHILE.js';
1
+ import { useAppConfig, useOrganisationSecurity } from './chunk-VBCS3DUA.js';
2
2
  import { useEventService, useUnifiedAuth, useOrganisations } from './chunk-FTCRZOG2.js';
3
3
  import { OrganisationContextRequiredError, getRBACLogger, resolveAppContext, getPageScopeType, ContextValidator, getPermissionMap, getRoleContext, getAccessLevel, isPermittedCached, isPermitted, isSuperAdmin } from './chunk-ZFYPMX46.js';
4
- import { cn, getCurrentAppName } from './chunk-A55DK444.js';
4
+ import { getCurrentAppName } from './chunk-OJ4SKRSV.js';
5
+ import { cn } from './chunk-7ILTDCL2.js';
5
6
  import { createLogger, logger } from './chunk-TTRFSOKR.js';
6
- import * as React from 'react';
7
+ import * as React2 from 'react';
7
8
  import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
8
9
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
10
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -52,7 +53,7 @@ function useEvents() {
52
53
  var TooltipProvider = TooltipPrimitive.Provider;
53
54
  var TooltipRoot = TooltipPrimitive.Root;
54
55
  var TooltipTrigger = TooltipPrimitive.Trigger;
55
- var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
56
+ var TooltipContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
56
57
  TooltipPrimitive.Content,
57
58
  {
58
59
  ref,
@@ -65,7 +66,7 @@ var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props },
65
66
  }
66
67
  ));
67
68
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
68
- var Tooltip = React.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
69
+ var Tooltip = React2.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
69
70
  /* @__PURE__ */ jsx(TooltipTrigger, { ref, asChild: true, children: /* @__PURE__ */ jsx("span", { children }) }),
70
71
  /* @__PURE__ */ jsx(TooltipContent, { children: content })
71
72
  ] }) }));
@@ -88,7 +89,7 @@ function getButtonClasses(variant = "default", size = "default") {
88
89
  };
89
90
  return `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
90
91
  }
91
- var Button = React.forwardRef(
92
+ var Button = React2.forwardRef(
92
93
  ({ className, variant, size, asChild = false, type = "button", disabled, ...props }, ref) => {
93
94
  const Comp = asChild ? Slot : "button";
94
95
  return /* @__PURE__ */ jsx(
@@ -105,7 +106,48 @@ var Button = React.forwardRef(
105
106
  }
106
107
  );
107
108
  Button.displayName = "Button";
108
- var IconButton = React.forwardRef(
109
+ function ButtonGroup({
110
+ children,
111
+ orientation = "horizontal",
112
+ variant,
113
+ size,
114
+ className,
115
+ spacing = "sm"
116
+ }) {
117
+ const spacingClasses = {
118
+ none: "",
119
+ sm: orientation === "horizontal" ? "space-x-1" : "space-y-1",
120
+ md: orientation === "horizontal" ? "space-x-2" : "space-y-2",
121
+ lg: orientation === "horizontal" ? "space-x-4" : "space-y-4"
122
+ };
123
+ return /* @__PURE__ */ jsx(
124
+ "fieldset",
125
+ {
126
+ className: cn(
127
+ "flex",
128
+ orientation === "horizontal" ? "flex-row items-center" : "flex-col",
129
+ spacingClasses[spacing],
130
+ className
131
+ ),
132
+ role: "group",
133
+ children: React2.Children.map(children, (child) => {
134
+ if (React2.isValidElement(child) && child.type) {
135
+ const componentType = child.type;
136
+ if (componentType.displayName === "Button") {
137
+ const childProps = child.props;
138
+ return React2.cloneElement(child, {
139
+ variant: childProps.variant || variant,
140
+ size: childProps.size || size,
141
+ ...childProps
142
+ });
143
+ }
144
+ }
145
+ return child;
146
+ })
147
+ }
148
+ );
149
+ }
150
+ var IconButton = React2.forwardRef(
109
151
  ({ icon, className, size = "icon", "aria-label": ariaLabel, tooltip, ...props }, ref) => {
110
152
  const button = /* @__PURE__ */ jsx(
111
153
  Button,
@@ -1958,4 +2000,4 @@ function useSecureSupabase(baseClient) {
1958
2000
  ]);
1959
2001
  }
1960
2002
 
1961
- export { Button, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };
2003
+ export { Button, ButtonGroup, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };