@jmruthers/pace-core 0.5.76 → 0.5.78

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 (447) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
  3. package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
  4. package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
  5. package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
  6. package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
  7. package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
  8. package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
  9. package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
  10. package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
  11. package/dist/chunk-2OGV6IRV.js.map +1 -0
  12. package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
  13. package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
  14. package/dist/chunk-CVMVPYAL.js.map +1 -0
  15. package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
  16. package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
  17. package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
  18. package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
  19. package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
  20. package/dist/chunk-LRQ6RBJC.js.map +1 -0
  21. package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
  22. package/dist/chunk-MNJXXD6C.js.map +1 -0
  23. package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
  24. package/dist/chunk-PTR5PMPE.js.map +1 -0
  25. package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
  26. package/dist/chunk-Q7APDV6H.js.map +1 -0
  27. package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
  28. package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
  29. package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
  30. package/dist/chunk-S63MFSY6.js.map +1 -0
  31. package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
  32. package/dist/chunk-WUXCWRL6.js +20 -0
  33. package/dist/chunk-WUXCWRL6.js.map +1 -0
  34. package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
  35. package/dist/chunk-YVVGHRGI.js.map +1 -0
  36. package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
  37. package/dist/chunk-ZMNXIJP4.js.map +1 -0
  38. package/dist/components.d.ts +6 -6
  39. package/dist/components.js +14 -18
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
  42. package/dist/hooks.d.ts +5 -5
  43. package/dist/hooks.js +8 -9
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.d.ts +19 -27
  46. package/dist/index.js +21 -29
  47. package/dist/index.js.map +1 -1
  48. package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
  49. package/dist/providers.d.ts +7 -21
  50. package/dist/providers.js +3 -10
  51. package/dist/rbac/index.d.ts +71 -221
  52. package/dist/rbac/index.js +15 -16
  53. package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +61 -18
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
  58. package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
  59. package/dist/utils.d.ts +2 -2
  60. package/dist/utils.js +52 -9
  61. package/dist/utils.js.map +1 -1
  62. package/docs/CONTENT_AUDIT_REPORT.md +253 -0
  63. package/docs/DOCUMENTATION_AUDIT.md +172 -0
  64. package/docs/README.md +142 -147
  65. package/docs/STYLE_GUIDE.md +37 -0
  66. package/docs/api/classes/ColumnFactory.md +17 -17
  67. package/docs/api/classes/ErrorBoundary.md +1 -1
  68. package/docs/api/classes/InvalidScopeError.md +4 -4
  69. package/docs/api/classes/MissingUserContextError.md +4 -4
  70. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  71. package/docs/api/classes/PermissionDeniedError.md +5 -5
  72. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  73. package/docs/api/classes/RBACAuditManager.md +8 -8
  74. package/docs/api/classes/RBACCache.md +35 -5
  75. package/docs/api/classes/RBACEngine.md +49 -20
  76. package/docs/api/classes/RBACError.md +4 -4
  77. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  78. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  79. package/docs/api/classes/StorageUtils.md +1 -1
  80. package/docs/api/enums/FileCategory.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +4 -4
  82. package/docs/api/interfaces/ButtonProps.md +1 -1
  83. package/docs/api/interfaces/CardProps.md +1 -1
  84. package/docs/api/interfaces/ColorPalette.md +1 -1
  85. package/docs/api/interfaces/ColorShade.md +1 -1
  86. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  87. package/docs/api/interfaces/DataRecord.md +11 -0
  88. package/docs/api/interfaces/DataTableAction.md +65 -29
  89. package/docs/api/interfaces/DataTableColumn.md +36 -23
  90. package/docs/api/interfaces/DataTableProps.md +80 -38
  91. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  92. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  93. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  94. package/docs/api/interfaces/EventLogoProps.md +1 -1
  95. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  96. package/docs/api/interfaces/FileMetadata.md +1 -1
  97. package/docs/api/interfaces/FileReference.md +1 -1
  98. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  99. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +11 -11
  107. package/docs/api/interfaces/NavigationContextType.md +9 -9
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +16 -3
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACLogger.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  134. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  135. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  136. package/docs/api/interfaces/RouteConfig.md +2 -2
  137. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  138. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  139. package/docs/api/interfaces/StorageConfig.md +1 -1
  140. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  141. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  142. package/docs/api/interfaces/StorageListOptions.md +1 -1
  143. package/docs/api/interfaces/StorageListResult.md +1 -1
  144. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  145. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  146. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  147. package/docs/api/interfaces/StyleImport.md +1 -1
  148. package/docs/api/interfaces/SwitchProps.md +1 -1
  149. package/docs/api/interfaces/ToastActionElement.md +1 -1
  150. package/docs/api/interfaces/ToastProps.md +1 -1
  151. package/docs/api/interfaces/UnifiedAuthContextType.md +94 -521
  152. package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
  153. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  159. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  160. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  161. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  162. package/docs/api/interfaces/UserEventAccess.md +11 -11
  163. package/docs/api/interfaces/UserMenuProps.md +1 -1
  164. package/docs/api/interfaces/UserProfile.md +1 -1
  165. package/docs/api/modules.md +251 -269
  166. package/docs/api-reference/components.md +193 -0
  167. package/docs/api-reference/hooks.md +265 -0
  168. package/docs/api-reference/providers.md +6 -0
  169. package/docs/api-reference/types.md +6 -0
  170. package/docs/api-reference/utilities.md +207 -0
  171. package/docs/architecture/README.md +6 -0
  172. package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
  173. package/docs/architecture/rbac-security-architecture.md +258 -0
  174. package/docs/architecture/services.md +9 -1
  175. package/docs/best-practices/README.md +6 -0
  176. package/docs/best-practices/accessibility.md +6 -0
  177. package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
  178. package/docs/best-practices/deployment.md +6 -0
  179. package/docs/best-practices/performance.md +475 -2
  180. package/docs/best-practices/security.md +6 -0
  181. package/docs/best-practices/testing.md +6 -0
  182. package/docs/core-concepts/authentication.md +6 -0
  183. package/docs/core-concepts/events.md +6 -0
  184. package/docs/core-concepts/organisations.md +6 -0
  185. package/docs/core-concepts/permissions.md +6 -0
  186. package/docs/core-concepts/rbac-system.md +8 -0
  187. package/docs/documentation-index.md +121 -182
  188. package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
  189. package/docs/getting-started/documentation-index.md +40 -0
  190. package/docs/getting-started/examples/README.md +878 -35
  191. package/docs/{faq.md → getting-started/faq.md} +7 -1
  192. package/docs/getting-started/installation-guide.md +6 -0
  193. package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
  194. package/docs/implementation-guides/app-layout.md +6 -0
  195. package/docs/implementation-guides/authentication.md +1021 -0
  196. package/docs/implementation-guides/component-styling.md +6 -0
  197. package/docs/implementation-guides/data-tables.md +1264 -2076
  198. package/docs/implementation-guides/dynamic-colors.md +6 -0
  199. package/docs/implementation-guides/event-theming-summary.md +6 -0
  200. package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
  201. package/docs/implementation-guides/file-upload-storage.md +6 -0
  202. package/docs/implementation-guides/forms.md +6 -0
  203. package/docs/implementation-guides/inactivity-tracking.md +6 -0
  204. package/docs/implementation-guides/navigation.md +6 -0
  205. package/docs/implementation-guides/organisation-security.md +6 -0
  206. package/docs/implementation-guides/permission-enforcement.md +6 -0
  207. package/docs/implementation-guides/public-pages-advanced.md +6 -0
  208. package/docs/implementation-guides/public-pages.md +6 -0
  209. package/docs/migration/MIGRATION_GUIDE.md +827 -351
  210. package/docs/migration/README.md +7 -1
  211. package/docs/migration/organisation-context-timing-fix.md +6 -0
  212. package/docs/migration/rbac-migration.md +44 -1
  213. package/docs/migration/service-architecture.md +6 -0
  214. package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
  215. package/docs/migration/v0.4.16-css-first-approach.md +6 -0
  216. package/docs/migration/v0.4.17-source-path-fix.md +6 -0
  217. package/docs/rbac/README-rbac-rls-integration.md +6 -0
  218. package/docs/rbac/README.md +6 -0
  219. package/docs/rbac/advanced-patterns.md +6 -0
  220. package/docs/rbac/api-reference.md +7 -1
  221. package/docs/rbac/breaking-changes-v3.md +222 -0
  222. package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
  223. package/docs/rbac/examples.md +6 -0
  224. package/docs/rbac/getting-started.md +6 -0
  225. package/docs/rbac/migration-guide.md +260 -0
  226. package/docs/rbac/quick-start.md +70 -13
  227. package/docs/rbac/rbac-rls-integration.md +6 -0
  228. package/docs/rbac/super-admin-guide.md +6 -0
  229. package/docs/rbac/troubleshooting.md +6 -0
  230. package/docs/security/README.md +6 -0
  231. package/docs/security/checklist.md +6 -0
  232. package/docs/styles/README.md +7 -1
  233. package/docs/{usage.md → styles/usage.md} +6 -0
  234. package/docs/testing/README.md +6 -0
  235. package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
  236. package/docs/troubleshooting/README.md +387 -5
  237. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
  238. package/docs/troubleshooting/common-issues.md +6 -0
  239. package/docs/troubleshooting/database-view-compatibility.md +6 -0
  240. package/docs/troubleshooting/organisation-context-setup.md +6 -0
  241. package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
  242. package/docs/troubleshooting/styling-issues.md +6 -0
  243. package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
  244. package/package.json +1 -1
  245. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
  246. package/src/__tests__/helpers/test-providers.tsx +3 -53
  247. package/src/components/DataTable/DataTable.test.tsx +319 -0
  248. package/src/components/DataTable/DataTable.tsx +32 -11
  249. package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
  250. package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
  251. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
  252. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
  253. package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
  254. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
  255. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
  256. package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
  257. package/src/components/DataTable/components/ActionButtons.tsx +88 -104
  258. package/src/components/DataTable/components/DataTableCore.tsx +309 -337
  259. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
  260. package/src/components/DataTable/components/DataTableModals.tsx +22 -1
  261. package/src/components/DataTable/components/EditableRow.tsx +69 -84
  262. package/src/components/DataTable/components/EmptyState.tsx +5 -1
  263. package/src/components/DataTable/components/ImportModal.tsx +65 -36
  264. package/src/components/DataTable/components/PaginationControls.tsx +40 -100
  265. package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
  266. package/src/components/DataTable/context/DataTableContext.tsx +1 -1
  267. package/src/components/DataTable/core/ColumnFactory.ts +5 -0
  268. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
  269. package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
  270. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
  271. package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
  272. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
  273. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
  274. package/src/components/DataTable/hooks/index.ts +7 -0
  275. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
  276. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
  277. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
  278. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
  280. package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
  281. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
  282. package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
  283. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
  284. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
  285. package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
  286. package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
  287. package/src/components/DataTable/index.ts +12 -3
  288. package/src/components/DataTable/types.ts +129 -9
  289. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
  290. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
  291. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
  292. package/src/components/DataTable/utils/a11yUtils.ts +244 -0
  293. package/src/components/DataTable/utils/debugTools.ts +609 -0
  294. package/src/components/DataTable/utils/exportUtils.ts +114 -16
  295. package/src/components/DataTable/utils/flexibleImport.ts +202 -32
  296. package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
  297. package/src/components/DataTable/utils/index.ts +2 -0
  298. package/src/components/DataTable/utils/paginationUtils.ts +350 -0
  299. package/src/components/DataTable/utils/rowUtils.ts +6 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
  301. package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
  302. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
  303. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
  304. package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
  305. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
  306. package/src/components/Select/Select.tsx +1 -0
  307. package/src/components/examples/PermissionExample.tsx +173 -0
  308. package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
  309. package/src/examples/PublicEventPage.tsx +274 -0
  310. package/src/examples/PublicPageApp.tsx +308 -0
  311. package/src/examples/PublicPageUsageExample.tsx +216 -0
  312. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
  313. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
  314. package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
  315. package/src/hooks/useOrganisationPermissions.test.ts +42 -18
  316. package/src/hooks/useOrganisationPermissions.ts +12 -6
  317. package/src/hooks/useOrganisationSecurity.test.ts +138 -85
  318. package/src/hooks/useOrganisationSecurity.ts +41 -10
  319. package/src/index.ts +0 -1
  320. package/src/providers/AuthProvider.simplified.tsx +880 -0
  321. package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
  322. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
  323. package/src/providers/index.ts +0 -1
  324. package/src/providers/services/EventServiceProvider.tsx +19 -15
  325. package/src/providers/services/InactivityServiceProvider.tsx +19 -15
  326. package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
  327. package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
  328. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
  329. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
  330. package/src/rbac/README.md +1 -1
  331. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
  332. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
  333. package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
  334. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
  335. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
  336. package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
  337. package/src/rbac/adapters.tsx +26 -69
  338. package/src/rbac/api.test.ts +90 -27
  339. package/src/rbac/api.ts +61 -10
  340. package/src/rbac/audit.test.ts +33 -38
  341. package/src/rbac/audit.ts +21 -6
  342. package/src/rbac/cache.ts +33 -1
  343. package/src/rbac/components/NavigationGuard.tsx +11 -11
  344. package/src/rbac/components/NavigationProvider.test.tsx +11 -5
  345. package/src/rbac/components/NavigationProvider.tsx +37 -13
  346. package/src/rbac/components/PagePermissionGuard.tsx +111 -50
  347. package/src/rbac/components/PagePermissionProvider.tsx +5 -5
  348. package/src/rbac/components/PermissionEnforcer.tsx +11 -11
  349. package/src/rbac/components/RoleBasedRouter.tsx +5 -5
  350. package/src/rbac/components/SecureDataProvider.tsx +5 -5
  351. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
  352. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
  353. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
  354. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
  355. package/src/rbac/engine.test.simple.ts +19 -13
  356. package/src/rbac/engine.test.ts +1 -0
  357. package/src/rbac/engine.ts +330 -766
  358. package/src/rbac/errors.ts +156 -0
  359. package/src/rbac/hooks/usePermissions.ts +32 -10
  360. package/src/rbac/hooks/useRBAC.test.ts +126 -512
  361. package/src/rbac/hooks/useRBAC.ts +147 -193
  362. package/src/rbac/hooks/useResolvedScope.ts +12 -0
  363. package/src/rbac/index.ts +7 -4
  364. package/src/rbac/security.ts +109 -18
  365. package/src/rbac/types.ts +12 -1
  366. package/src/services/AuthService.ts +2 -15
  367. package/src/services/EventService.ts +43 -46
  368. package/src/services/OrganisationService.ts +51 -31
  369. package/src/services/__tests__/AuthService.test.ts +1 -1
  370. package/src/services/__tests__/EventService.test.ts +1 -1
  371. package/src/services/__tests__/OrganisationService.test.ts +1 -1
  372. package/src/services/base/BaseService.ts +8 -0
  373. package/src/styles/base.css +208 -0
  374. package/src/styles/semantic.css +24 -0
  375. package/src/types/database.generated.ts +7347 -0
  376. package/src/types/database.ts +20 -0
  377. package/src/utils/logger.ts +179 -0
  378. package/src/utils/organisationContext.ts +11 -4
  379. package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
  380. package/dist/appNameResolver-UURKN7NF.js +0 -22
  381. package/dist/audit-6TOCAMKO.js.map +0 -1
  382. package/dist/chunk-B2WTCLCV.js.map +0 -1
  383. package/dist/chunk-FGMFQSHX.js.map +0 -1
  384. package/dist/chunk-K34IM5CT.js.map +0 -1
  385. package/dist/chunk-KHJS6VIA.js.map +0 -1
  386. package/dist/chunk-KK73ZB4E.js.map +0 -1
  387. package/dist/chunk-M5IWZRBT.js.map +0 -1
  388. package/dist/chunk-ULBI5JGB.js +0 -109
  389. package/dist/chunk-ULBI5JGB.js.map +0 -1
  390. package/dist/chunk-WN6XJWOS.js.map +0 -1
  391. package/dist/chunk-XLZ7U46Z.js.map +0 -1
  392. package/dist/chunk-Y6TXWPJO.js.map +0 -1
  393. package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
  394. package/docs/TERMINOLOGY.md +0 -231
  395. package/docs/api/interfaces/RBACContextType.md +0 -468
  396. package/docs/api/interfaces/RBACProviderProps.md +0 -107
  397. package/docs/best-practices/performance-expansion.md +0 -473
  398. package/docs/breaking-changes.md +0 -179
  399. package/docs/consuming-app-example.md +0 -290
  400. package/docs/documentation-templates.md +0 -539
  401. package/docs/examples/navigation-menu-auth-fix.md +0 -344
  402. package/docs/getting-started/examples/basic-auth-app.md +0 -520
  403. package/docs/getting-started/examples/full-featured-app.md +0 -616
  404. package/docs/getting-started/quick-start.md +0 -376
  405. package/docs/implementation-guides/datatable-filtering.md +0 -313
  406. package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
  407. package/docs/implementation-guides/hierarchical-datatable.md +0 -850
  408. package/docs/implementation-guides/large-datasets.md +0 -281
  409. package/docs/implementation-guides/performance.md +0 -403
  410. package/docs/migration/quick-migration-guide.md +0 -320
  411. package/docs/migration-guide.md +0 -193
  412. package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
  413. package/docs/performance/README.md +0 -551
  414. package/docs/style-guide.md +0 -964
  415. package/docs/troubleshooting/authentication-issues.md +0 -334
  416. package/docs/troubleshooting/debugging.md +0 -1117
  417. package/docs/troubleshooting/migration.md +0 -918
  418. package/src/__tests__/hooks/usePermissions.test.ts +0 -261
  419. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
  420. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
  421. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
  422. package/src/hooks/services/usePermissions.ts +0 -70
  423. package/src/hooks/services/useRBACService.ts +0 -30
  424. package/src/hooks/usePermissionCheck.ts +0 -150
  425. package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
  426. package/src/providers/services/RBACServiceProvider.tsx +0 -79
  427. package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
  428. package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
  429. package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
  430. package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
  431. package/src/rbac/providers/RBACProvider.tsx +0 -645
  432. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
  433. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
  434. package/src/rbac/providers/index.ts +0 -11
  435. package/src/services/RBACService.ts +0 -522
  436. package/src/services/__tests__/RBACService.test.ts +0 -492
  437. package/src/services/interfaces/IRBACService.ts +0 -62
  438. package/src/utils/appNameResolver.test 2.ts +0 -494
  439. /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
  440. /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
  441. /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
  442. /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
  443. /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
  444. /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
  445. /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
  446. /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
  447. /package/docs/{app.css.example → styles/app.css.example} +0 -0
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  useCan,
3
3
  useResolvedScope
4
- } from "./chunk-KHJS6VIA.js";
4
+ } from "./chunk-LRQ6RBJC.js";
5
5
  import {
6
6
  toast,
7
7
  useDataTablePerformance
8
8
  } from "./chunk-YCKPEMJA.js";
9
9
  import {
10
10
  init_UnifiedAuthProvider
11
- } from "./chunk-URUTVZ7N.js";
11
+ } from "./chunk-FL4ZCQLD.js";
12
12
  import {
13
13
  useUnifiedAuth
14
- } from "./chunk-WN6XJWOS.js";
14
+ } from "./chunk-MNJXXD6C.js";
15
15
  import {
16
16
  cn
17
17
  } from "./chunk-PYUXFQJ3.js";
@@ -5502,19 +5502,11 @@ var require_lodash = __commonJS({
5502
5502
  });
5503
5503
 
5504
5504
  // src/components/DataTable/DataTable.tsx
5505
- import React16 from "react";
5505
+ import React18 from "react";
5506
5506
 
5507
5507
  // src/components/DataTable/components/DataTableCore.tsx
5508
- import React15, { useMemo as useMemo9, useCallback as useCallback6, useEffect as useEffect8, useRef as useRef6 } from "react";
5509
- import {
5510
- useReactTable,
5511
- getCoreRowModel,
5512
- getFilteredRowModel,
5513
- getSortedRowModel,
5514
- getPaginationRowModel,
5515
- getGroupedRowModel,
5516
- getExpandedRowModel
5517
- } from "@tanstack/react-table";
5508
+ import React17, { useMemo as useMemo14, useCallback as useCallback10, useEffect as useEffect12, useRef as useRef7 } from "react";
5509
+ import { useReactTable } from "@tanstack/react-table";
5518
5510
  import { Edit, Trash, ChevronUp as ChevronUp2, ChevronDown as ChevronDown3, ChevronsUpDown } from "lucide-react";
5519
5511
 
5520
5512
  // src/components/Button/Button.tsx
@@ -6226,6 +6218,7 @@ var SelectItem = React5.forwardRef(
6226
6218
  "data-disabled": disabled ? "true" : void 0,
6227
6219
  role: "option",
6228
6220
  "aria-selected": isSelected,
6221
+ tabIndex: disabled ? -1 : 0,
6229
6222
  children: [
6230
6223
  children,
6231
6224
  isSelected && /* @__PURE__ */ jsx4(Check, { className: "absolute right-2 h-4 w-4 flex-shrink-0 mt-0.5" })
@@ -6566,7 +6559,7 @@ function DataTableToolbar({
6566
6559
  }
6567
6560
 
6568
6561
  // src/components/DataTable/components/UnifiedTableBody.tsx
6569
- import React7, { useRef as useRef3, useEffect as useEffect3 } from "react";
6562
+ import React8, { useRef as useRef3, useEffect as useEffect3 } from "react";
6570
6563
  import { flexRender as flexRender2 } from "@tanstack/react-table";
6571
6564
  import { useVirtualizer } from "@tanstack/react-virtual";
6572
6565
  import { ChevronDown as ChevronDown2, ChevronRight } from "lucide-react";
@@ -6584,29 +6577,37 @@ function EmptyState({
6584
6577
  }) {
6585
6578
  const defaultTitle = isFiltered ? "No results found" : "No data available";
6586
6579
  const defaultDescription = isFiltered ? "Try adjusting your search or filter criteria" : "Get started by adding your first entry";
6587
- return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center p-8 text-center", children: [
6588
- /* @__PURE__ */ jsx9(
6589
- Icon,
6590
- {
6591
- role: "img",
6592
- "aria-hidden": "true",
6593
- className: "h-12 w-12 text-muted-foreground mb-4",
6594
- "data-testid": Icon === Database ? "lucide-database" : Icon === User ? "lucide-user" : "custom-icon"
6595
- }
6596
- ),
6597
- /* @__PURE__ */ jsx9("h3", { className: "text-lg font-semibold mb-2", children: title || defaultTitle }),
6598
- /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground mb-4 max-w-sm", children: description || defaultDescription }),
6599
- isFiltered && onClearFilters || action ? /* @__PURE__ */ jsxs6("div", { className: "flex gap-2", children: [
6600
- isFiltered && onClearFilters && /* @__PURE__ */ jsxs6(Button, { variant: "outline", onClick: onClearFilters, children: [
6601
- /* @__PURE__ */ jsx9(Search3, { className: "h-4 w-4 mr-2" }),
6602
- "Clear filters"
6603
- ] }),
6604
- action && /* @__PURE__ */ jsxs6(Button, { onClick: action.onClick, children: [
6605
- /* @__PURE__ */ jsx9(Plus2, { className: "h-4 w-4 mr-2" }),
6606
- action.label
6607
- ] })
6608
- ] }) : null
6609
- ] });
6580
+ return /* @__PURE__ */ jsxs6(
6581
+ "div",
6582
+ {
6583
+ role: "status",
6584
+ "aria-live": "polite",
6585
+ className: "flex flex-col items-center justify-center p-8 text-center",
6586
+ children: [
6587
+ /* @__PURE__ */ jsx9(
6588
+ Icon,
6589
+ {
6590
+ role: "img",
6591
+ "aria-hidden": "true",
6592
+ className: "h-12 w-12 text-muted-foreground mb-4",
6593
+ "data-testid": Icon === Database ? "lucide-database" : Icon === User ? "lucide-user" : "custom-icon"
6594
+ }
6595
+ ),
6596
+ /* @__PURE__ */ jsx9("h3", { className: "text-lg font-semibold mb-2", children: title || defaultTitle }),
6597
+ /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground mb-4 max-w-sm", children: description || defaultDescription }),
6598
+ isFiltered && onClearFilters || action ? /* @__PURE__ */ jsxs6("div", { className: "flex gap-2", children: [
6599
+ isFiltered && onClearFilters && /* @__PURE__ */ jsxs6(Button, { variant: "outline", onClick: onClearFilters, children: [
6600
+ /* @__PURE__ */ jsx9(Search3, { className: "h-4 w-4 mr-2" }),
6601
+ "Clear filters"
6602
+ ] }),
6603
+ action && /* @__PURE__ */ jsxs6(Button, { onClick: action.onClick, children: [
6604
+ /* @__PURE__ */ jsx9(Plus2, { className: "h-4 w-4 mr-2" }),
6605
+ action.label
6606
+ ] })
6607
+ ] }) : null
6608
+ ]
6609
+ }
6610
+ );
6610
6611
  }
6611
6612
 
6612
6613
  // src/components/DataTable/components/ColumnFilter.tsx
@@ -6771,22 +6772,144 @@ function FilterRow({ table, visibleColumns }) {
6771
6772
  }
6772
6773
 
6773
6774
  // src/components/DataTable/components/ActionButtons.tsx
6775
+ import React7, { useMemo as useMemo2 } from "react";
6774
6776
  import { MoreHorizontal } from "lucide-react";
6777
+
6778
+ // src/utils/logger.ts
6779
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
6780
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
6781
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
6782
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
6783
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
6784
+ return LogLevel2;
6785
+ })(LogLevel || {});
6786
+ var Logger = class {
6787
+ /**
6788
+ * Check if we're in development mode
6789
+ */
6790
+ static get isDevelopment() {
6791
+ return import.meta.env.MODE === "development";
6792
+ }
6793
+ /**
6794
+ * Configure the logger
6795
+ */
6796
+ static configure(config) {
6797
+ this.config = { ...this.config, ...config };
6798
+ }
6799
+ /**
6800
+ * Format a log message with optional timestamp and component
6801
+ */
6802
+ static formatMessage(level, component, message) {
6803
+ const parts = [];
6804
+ if (this.config.prefix) {
6805
+ parts.push(`[${this.config.prefix}]`);
6806
+ }
6807
+ if (this.config.includeTimestamp) {
6808
+ parts.push(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
6809
+ }
6810
+ parts.push(`[${LogLevel[level]}]`);
6811
+ if (this.config.includeComponent && component) {
6812
+ parts.push(`[${component}]`);
6813
+ }
6814
+ parts.push(message);
6815
+ return parts.join(" ");
6816
+ }
6817
+ /**
6818
+ * Check if a log level should be output
6819
+ */
6820
+ static shouldLog(level) {
6821
+ return this.isDevelopment && level >= this.config.level;
6822
+ }
6823
+ /**
6824
+ * Log debug information (development only)
6825
+ */
6826
+ static debug(component, message, ...args) {
6827
+ if (this.shouldLog(0 /* DEBUG */)) {
6828
+ try {
6829
+ console.debug(this.formatMessage(0 /* DEBUG */, component, message), ...args);
6830
+ } catch (e) {
6831
+ }
6832
+ }
6833
+ }
6834
+ /**
6835
+ * Log info information (development only)
6836
+ */
6837
+ static info(component, message, ...args) {
6838
+ if (this.shouldLog(1 /* INFO */)) {
6839
+ try {
6840
+ console.info(this.formatMessage(1 /* INFO */, component, message), ...args);
6841
+ } catch (e) {
6842
+ }
6843
+ }
6844
+ }
6845
+ /**
6846
+ * Log warning information (development only)
6847
+ */
6848
+ static warn(component, message, ...args) {
6849
+ if (this.shouldLog(2 /* WARN */)) {
6850
+ try {
6851
+ console.warn(this.formatMessage(2 /* WARN */, component, message), ...args);
6852
+ } catch (e) {
6853
+ }
6854
+ }
6855
+ }
6856
+ /**
6857
+ * Log error information (development only)
6858
+ */
6859
+ static error(component, message, ...args) {
6860
+ if (this.shouldLog(3 /* ERROR */)) {
6861
+ try {
6862
+ console.error(this.formatMessage(3 /* ERROR */, component, message), ...args);
6863
+ } catch (e) {
6864
+ }
6865
+ }
6866
+ }
6867
+ /**
6868
+ * Create a scoped logger for a specific component
6869
+ */
6870
+ static createScopedLogger(component) {
6871
+ return {
6872
+ debug: (message, ...args) => this.debug(component, message, ...args),
6873
+ info: (message, ...args) => this.info(component, message, ...args),
6874
+ warn: (message, ...args) => this.warn(component, message, ...args),
6875
+ error: (message, ...args) => this.error(component, message, ...args)
6876
+ };
6877
+ }
6878
+ };
6879
+ Logger.config = {
6880
+ level: 0 /* DEBUG */,
6881
+ includeTimestamp: false,
6882
+ includeComponent: true
6883
+ };
6884
+ function createLogger(component) {
6885
+ return Logger.createScopedLogger(component);
6886
+ }
6887
+
6888
+ // src/components/DataTable/components/ActionButtons.tsx
6775
6889
  import { Fragment, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
6776
- function ActionButtons({
6890
+ var evaluateCondition = (condition, row, defaultValue) => {
6891
+ if (typeof condition === "boolean") {
6892
+ return condition;
6893
+ }
6894
+ if (typeof condition === "function") {
6895
+ return condition(row);
6896
+ }
6897
+ return defaultValue;
6898
+ };
6899
+ function ActionButtonsComponent({
6777
6900
  row,
6778
6901
  actions = [],
6779
6902
  isEditing = false,
6780
6903
  isParent = false,
6781
6904
  hierarchical = false,
6782
- rbac,
6783
6905
  permissions
6784
6906
  }) {
6907
+ const logger = createLogger("ActionButtons");
6908
+ const rowData = row.original;
6785
6909
  if (actions.length === 0) {
6786
6910
  return null;
6787
6911
  }
6788
- const allActions = actions;
6789
- const visibleActions = allActions.filter((action) => {
6912
+ const visibleActions = useMemo2(() => actions.filter((action) => {
6790
6913
  if (action.hidden) return false;
6791
6914
  if (permissions) {
6792
6915
  if (action.label === "Edit" && !permissions.canUpdate.can) return false;
@@ -6796,51 +6919,54 @@ function ActionButtons({
6796
6919
  if (action.showForParent && !isParent) return false;
6797
6920
  if (action.showForChild && isParent) return false;
6798
6921
  }
6799
- if (typeof action.visible === "function") {
6800
- return action.visible(row);
6801
- } else if (typeof action.visible === "boolean") {
6802
- return action.visible;
6922
+ if (!evaluateCondition(action.visible, rowData, true)) {
6923
+ return false;
6803
6924
  }
6804
6925
  if (isEditing) {
6805
6926
  return action.showInEditMode !== false;
6806
- } else {
6807
- return action.hideInViewMode !== true && action.showInViewMode !== false;
6808
6927
  }
6809
- });
6928
+ return action.hideInViewMode !== true && action.showInViewMode !== false;
6929
+ }), [actions, permissions, hierarchical, isParent, rowData, isEditing]);
6810
6930
  if (visibleActions.length === 0) {
6811
6931
  return null;
6812
6932
  }
6933
+ const renderAction = (action, actionIndex) => {
6934
+ let Icon = action.icon;
6935
+ let label = action.label;
6936
+ if (hierarchical) {
6937
+ if (isParent && action.parentIcon) {
6938
+ Icon = action.parentIcon;
6939
+ } else if (!isParent && action.childIcon) {
6940
+ Icon = action.childIcon;
6941
+ }
6942
+ if (isParent && action.parentLabel) {
6943
+ label = action.parentLabel;
6944
+ } else if (!isParent && action.childLabel) {
6945
+ label = action.childLabel;
6946
+ }
6947
+ }
6948
+ return { Icon, label };
6949
+ };
6813
6950
  if (visibleActions.length <= 6) {
6814
6951
  return /* @__PURE__ */ jsx12(Fragment, { children: visibleActions.map((action, actionIndex) => {
6815
- let Icon = action.icon;
6816
- let label = action.label;
6817
- if (hierarchical) {
6818
- if (isParent && action.parentIcon) {
6819
- Icon = action.parentIcon;
6820
- } else if (!isParent && action.childIcon) {
6821
- Icon = action.childIcon;
6822
- }
6823
- if (isParent && action.parentLabel) {
6824
- label = action.parentLabel;
6825
- } else if (!isParent && action.childLabel) {
6826
- label = action.childLabel;
6827
- }
6828
- }
6829
- const isDisabled = typeof action.disabled === "function" ? action.disabled(row) : action.disabled;
6952
+ const { Icon, label } = renderAction(action, actionIndex);
6953
+ const isDisabled = evaluateCondition(action.disabled, rowData, false);
6830
6954
  return /* @__PURE__ */ jsx12(
6831
6955
  Button,
6832
6956
  {
6833
6957
  variant: action.variant === "destructive" ? "destructive" : "ghost",
6834
6958
  size: "sm",
6835
6959
  onClick: () => {
6836
- if (import.meta.env.MODE === "development") {
6837
- console.log("[ActionButtons] Action clicked:", {
6960
+ if (import.meta.env.MODE === "development" && !isDisabled) {
6961
+ logger.debug("Action clicked:", {
6838
6962
  actionLabel: action.label,
6839
- rowOriginal: row.original,
6963
+ rowOriginal: rowData,
6840
6964
  actionOnClick: typeof action.onClick
6841
6965
  });
6842
6966
  }
6843
- action.onClick(row.original);
6967
+ if (!isDisabled) {
6968
+ action.onClick(rowData);
6969
+ }
6844
6970
  },
6845
6971
  disabled: isDisabled,
6846
6972
  "aria-disabled": isDisabled,
@@ -6859,38 +6985,29 @@ function ActionButtons({
6859
6985
  /* @__PURE__ */ jsx12(MoreHorizontal, { className: "h-4 w-4" })
6860
6986
  ] }) }),
6861
6987
  /* @__PURE__ */ jsx12(SelectContent, { className: "!bg-main-50 border border-sec-200 shadow-lg z-[9999]", style: { backgroundColor: "white" }, children: visibleActions.map((action, actionIndex) => {
6862
- let Icon = action.icon;
6863
- let label = action.label;
6864
- if (hierarchical) {
6865
- if (isParent && action.parentIcon) {
6866
- Icon = action.parentIcon;
6867
- } else if (!isParent && action.childIcon) {
6868
- Icon = action.childIcon;
6869
- }
6870
- if (isParent && action.parentLabel) {
6871
- label = action.parentLabel;
6872
- } else if (!isParent && action.childLabel) {
6873
- label = action.childLabel;
6874
- }
6875
- }
6988
+ const { Icon, label } = renderAction(action, actionIndex);
6989
+ const isDisabled = evaluateCondition(action.disabled, rowData, false);
6876
6990
  return /* @__PURE__ */ jsxs8(
6877
6991
  SelectItem,
6878
6992
  {
6879
6993
  value: `action-${actionIndex}`,
6880
6994
  onClick: () => {
6881
- if (import.meta.env.MODE === "development") {
6882
- console.log("[ActionButtons] Dropdown action clicked:", {
6995
+ if (import.meta.env.MODE === "development" && !isDisabled) {
6996
+ logger.debug("Action clicked from dropdown:", {
6883
6997
  actionLabel: action.label,
6884
- rowOriginal: row.original,
6885
- actionOnClick: typeof action.onClick
6998
+ rowOriginal: rowData
6886
6999
  });
6887
7000
  }
6888
- action.onClick(row.original);
7001
+ if (!isDisabled) {
7002
+ action.onClick(rowData);
7003
+ }
6889
7004
  },
6890
- className: action.variant === "destructive" ? "text-acc-600" : "",
7005
+ "data-testid": action.testId,
7006
+ className: "flex items-center gap-2",
7007
+ "aria-disabled": isDisabled,
6891
7008
  children: [
6892
- Icon && /* @__PURE__ */ jsx12(Icon, { className: "mr-2 h-4 w-4" }),
6893
- label
7009
+ Icon && /* @__PURE__ */ jsx12(Icon, { className: "h-4 w-4" }),
7010
+ /* @__PURE__ */ jsx12("span", { children: label })
6894
7011
  ]
6895
7012
  },
6896
7013
  actionIndex
@@ -6898,31 +7015,26 @@ function ActionButtons({
6898
7015
  }) })
6899
7016
  ] });
6900
7017
  }
7018
+ var ActionButtons = React7.memo(ActionButtonsComponent);
6901
7019
 
6902
7020
  // src/components/DataTable/components/EditableRow.tsx
6903
7021
  import { flexRender } from "@tanstack/react-table";
6904
7022
  import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
6905
- var renderEditField = (column, value, onChange, editingData = {}, placeholder) => {
7023
+ var renderEditField = (column, value, onChange, editingData = {}) => {
6906
7024
  const columnDef = column.columnDef;
6907
7025
  if (columnDef.editable === false) {
6908
- return /* @__PURE__ */ jsx13("span", { className: "text-sm text-gray-600", children: value || "" });
7026
+ return /* @__PURE__ */ jsx13("span", { className: "text-sm text-gray-600", children: String(value ?? "") });
6909
7027
  }
6910
7028
  if (columnDef.fieldType === "select" && columnDef.fieldOptions) {
6911
- const editKey = columnDef.editAccessorKey || column.id;
6912
- const editValue = editingData[editKey] || value;
7029
+ const accessorKey = columnDef.editAccessorKey || column.id;
7030
+ const currentValue = editingData[accessorKey] ?? value ?? "";
6913
7031
  return /* @__PURE__ */ jsxs9(
6914
7032
  Select,
6915
7033
  {
6916
- value: String(editValue || ""),
6917
- onValueChange: (newValue) => {
6918
- if (columnDef.editAccessorKey) {
6919
- onChange({ [columnDef.editAccessorKey]: Number(newValue) });
6920
- } else {
6921
- onChange(newValue);
6922
- }
6923
- },
7034
+ value: String(currentValue),
7035
+ onValueChange: (newValue) => onChange({ [accessorKey]: newValue }),
6924
7036
  children: [
6925
- /* @__PURE__ */ jsx13(SelectTrigger, { className: "w-full h-7", children: /* @__PURE__ */ jsx13(SelectValue, { placeholder: placeholder || `Select ${column.id}` }) }),
7037
+ /* @__PURE__ */ jsx13(SelectTrigger, { className: "w-full h-7", children: /* @__PURE__ */ jsx13(SelectValue, { placeholder: `Select ${column.id}` }) }),
6926
7038
  /* @__PURE__ */ jsx13(SelectContent, { children: columnDef.fieldOptions.map((option) => /* @__PURE__ */ jsx13(SelectItem, { value: String(option.value), children: option.label }, option.value)) })
6927
7039
  ]
6928
7040
  }
@@ -6933,7 +7045,18 @@ var renderEditField = (column, value, onChange, editingData = {}, placeholder) =
6933
7045
  Input,
6934
7046
  {
6935
7047
  type: "date",
6936
- value: value || "",
7048
+ value: String(value ?? ""),
7049
+ onChange: (e) => onChange(e.target.value),
7050
+ className: "w-full h-7"
7051
+ }
7052
+ );
7053
+ }
7054
+ if (columnDef.fieldType === "number") {
7055
+ return /* @__PURE__ */ jsx13(
7056
+ Input,
7057
+ {
7058
+ type: "number",
7059
+ value: String(value ?? ""),
6937
7060
  onChange: (e) => onChange(e.target.value),
6938
7061
  className: "w-full h-7"
6939
7062
  }
@@ -6943,10 +7066,10 @@ var renderEditField = (column, value, onChange, editingData = {}, placeholder) =
6943
7066
  Input,
6944
7067
  {
6945
7068
  type: "text",
6946
- value: value || "",
7069
+ value: String(value ?? ""),
6947
7070
  onChange: (e) => onChange(e.target.value),
6948
7071
  className: "w-full h-7",
6949
- placeholder: placeholder || `Enter ${column.id}`
7072
+ placeholder: `Enter ${column.id}`
6950
7073
  }
6951
7074
  );
6952
7075
  };
@@ -6962,72 +7085,48 @@ function EditableRow({
6962
7085
  hierarchical = false
6963
7086
  }) {
6964
7087
  const rowId = getRowId ? getRowId(row.original, row.index) : String(row.id);
6965
- const convertedActions = actions.map((action) => ({
6966
- label: action.label,
6967
- onClick: action.onClick,
6968
- icon: action.icon,
6969
- variant: action.variant === "destructive" ? "destructive" : "default",
6970
- disabled: action.disabled ? ((row2) => action.disabled(row2)) : false,
6971
- testId: action.testId || `action-${action.label.toLowerCase().replace(/\s+/g, "-")}-${rowId}`,
6972
- visible: true
6973
- }));
6974
- return /* @__PURE__ */ jsxs9("tr", { children: [
6975
- row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx13("td", { children: /* @__PURE__ */ jsx13("div", { className: cell.column.columnDef.meta?.align === "right" ? "text-right" : "", children: cell.column.id !== "actions" ? (
6976
- // Check if column has a custom cell renderer - if so, use it in edit mode
6977
- cell.column.columnDef.cell ? flexRender(cell.column.columnDef.cell, {
6978
- ...cell.getContext(),
6979
- getIsEditing: () => true,
6980
- // Always true in edit mode
6981
- setValue: (value) => {
6982
- if (typeof value === "object" && value !== null) {
6983
- onEditingDataChange({ ...editingData, ...value });
6984
- } else {
6985
- onEditingDataChange({ ...editingData, [cell.column.id]: value });
7088
+ return /* @__PURE__ */ jsxs9(
7089
+ "tr",
7090
+ {
7091
+ role: "row",
7092
+ "aria-selected": typeof row.getIsSelected === "function" ? row.getIsSelected() ? "true" : "false" : "false",
7093
+ "aria-rowindex": row.index + 1,
7094
+ children: [
7095
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx13("td", { role: "cell", children: /* @__PURE__ */ jsx13("div", { className: cell.column.columnDef.meta?.align === "right" ? "text-right" : "", children: cell.column.id !== "actions" ? cell.column.columnDef.cell ? flexRender(cell.column.columnDef.cell, {
7096
+ ...cell.getContext(),
7097
+ getIsEditing: () => true,
7098
+ setValue: (value) => {
7099
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
7100
+ onEditingDataChange({ ...editingData, ...value });
7101
+ } else {
7102
+ onEditingDataChange({ ...editingData, [cell.column.id]: value });
7103
+ }
6986
7104
  }
6987
- }
6988
- }) : (
6989
- // Fall back to default edit field rendering when no custom cell renderer
6990
- renderEditField(cell.column, editingData[cell.column.id], (value) => {
6991
- if (typeof value === "object" && value !== null) {
7105
+ }) : renderEditField(cell.column, editingData[cell.column.id], (value) => {
7106
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
6992
7107
  onEditingDataChange({ ...editingData, ...value });
6993
7108
  } else {
6994
7109
  onEditingDataChange({ ...editingData, [cell.column.id]: value });
6995
7110
  }
6996
- }, editingData)
6997
- )
6998
- ) : /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
6999
- /* @__PURE__ */ jsx13(
7000
- Button,
7001
- {
7002
- onClick: onSave,
7003
- size: "sm",
7004
- variant: "default",
7005
- children: "Save"
7006
- }
7007
- ),
7008
- /* @__PURE__ */ jsx13(
7009
- Button,
7010
- {
7011
- onClick: onCancel,
7012
- size: "sm",
7013
- variant: "outline",
7014
- children: "Cancel"
7015
- }
7016
- )
7017
- ] }) }) }, cell.id)),
7018
- actions.length > 0 && /* @__PURE__ */ jsx13("td", { children: /* @__PURE__ */ jsx13(
7019
- ActionButtons,
7020
- {
7021
- row: row.original,
7022
- rowId,
7023
- index: row.index,
7024
- actions: convertedActions,
7025
- isEditing: true,
7026
- isParent,
7027
- hierarchical
7028
- }
7029
- ) })
7030
- ] });
7111
+ }, editingData) : /* @__PURE__ */ jsxs9("div", { className: "flex gap-1", children: [
7112
+ /* @__PURE__ */ jsx13(Button, { onClick: onSave, size: "sm", variant: "default", children: "Save" }),
7113
+ /* @__PURE__ */ jsx13(Button, { onClick: onCancel, size: "sm", variant: "outline", children: "Cancel" })
7114
+ ] }) }) }, cell.id)),
7115
+ actions.length > 0 && /* @__PURE__ */ jsx13("td", { children: /* @__PURE__ */ jsx13(
7116
+ ActionButtons,
7117
+ {
7118
+ row,
7119
+ rowId,
7120
+ index: row.index,
7121
+ actions,
7122
+ isEditing: true,
7123
+ isParent,
7124
+ hierarchical
7125
+ }
7126
+ ) })
7127
+ ]
7128
+ }
7129
+ );
7031
7130
  }
7032
7131
 
7033
7132
  // src/components/DataTable/utils/hierarchicalUtils.ts
@@ -7214,10 +7313,12 @@ function getRowIdSafe(row, index, getRowId) {
7214
7313
  return String(customId);
7215
7314
  }
7216
7315
  }
7217
- if (row.id !== void 0 && row.id !== null) {
7316
+ if ("id" in row && row.id !== void 0 && row.id !== null) {
7218
7317
  return String(row.id);
7219
7318
  }
7220
- return String(index);
7319
+ throw new Error(
7320
+ '[DataTable] Unable to determine a stable row id. Provide a getRowId prop or ensure each record exposes an "id" field.'
7321
+ );
7221
7322
  }
7222
7323
  function hasValidRowId(row, getRowId) {
7223
7324
  try {
@@ -7234,11 +7335,11 @@ var VIRTUALIZATION_THRESHOLD = 1e3;
7234
7335
  var renderEditField2 = (column, value, onChange, editingData = {}, placeholder) => {
7235
7336
  const columnDef = column.columnDef;
7236
7337
  if (columnDef.editable === false) {
7237
- return /* @__PURE__ */ jsx14("span", { className: "text-sm text-gray-600", children: String(value || "") });
7338
+ return /* @__PURE__ */ jsx14("span", { className: "text-sm text-gray-600", children: String(value ?? "") });
7238
7339
  }
7239
7340
  if (columnDef.fieldType === "select" && columnDef.fieldOptions) {
7240
7341
  const accessorKey = columnDef.editAccessorKey || column.id;
7241
- const currentValue = editingData[accessorKey] || value || "";
7342
+ const currentValue = editingData[accessorKey] ?? value ?? "";
7242
7343
  return /* @__PURE__ */ jsxs10(
7243
7344
  Select,
7244
7345
  {
@@ -7256,7 +7357,7 @@ var renderEditField2 = (column, value, onChange, editingData = {}, placeholder)
7256
7357
  Input,
7257
7358
  {
7258
7359
  type: "number",
7259
- value: String(value || ""),
7360
+ value: String(value ?? ""),
7260
7361
  onChange: (e) => onChange(e.target.value),
7261
7362
  placeholder: placeholder || `Enter ${columnDef.header || column.id}...`,
7262
7363
  className: "h-8"
@@ -7268,7 +7369,7 @@ var renderEditField2 = (column, value, onChange, editingData = {}, placeholder)
7268
7369
  Input,
7269
7370
  {
7270
7371
  type: "date",
7271
- value: String(value || ""),
7372
+ value: String(value ?? ""),
7272
7373
  onChange: (e) => onChange(e.target.value),
7273
7374
  className: "h-8"
7274
7375
  }
@@ -7278,14 +7379,14 @@ var renderEditField2 = (column, value, onChange, editingData = {}, placeholder)
7278
7379
  Input,
7279
7380
  {
7280
7381
  type: "text",
7281
- value: String(value || ""),
7382
+ value: String(value ?? ""),
7282
7383
  onChange: (e) => onChange(e.target.value),
7283
7384
  placeholder: placeholder || `Enter ${columnDef.header || column.id}...`,
7284
7385
  className: "h-8"
7285
7386
  }
7286
7387
  );
7287
7388
  };
7288
- var RowComponent = React7.memo(({
7389
+ var RowComponent = React8.memo(({
7289
7390
  row,
7290
7391
  style,
7291
7392
  isEditing,
@@ -7340,7 +7441,7 @@ var RowComponent = React7.memo(({
7340
7441
  const groupValue = row.getValue(grouping[0]);
7341
7442
  const subRowsCount = row.subRows?.length || 0;
7342
7443
  const isExpanded = row.getIsExpanded();
7343
- return /* @__PURE__ */ jsxs10(React7.Fragment, { children: [
7444
+ return /* @__PURE__ */ jsxs10(React8.Fragment, { children: [
7344
7445
  /* @__PURE__ */ jsx14("tr", { className: "bg-sec-50 hover:bg-sec-100", style, children: /* @__PURE__ */ jsxs10(
7345
7446
  "td",
7346
7447
  {
@@ -7377,9 +7478,9 @@ var RowComponent = React7.memo(({
7377
7478
  {
7378
7479
  className: getTableCellClasses({
7379
7480
  isCompact: true,
7380
- className: "px-3 py-2 pl-8 whitespace-normal break-words"
7481
+ className: `px-3 py-2 pl-8 ${cell.column.id === "actions" ? "whitespace-nowrap" : "whitespace-normal break-words"} ${cell.column.columnDef.meta?.align === "right" ? "text-right" : ""}`
7381
7482
  }),
7382
- children: /* @__PURE__ */ jsx14("div", { className: `${cell.column.columnDef.meta?.align === "right" ? "text-right" : ""}`, children: isSubRowEditing && cell.column.id !== "actions" ? (
7483
+ children: isSubRowEditing && cell.column.id !== "actions" ? (
7383
7484
  // Check if column has a custom cell renderer - if so, use it in edit mode
7384
7485
  cell.column.columnDef.cell ? flexRender2(cell.column.columnDef.cell, {
7385
7486
  ...cell.getContext(),
@@ -7429,7 +7530,7 @@ var RowComponent = React7.memo(({
7429
7530
  rowId: subRowId,
7430
7531
  isExpanded: false,
7431
7532
  hasChildren: false
7432
- }) })
7533
+ })
7433
7534
  },
7434
7535
  cell.id
7435
7536
  )) }, subRow.id);
@@ -7448,7 +7549,7 @@ var RowComponent = React7.memo(({
7448
7549
  onEditingDataChange,
7449
7550
  onSave: onSaveEditing,
7450
7551
  onCancel: onCancelEditing,
7451
- actions: (actions || []).filter((a) => !a.disabled),
7552
+ actions: actions ?? [],
7452
7553
  getRowId,
7453
7554
  isParent,
7454
7555
  hierarchical: !!hierarchical
@@ -7464,24 +7565,26 @@ var RowComponent = React7.memo(({
7464
7565
  "tr",
7465
7566
  {
7466
7567
  ref: rowRef,
7568
+ role: "row",
7467
7569
  style: {
7468
7570
  ...style,
7469
7571
  ...isChild && indentation > 0 ? { paddingLeft: `${indentation}px` } : {}
7470
7572
  },
7471
7573
  className: rowClassName,
7574
+ "aria-selected": typeof row.getIsSelected === "function" ? row.getIsSelected() ? "true" : "false" : "false",
7472
7575
  children: visibleCells.map((cell, cellIndex) => {
7473
7576
  const isFirstCell = cellIndex === 0;
7474
7577
  const shouldShowExpansionButton = isHierarchical && isParent && isFirstCell && hierarchical?.state;
7475
7578
  const isExpanded = shouldShowExpansionButton ? hierarchical?.state?.isExpanded(rowId) : false;
7476
7579
  const hasChildren = shouldShowExpansionButton ? hierarchical?.state?.hasChildren(rowId) : false;
7477
- return /* @__PURE__ */ jsx14(
7580
+ return /* @__PURE__ */ jsxs10(
7478
7581
  "td",
7479
7582
  {
7480
7583
  className: getTableCellClasses({
7481
7584
  isCompact: true,
7482
- className: "px-3 py-2 whitespace-normal break-words"
7585
+ className: `px-3 py-2 ${cell.column.id === "actions" ? "whitespace-nowrap" : "whitespace-normal break-words"} ${cell.column.columnDef.meta?.align === "right" ? "text-right" : ""}`
7483
7586
  }),
7484
- children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
7587
+ children: [
7485
7588
  shouldShowExpansionButton && hasChildren && /* @__PURE__ */ jsx14(
7486
7589
  Button,
7487
7590
  {
@@ -7494,7 +7597,7 @@ var RowComponent = React7.memo(({
7494
7597
  children: isExpanded ? /* @__PURE__ */ jsx14(ChevronDown2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx14(ChevronRight, { className: "h-4 w-4" })
7495
7598
  }
7496
7599
  ),
7497
- /* @__PURE__ */ jsx14("div", { className: `flex-1 ${cell.column.columnDef.meta?.align === "right" ? "text-right" : ""}`, children: cell.column.id === "actions" ? /* @__PURE__ */ jsx14(
7600
+ cell.column.id === "actions" ? /* @__PURE__ */ jsx14(
7498
7601
  ActionButtons,
7499
7602
  {
7500
7603
  row,
@@ -7514,8 +7617,8 @@ var RowComponent = React7.memo(({
7514
7617
  rowId,
7515
7618
  isExpanded,
7516
7619
  hasChildren
7517
- }) })
7518
- ] })
7620
+ })
7621
+ ]
7519
7622
  },
7520
7623
  cell.id
7521
7624
  );
@@ -7662,7 +7765,7 @@ function UnifiedTableBody({
7662
7765
  className: "px-3 py-2"
7663
7766
  }),
7664
7767
  children: renderEditField2(header.column, creationData[header.column.id], (value) => {
7665
- if (typeof value === "object" && value !== null) {
7768
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
7666
7769
  onCreationDataChange({ ...creationData, ...value });
7667
7770
  } else {
7668
7771
  onCreationDataChange({ ...creationData, [header.column.id]: value });
@@ -7713,7 +7816,7 @@ function UnifiedTableBody({
7713
7816
  }
7714
7817
 
7715
7818
  // src/components/DataTable/components/PaginationControls.tsx
7716
- import React8 from "react";
7819
+ import React9 from "react";
7717
7820
  import {
7718
7821
  ChevronLeft,
7719
7822
  ChevronRight as ChevronRight2,
@@ -7723,6 +7826,161 @@ import {
7723
7826
  Database as Database2,
7724
7827
  Zap
7725
7828
  } from "lucide-react";
7829
+
7830
+ // src/components/DataTable/utils/paginationUtils.ts
7831
+ function getPaginationBinding(config) {
7832
+ const { mode, table, serverData, totalCount, onPageChange, onPageSizeChange } = config;
7833
+ const state = calculatePaginationState(config);
7834
+ const actions = {
7835
+ goToFirstPage: () => {
7836
+ if (mode === "server") {
7837
+ onPageChange?.(0);
7838
+ } else if (table) {
7839
+ table.setPageIndex(0);
7840
+ }
7841
+ },
7842
+ goToPreviousPage: () => {
7843
+ const targetPage = Math.max(0, state.currentPageIndex - 1);
7844
+ if (mode === "server") {
7845
+ onPageChange?.(targetPage);
7846
+ } else if (table) {
7847
+ table.previousPage();
7848
+ }
7849
+ },
7850
+ goToNextPage: () => {
7851
+ const targetPage = Math.min(state.pageCount - 1, state.currentPageIndex + 1);
7852
+ if (mode === "server") {
7853
+ onPageChange?.(targetPage);
7854
+ } else if (table) {
7855
+ table.nextPage();
7856
+ }
7857
+ },
7858
+ goToLastPage: () => {
7859
+ const lastPage = state.pageCount - 1;
7860
+ if (mode === "server") {
7861
+ onPageChange?.(lastPage);
7862
+ } else if (table) {
7863
+ table.setPageIndex(lastPage);
7864
+ }
7865
+ },
7866
+ goToPage: (pageIndex) => {
7867
+ const clampedIndex = Math.max(0, Math.min(state.pageCount - 1, pageIndex));
7868
+ if (mode === "server") {
7869
+ onPageChange?.(clampedIndex);
7870
+ } else if (table) {
7871
+ table.setPageIndex(clampedIndex);
7872
+ }
7873
+ },
7874
+ setPageSize: (pageSize) => {
7875
+ if (mode === "server") {
7876
+ onPageSizeChange?.(pageSize);
7877
+ } else if (table) {
7878
+ table.setPageSize(pageSize);
7879
+ }
7880
+ }
7881
+ };
7882
+ return { state, actions };
7883
+ }
7884
+ function calculatePaginationState(config) {
7885
+ const { mode, table, serverData, totalCount } = config;
7886
+ if (mode === "server" && serverData) {
7887
+ const startRow = serverData.pageIndex * serverData.pageSize + 1;
7888
+ const endRow = Math.min((serverData.pageIndex + 1) * serverData.pageSize, serverData.totalCount);
7889
+ return {
7890
+ currentPageIndex: serverData.pageIndex,
7891
+ currentPageSize: serverData.pageSize,
7892
+ pageCount: serverData.pageCount,
7893
+ totalRows: serverData.totalCount,
7894
+ canPreviousPage: serverData.hasPreviousPage,
7895
+ canNextPage: serverData.hasNextPage,
7896
+ startRow,
7897
+ endRow
7898
+ };
7899
+ }
7900
+ if (table) {
7901
+ const paginationState = table.getState().pagination;
7902
+ const rowCount = totalCount ?? table.getRowCount();
7903
+ const pageCount = Math.ceil(rowCount / paginationState.pageSize);
7904
+ const startRow = paginationState.pageIndex * paginationState.pageSize + 1;
7905
+ const endRow = Math.min((paginationState.pageIndex + 1) * paginationState.pageSize, rowCount);
7906
+ return {
7907
+ currentPageIndex: paginationState.pageIndex,
7908
+ currentPageSize: paginationState.pageSize,
7909
+ pageCount,
7910
+ totalRows: rowCount,
7911
+ canPreviousPage: table.getCanPreviousPage(),
7912
+ canNextPage: table.getCanNextPage(),
7913
+ startRow,
7914
+ endRow
7915
+ };
7916
+ }
7917
+ return {
7918
+ currentPageIndex: 0,
7919
+ currentPageSize: 10,
7920
+ pageCount: 1,
7921
+ totalRows: 0,
7922
+ canPreviousPage: false,
7923
+ canNextPage: false,
7924
+ startRow: 0,
7925
+ endRow: 0
7926
+ };
7927
+ }
7928
+ function validatePaginationConfig(config) {
7929
+ const { mode, table, serverData, onPageChange, onPageSizeChange } = config;
7930
+ const logger = createLogger("PaginationUtils");
7931
+ let isValid = true;
7932
+ if (mode === "server") {
7933
+ if (!serverData) {
7934
+ logger.warn("Server mode requires serverData");
7935
+ isValid = false;
7936
+ }
7937
+ if (!onPageChange) {
7938
+ logger.warn("Server mode requires onPageChange callback");
7939
+ isValid = false;
7940
+ }
7941
+ if (!onPageSizeChange) {
7942
+ logger.warn("Server mode requires onPageSizeChange callback");
7943
+ isValid = false;
7944
+ }
7945
+ }
7946
+ if ((mode === "client" || mode === "hybrid") && !table) {
7947
+ logger.warn(`${mode} mode requires table instance`);
7948
+ isValid = false;
7949
+ }
7950
+ if (mode === "hybrid") {
7951
+ if (!onPageChange) {
7952
+ logger.warn("Hybrid mode requires onPageChange callback for server pagination");
7953
+ isValid = false;
7954
+ }
7955
+ }
7956
+ return isValid;
7957
+ }
7958
+ function getPageSizeOptions(mode, defaultOptions = [10, 20, 30, 40, 50]) {
7959
+ switch (mode) {
7960
+ case "server":
7961
+ return defaultOptions.filter((size) => size <= 250);
7962
+ case "hybrid":
7963
+ return defaultOptions.filter((size) => size >= 50);
7964
+ default:
7965
+ return defaultOptions;
7966
+ }
7967
+ }
7968
+ function calculateOptimalPageSize(dataSize, mode, availableOptions = [10, 20, 30, 40, 50]) {
7969
+ const filteredOptions = getPageSizeOptions(mode, availableOptions);
7970
+ if (mode === "client" && dataSize <= 100) {
7971
+ return Math.max(dataSize, filteredOptions[0]);
7972
+ }
7973
+ if (mode === "server" && dataSize > 1e4) {
7974
+ return Math.min(...filteredOptions);
7975
+ }
7976
+ if (mode === "hybrid") {
7977
+ const sortedOptions = [...filteredOptions].sort((a, b) => a - b);
7978
+ return sortedOptions[0] || 50;
7979
+ }
7980
+ return filteredOptions[0] || 10;
7981
+ }
7982
+
7983
+ // src/components/DataTable/components/PaginationControls.tsx
7726
7984
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
7727
7985
  function PaginationControls({
7728
7986
  table,
@@ -7735,85 +7993,32 @@ function PaginationControls({
7735
7993
  showPerformanceInfo = false,
7736
7994
  totalCount
7737
7995
  }) {
7738
- const getPaginationState = () => {
7739
- if (paginationMode === "server" && serverData) {
7740
- return {
7741
- currentPageSize: serverData.pageSize,
7742
- currentPageIndex: serverData.pageIndex,
7743
- pageCount: serverData.pageCount,
7744
- totalRows: serverData.totalCount,
7745
- canPreviousPage: serverData.hasPreviousPage,
7746
- canNextPage: serverData.hasNextPage
7747
- };
7748
- }
7749
- const state = table.getState().pagination;
7750
- return {
7751
- currentPageSize: state.pageSize,
7752
- currentPageIndex: state.pageIndex,
7753
- pageCount: table.getPageCount(),
7754
- totalRows: totalCount ?? table.getRowCount(),
7755
- canPreviousPage: table.getCanPreviousPage(),
7756
- canNextPage: table.getCanNextPage()
7757
- };
7758
- };
7996
+ const pagination = getPaginationBinding({
7997
+ mode: paginationMode,
7998
+ table,
7999
+ serverData,
8000
+ totalCount,
8001
+ onPageChange,
8002
+ onPageSizeChange
8003
+ });
7759
8004
  const {
7760
8005
  currentPageSize,
7761
8006
  currentPageIndex,
7762
8007
  pageCount,
7763
8008
  totalRows,
7764
8009
  canPreviousPage,
7765
- canNextPage
7766
- } = getPaginationState();
7767
- const handlePageSizeChange = (newPageSize) => {
7768
- if (paginationMode === "server") {
7769
- onPageSizeChange?.(newPageSize);
7770
- } else {
7771
- table.setPageSize(newPageSize);
7772
- }
7773
- };
7774
- const handleFirstPage = () => {
7775
- if (paginationMode === "server") {
7776
- onPageChange?.(0);
7777
- } else {
7778
- table.setPageIndex(0);
7779
- }
7780
- };
7781
- const handlePreviousPage = () => {
7782
- if (paginationMode === "server") {
7783
- onPageChange?.(Math.max(0, currentPageIndex - 1));
7784
- } else {
7785
- table.previousPage();
7786
- }
7787
- };
7788
- const handleNextPage = () => {
7789
- if (paginationMode === "server") {
7790
- onPageChange?.(Math.min(pageCount - 1, currentPageIndex + 1));
7791
- } else {
7792
- table.nextPage();
7793
- }
7794
- };
7795
- const handleLastPage = () => {
7796
- if (paginationMode === "server") {
7797
- onPageChange?.(pageCount - 1);
7798
- } else {
7799
- table.setPageIndex(pageCount - 1);
7800
- }
7801
- };
7802
- const startRow = currentPageIndex * currentPageSize + 1;
7803
- const endRow = Math.min((currentPageIndex + 1) * currentPageSize, totalRows);
7804
- const getPageSizeOptions = () => {
7805
- switch (paginationMode) {
7806
- case "server":
7807
- return pageSizeOptions.filter((size) => size <= 250);
7808
- // Limit server-side page sizes
7809
- case "hybrid":
7810
- return pageSizeOptions.filter((size) => size >= 50);
7811
- // Hybrid mode prefers larger pages
7812
- default:
7813
- return pageSizeOptions;
7814
- }
7815
- };
7816
- const availablePageSizes = getPageSizeOptions();
8010
+ canNextPage,
8011
+ startRow,
8012
+ endRow
8013
+ } = pagination.state;
8014
+ const {
8015
+ goToFirstPage,
8016
+ goToPreviousPage,
8017
+ goToNextPage,
8018
+ goToLastPage,
8019
+ setPageSize
8020
+ } = pagination.actions;
8021
+ const availablePageSizes = getPageSizeOptions(paginationMode, pageSizeOptions);
7817
8022
  const getModeIcon = () => {
7818
8023
  switch (paginationMode) {
7819
8024
  case "server":
@@ -7846,7 +8051,7 @@ function PaginationControls({
7846
8051
  {
7847
8052
  value: currentPageSize?.toString() || "10",
7848
8053
  selectedText: currentPageSize?.toString() || "10",
7849
- onValueChange: (value) => handlePageSizeChange(Number(value)),
8054
+ onValueChange: (value) => setPageSize(Number(value)),
7850
8055
  disabled: isLoading,
7851
8056
  className: "w-36 h-8",
7852
8057
  children: [
@@ -7860,7 +8065,7 @@ function PaginationControls({
7860
8065
  children: /* @__PURE__ */ jsx15(SelectValue, {})
7861
8066
  }
7862
8067
  ),
7863
- /* @__PURE__ */ jsx15(SelectContent, { children: pageSizeOptions.map((pageSize) => /* @__PURE__ */ jsx15(SelectItem, { value: pageSize?.toString() || "10", children: pageSize }, pageSize)) })
8068
+ /* @__PURE__ */ jsx15(SelectContent, { children: availablePageSizes.map((pageSize) => /* @__PURE__ */ jsx15(SelectItem, { value: pageSize?.toString() || "10", children: pageSize }, pageSize)) })
7864
8069
  ]
7865
8070
  }
7866
8071
  ),
@@ -7880,7 +8085,7 @@ function PaginationControls({
7880
8085
  variant: "outline",
7881
8086
  size: "sm",
7882
8087
  className: "h-8 w-8 p-0",
7883
- onClick: handleFirstPage,
8088
+ onClick: goToFirstPage,
7884
8089
  disabled: !canPreviousPage || isLoading,
7885
8090
  "aria-label": "Go to first page",
7886
8091
  tabIndex: 0,
@@ -7893,7 +8098,7 @@ function PaginationControls({
7893
8098
  variant: "outline",
7894
8099
  size: "sm",
7895
8100
  className: "h-8 w-8 p-0",
7896
- onClick: handlePreviousPage,
8101
+ onClick: goToPreviousPage,
7897
8102
  disabled: !canPreviousPage || isLoading,
7898
8103
  "aria-label": "Go to previous page",
7899
8104
  tabIndex: 0,
@@ -7906,7 +8111,7 @@ function PaginationControls({
7906
8111
  variant: "outline",
7907
8112
  size: "sm",
7908
8113
  className: "h-8 w-8 p-0",
7909
- onClick: handleNextPage,
8114
+ onClick: goToNextPage,
7910
8115
  disabled: !canNextPage || isLoading,
7911
8116
  "aria-label": "Go to next page",
7912
8117
  tabIndex: 0,
@@ -7919,7 +8124,7 @@ function PaginationControls({
7919
8124
  variant: "outline",
7920
8125
  size: "sm",
7921
8126
  className: "h-8 w-8 p-0",
7922
- onClick: handleLastPage,
8127
+ onClick: goToLastPage,
7923
8128
  disabled: !canNextPage || isLoading,
7924
8129
  "aria-label": "Go to last page",
7925
8130
  tabIndex: 0,
@@ -7934,24 +8139,23 @@ function EnhancedPaginationControls({
7934
8139
  showJumpToPage = false,
7935
8140
  ...props
7936
8141
  }) {
7937
- const [jumpToPage, setJumpToPage] = React8.useState("");
7938
- const { table, paginationMode = "client", serverData, onPageChange } = props;
7939
- const { pageCount } = (() => {
7940
- if (paginationMode === "server" && serverData) {
7941
- return { pageCount: serverData.pageCount };
7942
- }
7943
- return { pageCount: table.getPageCount() };
7944
- })();
8142
+ const [jumpToPage, setJumpToPage] = React9.useState("");
8143
+ const { table, paginationMode = "client", serverData, onPageChange, totalCount } = props;
8144
+ const pagination = getPaginationBinding({
8145
+ mode: paginationMode,
8146
+ table,
8147
+ serverData,
8148
+ totalCount,
8149
+ onPageChange,
8150
+ onPageSizeChange: props.onPageSizeChange
8151
+ });
8152
+ const { pageCount } = pagination.state;
7945
8153
  const handleJumpToPage = (e) => {
7946
8154
  e.preventDefault();
7947
8155
  const pageNumber = parseInt(jumpToPage, 10);
7948
8156
  if (pageNumber >= 1 && pageNumber <= pageCount) {
7949
8157
  const pageIndex = pageNumber - 1;
7950
- if (paginationMode === "server") {
7951
- onPageChange?.(pageIndex);
7952
- } else {
7953
- table.setPageIndex(pageIndex);
7954
- }
8158
+ pagination.actions.goToPage(pageIndex);
7955
8159
  setJumpToPage("");
7956
8160
  }
7957
8161
  };
@@ -7985,11 +8189,14 @@ function LoadingState() {
7985
8189
  ] }) });
7986
8190
  }
7987
8191
 
8192
+ // src/components/DataTable/components/DataTableModals.tsx
8193
+ import { useEffect as useEffect6 } from "react";
8194
+
7988
8195
  // src/components/DataTable/components/ImportModal.tsx
7989
8196
  import { useState as useState4, useRef as useRef4, useEffect as useEffect5 } from "react";
7990
8197
 
7991
8198
  // src/components/Dialog/Dialog.tsx
7992
- import * as React9 from "react";
8199
+ import * as React10 from "react";
7993
8200
  import * as DialogPrimitive from "@radix-ui/react-dialog";
7994
8201
  import { X as X3 } from "lucide-react";
7995
8202
 
@@ -8065,7 +8272,7 @@ var Dialog = DialogPrimitive.Root;
8065
8272
  var DialogTrigger = DialogPrimitive.Trigger;
8066
8273
  var DialogPortal = DialogPrimitive.Portal;
8067
8274
  var DialogClose = DialogPrimitive.Close;
8068
- var DialogOverlay = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
8275
+ var DialogOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
8069
8276
  DialogPrimitive.Overlay,
8070
8277
  {
8071
8278
  ref,
@@ -8142,7 +8349,7 @@ var useSmartDimensions = ({
8142
8349
  }
8143
8350
  return result;
8144
8351
  };
8145
- var DialogContent = React9.forwardRef(({
8352
+ var DialogContent = React10.forwardRef(({
8146
8353
  className,
8147
8354
  children,
8148
8355
  size = "md",
@@ -8169,17 +8376,17 @@ var DialogContent = React9.forwardRef(({
8169
8376
  minWidth,
8170
8377
  enableScrolling
8171
8378
  });
8172
- const handleEscapeKeyDown = React9.useCallback((event) => {
8379
+ const handleEscapeKeyDown = React10.useCallback((event) => {
8173
8380
  if (preventCloseOnEscape) {
8174
8381
  event.preventDefault();
8175
8382
  }
8176
8383
  }, [preventCloseOnEscape]);
8177
- const handlePointerDownOutside = React9.useCallback((event) => {
8384
+ const handlePointerDownOutside = React10.useCallback((event) => {
8178
8385
  if (preventCloseOnOutsideClick) {
8179
8386
  event.preventDefault();
8180
8387
  }
8181
8388
  }, [preventCloseOnOutsideClick]);
8182
- const mergedStyle = React9.useMemo(() => {
8389
+ const mergedStyle = React10.useMemo(() => {
8183
8390
  if (Object.keys(smartDimensions).length === 0) {
8184
8391
  return style;
8185
8392
  }
@@ -8257,13 +8464,13 @@ var DialogBody = ({
8257
8464
  children,
8258
8465
  ...props
8259
8466
  }) => {
8260
- const mergedStyle = React9.useMemo(() => {
8467
+ const mergedStyle = React10.useMemo(() => {
8261
8468
  return {
8262
8469
  ...maxHeight && { maxHeight },
8263
8470
  ...style
8264
8471
  };
8265
8472
  }, [maxHeight, style]);
8266
- const processedHtmlContent = React9.useMemo(() => {
8473
+ const processedHtmlContent = React10.useMemo(() => {
8267
8474
  if (!htmlContent || !allowHtml) {
8268
8475
  return null;
8269
8476
  }
@@ -8325,8 +8532,8 @@ var DialogFooter = ({
8325
8532
  }
8326
8533
  );
8327
8534
  DialogFooter.displayName = "DialogFooter";
8328
- var DialogTitle = React9.forwardRef(({ className, htmlContent, allowHtml = true, children, ...props }, ref) => {
8329
- const processedHtmlContent = React9.useMemo(() => {
8535
+ var DialogTitle = React10.forwardRef(({ className, htmlContent, allowHtml = true, children, ...props }, ref) => {
8536
+ const processedHtmlContent = React10.useMemo(() => {
8330
8537
  if (!htmlContent || !allowHtml) {
8331
8538
  return null;
8332
8539
  }
@@ -8350,8 +8557,8 @@ var DialogTitle = React9.forwardRef(({ className, htmlContent, allowHtml = true,
8350
8557
  );
8351
8558
  });
8352
8559
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
8353
- var DialogDescription = React9.forwardRef(({ className, htmlContent, allowHtml = true, children, ...props }, ref) => {
8354
- const processedHtmlContent = React9.useMemo(() => {
8560
+ var DialogDescription = React10.forwardRef(({ className, htmlContent, allowHtml = true, children, ...props }, ref) => {
8561
+ const processedHtmlContent = React10.useMemo(() => {
8355
8562
  if (!htmlContent || !allowHtml) {
8356
8563
  return null;
8357
8564
  }
@@ -8377,11 +8584,13 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
8377
8584
  import { Upload as Upload2, FileText, AlertCircle } from "lucide-react";
8378
8585
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
8379
8586
  function ImportModal({ isOpen, onClose, onImport, config = {} }) {
8587
+ const logger = createLogger("ImportModal");
8380
8588
  const [file, setFile] = useState4(null);
8381
8589
  const [isProcessing, setIsProcessing] = useState4(false);
8382
8590
  const [error, setError] = useState4(null);
8383
8591
  const [previewData, setPreviewData] = useState4(null);
8384
8592
  const [totalCount, setTotalCount] = useState4(0);
8593
+ const [validationErrors, setValidationErrors] = useState4([]);
8385
8594
  const fileInputRef = useRef4(null);
8386
8595
  const isMountedRef = useRef4(true);
8387
8596
  useEffect5(() => {
@@ -8400,34 +8609,11 @@ function ImportModal({ isOpen, onClose, onImport, config = {} }) {
8400
8609
  previewHeaderText = "Preview (first 5 rows)",
8401
8610
  totalRowsText = "Total rows to import: {count}"
8402
8611
  } = config;
8403
- const handleFileSelect = async (event) => {
8404
- const selectedFile = event.target.files?.[0];
8405
- console.log("\u{1F4C1} File selected:", selectedFile?.name);
8406
- if (selectedFile) {
8407
- setFile(selectedFile);
8408
- setError(null);
8409
- try {
8410
- const text = await selectedFile.text();
8411
- console.log("\u{1F4C4} File content length:", text.length);
8412
- const data = processCSV(text);
8413
- console.log("\u{1F4CA} Parsed CSV data:", data.length, "rows");
8414
- console.log("\u{1F440} Setting preview data:", data.slice(0, 5));
8415
- setPreviewData(data.slice(0, 5));
8416
- setTotalCount(data.length);
8417
- console.log("\u{1F440} Preview data state should be updated");
8418
- } catch (err) {
8419
- console.error("\u274C CSV parsing error:", err);
8420
- setError(err instanceof Error ? err.message : "Failed to preview file");
8421
- setPreviewData(null);
8422
- setTotalCount(0);
8423
- }
8424
- }
8425
- };
8426
8612
  const processCSV = (csvText) => {
8427
- console.log("\u{1F4C4} Raw CSV text:", csvText.substring(0, 200) + "...");
8613
+ logger.debug("Raw CSV text:", csvText.substring(0, 200) + "...");
8428
8614
  const lines = csvText.split("\n").filter((line) => line.trim());
8429
- console.log("\u{1F4C4} CSV lines count:", lines.length);
8430
- console.log("\u{1F4C4} First few lines:", lines.slice(0, 3));
8615
+ logger.debug("CSV lines count:", lines.length);
8616
+ logger.debug("First few lines:", lines.slice(0, 3));
8431
8617
  if (lines.length < 2) {
8432
8618
  throw new Error("CSV must have at least a header row and one data row");
8433
8619
  }
@@ -8450,17 +8636,17 @@ function ImportModal({ isOpen, onClose, onImport, config = {} }) {
8450
8636
  return result;
8451
8637
  };
8452
8638
  const headers = parseCSVLine(lines[0]).map((h) => h.replace(/"/g, "").trim());
8453
- console.log("\u{1F4C4} Parsed headers:", headers);
8639
+ logger.debug("Parsed headers:", headers);
8454
8640
  const data = lines.slice(1).map((line, index) => {
8455
8641
  const values = parseCSVLine(line).map((v) => v.replace(/"/g, "").trim());
8456
8642
  const row = {};
8457
8643
  headers.forEach((header, colIndex) => {
8458
8644
  row[header] = values[colIndex] || "";
8459
8645
  });
8460
- console.log(`\u{1F4C4} Row ${index + 1}:`, row);
8646
+ logger.debug(`Row ${index + 1}:`, row);
8461
8647
  return row;
8462
8648
  });
8463
- console.log("\u{1F4C4} Final parsed data:", data);
8649
+ logger.debug("Final parsed data:", data);
8464
8650
  return data;
8465
8651
  };
8466
8652
  const handleImport = async () => {
@@ -8489,16 +8675,41 @@ function ImportModal({ isOpen, onClose, onImport, config = {} }) {
8489
8675
  setError(null);
8490
8676
  setPreviewData(null);
8491
8677
  setTotalCount(0);
8678
+ setValidationErrors([]);
8492
8679
  onClose();
8493
8680
  };
8494
- return /* @__PURE__ */ jsx18(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs14(DialogContent, { className: "sm:max-w-2xl bg-main-50", children: [
8495
- /* @__PURE__ */ jsxs14(DialogHeader, { children: [
8496
- /* @__PURE__ */ jsx18(DialogTitle, { children: title }),
8497
- /* @__PURE__ */ jsx18(DialogDescription, { children: description })
8498
- ] }),
8499
- /* @__PURE__ */ jsxs14("div", { className: "space-y-4", children: [
8500
- /* @__PURE__ */ jsxs14("div", { className: "border-2 border-dashed border-sec-200 rounded-lg p-6 text-center", children: [
8501
- /* @__PURE__ */ jsx18(FileText, { className: "h-8 w-8 mx-auto text-sec-400 mb-2" }),
8681
+ const handleFileSelect = async (event) => {
8682
+ const selectedFile = event.target.files?.[0];
8683
+ logger.debug("File selected:", selectedFile?.name);
8684
+ if (selectedFile) {
8685
+ setFile(selectedFile);
8686
+ setError(null);
8687
+ setValidationErrors([]);
8688
+ try {
8689
+ const text = await selectedFile.text();
8690
+ logger.debug("File content length:", text.length);
8691
+ const data = processCSV(text);
8692
+ logger.debug("Parsed CSV data:", data.length, "rows");
8693
+ logger.debug("Setting preview data:", data.slice(0, 5));
8694
+ setPreviewData(data.slice(0, 5));
8695
+ setTotalCount(data.length);
8696
+ logger.debug("Preview data state should be updated");
8697
+ } catch (err) {
8698
+ logger.error("CSV parsing error:", err);
8699
+ setError(err instanceof Error ? err.message : "Failed to preview file");
8700
+ setPreviewData(null);
8701
+ setTotalCount(0);
8702
+ }
8703
+ }
8704
+ };
8705
+ return /* @__PURE__ */ jsx18(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs14(DialogContent, { className: "sm:max-w-2xl bg-main-50", children: [
8706
+ /* @__PURE__ */ jsxs14(DialogHeader, { children: [
8707
+ /* @__PURE__ */ jsx18(DialogTitle, { children: title }),
8708
+ /* @__PURE__ */ jsx18(DialogDescription, { children: description })
8709
+ ] }),
8710
+ /* @__PURE__ */ jsxs14("div", { className: "space-y-4", children: [
8711
+ /* @__PURE__ */ jsxs14("div", { className: "border-2 border-dashed border-sec-200 rounded-lg p-6 text-center", children: [
8712
+ /* @__PURE__ */ jsx18(FileText, { className: "h-8 w-8 mx-auto text-sec-400 mb-2" }),
8502
8713
  /* @__PURE__ */ jsx18("p", { className: "text-sec-600 mb-2", children: file ? `Selected: ${file.name}` : uploadText }),
8503
8714
  file && /* @__PURE__ */ jsx18("p", { className: "text-xs text-sec-500", children: "File selected, processing preview..." }),
8504
8715
  /* @__PURE__ */ jsxs14(
@@ -8528,6 +8739,34 @@ function ImportModal({ isOpen, onClose, onImport, config = {} }) {
8528
8739
  /* @__PURE__ */ jsx18(AlertCircle, { className: "h-4 w-4" }),
8529
8740
  /* @__PURE__ */ jsx18("span", { className: "text-sm", children: error })
8530
8741
  ] }),
8742
+ validationErrors.length > 0 && /* @__PURE__ */ jsxs14("div", { className: "space-y-2", children: [
8743
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700", children: [
8744
+ /* @__PURE__ */ jsx18(AlertCircle, { className: "h-4 w-4" }),
8745
+ /* @__PURE__ */ jsxs14("span", { className: "text-sm font-medium", children: [
8746
+ validationErrors.length,
8747
+ " validation error",
8748
+ validationErrors.length !== 1 ? "s" : "",
8749
+ " found"
8750
+ ] })
8751
+ ] }),
8752
+ /* @__PURE__ */ jsxs14("div", { className: "max-h-32 overflow-y-auto space-y-1", children: [
8753
+ validationErrors.slice(0, 10).map((err, idx) => /* @__PURE__ */ jsxs14("div", { className: "text-xs text-acc-600 p-2 bg-acc-50 border border-acc-200 rounded", children: [
8754
+ /* @__PURE__ */ jsxs14("span", { className: "font-medium", children: [
8755
+ "Row ",
8756
+ err.row
8757
+ ] }),
8758
+ " \u2022 ",
8759
+ err.field,
8760
+ ": ",
8761
+ err.message
8762
+ ] }, idx)),
8763
+ validationErrors.length > 10 && /* @__PURE__ */ jsxs14("div", { className: "text-xs text-sec-500 italic", children: [
8764
+ "... and ",
8765
+ validationErrors.length - 10,
8766
+ " more errors"
8767
+ ] })
8768
+ ] })
8769
+ ] }),
8531
8770
  previewData && previewData.length > 0 && /* @__PURE__ */ jsxs14("div", { className: "space-y-3", children: [
8532
8771
  /* @__PURE__ */ jsx18("h4", { className: "text-sec-900", children: previewHeaderText }),
8533
8772
  /* @__PURE__ */ jsx18("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsx18("div", { className: "overflow-x-auto max-h-48", children: /* @__PURE__ */ jsxs14("table", { className: "min-w-full text-xs", children: [
@@ -8557,8 +8796,20 @@ function DataTableModals({
8557
8796
  showImportModal,
8558
8797
  onCloseImportModal,
8559
8798
  onImport,
8560
- importModalConfig
8799
+ importModalConfig,
8800
+ onStoreFocus,
8801
+ onRestoreFocus
8561
8802
  }) {
8803
+ useEffect6(() => {
8804
+ if (showImportModal) {
8805
+ onStoreFocus?.();
8806
+ } else {
8807
+ const timeoutId = setTimeout(() => {
8808
+ onRestoreFocus?.();
8809
+ }, 100);
8810
+ return () => clearTimeout(timeoutId);
8811
+ }
8812
+ }, [showImportModal, onStoreFocus, onRestoreFocus]);
8562
8813
  return /* @__PURE__ */ jsx19(Fragment3, { children: /* @__PURE__ */ jsx19(
8563
8814
  ImportModal,
8564
8815
  {
@@ -8571,12 +8822,12 @@ function DataTableModals({
8571
8822
  }
8572
8823
 
8573
8824
  // src/components/DataTable/components/DataTableErrorBoundary.tsx
8574
- import React12, { Component } from "react";
8825
+ import React14, { Component } from "react";
8575
8826
 
8576
8827
  // src/components/Alert/Alert.tsx
8577
- import * as React11 from "react";
8828
+ import * as React13 from "react";
8578
8829
  import { jsx as jsx20 } from "react/jsx-runtime";
8579
- var AlertContext = React11.createContext({ variant: "default" });
8830
+ var AlertContext = React13.createContext({ variant: "default" });
8580
8831
  var getAlertClasses = (variant = "default") => {
8581
8832
  const baseClasses = "relative w-full rounded-lg border p-4";
8582
8833
  const variantClasses = {
@@ -8587,10 +8838,10 @@ var getAlertClasses = (variant = "default") => {
8587
8838
  };
8588
8839
  return `${baseClasses} ${variantClasses[variant]}`;
8589
8840
  };
8590
- var Alert = React11.forwardRef(({ className, variant = "default", ...props }, ref) => {
8591
- const contextValue = React11.useMemo(() => ({ variant }), [variant]);
8841
+ var Alert = React13.forwardRef(({ className, variant = "default", ...props }, ref) => {
8842
+ const contextValue = React13.useMemo(() => ({ variant }), [variant]);
8592
8843
  if (variant === "inline") {
8593
- return /* @__PURE__ */ jsx20(AlertContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx20(React11.Fragment, { ...props }) });
8844
+ return /* @__PURE__ */ jsx20(AlertContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx20(React13.Fragment, { ...props }) });
8594
8845
  }
8595
8846
  return /* @__PURE__ */ jsx20(AlertContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx20(
8596
8847
  "div",
@@ -8603,8 +8854,8 @@ var Alert = React11.forwardRef(({ className, variant = "default", ...props }, re
8603
8854
  ) });
8604
8855
  });
8605
8856
  Alert.displayName = "Alert";
8606
- var AlertTitle = React11.forwardRef(({ className, ...props }, ref) => {
8607
- const { variant } = React11.useContext(AlertContext);
8857
+ var AlertTitle = React13.forwardRef(({ className, ...props }, ref) => {
8858
+ const { variant } = React13.useContext(AlertContext);
8608
8859
  if (variant === "inline") {
8609
8860
  return /* @__PURE__ */ jsx20("strong", { ...props });
8610
8861
  }
@@ -8618,8 +8869,8 @@ var AlertTitle = React11.forwardRef(({ className, ...props }, ref) => {
8618
8869
  );
8619
8870
  });
8620
8871
  AlertTitle.displayName = "AlertTitle";
8621
- var AlertDescription = React11.forwardRef(({ className, ...props }, ref) => {
8622
- const { variant } = React11.useContext(AlertContext);
8872
+ var AlertDescription = React13.forwardRef(({ className, ...props }, ref) => {
8873
+ const { variant } = React13.useContext(AlertContext);
8623
8874
  if (variant === "inline") {
8624
8875
  return /* @__PURE__ */ jsx20("span", { ...props });
8625
8876
  }
@@ -8639,12 +8890,13 @@ import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs15 } from "react/jsx-r
8639
8890
  var DataTableErrorBoundary = class extends Component {
8640
8891
  constructor(props) {
8641
8892
  super(props);
8893
+ this.logger = createLogger("DataTableErrorBoundary");
8642
8894
  this.retryTimeoutId = null;
8643
8895
  this.handleRetry = () => {
8644
8896
  const { onRetry, maxRetries = 3 } = this.props;
8645
8897
  const { retryCount } = this.state;
8646
8898
  if (retryCount >= maxRetries) {
8647
- console.warn("DataTable Error Boundary: Maximum retry attempts reached");
8899
+ this.logger.warn("Error Boundary: Maximum retry attempts reached");
8648
8900
  return;
8649
8901
  }
8650
8902
  if (onRetry) {
@@ -8686,7 +8938,7 @@ var DataTableErrorBoundary = class extends Component {
8686
8938
  errorInfo
8687
8939
  });
8688
8940
  this.props.onError?.(error, errorInfo);
8689
- console.error("DataTable Error Boundary caught an error:", error, errorInfo);
8941
+ this.logger.error("Error Boundary caught an error:", error, errorInfo);
8690
8942
  }
8691
8943
  componentWillUnmount() {
8692
8944
  if (this.retryTimeoutId) {
@@ -8753,22 +9005,28 @@ var DataTableErrorBoundary = class extends Component {
8753
9005
  };
8754
9006
 
8755
9007
  // src/components/DataTable/hooks/useColumnOrderPersistence.ts
8756
- import { useState as useState5, useEffect as useEffect6, useCallback as useCallback3 } from "react";
9008
+ import { useState as useState5, useEffect as useEffect7, useCallback as useCallback3 } from "react";
8757
9009
  function useColumnOrderPersistence({
8758
9010
  tableId,
8759
9011
  defaultOrder = [],
8760
- enablePersistence = false
9012
+ enablePersistence = false,
9013
+ storageKey
8761
9014
  }) {
9015
+ const logger = createLogger("ColumnOrderPersistence");
8762
9016
  const [columnOrder, setColumnOrder] = useState5(defaultOrder);
8763
9017
  const [isLoaded, setIsLoaded] = useState5(false);
8764
- const storageKey = tableId ? `datatable-column-order-${tableId}` : "datatable-column-order";
8765
- useEffect6(() => {
8766
- if (!enablePersistence || !tableId) {
9018
+ const finalStorageKey = storageKey ? `${storageKey}-column-order` : tableId ? `datatable-column-order-${tableId}` : "datatable-column-order";
9019
+ useEffect7(() => {
9020
+ if (!enablePersistence || typeof window === "undefined") {
9021
+ setIsLoaded(true);
9022
+ return;
9023
+ }
9024
+ if (!storageKey && !tableId) {
8767
9025
  setIsLoaded(true);
8768
9026
  return;
8769
9027
  }
8770
9028
  try {
8771
- const savedOrder = localStorage.getItem(storageKey);
9029
+ const savedOrder = localStorage.getItem(finalStorageKey);
8772
9030
  if (savedOrder) {
8773
9031
  const parsedOrder = JSON.parse(savedOrder);
8774
9032
  if (Array.isArray(parsedOrder)) {
@@ -8776,35 +9034,36 @@ function useColumnOrderPersistence({
8776
9034
  }
8777
9035
  }
8778
9036
  } catch (error) {
8779
- console.warn("Failed to load column order from localStorage:", error);
9037
+ logger.warn("Failed to load column order from localStorage:", error);
8780
9038
  } finally {
8781
9039
  setIsLoaded(true);
8782
9040
  }
8783
- }, [enablePersistence, tableId, storageKey]);
9041
+ }, [enablePersistence, finalStorageKey, storageKey, tableId]);
8784
9042
  const saveColumnOrder = useCallback3((newOrder) => {
8785
- if (!enablePersistence || !tableId) return;
9043
+ if (!enablePersistence || typeof window === "undefined") return;
9044
+ if (!storageKey && !tableId) return;
8786
9045
  try {
8787
- localStorage.setItem(storageKey, JSON.stringify(newOrder));
9046
+ localStorage.setItem(finalStorageKey, JSON.stringify(newOrder));
8788
9047
  } catch (error) {
8789
- console.warn("Failed to save column order to localStorage:", error);
9048
+ logger.warn("Failed to save column order to localStorage:", error);
8790
9049
  }
8791
- }, [enablePersistence, tableId, storageKey]);
9050
+ }, [enablePersistence, finalStorageKey, storageKey, tableId]);
8792
9051
  const updateColumnOrder = useCallback3((newOrder) => {
8793
9052
  setColumnOrder(newOrder);
8794
9053
  saveColumnOrder(newOrder);
8795
9054
  }, [saveColumnOrder]);
8796
9055
  const resetColumnOrder = useCallback3(() => {
8797
9056
  setColumnOrder(defaultOrder);
8798
- if (enablePersistence && tableId) {
9057
+ if (enablePersistence && (storageKey || tableId) && typeof window !== "undefined") {
8799
9058
  try {
8800
- localStorage.removeItem(storageKey);
9059
+ localStorage.removeItem(finalStorageKey);
8801
9060
  } catch (error) {
8802
- console.warn("Failed to remove column order from localStorage:", error);
9061
+ logger.warn("Failed to remove column order from localStorage:", error);
8803
9062
  }
8804
9063
  }
8805
- }, [defaultOrder, enablePersistence, tableId, storageKey]);
9064
+ }, [defaultOrder, enablePersistence, finalStorageKey, storageKey, tableId]);
8806
9065
  const clearAllPreferences = useCallback3(() => {
8807
- if (!enablePersistence) return;
9066
+ if (!enablePersistence || typeof window === "undefined") return;
8808
9067
  try {
8809
9068
  const keys = Object.keys(localStorage);
8810
9069
  keys.forEach((key) => {
@@ -8813,7 +9072,7 @@ function useColumnOrderPersistence({
8813
9072
  }
8814
9073
  });
8815
9074
  } catch (error) {
8816
- console.warn("Failed to clear datatable preferences:", error);
9075
+ logger.warn("Failed to clear datatable preferences:", error);
8817
9076
  }
8818
9077
  }, [enablePersistence]);
8819
9078
  return {
@@ -8825,127 +9084,78 @@ function useColumnOrderPersistence({
8825
9084
  };
8826
9085
  }
8827
9086
 
8828
- // src/components/DataTable/hooks/useHierarchicalState.ts
8829
- import { useState as useState6, useCallback as useCallback4, useMemo as useMemo5, useEffect as useEffect7 } from "react";
8830
- function useHierarchicalState(data, config) {
8831
- const initialExpandedState = useMemo5(() => {
8832
- if (!config?.defaultExpanded) {
8833
- return /* @__PURE__ */ new Set();
9087
+ // src/components/DataTable/hooks/useColumnVisibilityPersistence.ts
9088
+ import { useState as useState6, useEffect as useEffect8, useCallback as useCallback4 } from "react";
9089
+ function useColumnVisibilityPersistence({
9090
+ tableId,
9091
+ defaultVisibility = {},
9092
+ enablePersistence = false,
9093
+ storageKey
9094
+ }) {
9095
+ const logger = createLogger("ColumnVisibilityPersistence");
9096
+ const [columnVisibility, setColumnVisibility] = useState6(defaultVisibility);
9097
+ const [isLoaded, setIsLoaded] = useState6(false);
9098
+ const finalStorageKey = storageKey ? `${storageKey}-column-visibility` : tableId ? `datatable-column-visibility-${tableId}` : "datatable-column-visibility";
9099
+ useEffect8(() => {
9100
+ if (!enablePersistence || typeof window === "undefined") {
9101
+ setIsLoaded(true);
9102
+ return;
8834
9103
  }
8835
- if (config.defaultExpanded === true) {
8836
- return new Set(data.filter((row) => row.isParent).map((row) => row.id));
9104
+ try {
9105
+ const savedVisibility = localStorage.getItem(finalStorageKey);
9106
+ if (savedVisibility) {
9107
+ const parsedVisibility = JSON.parse(savedVisibility);
9108
+ if (typeof parsedVisibility === "object" && parsedVisibility !== null) {
9109
+ setColumnVisibility(parsedVisibility);
9110
+ }
9111
+ }
9112
+ } catch (error) {
9113
+ logger.warn("Failed to load column visibility from localStorage:", error);
9114
+ } finally {
9115
+ setIsLoaded(true);
8837
9116
  }
8838
- if (Array.isArray(config.defaultExpanded)) {
8839
- return new Set(config.defaultExpanded);
9117
+ }, [enablePersistence, finalStorageKey]);
9118
+ const saveColumnVisibility = useCallback4((newVisibility) => {
9119
+ if (!enablePersistence || typeof window === "undefined") return;
9120
+ try {
9121
+ localStorage.setItem(finalStorageKey, JSON.stringify(newVisibility));
9122
+ } catch (error) {
9123
+ logger.warn("Failed to save column visibility to localStorage:", error);
8840
9124
  }
8841
- return /* @__PURE__ */ new Set();
8842
- }, [data, config?.defaultExpanded]);
8843
- const [expandedRows, setExpandedRows] = useState6(initialExpandedState);
8844
- const [prevDataLength, setPrevDataLength] = useState6(data.length);
8845
- const [prevDefaultExpanded, setPrevDefaultExpanded] = useState6(config?.defaultExpanded);
8846
- useEffect7(() => {
8847
- const dataLengthChanged = data.length !== prevDataLength;
8848
- const configChanged = config?.defaultExpanded !== prevDefaultExpanded;
8849
- if (configChanged || dataLengthChanged) {
8850
- if (!config?.defaultExpanded) {
8851
- setExpandedRows(/* @__PURE__ */ new Set());
8852
- } else if (config.defaultExpanded === true) {
8853
- setExpandedRows(new Set(data.filter((row) => row.isParent).map((row) => row.id)));
8854
- } else if (Array.isArray(config.defaultExpanded)) {
8855
- setExpandedRows(new Set(config.defaultExpanded));
9125
+ }, [enablePersistence, finalStorageKey]);
9126
+ const updateColumnVisibility = useCallback4((newVisibility) => {
9127
+ setColumnVisibility(newVisibility);
9128
+ saveColumnVisibility(newVisibility);
9129
+ }, [saveColumnVisibility]);
9130
+ const resetColumnVisibility = useCallback4(() => {
9131
+ setColumnVisibility(defaultVisibility);
9132
+ if (enablePersistence && typeof window !== "undefined") {
9133
+ try {
9134
+ localStorage.removeItem(finalStorageKey);
9135
+ } catch (error) {
9136
+ logger.warn("Failed to remove column visibility from localStorage:", error);
8856
9137
  }
8857
- setPrevDataLength(data.length);
8858
- setPrevDefaultExpanded(config?.defaultExpanded);
8859
- }
8860
- }, [data, config?.defaultExpanded, prevDataLength, prevDefaultExpanded]);
8861
- const parentChildMap = useMemo5(() => {
8862
- const map = /* @__PURE__ */ new Map();
8863
- if (Array.isArray(data)) {
8864
- data.forEach((row) => {
8865
- if (row.isParent) {
8866
- map.set(row.id, []);
8867
- } else if (row.parentId) {
8868
- const children = map.get(row.parentId) || [];
8869
- children.push(row);
8870
- map.set(row.parentId, children);
8871
- }
8872
- });
8873
9138
  }
8874
- return map;
8875
- }, [data]);
8876
- const visibleRows = useMemo5(() => {
8877
- const visible = [];
8878
- if (Array.isArray(data)) {
8879
- data.forEach((row) => {
8880
- if (row.isParent) {
8881
- visible.push(row);
8882
- if (expandedRows.has(row.id)) {
8883
- const children = parentChildMap.get(row.id) || [];
8884
- visible.push(...children);
8885
- }
9139
+ }, [defaultVisibility, enablePersistence, finalStorageKey]);
9140
+ const clearAllPreferences = useCallback4(() => {
9141
+ if (!enablePersistence || typeof window === "undefined") return;
9142
+ try {
9143
+ const keys = Object.keys(localStorage);
9144
+ keys.forEach((key) => {
9145
+ if (key.startsWith("datatable-")) {
9146
+ localStorage.removeItem(key);
8886
9147
  }
8887
9148
  });
9149
+ } catch (error) {
9150
+ logger.warn("Failed to clear datatable preferences:", error);
8888
9151
  }
8889
- return visible;
8890
- }, [data, expandedRows, parentChildMap]);
8891
- const toggleRow = useCallback4((rowId) => {
8892
- setExpandedRows((prev) => {
8893
- const newSet = new Set(prev);
8894
- if (newSet.has(rowId)) {
8895
- newSet.delete(rowId);
8896
- } else {
8897
- newSet.add(rowId);
8898
- }
8899
- if (config?.onExpandedChange) {
8900
- config.onExpandedChange(Array.from(newSet));
8901
- }
8902
- return newSet;
8903
- });
8904
- }, [config]);
8905
- const expandAll = useCallback4(() => {
8906
- const parentIds = data.filter((row) => row.isParent).map((row) => row.id);
8907
- setExpandedRows(new Set(parentIds));
8908
- if (config?.onExpandedChange) {
8909
- config.onExpandedChange(parentIds);
8910
- }
8911
- }, [data, config]);
8912
- const collapseAll = useCallback4(() => {
8913
- setExpandedRows(/* @__PURE__ */ new Set());
8914
- if (config?.onExpandedChange) {
8915
- config.onExpandedChange([]);
8916
- }
8917
- }, [config]);
8918
- const isExpanded = useCallback4((rowId) => {
8919
- return expandedRows.has(rowId);
8920
- }, [expandedRows]);
8921
- const hasChildren = useCallback4((rowId) => {
8922
- return parentChildMap.has(rowId) && (parentChildMap.get(rowId)?.length || 0) > 0;
8923
- }, [parentChildMap]);
8924
- const getChildrenCount = useCallback4((rowId) => {
8925
- return parentChildMap.get(rowId)?.length || 0;
8926
- }, [parentChildMap]);
8927
- const getExpandedIds = useCallback4(() => {
8928
- return Array.from(expandedRows);
8929
- }, [expandedRows]);
8930
- const setExpandedIds = useCallback4((ids) => {
8931
- setExpandedRows(new Set(ids));
8932
- }, []);
9152
+ }, [enablePersistence]);
8933
9153
  return {
8934
- // State
8935
- expandedRows,
8936
- visibleRows,
8937
- // Actions
8938
- toggleRow,
8939
- expandAll,
8940
- collapseAll,
8941
- setExpandedIds,
8942
- // Getters
8943
- isExpanded,
8944
- hasChildren,
8945
- getChildrenCount,
8946
- getExpandedIds,
8947
- // Utilities
8948
- parentChildMap
9154
+ columnVisibility,
9155
+ isLoaded,
9156
+ updateColumnVisibility,
9157
+ resetColumnVisibility,
9158
+ clearAllPreferences
8949
9159
  };
8950
9160
  }
8951
9161
 
@@ -9098,80 +9308,207 @@ function useDataTableState({
9098
9308
  };
9099
9309
  }
9100
9310
 
9101
- // src/components/DataTable/utils/hierarchicalSorting.ts
9102
- function sortHierarchicalDataByStructure(data) {
9103
- const sorted = [];
9104
- const processed = /* @__PURE__ */ new Set();
9105
- data.forEach((row) => {
9106
- if (row.isParent && !processed.has(row.id)) {
9107
- sorted.push(row);
9108
- processed.add(row.id);
9311
+ // src/components/DataTable/hooks/useDataTableDataPipeline.ts
9312
+ import { useMemo as useMemo8 } from "react";
9313
+
9314
+ // src/components/DataTable/hooks/useHierarchicalState.ts
9315
+ import { useState as useState7, useCallback as useCallback6, useMemo as useMemo7, useEffect as useEffect9 } from "react";
9316
+ function useHierarchicalState(data, config) {
9317
+ const initialExpandedState = useMemo7(() => {
9318
+ if (!config?.defaultExpanded) {
9319
+ return /* @__PURE__ */ new Set();
9109
9320
  }
9110
- });
9111
- data.forEach((row) => {
9112
- if (!row.isParent && !processed.has(row.id)) {
9113
- sorted.push(row);
9114
- processed.add(row.id);
9321
+ if (config.defaultExpanded === true) {
9322
+ return new Set(data.filter((row) => row.isParent).map((row) => row.id));
9115
9323
  }
9116
- });
9117
- return sorted;
9118
- }
9119
- function sortHierarchicalDataWithSorting(data, sorting) {
9120
- if (sorting.length === 0) {
9121
- return data;
9122
- }
9123
- const [sortConfig] = sorting;
9124
- const { id: columnId, desc } = sortConfig;
9125
- const parentGroups = /* @__PURE__ */ new Map();
9126
- data.forEach((row) => {
9127
- if (row.isParent) {
9128
- parentGroups.set(row.id, { parent: row, children: [] });
9129
- } else if (row.parentId) {
9130
- const group = parentGroups.get(row.parentId);
9131
- if (group) {
9132
- group.children.push(row);
9133
- }
9324
+ if (Array.isArray(config.defaultExpanded)) {
9325
+ return new Set(config.defaultExpanded);
9134
9326
  }
9135
- });
9136
- const sortedGroups = Array.from(parentGroups.values()).map((group) => {
9137
- const sortedChildren = [...group.children].sort((a, b) => {
9138
- const aValue = getSortValue(a, columnId);
9139
- const bValue = getSortValue(b, columnId);
9140
- if (aValue === bValue) return 0;
9141
- const comparison = compareValues(aValue, bValue);
9142
- return desc ? -comparison : comparison;
9143
- });
9144
- return {
9145
- parent: group.parent,
9146
- children: sortedChildren
9147
- };
9148
- });
9149
- const sortedData = [];
9150
- sortedGroups.forEach((group) => {
9151
- sortedData.push(group.parent);
9152
- sortedData.push(...group.children);
9153
- });
9154
- return sortedData;
9155
- }
9156
- function getSortValue(row, columnId) {
9157
- const keys = columnId.split(".");
9158
- let value = row;
9159
- for (const key of keys) {
9160
- if (value && typeof value === "object" && key in value) {
9161
- value = value[key];
9162
- } else {
9163
- return null;
9327
+ return /* @__PURE__ */ new Set();
9328
+ }, [data, config?.defaultExpanded]);
9329
+ const [expandedRows, setExpandedRows] = useState7(initialExpandedState);
9330
+ const [prevDataLength, setPrevDataLength] = useState7(data.length);
9331
+ const [prevDefaultExpanded, setPrevDefaultExpanded] = useState7(config?.defaultExpanded);
9332
+ useEffect9(() => {
9333
+ const dataLengthChanged = data.length !== prevDataLength;
9334
+ const configChanged = config?.defaultExpanded !== prevDefaultExpanded;
9335
+ if (configChanged || dataLengthChanged) {
9336
+ if (!config?.defaultExpanded) {
9337
+ setExpandedRows(/* @__PURE__ */ new Set());
9338
+ } else if (config.defaultExpanded === true) {
9339
+ setExpandedRows(new Set(data.filter((row) => row.isParent).map((row) => row.id)));
9340
+ } else if (Array.isArray(config.defaultExpanded)) {
9341
+ setExpandedRows(new Set(config.defaultExpanded));
9342
+ }
9343
+ setPrevDataLength(data.length);
9344
+ setPrevDefaultExpanded(config?.defaultExpanded);
9164
9345
  }
9165
- }
9166
- return value;
9167
- }
9168
- function compareValues(a, b) {
9169
- if (a == null && b == null) return 0;
9170
- if (a == null) return -1;
9171
- if (b == null) return 1;
9172
- if (typeof a === "number" && typeof b === "number") {
9173
- return a - b;
9174
- }
9346
+ }, [data, config?.defaultExpanded, prevDataLength, prevDefaultExpanded]);
9347
+ const parentChildMap = useMemo7(() => {
9348
+ const map = /* @__PURE__ */ new Map();
9349
+ if (Array.isArray(data)) {
9350
+ data.forEach((row) => {
9351
+ if (row.isParent) {
9352
+ map.set(row.id, []);
9353
+ } else if (row.parentId) {
9354
+ const children = map.get(row.parentId) || [];
9355
+ children.push(row);
9356
+ map.set(row.parentId, children);
9357
+ }
9358
+ });
9359
+ }
9360
+ return map;
9361
+ }, [data]);
9362
+ const visibleRows = useMemo7(() => {
9363
+ const visible = [];
9364
+ if (Array.isArray(data)) {
9365
+ data.forEach((row) => {
9366
+ if (row.isParent) {
9367
+ visible.push(row);
9368
+ if (expandedRows.has(row.id)) {
9369
+ const children = parentChildMap.get(row.id) || [];
9370
+ visible.push(...children);
9371
+ }
9372
+ }
9373
+ });
9374
+ }
9375
+ return visible;
9376
+ }, [data, expandedRows, parentChildMap]);
9377
+ const toggleRow = useCallback6((rowId) => {
9378
+ setExpandedRows((prev) => {
9379
+ const newSet = new Set(prev);
9380
+ if (newSet.has(rowId)) {
9381
+ newSet.delete(rowId);
9382
+ } else {
9383
+ newSet.add(rowId);
9384
+ }
9385
+ if (config?.onExpandedChange) {
9386
+ config.onExpandedChange(Array.from(newSet));
9387
+ }
9388
+ return newSet;
9389
+ });
9390
+ }, [config]);
9391
+ const expandAll = useCallback6(() => {
9392
+ const parentIds = data.filter((row) => row.isParent).map((row) => row.id);
9393
+ setExpandedRows(new Set(parentIds));
9394
+ if (config?.onExpandedChange) {
9395
+ config.onExpandedChange(parentIds);
9396
+ }
9397
+ }, [data, config]);
9398
+ const collapseAll = useCallback6(() => {
9399
+ setExpandedRows(/* @__PURE__ */ new Set());
9400
+ if (config?.onExpandedChange) {
9401
+ config.onExpandedChange([]);
9402
+ }
9403
+ }, [config]);
9404
+ const isExpanded = useCallback6((rowId) => {
9405
+ return expandedRows.has(rowId);
9406
+ }, [expandedRows]);
9407
+ const hasChildren = useCallback6((rowId) => {
9408
+ return parentChildMap.has(rowId) && (parentChildMap.get(rowId)?.length || 0) > 0;
9409
+ }, [parentChildMap]);
9410
+ const getChildrenCount = useCallback6((rowId) => {
9411
+ return parentChildMap.get(rowId)?.length || 0;
9412
+ }, [parentChildMap]);
9413
+ const getExpandedIds = useCallback6(() => {
9414
+ return Array.from(expandedRows);
9415
+ }, [expandedRows]);
9416
+ const setExpandedIds = useCallback6((ids) => {
9417
+ setExpandedRows(new Set(ids));
9418
+ }, []);
9419
+ return {
9420
+ // State
9421
+ expandedRows,
9422
+ visibleRows,
9423
+ // Actions
9424
+ toggleRow,
9425
+ expandAll,
9426
+ collapseAll,
9427
+ setExpandedIds,
9428
+ // Getters
9429
+ isExpanded,
9430
+ hasChildren,
9431
+ getChildrenCount,
9432
+ getExpandedIds,
9433
+ // Utilities
9434
+ parentChildMap
9435
+ };
9436
+ }
9437
+
9438
+ // src/components/DataTable/utils/hierarchicalSorting.ts
9439
+ function sortHierarchicalDataByStructure(data) {
9440
+ const sorted = [];
9441
+ const processed = /* @__PURE__ */ new Set();
9442
+ data.forEach((row) => {
9443
+ if (row.isParent && !processed.has(row.id)) {
9444
+ sorted.push(row);
9445
+ processed.add(row.id);
9446
+ }
9447
+ });
9448
+ data.forEach((row) => {
9449
+ if (!row.isParent && !processed.has(row.id)) {
9450
+ sorted.push(row);
9451
+ processed.add(row.id);
9452
+ }
9453
+ });
9454
+ return sorted;
9455
+ }
9456
+ function sortHierarchicalDataWithSorting(data, sorting) {
9457
+ if (sorting.length === 0) {
9458
+ return data;
9459
+ }
9460
+ const [sortConfig] = sorting;
9461
+ const { id: columnId, desc } = sortConfig;
9462
+ const parentGroups = /* @__PURE__ */ new Map();
9463
+ data.forEach((row) => {
9464
+ if (row.isParent) {
9465
+ parentGroups.set(row.id, { parent: row, children: [] });
9466
+ } else if (row.parentId) {
9467
+ const group = parentGroups.get(row.parentId);
9468
+ if (group) {
9469
+ group.children.push(row);
9470
+ }
9471
+ }
9472
+ });
9473
+ const sortedGroups = Array.from(parentGroups.values()).map((group) => {
9474
+ const sortedChildren = [...group.children].sort((a, b) => {
9475
+ const aValue = getSortValue(a, columnId);
9476
+ const bValue = getSortValue(b, columnId);
9477
+ if (aValue === bValue) return 0;
9478
+ const comparison = compareValues(aValue, bValue);
9479
+ return desc ? -comparison : comparison;
9480
+ });
9481
+ return {
9482
+ parent: group.parent,
9483
+ children: sortedChildren
9484
+ };
9485
+ });
9486
+ const sortedData = [];
9487
+ sortedGroups.forEach((group) => {
9488
+ sortedData.push(group.parent);
9489
+ sortedData.push(...group.children);
9490
+ });
9491
+ return sortedData;
9492
+ }
9493
+ function getSortValue(row, columnId) {
9494
+ const keys = columnId.split(".");
9495
+ let value = row;
9496
+ for (const key of keys) {
9497
+ if (value && typeof value === "object" && key in value) {
9498
+ value = value[key];
9499
+ } else {
9500
+ return null;
9501
+ }
9502
+ }
9503
+ return value;
9504
+ }
9505
+ function compareValues(a, b) {
9506
+ if (a == null && b == null) return 0;
9507
+ if (a == null) return -1;
9508
+ if (b == null) return 1;
9509
+ if (typeof a === "number" && typeof b === "number") {
9510
+ return a - b;
9511
+ }
9175
9512
  if (a instanceof Date && b instanceof Date) {
9176
9513
  return a.getTime() - b.getTime();
9177
9514
  }
@@ -9193,8 +9530,301 @@ function getHierarchicalSortConfig(sorting, columns) {
9193
9530
  return sorting;
9194
9531
  }
9195
9532
 
9533
+ // src/components/DataTable/hooks/useDataTableDataPipeline.ts
9534
+ function useDataTableDataPipeline({
9535
+ data,
9536
+ features,
9537
+ hierarchical,
9538
+ sorting,
9539
+ finalPaginationMode,
9540
+ serverData
9541
+ }) {
9542
+ const hierarchicalEnabled = Boolean(features.hierarchical && hierarchical?.enabled);
9543
+ const hierarchicalValidation = useMemo8(() => {
9544
+ if (!hierarchicalEnabled) {
9545
+ return { isValid: true, errors: [] };
9546
+ }
9547
+ return validateHierarchicalData(data);
9548
+ }, [data, hierarchicalEnabled]);
9549
+ const structuredHierarchicalData = useMemo8(() => {
9550
+ if (!hierarchicalEnabled || !hierarchicalValidation.isValid) {
9551
+ return data;
9552
+ }
9553
+ return sortHierarchicalDataByStructure(data);
9554
+ }, [data, hierarchicalEnabled, hierarchicalValidation.isValid]);
9555
+ const hierarchicalState = useHierarchicalState(
9556
+ hierarchicalEnabled && hierarchicalValidation.isValid ? structuredHierarchicalData : [],
9557
+ hierarchicalEnabled ? hierarchical : void 0
9558
+ );
9559
+ const baseData = useMemo8(() => {
9560
+ if (finalPaginationMode === "server") {
9561
+ return serverData?.data ?? [];
9562
+ }
9563
+ return structuredHierarchicalData;
9564
+ }, [finalPaginationMode, serverData?.data, structuredHierarchicalData]);
9565
+ const tableData = useMemo8(() => {
9566
+ if (!hierarchicalEnabled) {
9567
+ return baseData;
9568
+ }
9569
+ return hierarchicalState.visibleRows ?? [];
9570
+ }, [baseData, hierarchicalEnabled, hierarchicalState.visibleRows]);
9571
+ const sortedHierarchicalData = useMemo8(() => {
9572
+ if (!hierarchicalEnabled || sorting.length === 0) {
9573
+ return tableData;
9574
+ }
9575
+ const visibleRows = hierarchicalState.visibleRows;
9576
+ return sortHierarchicalDataWithSorting(visibleRows, sorting);
9577
+ }, [hierarchicalEnabled, hierarchicalState.visibleRows, sorting, tableData]);
9578
+ const finalTableData = hierarchicalEnabled && sorting.length > 0 ? sortedHierarchicalData : tableData;
9579
+ const dataCount = useMemo8(() => {
9580
+ if (finalPaginationMode === "server") {
9581
+ return serverData?.totalCount ?? 0;
9582
+ }
9583
+ return finalTableData?.length ?? 0;
9584
+ }, [finalPaginationMode, finalTableData?.length, serverData?.totalCount]);
9585
+ return {
9586
+ finalTableData,
9587
+ dataCount,
9588
+ hierarchicalState: hierarchicalEnabled ? hierarchicalState : void 0,
9589
+ hierarchicalValidation
9590
+ };
9591
+ }
9592
+
9593
+ // src/components/DataTable/hooks/useServerSideDataEffect.ts
9594
+ import { useCallback as useCallback7, useEffect as useEffect10 } from "react";
9595
+ function useServerSideDataEffect({
9596
+ finalPaginationMode,
9597
+ serverSide,
9598
+ pagination,
9599
+ sorting,
9600
+ columnFilters,
9601
+ grouping,
9602
+ searchQuery,
9603
+ tableDataLength,
9604
+ fetchServerData,
9605
+ cleanup
9606
+ }) {
9607
+ const handleServerSideChange = useCallback7(async () => {
9608
+ if (finalPaginationMode !== "server" || !serverSide) {
9609
+ return;
9610
+ }
9611
+ const params = {
9612
+ pageIndex: pagination.pageIndex,
9613
+ pageSize: pagination.pageSize,
9614
+ sorting,
9615
+ columnFilters,
9616
+ globalFilter: searchQuery,
9617
+ grouping
9618
+ };
9619
+ await fetchServerData(params);
9620
+ }, [
9621
+ finalPaginationMode,
9622
+ serverSide,
9623
+ pagination.pageIndex,
9624
+ pagination.pageSize,
9625
+ sorting,
9626
+ columnFilters,
9627
+ searchQuery,
9628
+ grouping,
9629
+ fetchServerData
9630
+ ]);
9631
+ useEffect10(() => {
9632
+ if (finalPaginationMode !== "server" || !serverSide) {
9633
+ return;
9634
+ }
9635
+ if (tableDataLength > 0) {
9636
+ return;
9637
+ }
9638
+ handleServerSideChange();
9639
+ }, [
9640
+ finalPaginationMode,
9641
+ serverSide,
9642
+ tableDataLength,
9643
+ handleServerSideChange
9644
+ ]);
9645
+ useEffect10(() => () => {
9646
+ cleanup?.();
9647
+ }, [cleanup]);
9648
+ return handleServerSideChange;
9649
+ }
9650
+
9651
+ // src/components/DataTable/hooks/useEffectiveColumnOrder.ts
9652
+ import { useMemo as useMemo9 } from "react";
9653
+ function useEffectiveColumnOrder({
9654
+ columns,
9655
+ externalColumnOrder,
9656
+ selectionEnabled
9657
+ }) {
9658
+ const baseOrder = useMemo9(() => {
9659
+ if (externalColumnOrder && externalColumnOrder.length > 0) {
9660
+ return externalColumnOrder;
9661
+ }
9662
+ return columns.map((column) => column.id || column.accessorKey || "").filter((identifier) => Boolean(identifier));
9663
+ }, [columns, externalColumnOrder]);
9664
+ return useMemo9(() => {
9665
+ if (selectionEnabled && !baseOrder.includes("select")) {
9666
+ return ["select", ...baseOrder];
9667
+ }
9668
+ return baseOrder;
9669
+ }, [baseOrder, selectionEnabled]);
9670
+ }
9671
+
9672
+ // src/components/DataTable/hooks/useTableHandlers.ts
9673
+ import { useCallback as useCallback8, useMemo as useMemo10 } from "react";
9674
+ function useTableHandlers({
9675
+ state,
9676
+ stateSnapshot,
9677
+ actions,
9678
+ selection,
9679
+ onRowSelectionChange,
9680
+ effectiveColumnOrder,
9681
+ canPersistVisibility,
9682
+ canPersistOrder,
9683
+ updateSavedColumnVisibility,
9684
+ updateColumnOrder,
9685
+ onLayoutChange
9686
+ }) {
9687
+ const handleSortingChange = useCallback8((updaterOrValue) => {
9688
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.sorting) : updaterOrValue;
9689
+ actions.setSorting(nextValue);
9690
+ }, [actions, stateSnapshot.sorting]);
9691
+ const handleColumnFiltersChange = useCallback8((updaterOrValue) => {
9692
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.columnFilters) : updaterOrValue;
9693
+ actions.setColumnFilters(nextValue);
9694
+ }, [actions, stateSnapshot.columnFilters]);
9695
+ const handleColumnVisibilityChange = useCallback8((updaterOrValue) => {
9696
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.columnVisibility) : updaterOrValue;
9697
+ actions.setColumnVisibility(nextValue);
9698
+ if (canPersistVisibility) {
9699
+ updateSavedColumnVisibility(nextValue);
9700
+ }
9701
+ onLayoutChange?.({
9702
+ columnOrder: effectiveColumnOrder,
9703
+ columnVisibility: nextValue
9704
+ });
9705
+ }, [actions, stateSnapshot.columnVisibility, canPersistVisibility, updateSavedColumnVisibility, onLayoutChange, effectiveColumnOrder]);
9706
+ const handleRowSelectionChange = useCallback8((updaterOrValue) => {
9707
+ const currentSelection = selection ?? state.rowSelection;
9708
+ const nextSelection = typeof updaterOrValue === "function" ? updaterOrValue(currentSelection) : updaterOrValue;
9709
+ if (selection === void 0) {
9710
+ actions.setRowSelection(nextSelection);
9711
+ return;
9712
+ }
9713
+ onRowSelectionChange?.(nextSelection);
9714
+ }, [actions, selection, state.rowSelection, onRowSelectionChange]);
9715
+ const handleGroupingChange = useCallback8((updaterOrValue) => {
9716
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.grouping) : updaterOrValue;
9717
+ actions.setGrouping(nextValue);
9718
+ }, [actions, stateSnapshot.grouping]);
9719
+ const handleExpandedChange = useCallback8((updaterOrValue) => {
9720
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.expanded) : updaterOrValue;
9721
+ actions.setExpanded(nextValue);
9722
+ }, [actions, stateSnapshot.expanded]);
9723
+ const handlePaginationChange = useCallback8((updaterOrValue) => {
9724
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.pagination) : updaterOrValue;
9725
+ actions.setPagination(nextValue);
9726
+ }, [actions, stateSnapshot.pagination]);
9727
+ const handleColumnOrderChange = useCallback8((updaterOrValue) => {
9728
+ const nextValue = typeof updaterOrValue === "function" ? updaterOrValue(stateSnapshot.columnOrder) : updaterOrValue;
9729
+ actions.setColumnOrder(nextValue);
9730
+ if (canPersistOrder) {
9731
+ updateColumnOrder(nextValue);
9732
+ }
9733
+ onLayoutChange?.({
9734
+ columnOrder: nextValue,
9735
+ columnVisibility: stateSnapshot.columnVisibility
9736
+ });
9737
+ }, [actions, stateSnapshot.columnOrder, stateSnapshot.columnVisibility, canPersistOrder, updateColumnOrder, onLayoutChange]);
9738
+ return useMemo10(() => ({
9739
+ onSortingChange: handleSortingChange,
9740
+ onColumnFiltersChange: handleColumnFiltersChange,
9741
+ onColumnVisibilityChange: handleColumnVisibilityChange,
9742
+ onRowSelectionChange: handleRowSelectionChange,
9743
+ onGroupingChange: handleGroupingChange,
9744
+ onExpandedChange: handleExpandedChange,
9745
+ onPaginationChange: handlePaginationChange,
9746
+ onColumnOrderChange: handleColumnOrderChange
9747
+ }), [
9748
+ handleSortingChange,
9749
+ handleColumnFiltersChange,
9750
+ handleColumnVisibilityChange,
9751
+ handleRowSelectionChange,
9752
+ handleGroupingChange,
9753
+ handleExpandedChange,
9754
+ handlePaginationChange,
9755
+ handleColumnOrderChange
9756
+ ]);
9757
+ }
9758
+
9759
+ // src/components/DataTable/hooks/useDataTableConfiguration.ts
9760
+ import { useMemo as useMemo11 } from "react";
9761
+ import {
9762
+ getCoreRowModel,
9763
+ getExpandedRowModel,
9764
+ getFilteredRowModel,
9765
+ getGroupedRowModel,
9766
+ getPaginationRowModel,
9767
+ getSortedRowModel
9768
+ } from "@tanstack/react-table";
9769
+ function useDataTableConfiguration({
9770
+ data,
9771
+ columns,
9772
+ stateSnapshot,
9773
+ handlers,
9774
+ features,
9775
+ getRowId,
9776
+ finalPaginationMode,
9777
+ finalDataCount,
9778
+ pageSize
9779
+ }) {
9780
+ return useMemo11(() => ({
9781
+ data,
9782
+ columns,
9783
+ state: {
9784
+ sorting: stateSnapshot.sorting,
9785
+ columnFilters: stateSnapshot.columnFilters,
9786
+ columnVisibility: stateSnapshot.columnVisibility,
9787
+ rowSelection: stateSnapshot.rowSelection,
9788
+ grouping: stateSnapshot.grouping,
9789
+ expanded: stateSnapshot.expanded,
9790
+ pagination: stateSnapshot.pagination,
9791
+ globalFilter: stateSnapshot.globalFilter,
9792
+ columnOrder: stateSnapshot.columnOrder
9793
+ },
9794
+ initialState: {
9795
+ expanded: features.grouping ? {} : void 0
9796
+ },
9797
+ enableRowSelection: features.selection,
9798
+ enableGrouping: features.grouping,
9799
+ getRowId,
9800
+ ...handlers,
9801
+ getCoreRowModel: getCoreRowModel(),
9802
+ getFilteredRowModel: finalPaginationMode === "client" ? getFilteredRowModel() : void 0,
9803
+ getSortedRowModel: finalPaginationMode === "client" ? getSortedRowModel() : void 0,
9804
+ getPaginationRowModel: features.pagination ? getPaginationRowModel() : void 0,
9805
+ getGroupedRowModel: features.grouping ? getGroupedRowModel() : void 0,
9806
+ getExpandedRowModel: features.grouping ? getExpandedRowModel() : void 0,
9807
+ manualSorting: finalPaginationMode === "server",
9808
+ manualFiltering: finalPaginationMode === "server",
9809
+ manualPagination: finalPaginationMode === "server",
9810
+ pageCount: finalPaginationMode === "server" ? Math.ceil(finalDataCount / pageSize) : void 0
9811
+ }), [
9812
+ data,
9813
+ columns,
9814
+ stateSnapshot,
9815
+ handlers,
9816
+ features.selection,
9817
+ features.grouping,
9818
+ features.pagination,
9819
+ getRowId,
9820
+ finalPaginationMode,
9821
+ finalDataCount,
9822
+ pageSize
9823
+ ]);
9824
+ }
9825
+
9196
9826
  // src/components/Card/Card.tsx
9197
- import * as React13 from "react";
9827
+ import * as React15 from "react";
9198
9828
  import { jsx as jsx22 } from "react/jsx-runtime";
9199
9829
  function getCardClasses(variant = "default", size = "default") {
9200
9830
  const baseClasses = "rounded-lg border bg-card text-card-foreground shadow-sm";
@@ -9210,7 +9840,7 @@ function getCardClasses(variant = "default", size = "default") {
9210
9840
  };
9211
9841
  return `${baseClasses} ${variantClasses[variant]} ${sizeClasses2[size]}`;
9212
9842
  }
9213
- var Card = React13.forwardRef(({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx22(
9843
+ var Card = React15.forwardRef(({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx22(
9214
9844
  "article",
9215
9845
  {
9216
9846
  ref,
@@ -9223,7 +9853,7 @@ var Card = React13.forwardRef(({ className, variant, size, ...props }, ref) => /
9223
9853
  }
9224
9854
  ));
9225
9855
  Card.displayName = "Card";
9226
- var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9856
+ var CardHeader = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9227
9857
  "header",
9228
9858
  {
9229
9859
  ref,
@@ -9232,7 +9862,7 @@ var CardHeader = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE
9232
9862
  }
9233
9863
  ));
9234
9864
  CardHeader.displayName = "CardHeader";
9235
- var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9865
+ var CardTitle = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9236
9866
  "h3",
9237
9867
  {
9238
9868
  ref,
@@ -9244,7 +9874,7 @@ var CardTitle = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE_
9244
9874
  }
9245
9875
  ));
9246
9876
  CardTitle.displayName = "CardTitle";
9247
- var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9877
+ var CardDescription = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9248
9878
  "p",
9249
9879
  {
9250
9880
  ref,
@@ -9253,7 +9883,7 @@ var CardDescription = React13.forwardRef(({ className, ...props }, ref) => /* @_
9253
9883
  }
9254
9884
  ));
9255
9885
  CardDescription.displayName = "CardDescription";
9256
- var CardContent = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9886
+ var CardContent = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9257
9887
  "main",
9258
9888
  {
9259
9889
  ref,
@@ -9262,7 +9892,7 @@ var CardContent = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
9262
9892
  }
9263
9893
  ));
9264
9894
  CardContent.displayName = "CardContent";
9265
- var CardFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9895
+ var CardFooter = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9266
9896
  "footer",
9267
9897
  {
9268
9898
  ref,
@@ -9271,7 +9901,7 @@ var CardFooter = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE
9271
9901
  }
9272
9902
  ));
9273
9903
  CardFooter.displayName = "CardFooter";
9274
- var CardActions = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9904
+ var CardActions = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9275
9905
  "nav",
9276
9906
  {
9277
9907
  ref,
@@ -9282,7 +9912,7 @@ var CardActions = React13.forwardRef(({ className, ...props }, ref) => /* @__PUR
9282
9912
  }
9283
9913
  ));
9284
9914
  CardActions.displayName = "CardActions";
9285
- var HoverCard = React13.forwardRef(({ children, className, ...props }, ref) => {
9915
+ var HoverCard = React15.forwardRef(({ children, className, ...props }, ref) => {
9286
9916
  return /* @__PURE__ */ jsx22(
9287
9917
  "section",
9288
9918
  {
@@ -9294,7 +9924,7 @@ var HoverCard = React13.forwardRef(({ children, className, ...props }, ref) => {
9294
9924
  );
9295
9925
  });
9296
9926
  HoverCard.displayName = "HoverCard";
9297
- var HoverCardTrigger = React13.forwardRef(({ className, asChild, children, ...props }, ref) => {
9927
+ var HoverCardTrigger = React15.forwardRef(({ className, asChild, children, ...props }, ref) => {
9298
9928
  if (asChild) {
9299
9929
  return /* @__PURE__ */ jsx22("span", { className: cn("cursor-pointer", className), children });
9300
9930
  }
@@ -9313,7 +9943,7 @@ var HoverCardTrigger = React13.forwardRef(({ className, asChild, children, ...pr
9313
9943
  );
9314
9944
  });
9315
9945
  HoverCardTrigger.displayName = "HoverCardTrigger";
9316
- var HoverCardContent = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9946
+ var HoverCardContent = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
9317
9947
  "aside",
9318
9948
  {
9319
9949
  ref,
@@ -9342,14 +9972,14 @@ function AccessDeniedPage({
9342
9972
  const handleRetry = () => {
9343
9973
  if (onRetry) {
9344
9974
  onRetry();
9345
- } else {
9975
+ } else if (typeof window !== "undefined") {
9346
9976
  window.location.reload();
9347
9977
  }
9348
9978
  };
9349
9979
  const handleBack = () => {
9350
9980
  if (onBack) {
9351
9981
  onBack();
9352
- } else {
9982
+ } else if (typeof window !== "undefined") {
9353
9983
  window.history.back();
9354
9984
  }
9355
9985
  };
@@ -9401,31 +10031,76 @@ function AccessDeniedPage({
9401
10031
  }
9402
10032
 
9403
10033
  // src/components/DataTable/utils/exportUtils.ts
10034
+ function escapeCSVValue(value, sanitizeForSecurity = true) {
10035
+ if (value === null || value === void 0) {
10036
+ return sanitizeForSecurity ? '""' : "";
10037
+ }
10038
+ let stringValue = String(value);
10039
+ if (sanitizeForSecurity) {
10040
+ if (/^[=+\-@]/.test(stringValue) || stringValue.startsWith(" ")) {
10041
+ stringValue = "'" + stringValue;
10042
+ }
10043
+ stringValue = stringValue.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F]/g, "");
10044
+ const escaped = stringValue.replace(/"/g, '""');
10045
+ return `"${escaped}"`;
10046
+ } else {
10047
+ const escaped = stringValue.replace(/"/g, '""');
10048
+ return `"${escaped}"`;
10049
+ }
10050
+ }
10051
+ function formatLocaleValue(value, locale) {
10052
+ if (value === null || value === void 0) {
10053
+ return "";
10054
+ }
10055
+ if (typeof value === "number") {
10056
+ return new Intl.NumberFormat(locale).format(value);
10057
+ }
10058
+ if (value instanceof Date) {
10059
+ return new Intl.DateTimeFormat(locale).format(value);
10060
+ }
10061
+ if (typeof value === "boolean") {
10062
+ return "";
10063
+ }
10064
+ return String(value);
10065
+ }
9404
10066
  function generateCSVContent(data, columns, options = {}) {
9405
10067
  if (!data.length) return "";
9406
- const { includeHeaders = true } = options;
9407
- const headers = columns.map((col) => col.header || col.id || "Column");
10068
+ const {
10069
+ includeHeaders = true,
10070
+ locale,
10071
+ sanitizeForSecurity = true
10072
+ } = options;
10073
+ const headers = columns.map((col) => {
10074
+ const headerValue = col.header || col.id || "Column";
10075
+ return escapeCSVValue(headerValue, sanitizeForSecurity);
10076
+ });
9408
10077
  const csvData = data.map((row) => {
9409
10078
  return columns.map((col) => {
9410
10079
  const key = col.accessorKey || col.id;
9411
- const value = row[key];
9412
- const escapedValue = String(value || "").replace(/"/g, '""');
9413
- return `"${escapedValue}"`;
10080
+ let value = key ? row[key] : void 0;
10081
+ if (locale && (typeof value === "number" || value instanceof Date || typeof value === "boolean")) {
10082
+ value = formatLocaleValue(value, locale);
10083
+ }
10084
+ return escapeCSVValue(value, sanitizeForSecurity);
9414
10085
  }).join(",");
9415
10086
  });
9416
10087
  const csvContent = includeHeaders ? [headers.join(","), ...csvData].join("\n") : csvData.join("\n");
9417
10088
  return csvContent;
9418
10089
  }
9419
- function exportToCSV(data, columns, filename = "download.csv") {
10090
+ function exportToCSV(data, columns, filename = "download.csv", options = {}) {
10091
+ const logger = createLogger("ExportUtils");
9420
10092
  return new Promise((resolve, reject) => {
9421
10093
  try {
10094
+ if (typeof window === "undefined") {
10095
+ throw new Error("CSV export is only available in browser environments");
10096
+ }
9422
10097
  if (!data || data.length === 0) {
9423
10098
  throw new Error("No data to export");
9424
10099
  }
9425
10100
  if (!columns || columns.length === 0) {
9426
10101
  throw new Error("No columns defined for export");
9427
10102
  }
9428
- const csvContent = generateCSVContent(data, columns);
10103
+ const csvContent = generateCSVContent(data, columns, options);
9429
10104
  const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
9430
10105
  const link = document.createElement("a");
9431
10106
  const url = URL.createObjectURL(blob);
@@ -9442,7 +10117,7 @@ function exportToCSV(data, columns, filename = "download.csv") {
9442
10117
  link.click();
9443
10118
  document.body.removeChild(link);
9444
10119
  } catch (error) {
9445
- console.error("Failed to export data to CSV:", error);
10120
+ logger.error("Failed to export data to CSV:", error);
9446
10121
  reject(error);
9447
10122
  }
9448
10123
  });
@@ -9453,8 +10128,36 @@ init_UnifiedAuthProvider();
9453
10128
 
9454
10129
  // src/components/DataTable/hooks/useDataTablePermissions.ts
9455
10130
  init_UnifiedAuthProvider();
9456
- import { useMemo as useMemo7, useRef as useRef5 } from "react";
9457
- function useDataTablePermissions(rbac, features) {
10131
+ import { useMemo as useMemo12, useRef as useRef5 } from "react";
10132
+
10133
+ // src/components/DataTable/types.ts
10134
+ var defaultDataTableFeatures = {
10135
+ search: false,
10136
+ pagination: false,
10137
+ sorting: false,
10138
+ filtering: false,
10139
+ import: false,
10140
+ export: false,
10141
+ selection: false,
10142
+ creation: false,
10143
+ editing: false,
10144
+ deletion: false,
10145
+ deleteSelected: false,
10146
+ grouping: false,
10147
+ columnVisibility: false,
10148
+ columnReordering: false,
10149
+ hierarchical: false
10150
+ };
10151
+ function normalizeDataTableFeatures(features) {
10152
+ return {
10153
+ ...defaultDataTableFeatures,
10154
+ ...features ?? {}
10155
+ };
10156
+ }
10157
+
10158
+ // src/components/DataTable/hooks/useDataTablePermissions.ts
10159
+ function useDataTablePermissions(rbac, features = {}) {
10160
+ const logger = createLogger("DataTablePermissions");
9458
10161
  const authResult = useUnifiedAuth();
9459
10162
  const user = authResult.user;
9460
10163
  const pageId = rbac?.pageId;
@@ -9463,11 +10166,18 @@ function useDataTablePermissions(rbac, features) {
9463
10166
  throw new Error("DataTable requires either rbac.pageId or rbac.pageName for permission checking");
9464
10167
  }
9465
10168
  const effectivePageId = pageId || pageName;
9466
- const { selectedOrganisationId, selectedEventId, supabase } = useUnifiedAuth();
9467
- const { resolvedScope: rawResolvedScope } = useResolvedScope({
10169
+ const { selectedOrganisation, selectedEvent, supabase, organisations } = useUnifiedAuth();
10170
+ logger.debug("Organisation context:", {
10171
+ hasSelectedOrg: !!selectedOrganisation,
10172
+ selectedOrgId: selectedOrganisation?.id,
10173
+ hasOrganisations: organisations?.length > 0,
10174
+ organisationCount: organisations?.length,
10175
+ selectedEvent: selectedEvent?.event_id
10176
+ });
10177
+ const { resolvedScope: rawResolvedScope, isLoading: scopeLoading } = useResolvedScope({
9468
10178
  supabase,
9469
- selectedOrganisationId,
9470
- selectedEventId
10179
+ selectedOrganisationId: selectedOrganisation?.id || null,
10180
+ selectedEventId: selectedEvent?.event_id || null
9471
10181
  });
9472
10182
  const stableScopeRef = useRef5({
9473
10183
  organisationId: "",
@@ -9491,26 +10201,46 @@ function useDataTablePermissions(rbac, features) {
9491
10201
  stableScopeRef.current = { organisationId: "", appId: "", eventId: void 0 };
9492
10202
  }
9493
10203
  const stableScope = stableScopeRef.current;
9494
- const effectiveScope = stableScope.organisationId ? stableScope : { organisationId: "", eventId: void 0, appId: void 0 };
10204
+ const effectiveScope = !scopeLoading && stableScope.organisationId ? stableScope : null;
10205
+ const userId = user?.id || "";
10206
+ const readPermission = `read:page.${effectivePageId}`;
10207
+ const createPermission = `create:page.${effectivePageId}`;
10208
+ const updatePermission = `update:page.${effectivePageId}`;
10209
+ const deletePermission = `delete:page.${effectivePageId}`;
10210
+ const consistentScope = effectiveScope || { organisationId: "", eventId: void 0, appId: void 0 };
9495
10211
  const permissions = {
9496
- canRead: useCan(user?.id || "", effectiveScope, `read:page.${effectivePageId}`, effectivePageId, true),
9497
- canCreate: useCan(user?.id || "", effectiveScope, `create:page.${effectivePageId}`, effectivePageId, true),
9498
- canUpdate: useCan(user?.id || "", effectiveScope, `update:page.${effectivePageId}`, effectivePageId, true),
9499
- canDelete: useCan(user?.id || "", effectiveScope, `delete:page.${effectivePageId}`, effectivePageId, true),
9500
- canExport: useCan(user?.id || "", effectiveScope, `read:page.${effectivePageId}`, effectivePageId, true),
10212
+ canRead: useCan(userId, consistentScope, readPermission, effectivePageId, true),
10213
+ canCreate: useCan(userId, consistentScope, createPermission, effectivePageId, true),
10214
+ canUpdate: useCan(userId, consistentScope, updatePermission, effectivePageId, true),
10215
+ canDelete: useCan(userId, consistentScope, deletePermission, effectivePageId, true),
10216
+ canExport: useCan(userId, consistentScope, readPermission, effectivePageId, true),
9501
10217
  // Use read permission for export
9502
- canImport: useCan(user?.id || "", effectiveScope, `create:page.${effectivePageId}`, effectivePageId, true)
10218
+ canImport: useCan(userId, consistentScope, createPermission, effectivePageId, true)
9503
10219
  // Use create permission for import
9504
10220
  };
9505
- const secureFeatures = useMemo7(() => ({
9506
- ...features,
9507
- creation: features.creation && permissions.canCreate.can,
9508
- editing: features.editing && permissions.canUpdate.can,
9509
- deletion: features.deletion && permissions.canDelete.can,
9510
- deleteSelected: features.deleteSelected && permissions.canDelete.can,
9511
- export: features.export && permissions.canExport.can,
9512
- import: features.import && permissions.canImport.can
9513
- }), [features, permissions.canCreate.can, permissions.canUpdate.can, permissions.canDelete.can, permissions.canExport.can, permissions.canImport.can]);
10221
+ logger.debug("Permission check results:", {
10222
+ canRead: permissions.canRead.can,
10223
+ canReadLoading: permissions.canRead.isLoading,
10224
+ canReadError: permissions.canRead.error?.message,
10225
+ canCreate: permissions.canCreate.can,
10226
+ pageName: effectivePageId,
10227
+ scope: consistentScope,
10228
+ hasValidScope: !!effectiveScope,
10229
+ scopeLoading
10230
+ });
10231
+ const normalizedFeatures = useMemo12(
10232
+ () => normalizeDataTableFeatures(features),
10233
+ [features]
10234
+ );
10235
+ const secureFeatures = useMemo12(() => ({
10236
+ ...normalizedFeatures,
10237
+ creation: normalizedFeatures.creation && permissions.canCreate.can,
10238
+ editing: normalizedFeatures.editing && permissions.canUpdate.can,
10239
+ deletion: normalizedFeatures.deletion && permissions.canDelete.can,
10240
+ deleteSelected: normalizedFeatures.deleteSelected && permissions.canDelete.can,
10241
+ export: normalizedFeatures.export && permissions.canExport.can,
10242
+ import: normalizedFeatures.import && permissions.canImport.can
10243
+ }), [normalizedFeatures, permissions.canCreate.can, permissions.canUpdate.can, permissions.canDelete.can, permissions.canExport.can, permissions.canImport.can]);
9514
10244
  return {
9515
10245
  permissions,
9516
10246
  secureFeatures,
@@ -9519,7 +10249,7 @@ function useDataTablePermissions(rbac, features) {
9519
10249
  }
9520
10250
 
9521
10251
  // src/components/DataTable/hooks/useTableColumns.ts
9522
- import React14, { useMemo as useMemo8 } from "react";
10252
+ import React16, { useMemo as useMemo13 } from "react";
9523
10253
 
9524
10254
  // src/components/DataTable/core/ColumnFactory.ts
9525
10255
  var ColumnFactory = class {
@@ -9647,7 +10377,8 @@ var ColumnFactory = class {
9647
10377
  },
9648
10378
  size: options.size || 150,
9649
10379
  minSize: options.minSize || 100,
9650
- maxSize: options.maxSize || 200
10380
+ maxSize: options.maxSize || 200,
10381
+ meta: options.meta
9651
10382
  };
9652
10383
  }
9653
10384
  /**
@@ -9699,7 +10430,7 @@ function useTableColumns({
9699
10430
  effectiveActions,
9700
10431
  columnOrder
9701
10432
  }) {
9702
- const enhancedColumns = useMemo8(() => {
10433
+ const enhancedColumns = useMemo13(() => {
9703
10434
  const baseColumns = [...columns].map((column) => ({
9704
10435
  ...column,
9705
10436
  enableSorting: features.sorting && column.enableSorting !== false,
@@ -9711,14 +10442,14 @@ function useTableColumns({
9711
10442
  header: ({ table }) => {
9712
10443
  const isAllSelected = table.getIsAllPageRowsSelected();
9713
10444
  const isSomeSelected = table.getIsSomePageRowsSelected();
9714
- return React14.createElement(Checkbox, {
10445
+ return React16.createElement(Checkbox, {
9715
10446
  checked: isAllSelected ? true : isSomeSelected ? "indeterminate" : false,
9716
10447
  onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value),
9717
10448
  "aria-label": "Select all"
9718
10449
  });
9719
10450
  },
9720
10451
  cell: ({ row }) => {
9721
- return React14.createElement(Checkbox, {
10452
+ return React16.createElement(Checkbox, {
9722
10453
  checked: row.getIsSelected(),
9723
10454
  onCheckedChange: (value) => row.toggleSelected(!!value),
9724
10455
  "aria-label": "Select row"
@@ -9734,7 +10465,11 @@ function useTableColumns({
9734
10465
  } : null;
9735
10466
  const actionsColumn = effectiveActions.length > 0 ? ColumnFactory.createActionColumn(effectiveActions, {
9736
10467
  header: "Actions",
9737
- size: 120
10468
+ size: 1,
10469
+ // Shrink to fit content
10470
+ minSize: 0,
10471
+ maxSize: 0,
10472
+ meta: { align: "right" }
9738
10473
  }) : null;
9739
10474
  const finalColumns = [];
9740
10475
  if (columnOrder && columnOrder.length > 0) {
@@ -9754,34 +10489,471 @@ function useTableColumns({
9754
10489
  if (dataColumn) {
9755
10490
  finalColumns.push(dataColumn);
9756
10491
  }
9757
- }
9758
- }
9759
- const remainingDataColumns = baseColumns.filter((col) => {
9760
- const colId = col.id ? String(col.id) : "accessorKey" in col ? String(col.accessorKey) : "";
9761
- return !usedColumnIds.has(colId);
9762
- });
9763
- finalColumns.push(...remainingDataColumns);
9764
- if (actionsColumn && !usedColumnIds.has("actions")) {
9765
- finalColumns.push(actionsColumn);
9766
- }
9767
- } else {
9768
- if (selectionColumn) {
9769
- finalColumns.push(selectionColumn);
10492
+ }
10493
+ }
10494
+ const remainingDataColumns = baseColumns.filter((col) => {
10495
+ const colId = col.id ? String(col.id) : "accessorKey" in col ? String(col.accessorKey) : "";
10496
+ return !usedColumnIds.has(colId);
10497
+ });
10498
+ finalColumns.push(...remainingDataColumns);
10499
+ if (actionsColumn && !usedColumnIds.has("actions")) {
10500
+ finalColumns.push(actionsColumn);
10501
+ }
10502
+ } else {
10503
+ if (selectionColumn) {
10504
+ finalColumns.push(selectionColumn);
10505
+ }
10506
+ finalColumns.push(...baseColumns);
10507
+ if (actionsColumn) {
10508
+ finalColumns.push(actionsColumn);
10509
+ }
10510
+ }
10511
+ return finalColumns;
10512
+ }, [columns, features, effectiveActions, columnOrder]);
10513
+ return {
10514
+ enhancedColumns
10515
+ };
10516
+ }
10517
+
10518
+ // src/components/DataTable/utils/a11yUtils.ts
10519
+ var liveRegion = null;
10520
+ function initializeLiveRegion() {
10521
+ if (typeof window === "undefined") return null;
10522
+ if (liveRegion && document.contains(liveRegion)) {
10523
+ return liveRegion;
10524
+ }
10525
+ liveRegion = document.createElement("div");
10526
+ liveRegion.setAttribute("aria-live", "polite");
10527
+ liveRegion.setAttribute("aria-atomic", "true");
10528
+ liveRegion.setAttribute("class", "sr-only");
10529
+ liveRegion.style.position = "absolute";
10530
+ liveRegion.style.left = "-10000px";
10531
+ liveRegion.style.width = "1px";
10532
+ liveRegion.style.height = "1px";
10533
+ liveRegion.style.overflow = "hidden";
10534
+ document.body.appendChild(liveRegion);
10535
+ return liveRegion;
10536
+ }
10537
+ function cleanupLiveRegion() {
10538
+ if (typeof window === "undefined") return;
10539
+ if (liveRegion && document.contains(liveRegion)) {
10540
+ document.body.removeChild(liveRegion);
10541
+ liveRegion = null;
10542
+ }
10543
+ }
10544
+ function announce(message, priority = "polite") {
10545
+ if (!message.trim() || typeof window === "undefined") return;
10546
+ const region = liveRegion || initializeLiveRegion();
10547
+ if (!region) return;
10548
+ if (region.getAttribute("aria-live") !== priority) {
10549
+ region.setAttribute("aria-live", priority);
10550
+ }
10551
+ region.textContent = "";
10552
+ setTimeout(() => {
10553
+ region.textContent = message;
10554
+ }, 100);
10555
+ setTimeout(() => {
10556
+ if (region.textContent === message) {
10557
+ region.textContent = "";
10558
+ }
10559
+ }, 1e3);
10560
+ }
10561
+ function getSortButtonLabel(columnName, currentSort) {
10562
+ if (currentSort === "asc") {
10563
+ return `Sort ${columnName} descending`;
10564
+ } else if (currentSort === "desc") {
10565
+ return `Remove sort from ${columnName}`;
10566
+ } else {
10567
+ return `Sort ${columnName} ascending`;
10568
+ }
10569
+ }
10570
+ function announceSortChange(columnName, sortDirection) {
10571
+ let message;
10572
+ if (sortDirection === "asc") {
10573
+ message = `Table sorted by ${columnName} in ascending order`;
10574
+ } else if (sortDirection === "desc") {
10575
+ message = `Table sorted by ${columnName} in descending order`;
10576
+ } else {
10577
+ message = `Sort removed from ${columnName}`;
10578
+ }
10579
+ announce(message);
10580
+ }
10581
+ function announceFilterChange(columnName, filterValue, resultCount) {
10582
+ if (filterValue.trim()) {
10583
+ const message = `Filtered ${columnName} by "${filterValue}". ${resultCount} ${resultCount === 1 ? "result" : "results"} found.`;
10584
+ announce(message);
10585
+ } else {
10586
+ announce(`Filter removed from ${columnName}`);
10587
+ }
10588
+ }
10589
+ function announceSearchResults(query, resultCount) {
10590
+ if (query.trim()) {
10591
+ const message = `Search for "${query}" returned ${resultCount} ${resultCount === 1 ? "result" : "results"}.`;
10592
+ announce(message);
10593
+ } else {
10594
+ announce("Search cleared");
10595
+ }
10596
+ }
10597
+ function announcePaginationChange(currentPage, totalPages, pageSize, totalItems) {
10598
+ const startItem = (currentPage - 1) * pageSize + 1;
10599
+ const endItem = Math.min(currentPage * pageSize, totalItems);
10600
+ const message = `Page ${currentPage} of ${totalPages}. Showing items ${startItem} to ${endItem} of ${totalItems}.`;
10601
+ announce(message);
10602
+ }
10603
+ function announceSelectionChange(selectedCount, totalCount) {
10604
+ if (selectedCount === 0) {
10605
+ announce("All rows deselected");
10606
+ } else if (selectedCount === totalCount) {
10607
+ announce(`All ${totalCount} rows selected`);
10608
+ } else {
10609
+ announce(`${selectedCount} of ${totalCount} rows selected`);
10610
+ }
10611
+ }
10612
+ function announceLoadingState(isLoading, hasError = false) {
10613
+ if (hasError) {
10614
+ announce("Error loading data", "assertive");
10615
+ } else if (isLoading) {
10616
+ announce("Loading data...");
10617
+ } else {
10618
+ announce("Data loaded");
10619
+ }
10620
+ }
10621
+ function announceBulkOperation(operation, count) {
10622
+ const message = `${operation} completed for ${count} ${count === 1 ? "item" : "items"}`;
10623
+ announce(message);
10624
+ }
10625
+ function getAriaSortValue(sortDirection) {
10626
+ if (sortDirection === "asc") return "ascending";
10627
+ if (sortDirection === "desc") return "descending";
10628
+ return "none";
10629
+ }
10630
+ function getRowDescription(rowIndex, totalRows, isSelected = false, isEditing = false) {
10631
+ let description = `Row ${rowIndex + 1} of ${totalRows}`;
10632
+ if (isSelected) {
10633
+ description += ", selected";
10634
+ }
10635
+ if (isEditing) {
10636
+ description += ", editing mode";
10637
+ }
10638
+ return description;
10639
+ }
10640
+
10641
+ // src/components/DataTable/hooks/useKeyboardNavigation.ts
10642
+ import { useCallback as useCallback9, useEffect as useEffect11, useRef as useRef6, useState as useState8 } from "react";
10643
+ function useKeyboardNavigation(rowCount, columnCount, options = {}) {
10644
+ const {
10645
+ enabled = true,
10646
+ announceNavigation = true,
10647
+ supportsColumnReorder = false,
10648
+ supportsColumnResize = false,
10649
+ onFocusChange,
10650
+ tableRef: externalTableRef
10651
+ } = options;
10652
+ const [state, setState] = useState8({
10653
+ focusedRowIndex: 0,
10654
+ focusedColumnIndex: 0,
10655
+ isNavigating: false
10656
+ });
10657
+ const internalTableRef = useRef6(null);
10658
+ const tableRef = externalTableRef || internalTableRef;
10659
+ const storedFocusRef = useRef6(null);
10660
+ const navigationTimeoutRef = useRef6();
10661
+ const getCellElement = useCallback9((rowIndex, columnIndex) => {
10662
+ if (!tableRef.current) return null;
10663
+ const tbody = tableRef.current.querySelector("tbody");
10664
+ if (!tbody) return null;
10665
+ const rows = tbody.querySelectorAll('tr[role="row"]');
10666
+ const row = rows[rowIndex];
10667
+ if (!row) return null;
10668
+ const cells = row.querySelectorAll('td[role="cell"], th[role="columnheader"]');
10669
+ return cells[columnIndex] || null;
10670
+ }, []);
10671
+ const getHeaderElement = useCallback9((columnIndex) => {
10672
+ if (!tableRef.current) return null;
10673
+ const thead = tableRef.current.querySelector("thead");
10674
+ if (!thead) return null;
10675
+ const headerRow = thead.querySelector('tr[role="row"]');
10676
+ if (!headerRow) return null;
10677
+ const headers = headerRow.querySelectorAll('th[role="columnheader"]');
10678
+ return headers[columnIndex] || null;
10679
+ }, []);
10680
+ const focusCell = useCallback9((rowIndex, columnIndex) => {
10681
+ if (!enabled) return;
10682
+ const clampedRowIndex = Math.max(0, Math.min(rowIndex, rowCount - 1));
10683
+ const clampedColumnIndex = Math.max(0, Math.min(columnIndex, columnCount - 1));
10684
+ setState((prev) => ({
10685
+ ...prev,
10686
+ focusedRowIndex: clampedRowIndex,
10687
+ focusedColumnIndex: clampedColumnIndex,
10688
+ isNavigating: true
10689
+ }));
10690
+ const cellElement = getCellElement(clampedRowIndex, clampedColumnIndex);
10691
+ if (cellElement) {
10692
+ cellElement.focus();
10693
+ }
10694
+ onFocusChange?.(clampedRowIndex, clampedColumnIndex);
10695
+ if (announceNavigation) {
10696
+ announce(`Row ${clampedRowIndex + 1}, Column ${clampedColumnIndex + 1}`);
10697
+ }
10698
+ }, [enabled, rowCount, columnCount, getCellElement, onFocusChange, announceNavigation]);
10699
+ const focusNext = useCallback9(() => {
10700
+ const { focusedRowIndex, focusedColumnIndex } = state;
10701
+ if (focusedColumnIndex < columnCount - 1) {
10702
+ focusCell(focusedRowIndex, focusedColumnIndex + 1);
10703
+ } else if (focusedRowIndex < rowCount - 1) {
10704
+ focusCell(focusedRowIndex + 1, 0);
10705
+ }
10706
+ }, [state, columnCount, rowCount, focusCell]);
10707
+ const focusPrevious = useCallback9(() => {
10708
+ const { focusedRowIndex, focusedColumnIndex } = state;
10709
+ if (focusedColumnIndex > 0) {
10710
+ focusCell(focusedRowIndex, focusedColumnIndex - 1);
10711
+ } else if (focusedRowIndex > 0) {
10712
+ focusCell(focusedRowIndex - 1, columnCount - 1);
10713
+ }
10714
+ }, [state, columnCount, focusCell]);
10715
+ const focusUp = useCallback9(() => {
10716
+ const { focusedRowIndex, focusedColumnIndex } = state;
10717
+ if (focusedRowIndex > 0) {
10718
+ focusCell(focusedRowIndex - 1, focusedColumnIndex);
10719
+ }
10720
+ }, [state, focusCell]);
10721
+ const focusDown = useCallback9(() => {
10722
+ const { focusedRowIndex, focusedColumnIndex } = state;
10723
+ if (focusedRowIndex < rowCount - 1) {
10724
+ focusCell(focusedRowIndex + 1, focusedColumnIndex);
10725
+ }
10726
+ }, [state, rowCount, focusCell]);
10727
+ const focusRowStart = useCallback9(() => {
10728
+ const { focusedRowIndex } = state;
10729
+ focusCell(focusedRowIndex, 0);
10730
+ }, [state, focusCell]);
10731
+ const focusRowEnd = useCallback9(() => {
10732
+ const { focusedRowIndex } = state;
10733
+ focusCell(focusedRowIndex, columnCount - 1);
10734
+ }, [state, columnCount, focusCell]);
10735
+ const focusTableStart = useCallback9(() => {
10736
+ focusCell(0, 0);
10737
+ }, [focusCell]);
10738
+ const focusTableEnd = useCallback9(() => {
10739
+ focusCell(rowCount - 1, columnCount - 1);
10740
+ }, [rowCount, columnCount, focusCell]);
10741
+ const getCellTabIndex = useCallback9((rowIndex, columnIndex) => {
10742
+ if (!enabled) return -1;
10743
+ return state.focusedRowIndex === rowIndex && state.focusedColumnIndex === columnIndex ? 0 : -1;
10744
+ }, [enabled, state.focusedRowIndex, state.focusedColumnIndex]);
10745
+ const getCellKeyboardHandlers = useCallback9((rowIndex, columnIndex) => {
10746
+ const onKeyDown = (event) => {
10747
+ if (!enabled) return;
10748
+ switch (event.key) {
10749
+ case "ArrowRight":
10750
+ event.preventDefault();
10751
+ if (event.ctrlKey || event.metaKey) {
10752
+ focusRowEnd();
10753
+ } else {
10754
+ focusNext();
10755
+ }
10756
+ break;
10757
+ case "ArrowLeft":
10758
+ event.preventDefault();
10759
+ if (event.ctrlKey || event.metaKey) {
10760
+ focusRowStart();
10761
+ } else {
10762
+ focusPrevious();
10763
+ }
10764
+ break;
10765
+ case "ArrowDown":
10766
+ event.preventDefault();
10767
+ if (event.ctrlKey || event.metaKey) {
10768
+ focusTableEnd();
10769
+ } else {
10770
+ focusDown();
10771
+ }
10772
+ break;
10773
+ case "ArrowUp":
10774
+ event.preventDefault();
10775
+ if (event.ctrlKey || event.metaKey) {
10776
+ focusTableStart();
10777
+ } else {
10778
+ focusUp();
10779
+ }
10780
+ break;
10781
+ case "Home":
10782
+ event.preventDefault();
10783
+ if (event.ctrlKey || event.metaKey) {
10784
+ focusTableStart();
10785
+ } else {
10786
+ focusRowStart();
10787
+ }
10788
+ break;
10789
+ case "End":
10790
+ event.preventDefault();
10791
+ if (event.ctrlKey || event.metaKey) {
10792
+ focusTableEnd();
10793
+ } else {
10794
+ focusRowEnd();
10795
+ }
10796
+ break;
10797
+ case "Tab":
10798
+ break;
10799
+ default:
10800
+ break;
9770
10801
  }
9771
- finalColumns.push(...baseColumns);
9772
- if (actionsColumn) {
9773
- finalColumns.push(actionsColumn);
10802
+ };
10803
+ const onFocus = (event) => {
10804
+ setState((prev) => ({
10805
+ ...prev,
10806
+ focusedRowIndex: rowIndex,
10807
+ focusedColumnIndex: columnIndex,
10808
+ isNavigating: true
10809
+ }));
10810
+ onFocusChange?.(rowIndex, columnIndex);
10811
+ };
10812
+ const onBlur = (event) => {
10813
+ if (navigationTimeoutRef.current) {
10814
+ clearTimeout(navigationTimeoutRef.current);
10815
+ }
10816
+ navigationTimeoutRef.current = setTimeout(() => {
10817
+ setState((prev) => ({
10818
+ ...prev,
10819
+ isNavigating: false
10820
+ }));
10821
+ }, 100);
10822
+ };
10823
+ return { onKeyDown, onFocus, onBlur };
10824
+ }, [enabled, focusNext, focusPrevious, focusUp, focusDown, focusRowStart, focusRowEnd, focusTableStart, focusTableEnd, onFocusChange]);
10825
+ const getHeaderKeyboardHandlers = useCallback9((columnIndex, onSort) => {
10826
+ const onKeyDown = (event) => {
10827
+ if (!enabled) return;
10828
+ switch (event.key) {
10829
+ case "Enter":
10830
+ case " ":
10831
+ event.preventDefault();
10832
+ onSort?.();
10833
+ break;
10834
+ case "ArrowRight":
10835
+ event.preventDefault();
10836
+ const nextHeader = getHeaderElement(columnIndex + 1);
10837
+ if (nextHeader) {
10838
+ nextHeader.focus();
10839
+ }
10840
+ break;
10841
+ case "ArrowLeft":
10842
+ event.preventDefault();
10843
+ const prevHeader = getHeaderElement(columnIndex - 1);
10844
+ if (prevHeader) {
10845
+ prevHeader.focus();
10846
+ }
10847
+ break;
10848
+ case "Home":
10849
+ event.preventDefault();
10850
+ const firstHeader = getHeaderElement(0);
10851
+ if (firstHeader) {
10852
+ firstHeader.focus();
10853
+ }
10854
+ break;
10855
+ case "End":
10856
+ event.preventDefault();
10857
+ const lastHeader = getHeaderElement(columnCount - 1);
10858
+ if (lastHeader) {
10859
+ lastHeader.focus();
10860
+ }
10861
+ break;
10862
+ // Disable unsupported keyboard operations
10863
+ case "r":
10864
+ if (!supportsColumnReorder && (event.ctrlKey || event.metaKey)) {
10865
+ event.preventDefault();
10866
+ announce("Column reordering is not supported");
10867
+ }
10868
+ break;
10869
+ case "=":
10870
+ case "+":
10871
+ case "-":
10872
+ if (!supportsColumnResize && (event.ctrlKey || event.metaKey)) {
10873
+ event.preventDefault();
10874
+ announce("Column resizing is not supported");
10875
+ }
10876
+ break;
9774
10877
  }
10878
+ };
10879
+ const onFocus = (event) => {
10880
+ };
10881
+ return { onKeyDown, onFocus };
10882
+ }, [enabled, getHeaderElement, columnCount, supportsColumnReorder, supportsColumnResize]);
10883
+ const resetFocus = useCallback9(() => {
10884
+ setState({
10885
+ focusedRowIndex: 0,
10886
+ focusedColumnIndex: 0,
10887
+ isNavigating: false
10888
+ });
10889
+ }, []);
10890
+ const storeFocus = useCallback9(() => {
10891
+ storedFocusRef.current = {
10892
+ rowIndex: state.focusedRowIndex,
10893
+ columnIndex: state.focusedColumnIndex
10894
+ };
10895
+ }, [state.focusedRowIndex, state.focusedColumnIndex]);
10896
+ const restoreFocus = useCallback9(() => {
10897
+ if (storedFocusRef.current) {
10898
+ const { rowIndex, columnIndex } = storedFocusRef.current;
10899
+ focusCell(rowIndex, columnIndex);
10900
+ storedFocusRef.current = null;
9775
10901
  }
9776
- return finalColumns;
9777
- }, [columns, features, effectiveActions, columnOrder]);
10902
+ }, [focusCell]);
10903
+ useEffect11(() => {
10904
+ return () => {
10905
+ if (navigationTimeoutRef.current) {
10906
+ clearTimeout(navigationTimeoutRef.current);
10907
+ }
10908
+ };
10909
+ }, []);
9778
10910
  return {
9779
- enhancedColumns
10911
+ state,
10912
+ focusCell,
10913
+ focusNext,
10914
+ focusPrevious,
10915
+ focusUp,
10916
+ focusDown,
10917
+ focusRowStart,
10918
+ focusRowEnd,
10919
+ focusTableStart,
10920
+ focusTableEnd,
10921
+ getCellTabIndex,
10922
+ getCellKeyboardHandlers,
10923
+ getHeaderKeyboardHandlers,
10924
+ resetFocus,
10925
+ storeFocus,
10926
+ restoreFocus
9780
10927
  };
9781
10928
  }
9782
10929
 
9783
10930
  // src/components/DataTable/components/DataTableCore.tsx
9784
10931
  import { Fragment as Fragment7, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
10932
+ var isCellValue = (value) => {
10933
+ if (value === null || value === void 0) {
10934
+ return true;
10935
+ }
10936
+ if (value instanceof Date) {
10937
+ return true;
10938
+ }
10939
+ const valueType = typeof value;
10940
+ return valueType === "string" || valueType === "number" || valueType === "boolean";
10941
+ };
10942
+ var toCellValueRecord = (row) => {
10943
+ if (typeof row !== "object" || row === null) {
10944
+ return {};
10945
+ }
10946
+ return Object.entries(row).reduce((accumulator, [key, entryValue]) => {
10947
+ if (isCellValue(entryValue)) {
10948
+ accumulator[key] = entryValue;
10949
+ } else if (entryValue && typeof entryValue === "object" && "toString" in entryValue) {
10950
+ accumulator[key] = String(entryValue);
10951
+ } else {
10952
+ accumulator[key] = entryValue;
10953
+ }
10954
+ return accumulator;
10955
+ }, {});
10956
+ };
9785
10957
  function DataTableInternal({
9786
10958
  data,
9787
10959
  columns,
@@ -9791,7 +10963,7 @@ function DataTableInternal({
9791
10963
  description,
9792
10964
  variant = "default",
9793
10965
  className,
9794
- features,
10966
+ features: incomingFeatures = {},
9795
10967
  hierarchical,
9796
10968
  performance = {},
9797
10969
  serverSide,
@@ -9819,23 +10991,38 @@ function DataTableInternal({
9819
10991
  actions = [],
9820
10992
  columnOrder: externalColumnOrder,
9821
10993
  defaultGrouping,
9822
- defaultSorting
10994
+ defaultSorting,
10995
+ storageKey,
10996
+ onLayoutChange
9823
10997
  }) {
9824
10998
  const authResult = useUnifiedAuth();
9825
10999
  const user = authResult.user;
9826
- const { permissions, secureFeatures, effectivePageId } = useDataTablePermissions(rbac, features);
9827
- const baseColumnOrder = useMemo9(() => {
9828
- if (externalColumnOrder && externalColumnOrder.length > 0) {
9829
- return externalColumnOrder;
9830
- }
9831
- return columns.map((col) => col.id || col.accessorKey || "").filter(Boolean);
9832
- }, [externalColumnOrder, columns]);
9833
- const effectiveColumnOrder = useMemo9(() => {
9834
- if (features.selection && !baseColumnOrder.includes("select")) {
9835
- return ["select", ...baseColumnOrder];
11000
+ const requestedFeatures = useMemo14(
11001
+ () => normalizeDataTableFeatures(incomingFeatures),
11002
+ [incomingFeatures]
11003
+ );
11004
+ const { permissions, secureFeatures, effectivePageId } = useDataTablePermissions(rbac, requestedFeatures);
11005
+ const effectiveColumnOrder = useEffectiveColumnOrder({
11006
+ columns,
11007
+ externalColumnOrder,
11008
+ selectionEnabled: secureFeatures.selection
11009
+ });
11010
+ const {
11011
+ columnVisibility: savedColumnVisibility,
11012
+ isLoaded: isColumnVisibilityLoaded,
11013
+ updateColumnVisibility: updateSavedColumnVisibility
11014
+ } = useColumnVisibilityPersistence({
11015
+ tableId: title ? `datatable-${title.toLowerCase().replace(/\s+/g, "-")}` : void 0,
11016
+ defaultVisibility: {},
11017
+ enablePersistence: secureFeatures.columnVisibility,
11018
+ storageKey
11019
+ });
11020
+ const initialColumnVisibility = useMemo14(() => {
11021
+ if (secureFeatures.columnVisibility && savedColumnVisibility && Object.keys(savedColumnVisibility).length > 0) {
11022
+ return savedColumnVisibility;
9836
11023
  }
9837
- return baseColumnOrder;
9838
- }, [baseColumnOrder, features.selection]);
11024
+ return {};
11025
+ }, [secureFeatures.columnVisibility, savedColumnVisibility]);
9839
11026
  const { state, actions: stateActions } = useDataTableState({
9840
11027
  initialPageSize,
9841
11028
  columnIds: effectiveColumnOrder,
@@ -9844,9 +11031,21 @@ function DataTableInternal({
9844
11031
  defaultSorting: defaultSorting || [],
9845
11032
  defaultGrouping: defaultGrouping || []
9846
11033
  });
11034
+ useEffect12(() => {
11035
+ if (secureFeatures.columnVisibility && isColumnVisibilityLoaded && Object.keys(initialColumnVisibility).length > 0) {
11036
+ stateActions.setColumnVisibility(initialColumnVisibility);
11037
+ }
11038
+ }, [secureFeatures.columnVisibility, isColumnVisibilityLoaded, initialColumnVisibility, stateActions]);
11039
+ useEffect12(() => {
11040
+ initializeLiveRegion();
11041
+ }, []);
9847
11042
  const rowSelection = selection !== void 0 ? selection : state.rowSelection;
9848
- const hasInitializedExpansion = useRef6(false);
9849
- useEffect8(() => {
11043
+ const resolvedGetRowId = useCallback10(
11044
+ (row, index) => getRowIdSafe(row, index, getRowId),
11045
+ [getRowId]
11046
+ );
11047
+ const hasInitializedExpansion = useRef7(false);
11048
+ useEffect12(() => {
9850
11049
  if (!hasInitializedExpansion.current && defaultGrouping && defaultGrouping.length > 0) {
9851
11050
  stateActions.setExpanded(true);
9852
11051
  hasInitializedExpansion.current = true;
@@ -9878,8 +11077,6 @@ function DataTableInternal({
9878
11077
  paginationMode: detectedMode,
9879
11078
  isVirtualized,
9880
11079
  pageSizeOptions: optimizedPageSizeOptions,
9881
- processedData,
9882
- totalCount,
9883
11080
  isLoading: performanceLoading,
9884
11081
  searchQuery,
9885
11082
  setSearchQuery,
@@ -9887,22 +11084,48 @@ function DataTableInternal({
9887
11084
  serverData,
9888
11085
  cleanup
9889
11086
  } = performanceHook;
9890
- const hierarchicalValidation = useMemo9(() => {
9891
- if (features.hierarchical && hierarchical?.enabled) {
9892
- return validateHierarchicalData(data);
9893
- }
9894
- return { isValid: true, errors: [] };
9895
- }, [features.hierarchical, hierarchical?.enabled, data]);
9896
- const processedHierarchicalData = useMemo9(() => {
9897
- if (features.hierarchical && hierarchical?.enabled && hierarchicalValidation.isValid) {
9898
- return sortHierarchicalDataByStructure(data);
11087
+ const finalPaginationMode = paginationMode || detectedMode;
11088
+ const keyboardNavigation = useKeyboardNavigation(
11089
+ data.length,
11090
+ columns.length,
11091
+ {
11092
+ enabled: true,
11093
+ announceNavigation: true,
11094
+ supportsColumnReorder: secureFeatures.columnReordering,
11095
+ supportsColumnResize: false
11096
+ // Column resizing is not currently supported
9899
11097
  }
9900
- return data;
9901
- }, [features.hierarchical, hierarchical?.enabled, hierarchicalValidation.isValid, data]);
9902
- const hierarchicalState = useHierarchicalState(
9903
- processedHierarchicalData,
9904
- hierarchical
9905
11098
  );
11099
+ useEffect12(() => {
11100
+ if (state.showImportModal) {
11101
+ keyboardNavigation.storeFocus();
11102
+ }
11103
+ }, [state.showImportModal, keyboardNavigation]);
11104
+ useEffect12(() => {
11105
+ if (!state.showImportModal) {
11106
+ setTimeout(() => {
11107
+ keyboardNavigation.restoreFocus();
11108
+ }, 100);
11109
+ }
11110
+ }, [state.showImportModal, keyboardNavigation]);
11111
+ const {
11112
+ finalTableData,
11113
+ dataCount: finalDataCount,
11114
+ hierarchicalState,
11115
+ hierarchicalValidation
11116
+ } = useDataTableDataPipeline({
11117
+ data,
11118
+ features: secureFeatures,
11119
+ hierarchical,
11120
+ sorting: state.sorting,
11121
+ finalPaginationMode,
11122
+ serverData
11123
+ });
11124
+ useEffect12(() => {
11125
+ if (!hierarchicalValidation.isValid && import.meta.env?.MODE === "development") {
11126
+ console.error("[DataTable] Hierarchical data validation failed:", hierarchicalValidation.errors);
11127
+ }
11128
+ }, [hierarchicalValidation]);
9906
11129
  const {
9907
11130
  columnOrder: savedColumnOrder,
9908
11131
  isLoaded: isColumnOrderLoaded,
@@ -9910,12 +11133,17 @@ function DataTableInternal({
9910
11133
  } = useColumnOrderPersistence({
9911
11134
  tableId: title ? `datatable-${title.toLowerCase().replace(/\s+/g, "-")}` : void 0,
9912
11135
  defaultOrder: columns.map((col) => col.id || col.accessorKey || ""),
9913
- enablePersistence: features.columnReordering
11136
+ enablePersistence: secureFeatures.columnReordering,
11137
+ storageKey
9914
11138
  });
9915
- const finalPaginationMode = paginationMode || detectedMode;
11139
+ useEffect12(() => {
11140
+ if (secureFeatures.columnReordering && isColumnOrderLoaded && savedColumnOrder && savedColumnOrder.length > 0) {
11141
+ stateActions.setColumnOrder(savedColumnOrder);
11142
+ }
11143
+ }, [secureFeatures.columnReordering, isColumnOrderLoaded, savedColumnOrder, stateActions]);
9916
11144
  const finalPageSizeOptions = optimizedPageSizeOptions;
9917
- const validatedInitialPageSize = useMemo9(() => {
9918
- if (!features.pagination || !finalPageSizeOptions.length) {
11145
+ const validatedInitialPageSize = useMemo14(() => {
11146
+ if (!secureFeatures.pagination || !finalPageSizeOptions.length) {
9919
11147
  return initialPageSize;
9920
11148
  }
9921
11149
  if (finalPageSizeOptions.includes(initialPageSize)) {
@@ -9925,73 +11153,33 @@ function DataTableInternal({
9925
11153
  const closestOption = sortedOptions.reduce(
9926
11154
  (prev, curr) => Math.abs(curr - initialPageSize) < Math.abs(prev - initialPageSize) ? curr : prev
9927
11155
  );
9928
- console.warn(
9929
- `DataTable: initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(", ")}]. Using closest option: ${closestOption}`
9930
- );
11156
+ if (import.meta.env?.MODE === "development") {
11157
+ console.warn(
11158
+ `DataTable: initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(", ")}]. Using closest option: ${closestOption}`
11159
+ );
11160
+ }
9931
11161
  return closestOption;
9932
- }, [initialPageSize, finalPageSizeOptions, features.pagination]);
11162
+ }, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination]);
9933
11163
  const isLoading = externalIsLoading || performanceLoading;
9934
- const baseData = useMemo9(() => {
9935
- return finalPaginationMode === "server" ? serverData?.data || [] : processedHierarchicalData;
9936
- }, [finalPaginationMode, serverData?.data, processedHierarchicalData]);
9937
- const tableData = useMemo9(() => {
9938
- return features.hierarchical && hierarchical?.enabled ? hierarchicalState.visibleRows : baseData;
9939
- }, [features.hierarchical, hierarchical?.enabled, hierarchicalState.visibleRows, baseData]);
9940
- const dataCount = useMemo9(() => {
9941
- return finalPaginationMode === "server" ? serverData?.totalCount || 0 : data?.length || 0;
9942
- }, [finalPaginationMode, serverData?.totalCount, data?.length]);
9943
- const sortedTableData = useMemo9(() => {
9944
- if (features.hierarchical && hierarchical?.enabled && sorting.length > 0) {
9945
- const hierarchicalVisibleRows = hierarchicalState.visibleRows;
9946
- return sortHierarchicalDataWithSorting(hierarchicalVisibleRows, sorting);
9947
- }
9948
- return tableData;
9949
- }, [features.hierarchical, hierarchical?.enabled, hierarchicalState.visibleRows, sorting, tableData]);
9950
- const finalTableData = useMemo9(() => {
9951
- return features.hierarchical && hierarchical?.enabled && sorting.length > 0 ? sortedTableData : tableData;
9952
- }, [features.hierarchical, hierarchical?.enabled, sorting.length, sortedTableData, tableData]);
9953
- const finalDataCount = finalPaginationMode === "server" ? serverData?.totalCount || 0 : finalTableData?.length || 0;
9954
- const handleSearch = useCallback6((value) => {
11164
+ const handleSearch = useCallback10((value) => {
9955
11165
  stateActions.setSearchQuery(value);
9956
- if (features.pagination) {
11166
+ if (secureFeatures.pagination) {
9957
11167
  stateActions.setPagination({ ...state.pagination, pageIndex: 0 });
9958
11168
  }
9959
- }, [stateActions, features.pagination, state.pagination]);
9960
- const handleServerSideChange = useCallback6(async () => {
9961
- if (finalPaginationMode !== "server" || !serverSide) return;
9962
- const params = {
9963
- pageIndex: state.pagination.pageIndex,
9964
- pageSize: state.pagination.pageSize,
9965
- sorting: state.sorting,
9966
- columnFilters: state.columnFilters,
9967
- globalFilter: searchQuery,
9968
- grouping: state.grouping
9969
- };
9970
- await fetchServerData(params);
9971
- }, [
11169
+ }, [stateActions, secureFeatures.pagination, state.pagination]);
11170
+ useServerSideDataEffect({
9972
11171
  finalPaginationMode,
9973
11172
  serverSide,
9974
- state.pagination,
9975
- state.sorting,
9976
- state.columnFilters,
11173
+ pagination: state.pagination,
11174
+ sorting: state.sorting,
11175
+ columnFilters: state.columnFilters,
11176
+ grouping: state.grouping,
9977
11177
  searchQuery,
9978
- state.grouping,
9979
- fetchServerData
9980
- ]);
9981
- useEffect8(() => {
9982
- if (finalPaginationMode !== "server") return;
9983
- if (!serverSide) return;
9984
- if (tableData && tableData.length > 0 && finalPaginationMode !== "server") return;
9985
- handleServerSideChange();
9986
- }, [handleServerSideChange, tableData, finalPaginationMode, serverSide]);
9987
- useEffect8(() => {
9988
- return () => {
9989
- if (typeof cleanup === "function") {
9990
- cleanup();
9991
- }
9992
- };
9993
- }, [cleanup]);
9994
- const secureHandlers = useMemo9(() => ({
11178
+ tableDataLength: finalTableData.length,
11179
+ fetchServerData,
11180
+ cleanup
11181
+ });
11182
+ const secureHandlers = useMemo14(() => ({
9995
11183
  onEditRow: permissions.canUpdate.can ? onEditRow : void 0,
9996
11184
  onDeleteRow: permissions.canDelete.can ? onDeleteRow : void 0,
9997
11185
  onCreateRow: permissions.canCreate.can ? onCreateRow : void 0,
@@ -9999,7 +11187,7 @@ function DataTableInternal({
9999
11187
  onExport: permissions.canExport.can ? onExport : void 0,
10000
11188
  onDeleteSelected: permissions.canDelete.can ? onDeleteSelected : void 0
10001
11189
  }), [permissions.canUpdate.can, permissions.canDelete.can, permissions.canCreate.can, permissions.canImport.can, permissions.canExport.can, onEditRow, onDeleteRow, onCreateRow, onImport, onExport, onDeleteSelected]);
10002
- const effectiveActions = useMemo9(() => {
11190
+ const effectiveActions = useMemo14(() => {
10003
11191
  const result = [...actions];
10004
11192
  if (import.meta.env.MODE === "development") {
10005
11193
  console.log("[DataTable] Action Configuration Debug:", {
@@ -10025,18 +11213,9 @@ function DataTableInternal({
10025
11213
  if (!permissions.canUpdate.can) {
10026
11214
  throw new Error("Insufficient permissions to edit this resource");
10027
11215
  }
10028
- let rowId;
10029
- if (getRowId) {
10030
- const rowIndex = data.findIndex((r) => r === row);
10031
- rowId = getRowId(row, rowIndex);
10032
- } else {
10033
- rowId = row.id;
10034
- }
10035
- if (!rowId) {
10036
- console.error("[DataTable] Cannot edit row: no id found. Make sure to provide getRowId or ensure row data has an id property.");
10037
- return;
10038
- }
10039
- stateActions.setEditingRow(rowId, { ...row });
11216
+ const rowIndex = data.findIndex((r) => r === row);
11217
+ const rowId = resolvedGetRowId(row, rowIndex >= 0 ? rowIndex : 0);
11218
+ stateActions.setEditingRow(rowId, toCellValueRecord(row));
10040
11219
  },
10041
11220
  icon: Edit,
10042
11221
  testId: "edit",
@@ -10066,81 +11245,24 @@ function DataTableInternal({
10066
11245
  });
10067
11246
  }
10068
11247
  return result;
10069
- }, [actions, secureFeatures, permissions, secureHandlers, getRowId, stateActions]);
11248
+ }, [actions, secureFeatures, permissions, secureHandlers, resolvedGetRowId, stateActions, data]);
10070
11249
  const { enhancedColumns } = useTableColumns({
10071
11250
  columns,
10072
11251
  features: secureFeatures,
10073
11252
  effectiveActions,
10074
11253
  columnOrder: state.columnOrder
10075
11254
  });
10076
- const tableConfig = useMemo9(() => ({
10077
- data: finalTableData,
10078
- columns: enhancedColumns,
10079
- state: {
10080
- sorting: state.sorting,
10081
- columnFilters: state.columnFilters,
10082
- columnVisibility: state.columnVisibility,
10083
- rowSelection,
10084
- grouping: state.grouping,
10085
- expanded: state.expanded,
10086
- pagination: state.pagination,
10087
- globalFilter: searchQuery,
10088
- columnOrder: effectiveColumnOrder
10089
- },
10090
- initialState: {
10091
- expanded: features.grouping ? {} : void 0
10092
- },
10093
- enableRowSelection: features.selection,
10094
- enableGrouping: features.grouping,
10095
- getRowId: getRowId || ((row) => row?.id || row?.toString() || "unknown"),
10096
- onSortingChange: (updaterOrValue) => {
10097
- const newSorting = typeof updaterOrValue === "function" ? updaterOrValue(state.sorting) : updaterOrValue;
10098
- stateActions.setSorting(newSorting);
10099
- },
10100
- onColumnFiltersChange: (updaterOrValue) => {
10101
- const newFilters = typeof updaterOrValue === "function" ? updaterOrValue(state.columnFilters) : updaterOrValue;
10102
- stateActions.setColumnFilters(newFilters);
10103
- },
10104
- onColumnVisibilityChange: (updaterOrValue) => {
10105
- const newVisibility = typeof updaterOrValue === "function" ? updaterOrValue(state.columnVisibility) : updaterOrValue;
10106
- stateActions.setColumnVisibility(newVisibility);
10107
- },
10108
- onRowSelectionChange: (updaterOrValue) => {
10109
- const newSelection = typeof updaterOrValue === "function" ? updaterOrValue(selection !== void 0 ? selection : state.rowSelection) : updaterOrValue;
10110
- if (selection === void 0) {
10111
- stateActions.setRowSelection(newSelection);
10112
- }
10113
- onRowSelectionChange?.(newSelection);
10114
- },
10115
- onGroupingChange: (updaterOrValue) => {
10116
- const newGrouping = typeof updaterOrValue === "function" ? updaterOrValue(state.grouping) : updaterOrValue;
10117
- stateActions.setGrouping(newGrouping);
10118
- },
10119
- onExpandedChange: (updaterOrValue) => {
10120
- const newExpanded = typeof updaterOrValue === "function" ? updaterOrValue(state.expanded) : updaterOrValue;
10121
- stateActions.setExpanded(newExpanded);
10122
- },
10123
- onPaginationChange: (updaterOrValue) => {
10124
- const newPagination = typeof updaterOrValue === "function" ? updaterOrValue(state.pagination) : updaterOrValue;
10125
- stateActions.setPagination(newPagination);
10126
- },
10127
- onColumnOrderChange: (updaterOrValue) => {
10128
- const newOrder = typeof updaterOrValue === "function" ? updaterOrValue(state.columnOrder) : updaterOrValue;
10129
- stateActions.setColumnOrder(newOrder);
10130
- },
10131
- getCoreRowModel: getCoreRowModel(),
10132
- getFilteredRowModel: finalPaginationMode === "client" ? getFilteredRowModel() : void 0,
10133
- getSortedRowModel: finalPaginationMode === "client" ? getSortedRowModel() : void 0,
10134
- getPaginationRowModel: features.pagination ? getPaginationRowModel() : void 0,
10135
- getGroupedRowModel: features.grouping ? getGroupedRowModel() : void 0,
10136
- getExpandedRowModel: features.grouping ? getExpandedRowModel() : void 0,
10137
- manualSorting: finalPaginationMode === "server",
10138
- manualFiltering: finalPaginationMode === "server",
10139
- manualPagination: finalPaginationMode === "server",
10140
- pageCount: finalPaginationMode === "server" ? Math.ceil(dataCount / state.pagination.pageSize) : void 0
11255
+ const tableStateSnapshot = useMemo14(() => ({
11256
+ sorting: state.sorting,
11257
+ columnFilters: state.columnFilters,
11258
+ columnVisibility: state.columnVisibility,
11259
+ rowSelection,
11260
+ grouping: state.grouping,
11261
+ expanded: state.expanded,
11262
+ pagination: state.pagination,
11263
+ globalFilter: searchQuery,
11264
+ columnOrder: state.columnOrder
10141
11265
  }), [
10142
- finalTableData,
10143
- enhancedColumns,
10144
11266
  state.sorting,
10145
11267
  state.columnFilters,
10146
11268
  state.columnVisibility,
@@ -10149,16 +11271,32 @@ function DataTableInternal({
10149
11271
  state.expanded,
10150
11272
  state.pagination,
10151
11273
  searchQuery,
10152
- effectiveColumnOrder,
10153
- features.selection,
10154
- features.grouping,
10155
- getRowId,
11274
+ state.columnOrder
11275
+ ]);
11276
+ const tableHandlers = useTableHandlers({
11277
+ state,
11278
+ stateSnapshot: tableStateSnapshot,
11279
+ actions: stateActions,
11280
+ selection,
10156
11281
  onRowSelectionChange,
11282
+ effectiveColumnOrder,
11283
+ canPersistVisibility: secureFeatures.columnVisibility && Boolean(storageKey),
11284
+ canPersistOrder: secureFeatures.columnReordering && Boolean(storageKey),
11285
+ updateSavedColumnVisibility,
11286
+ updateColumnOrder,
11287
+ onLayoutChange
11288
+ });
11289
+ const tableConfig = useDataTableConfiguration({
11290
+ data: finalTableData,
11291
+ columns: enhancedColumns,
11292
+ stateSnapshot: tableStateSnapshot,
11293
+ handlers: tableHandlers,
11294
+ features: secureFeatures,
11295
+ getRowId: resolvedGetRowId,
10157
11296
  finalPaginationMode,
10158
- features.pagination,
10159
- dataCount,
10160
- state.pagination.pageSize
10161
- ]);
11297
+ finalDataCount,
11298
+ pageSize: state.pagination.pageSize
11299
+ });
10162
11300
  const table = useReactTable(tableConfig);
10163
11301
  if (!user) {
10164
11302
  throw new Error("DataTable requires authenticated user for RBAC");
@@ -10177,189 +11315,228 @@ function DataTableInternal({
10177
11315
  const hasSelectColumn = visibleColumns.some((col) => col.id === "select");
10178
11316
  const hasActionsColumn = visibleColumns.some((col) => col.id === "actions");
10179
11317
  return /* @__PURE__ */ jsxs17(Fragment7, { children: [
10180
- /* @__PURE__ */ jsxs17("table", { className: getTableClasses({
10181
- isFixed: true,
10182
- variant,
10183
- className: cn("border-collapse relative w-full", className)
10184
- }), style: {
10185
- tableLayout: "fixed",
10186
- width: "100%"
10187
- }, children: [
10188
- /* @__PURE__ */ jsxs17("caption", { className: "text-left pb-2", children: [
10189
- (title || description) && /* @__PURE__ */ jsxs17(Fragment7, { children: [
10190
- title && /* @__PURE__ */ jsx24("h2", { children: title }),
10191
- description && /* @__PURE__ */ jsx24("p", { children: description })
10192
- ] }),
10193
- /* @__PURE__ */ jsx24(Fragment7, { children: /* @__PURE__ */ jsx24(
10194
- DataTableToolbar,
10195
- {
10196
- features: secureFeatures,
10197
- globalFilter: searchQuery,
10198
- onGlobalFilterChange: handleSearch,
10199
- columns,
10200
- grouping: state.grouping,
10201
- onGroupByChange: (columnId) => {
10202
- stateActions.setGrouping(columnId ? [columnId] : []);
10203
- },
10204
- tableColumns: table?.getAllColumns() || [],
10205
- onColumnVisibilityChange: (columnId, visible) => {
10206
- stateActions.setColumnVisibility({ ...state.columnVisibility, [columnId]: visible });
10207
- },
10208
- onCreateRow: secureFeatures.creation && secureHandlers.onCreateRow ? () => stateActions.setCreating(true) : void 0,
10209
- onImportClick: () => stateActions.setImportModal(true),
10210
- onExport: secureHandlers.onExport || (async () => {
10211
- try {
10212
- const currentData = table.getFilteredRowModel().rows.map((row) => row.original);
10213
- const visibleColumns2 = columns.filter((col) => {
10214
- const column = table.getColumn(col.accessorKey);
10215
- return column && column.getIsVisible();
10216
- }).map((col) => ({
10217
- ...col,
10218
- header: typeof col.header === "string" ? col.header : col.accessorKey || "Column"
10219
- }));
10220
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10221
- const filename = title ? `${title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}_${timestamp}.csv` : `data_export_${timestamp}.csv`;
10222
- await exportToCSV(currentData, visibleColumns2, filename);
10223
- toast({
10224
- title: "Export Successful",
10225
- description: `Data exported to ${filename}`,
10226
- variant: "default"
10227
- });
10228
- if (import.meta.env.MODE === "development") {
10229
- console.log("DataTable: Export completed successfully");
10230
- }
10231
- } catch (error) {
10232
- console.error("DataTable: Failed to export data:", error);
10233
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
10234
- toast({
10235
- title: "Export Failed",
10236
- description: `Failed to export data: ${errorMessage}`,
10237
- variant: "destructive"
10238
- });
10239
- if (import.meta.env.MODE === "development") {
10240
- console.error("DataTable: Export error details:", error);
11318
+ /* @__PURE__ */ jsxs17(
11319
+ "table",
11320
+ {
11321
+ className: getTableClasses({
11322
+ isFixed: true,
11323
+ variant,
11324
+ className: cn("border-collapse relative w-full", className)
11325
+ }),
11326
+ "aria-label": title,
11327
+ "aria-describedby": description ? "table-description" : void 0,
11328
+ "aria-busy": isLoading ? "true" : "false",
11329
+ children: [
11330
+ /* @__PURE__ */ jsxs17("caption", { className: "text-left pb-2", children: [
11331
+ (title || description) && /* @__PURE__ */ jsxs17(Fragment7, { children: [
11332
+ title && /* @__PURE__ */ jsx24("h2", { children: title }),
11333
+ description && /* @__PURE__ */ jsx24("p", { id: "table-description", children: description })
11334
+ ] }),
11335
+ /* @__PURE__ */ jsx24(Fragment7, { children: /* @__PURE__ */ jsx24(
11336
+ DataTableToolbar,
11337
+ {
11338
+ features: secureFeatures,
11339
+ globalFilter: searchQuery,
11340
+ onGlobalFilterChange: handleSearch,
11341
+ columns,
11342
+ grouping: state.grouping,
11343
+ onGroupByChange: (columnId) => {
11344
+ stateActions.setGrouping(columnId ? [columnId] : []);
11345
+ },
11346
+ tableColumns: table?.getAllColumns() || [],
11347
+ onColumnVisibilityChange: (columnId, visible) => {
11348
+ stateActions.setColumnVisibility({ ...state.columnVisibility, [columnId]: visible });
11349
+ },
11350
+ onCreateRow: secureFeatures.creation && secureHandlers.onCreateRow ? () => stateActions.setCreating(true) : void 0,
11351
+ onImportClick: () => stateActions.setImportModal(true),
11352
+ onExport: secureHandlers.onExport || (async () => {
11353
+ try {
11354
+ const currentData = table.getFilteredRowModel().rows.map((row) => row.original);
11355
+ const visibleColumns2 = columns.filter((col) => {
11356
+ const column = table.getColumn(col.accessorKey);
11357
+ return column && column.getIsVisible();
11358
+ }).map((col) => ({
11359
+ ...col,
11360
+ header: typeof col.header === "string" ? col.header : col.accessorKey || "Column"
11361
+ }));
11362
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
11363
+ const filename = title ? `${title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}_${timestamp}.csv` : `data_export_${timestamp}.csv`;
11364
+ await exportToCSV(currentData, visibleColumns2, filename);
11365
+ toast({
11366
+ title: "Export Successful",
11367
+ description: `Data exported to ${filename}`,
11368
+ variant: "default"
11369
+ });
11370
+ if (import.meta.env.MODE === "development") {
11371
+ console.log("DataTable: Export completed successfully");
11372
+ }
11373
+ } catch (error) {
11374
+ console.error("DataTable: Failed to export data:", error);
11375
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
11376
+ toast({
11377
+ title: "Export Failed",
11378
+ description: `Failed to export data: ${errorMessage}`,
11379
+ variant: "destructive"
11380
+ });
11381
+ if (import.meta.env.MODE === "development") {
11382
+ console.error("DataTable: Export error details:", error);
11383
+ }
11384
+ }
11385
+ }),
11386
+ rowSelection,
11387
+ onDeleteSelected: secureHandlers.onDeleteSelected,
11388
+ onToggleFilterRow: () => stateActions.setFilterRow(!state.showFilterRow),
11389
+ showFilterRow: state.showFilterRow,
11390
+ rbac,
11391
+ permissions
11392
+ }
11393
+ ) })
11394
+ ] }),
11395
+ /* @__PURE__ */ jsxs17("colgroup", { children: [
11396
+ hasSelectColumn && /* @__PURE__ */ jsx24("col", { span: 1, "data-col-type": "select", className: "w-12" }),
11397
+ /* @__PURE__ */ jsx24("col", { span: dataColumns, "data-col-type": "data" }),
11398
+ hasActionsColumn && /* @__PURE__ */ jsx24("col", { span: 1, "data-col-type": "actions" })
11399
+ ] }),
11400
+ /* @__PURE__ */ jsx24("thead", { children: table?.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx24("tr", { children: headerGroup.headers.filter((header) => {
11401
+ return typeof header.column.getIsVisible === "function" ? header.column.getIsVisible() : true;
11402
+ }).map((header) => {
11403
+ const isSortable = header.column.getCanSort();
11404
+ const ariaSort = isSortable ? header.column.getIsSorted() === "asc" ? "ascending" : header.column.getIsSorted() === "desc" ? "descending" : "none" : void 0;
11405
+ const isRightAligned = header.column.columnDef.meta?.align === "right";
11406
+ const handleSortClick = (event) => {
11407
+ const originalHandler = header.column.getToggleSortingHandler();
11408
+ if (originalHandler) {
11409
+ originalHandler(event);
11410
+ }
11411
+ const columnName = typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : "column";
11412
+ const currentSort = header.column.getIsSorted();
11413
+ const newSort = currentSort === "asc" ? "desc" : currentSort === "desc" ? null : "asc";
11414
+ announceSortChange(columnName, newSort);
11415
+ };
11416
+ const headerKeyboardHandlers = keyboardNavigation.getHeaderKeyboardHandlers(
11417
+ header.index,
11418
+ () => {
11419
+ const originalHandler = header.column.getToggleSortingHandler();
11420
+ if (originalHandler) {
11421
+ originalHandler({});
10241
11422
  }
11423
+ const columnName = typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : "column";
11424
+ const currentSort = header.column.getIsSorted();
11425
+ const newSort = currentSort === "asc" ? "desc" : currentSort === "desc" ? null : "asc";
11426
+ announceSortChange(columnName, newSort);
10242
11427
  }
10243
- }),
10244
- rowSelection,
10245
- onDeleteSelected: secureHandlers.onDeleteSelected,
10246
- onToggleFilterRow: () => stateActions.setFilterRow(!state.showFilterRow),
10247
- showFilterRow: state.showFilterRow,
10248
- rbac,
10249
- permissions
10250
- }
10251
- ) })
10252
- ] }),
10253
- /* @__PURE__ */ jsxs17("colgroup", { children: [
10254
- hasSelectColumn && /* @__PURE__ */ jsx24("col", { span: 1, "data-col-type": "select" }),
10255
- /* @__PURE__ */ jsx24("col", { span: dataColumns, "data-col-type": "data" }),
10256
- hasActionsColumn && /* @__PURE__ */ jsx24("col", { span: 1, "data-col-type": "actions" })
10257
- ] }),
10258
- /* @__PURE__ */ jsx24("thead", { children: table?.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx24("tr", { children: headerGroup.headers.filter((header) => {
10259
- return typeof header.column.getIsVisible === "function" ? header.column.getIsVisible() : true;
10260
- }).map((header) => {
10261
- const isSortable = header.column.getCanSort();
10262
- const ariaSort = isSortable ? header.column.getIsSorted() === "asc" ? "ascending" : header.column.getIsSorted() === "desc" ? "descending" : "none" : void 0;
10263
- return /* @__PURE__ */ jsx24(
10264
- "th",
10265
- {
10266
- ...isSortable ? { "aria-sort": ariaSort } : {},
10267
- children: header.isPlaceholder ? null : isSortable ? /* @__PURE__ */ jsx24(
10268
- Button,
11428
+ );
11429
+ return /* @__PURE__ */ jsx24(
11430
+ "th",
10269
11431
  {
10270
- variant: "ghost",
10271
- className: "h-auto p-0 font-medium hover:bg-transparent",
10272
- onClick: header.column.getToggleSortingHandler(),
10273
- "aria-label": `Sort by ${typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : "column"}`,
10274
- tabIndex: 0,
10275
- children: /* @__PURE__ */ jsxs17("div", { className: `flex items-center gap-1 ${header.column.columnDef.meta?.align === "right" ? "justify-end" : ""}`, children: [
10276
- typeof header.column.columnDef.header === "function" ? header.column.columnDef.header(header.getContext()) : header.column.columnDef.header,
10277
- header.column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx24(ChevronUp2, { className: "h-4 w-4" }) : header.column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx24(ChevronDown3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx24(ChevronsUpDown, { className: "h-4 w-4" })
10278
- ] })
10279
- }
10280
- ) : /* @__PURE__ */ jsx24("div", { className: header.column.columnDef.meta?.align === "right" ? "text-right" : "", children: typeof header.column.columnDef.header === "function" ? header.column.columnDef.header(header.getContext()) : header.column.columnDef.header })
10281
- },
10282
- header.id
10283
- );
10284
- }) }, headerGroup.id)) }),
10285
- /* @__PURE__ */ jsx24(
10286
- UnifiedTableBody,
10287
- {
10288
- table,
10289
- isCreating,
10290
- creationData,
10291
- onCreationDataChange: stateActions.setCreationData,
10292
- onSaveCreation: () => {
10293
- if (onCreateRow) {
10294
- onCreateRow(creationData);
10295
- stateActions.clearCreationData();
10296
- stateActions.setCreating(false);
10297
- }
10298
- },
10299
- onCancelCreation: () => {
10300
- stateActions.clearCreationData();
10301
- stateActions.setCreating(false);
10302
- },
10303
- editingRowId,
10304
- editingData,
10305
- onEditingDataChange: (data2) => {
10306
- if (editingRowId) {
10307
- stateActions.setEditingRow(editingRowId, data2);
11432
+ className: `px-3 py-2 ${isRightAligned ? "text-right" : "text-left"}`,
11433
+ scope: "col",
11434
+ role: "columnheader",
11435
+ ...isSortable ? { "aria-sort": ariaSort } : {},
11436
+ ...isSortable ? headerKeyboardHandlers : {},
11437
+ children: header.isPlaceholder ? null : isSortable ? /* @__PURE__ */ jsxs17(
11438
+ Button,
11439
+ {
11440
+ variant: "ghost",
11441
+ className: `h-auto p-0 font-medium hover:bg-transparent ${isRightAligned ? "justify-end" : "justify-start"}`,
11442
+ onClick: handleSortClick,
11443
+ ...headerKeyboardHandlers,
11444
+ "aria-label": `Sort by ${typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : "column"}`,
11445
+ tabIndex: 0,
11446
+ children: [
11447
+ typeof header.column.columnDef.header === "function" ? header.column.columnDef.header(header.getContext()) : header.column.columnDef.header,
11448
+ header.column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx24(ChevronUp2, { className: "h-4 w-4" }) : header.column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx24(ChevronDown3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx24(ChevronsUpDown, { className: "h-4 w-4" })
11449
+ ]
11450
+ }
11451
+ ) : typeof header.column.columnDef.header === "function" ? header.column.columnDef.header(header.getContext()) : header.column.columnDef.header
11452
+ },
11453
+ header.id
11454
+ );
11455
+ }) }, headerGroup.id)) }),
11456
+ /* @__PURE__ */ jsx24(
11457
+ UnifiedTableBody,
11458
+ {
11459
+ table,
11460
+ isCreating,
11461
+ creationData,
11462
+ onCreationDataChange: stateActions.setCreationData,
11463
+ onSaveCreation: () => {
11464
+ if (onCreateRow) {
11465
+ onCreateRow(creationData);
11466
+ stateActions.clearCreationData();
11467
+ stateActions.setCreating(false);
11468
+ }
11469
+ },
11470
+ onCancelCreation: () => {
11471
+ stateActions.clearCreationData();
11472
+ stateActions.setCreating(false);
11473
+ },
11474
+ editingRowId,
11475
+ editingData,
11476
+ onEditingDataChange: (data2) => {
11477
+ if (editingRowId) {
11478
+ stateActions.setEditingRow(editingRowId, data2);
11479
+ }
11480
+ },
11481
+ onSaveEditing: () => {
11482
+ if (onEditRow && editingRowId) {
11483
+ const originalRow = data.find((row) => {
11484
+ try {
11485
+ const rowId = resolvedGetRowId(row, 0);
11486
+ return rowId === editingRowId;
11487
+ } catch {
11488
+ return false;
11489
+ }
11490
+ });
11491
+ if (originalRow) {
11492
+ onEditRow(originalRow, editingData);
11493
+ }
11494
+ }
11495
+ stateActions.clearEditing();
11496
+ },
11497
+ onCancelEditing: () => {
11498
+ stateActions.clearEditing();
11499
+ },
11500
+ grouping: state.grouping,
11501
+ aggregates,
11502
+ getRowId: resolvedGetRowId,
11503
+ emptyState: React17.isValidElement(emptyState) ? void 0 : emptyState,
11504
+ isFiltered: searchQuery !== "" || state.columnFilters.length > 0,
11505
+ onClearFilters: () => {
11506
+ stateActions.setSearchQuery("");
11507
+ stateActions.setColumnFilters([]);
11508
+ },
11509
+ enableFiltering: secureFeatures.filtering,
11510
+ showFilterRow,
11511
+ dataLength: finalTableData?.length || 0,
11512
+ virtualHeight,
11513
+ forceVirtualization: false,
11514
+ hierarchical: secureFeatures.hierarchical && hierarchical?.enabled && hierarchicalState ? {
11515
+ ...hierarchical,
11516
+ state: hierarchicalState,
11517
+ expandAll: hierarchicalState.expandAll,
11518
+ collapseAll: hierarchicalState.collapseAll,
11519
+ isAllExpanded: hierarchicalState.getExpandedIds().length > 0 && hierarchicalState.getExpandedIds().length === finalTableData.filter((row) => row.isParent).length,
11520
+ hasAnyChildren: finalTableData.some((row) => row.isParent)
11521
+ } : void 0,
11522
+ actions: effectiveActions,
11523
+ rbac,
11524
+ permissions
10308
11525
  }
10309
- },
10310
- onSaveEditing: () => {
10311
- if (onEditRow && editingRowId) {
10312
- const originalRow = data.find((row) => {
10313
- const rowId = getRowId ? getRowId(row, 0) : row.id || String(0);
10314
- return rowId === editingRowId;
10315
- });
10316
- if (originalRow) {
10317
- onEditRow(originalRow, editingData);
10318
- }
11526
+ ),
11527
+ secureFeatures.pagination && /* @__PURE__ */ jsx24("tfoot", { children: /* @__PURE__ */ jsx24("tr", { children: /* @__PURE__ */ jsx24("td", { colSpan: visibleColumns.length, children: /* @__PURE__ */ jsx24(
11528
+ PaginationComponent,
11529
+ {
11530
+ table,
11531
+ pageSizeOptions: finalPageSizeOptions,
11532
+ paginationMode: finalPaginationMode,
11533
+ totalCount: finalDataCount,
11534
+ isLoading
10319
11535
  }
10320
- stateActions.clearEditing();
10321
- },
10322
- onCancelEditing: () => {
10323
- stateActions.clearEditing();
10324
- },
10325
- grouping: state.grouping,
10326
- aggregates,
10327
- getRowId,
10328
- emptyState: React15.isValidElement(emptyState) ? void 0 : emptyState,
10329
- isFiltered: searchQuery !== "" || state.columnFilters.length > 0,
10330
- onClearFilters: () => {
10331
- stateActions.setSearchQuery("");
10332
- stateActions.setColumnFilters([]);
10333
- },
10334
- enableFiltering: features.filtering,
10335
- showFilterRow,
10336
- dataLength: finalTableData?.length || 0,
10337
- virtualHeight,
10338
- forceVirtualization: false,
10339
- hierarchical: features.hierarchical && hierarchical?.enabled ? {
10340
- ...hierarchical,
10341
- state: hierarchicalState,
10342
- expandAll: hierarchicalState.expandAll,
10343
- collapseAll: hierarchicalState.collapseAll,
10344
- isAllExpanded: hierarchicalState.getExpandedIds().length > 0 && hierarchicalState.getExpandedIds().length === finalTableData.filter((row) => row.isParent).length,
10345
- hasAnyChildren: finalTableData.some((row) => row.isParent)
10346
- } : void 0,
10347
- actions: effectiveActions,
10348
- rbac,
10349
- permissions
10350
- }
10351
- ),
10352
- features.pagination && /* @__PURE__ */ jsx24("tfoot", { children: /* @__PURE__ */ jsx24("tr", { children: /* @__PURE__ */ jsx24("td", { colSpan: visibleColumns.length, children: /* @__PURE__ */ jsx24(
10353
- PaginationComponent,
10354
- {
10355
- table,
10356
- pageSizeOptions: finalPageSizeOptions,
10357
- paginationMode: finalPaginationMode,
10358
- totalCount: finalDataCount,
10359
- isLoading
10360
- }
10361
- ) }) }) })
10362
- ] }),
11536
+ ) }) }) })
11537
+ ]
11538
+ }
11539
+ ),
10363
11540
  /* @__PURE__ */ jsx24(
10364
11541
  DataTableModals,
10365
11542
  {
@@ -10386,15 +11563,25 @@ function DataTableCore(props) {
10386
11563
  // src/components/DataTable/DataTable.tsx
10387
11564
  import { jsx as jsx25 } from "react/jsx-runtime";
10388
11565
  function DataTable(props) {
10389
- if (!props.features) {
10390
- throw new Error("DataTable: features configuration is required");
10391
- }
10392
- if (props.features.deleteSelected && !props.features.deletion) {
10393
- console.warn("DataTable: deleteSelected requires deletion to be enabled");
10394
- }
10395
- return /* @__PURE__ */ jsx25(DataTableCore, { ...props });
11566
+ const logger = React18.useMemo(() => createLogger("DataTable"), []);
11567
+ const { features, ...rest } = props;
11568
+ const normalizedFeatures = React18.useMemo(
11569
+ () => normalizeDataTableFeatures(features),
11570
+ [features]
11571
+ );
11572
+ React18.useEffect(() => {
11573
+ if (!features && import.meta.env?.MODE === "development") {
11574
+ logger.info("DataTable: no features provided; all capabilities default to disabled. Pass a features object to enable functionality.");
11575
+ }
11576
+ }, [features, logger]);
11577
+ React18.useEffect(() => {
11578
+ if (normalizedFeatures.deleteSelected && !normalizedFeatures.deletion) {
11579
+ logger.warn("deleteSelected requires deletion to be enabled");
11580
+ }
11581
+ }, [normalizedFeatures.deleteSelected, normalizedFeatures.deletion, logger]);
11582
+ return /* @__PURE__ */ jsx25(DataTableCore, { ...rest, features: normalizedFeatures });
10396
11583
  }
10397
- var DataTableComponent = React16.memo(DataTable);
11584
+ var DataTableComponent = React18.memo(DataTable);
10398
11585
 
10399
11586
  // src/components/DataTable/components/BulkOperationsDropdown.tsx
10400
11587
  import {
@@ -10557,6 +11744,10 @@ export {
10557
11744
  getRowIdSafe,
10558
11745
  hasValidRowId,
10559
11746
  UnifiedTableBody,
11747
+ getPaginationBinding,
11748
+ validatePaginationConfig,
11749
+ getPageSizeOptions,
11750
+ calculateOptimalPageSize,
10560
11751
  PaginationControls,
10561
11752
  EnhancedPaginationControls,
10562
11753
  LoadingState,
@@ -10569,7 +11760,22 @@ export {
10569
11760
  getHierarchicalSortConfig,
10570
11761
  generateCSVContent,
10571
11762
  exportToCSV,
11763
+ defaultDataTableFeatures,
11764
+ normalizeDataTableFeatures,
10572
11765
  ColumnFactory,
11766
+ initializeLiveRegion,
11767
+ cleanupLiveRegion,
11768
+ announce,
11769
+ getSortButtonLabel,
11770
+ announceSortChange,
11771
+ announceFilterChange,
11772
+ announceSearchResults,
11773
+ announcePaginationChange,
11774
+ announceSelectionChange,
11775
+ announceLoadingState,
11776
+ announceBulkOperation,
11777
+ getAriaSortValue,
11778
+ getRowDescription,
10573
11779
  DataTableCore,
10574
11780
  DataTable,
10575
11781
  BulkOperationsDropdown,
@@ -10587,4 +11793,4 @@ lodash/lodash.js:
10587
11793
  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
10588
11794
  *)
10589
11795
  */
10590
- //# sourceMappingURL=chunk-M5IWZRBT.js.map
11796
+ //# sourceMappingURL=chunk-ZMNXIJP4.js.map