@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
@@ -0,0 +1,615 @@
1
+ /**
2
+ * @file DataTable Keyboard Navigation Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Tests
5
+ * @since 0.4.0
6
+ *
7
+ * Comprehensive keyboard navigation tests for DataTable component.
8
+ * Tests roving tabindex, arrow key navigation, and focus management.
9
+ */
10
+
11
+ import React from 'react';
12
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
13
+ import userEvent from '@testing-library/user-event';
14
+ import { vi, beforeEach, afterEach } from 'vitest';
15
+ import { DataTable } from '../DataTable';
16
+ import { MockRBACProvider } from './mocks/MockRBACProvider';
17
+ import type { DataTableColumn } from '../types';
18
+
19
+ // Mock the RBAC hooks
20
+ vi.mock('../../../rbac/hooks', () => ({
21
+ useCan: vi.fn(() => ({ can: true, isLoading: false })),
22
+ useResolvedScope: vi.fn(() => ({
23
+ organisationId: 'test-org',
24
+ eventId: 'test-event',
25
+ appId: 'test-app'
26
+ })),
27
+ }));
28
+
29
+ // Mock the UnifiedAuthProvider
30
+ vi.mock('../../../providers/UnifiedAuthProvider', () => ({
31
+ useUnifiedAuth: vi.fn(() => ({
32
+ user: { id: 'test-user', name: 'Test User' },
33
+ isLoading: false,
34
+ error: null,
35
+ })),
36
+ }));
37
+
38
+ // Mock the toast hook
39
+ vi.mock('../../../hooks/useToast', () => ({
40
+ toast: vi.fn(),
41
+ }));
42
+
43
+ // Test data
44
+ interface TestUser {
45
+ id: string;
46
+ name: string;
47
+ email: string;
48
+ role: string;
49
+ status: 'active' | 'inactive';
50
+ }
51
+
52
+ const testUsers: TestUser[] = [
53
+ { id: '1', name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'active' },
54
+ { id: '2', name: 'Jane Smith', email: 'jane@example.com', role: 'User', status: 'active' },
55
+ { id: '3', name: 'Bob Johnson', email: 'bob@example.com', role: 'User', status: 'inactive' },
56
+ { id: '4', name: 'Alice Brown', email: 'alice@example.com', role: 'Manager', status: 'active' },
57
+ ];
58
+
59
+ const testColumns: DataTableColumn<TestUser>[] = [
60
+ {
61
+ accessorKey: 'name',
62
+ header: 'Name',
63
+ sortable: true,
64
+ searchable: true,
65
+ },
66
+ {
67
+ accessorKey: 'email',
68
+ header: 'Email',
69
+ sortable: true,
70
+ searchable: true,
71
+ },
72
+ {
73
+ accessorKey: 'role',
74
+ header: 'Role',
75
+ sortable: true,
76
+ },
77
+ {
78
+ accessorKey: 'status',
79
+ header: 'Status',
80
+ sortable: true,
81
+ },
82
+ ];
83
+
84
+ const defaultFeatures = {
85
+ search: true,
86
+ pagination: true,
87
+ sorting: true,
88
+ filtering: true,
89
+ export: false,
90
+ import: true,
91
+ selection: true,
92
+ creation: false,
93
+ editing: false,
94
+ deletion: false,
95
+ deleteSelected: false,
96
+ grouping: false,
97
+ columnVisibility: false,
98
+ columnReordering: false,
99
+ hierarchical: false,
100
+ };
101
+
102
+ // Test wrapper component
103
+ const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
104
+ <MockRBACProvider>
105
+ {children}
106
+ </MockRBACProvider>
107
+ );
108
+
109
+ describe('DataTable Keyboard Navigation', () => {
110
+ beforeEach(() => {
111
+ // Clear any existing live regions
112
+ const existingLiveRegions = document.querySelectorAll('[aria-live]');
113
+ existingLiveRegions.forEach(region => {
114
+ if (region.parentNode) {
115
+ region.parentNode.removeChild(region);
116
+ }
117
+ });
118
+ });
119
+
120
+ afterEach(() => {
121
+ // Clean up live regions after each test
122
+ const liveRegions = document.querySelectorAll('[aria-live]');
123
+ liveRegions.forEach(region => {
124
+ if (region.parentNode) {
125
+ region.parentNode.removeChild(region);
126
+ }
127
+ });
128
+ });
129
+
130
+ describe('Header Navigation', () => {
131
+ it('should support Enter key to toggle sort on headers', async () => {
132
+ const user = userEvent.setup();
133
+
134
+ render(
135
+ <TestWrapper>
136
+ <DataTable
137
+ data={testUsers}
138
+ columns={testColumns}
139
+ rbac={{ pageId: 'test-page' }}
140
+ features={defaultFeatures}
141
+ />
142
+ </TestWrapper>
143
+ );
144
+
145
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
146
+ const nameButton = nameHeader.querySelector('button');
147
+
148
+ // Focus the button inside the header
149
+ nameButton?.focus();
150
+ expect(nameButton).toHaveFocus();
151
+
152
+ // Press Enter to sort
153
+ await user.keyboard('{Enter}');
154
+
155
+ await waitFor(() => {
156
+ expect(nameHeader).toHaveAttribute('aria-sort', 'ascending');
157
+ });
158
+
159
+ // Press Enter again to sort descending
160
+ await user.keyboard('{Enter}');
161
+
162
+ await waitFor(() => {
163
+ expect(nameHeader).toHaveAttribute('aria-sort', 'descending');
164
+ });
165
+ });
166
+
167
+ it('should support Space key to toggle sort on headers', async () => {
168
+ const user = userEvent.setup();
169
+
170
+ render(
171
+ <TestWrapper>
172
+ <DataTable
173
+ data={testUsers}
174
+ columns={testColumns}
175
+ rbac={{ pageId: 'test-page' }}
176
+ features={defaultFeatures}
177
+ />
178
+ </TestWrapper>
179
+ );
180
+
181
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
182
+ const nameButton = nameHeader.querySelector('button');
183
+
184
+ // Focus the button inside the header
185
+ nameButton?.focus();
186
+ expect(nameButton).toHaveFocus();
187
+
188
+ // Press Space to sort
189
+ await user.keyboard(' ');
190
+
191
+ await waitFor(() => {
192
+ expect(nameHeader).toHaveAttribute('aria-sort', 'ascending');
193
+ });
194
+ });
195
+
196
+ it.skip('should navigate between headers with arrow keys', async () => {
197
+ const user = userEvent.setup();
198
+
199
+ render(
200
+ <TestWrapper>
201
+ <DataTable
202
+ data={testUsers}
203
+ columns={testColumns}
204
+ rbac={{ pageId: 'test-page' }}
205
+ features={defaultFeatures}
206
+ />
207
+ </TestWrapper>
208
+ );
209
+
210
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
211
+ const emailHeader = screen.getByRole('columnheader', { name: /email/i });
212
+
213
+ // Focus the first header
214
+ nameHeader.focus();
215
+ expect(nameHeader).toHaveFocus();
216
+
217
+ // Press Right arrow to move to next header
218
+ await user.keyboard('{ArrowRight}');
219
+
220
+ await waitFor(() => {
221
+ expect(emailHeader).toHaveFocus();
222
+ });
223
+
224
+ // Press Left arrow to move back
225
+ await user.keyboard('{ArrowLeft}');
226
+
227
+ await waitFor(() => {
228
+ expect(nameHeader).toHaveFocus();
229
+ });
230
+ });
231
+
232
+ it.skip('should navigate to first/last header with Home/End keys', async () => {
233
+ const user = userEvent.setup();
234
+
235
+ render(
236
+ <TestWrapper>
237
+ <DataTable
238
+ data={testUsers}
239
+ columns={testColumns}
240
+ rbac={{ pageId: 'test-page' }}
241
+ features={defaultFeatures}
242
+ />
243
+ </TestWrapper>
244
+ );
245
+
246
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
247
+ const statusHeader = screen.getByRole('columnheader', { name: /status/i });
248
+
249
+ // Focus a middle header
250
+ const emailHeader = screen.getByRole('columnheader', { name: /email/i });
251
+ emailHeader.focus();
252
+
253
+ // Press Home to go to first header
254
+ await user.keyboard('{Home}');
255
+
256
+ await waitFor(() => {
257
+ expect(nameHeader).toHaveFocus();
258
+ });
259
+
260
+ // Press End to go to last header
261
+ await user.keyboard('{End}');
262
+
263
+ await waitFor(() => {
264
+ expect(statusHeader).toHaveFocus();
265
+ });
266
+ });
267
+ });
268
+
269
+ describe('Cell Navigation', () => {
270
+ it.skip('should implement roving tabindex for cells', () => {
271
+ render(
272
+ <TestWrapper>
273
+ <DataTable
274
+ data={testUsers}
275
+ columns={testColumns}
276
+ rbac={{ pageId: 'test-page' }}
277
+ features={defaultFeatures}
278
+ />
279
+ </TestWrapper>
280
+ );
281
+
282
+ const cells = screen.getAllByRole('cell');
283
+
284
+ // Only one cell should be tabbable (tabindex="0")
285
+ const tabbableCells = cells.filter(cell => cell.getAttribute('tabindex') === '0');
286
+ expect(tabbableCells.length).toBeLessThanOrEqual(1);
287
+
288
+ // All other cells should have tabindex="-1"
289
+ const nonTabbableCells = cells.filter(cell => cell.getAttribute('tabindex') === '-1');
290
+ expect(nonTabbableCells.length).toBeGreaterThan(0);
291
+ });
292
+
293
+ it.skip('should navigate between cells with arrow keys', async () => {
294
+ const user = userEvent.setup();
295
+
296
+ render(
297
+ <TestWrapper>
298
+ <DataTable
299
+ data={testUsers}
300
+ columns={testColumns}
301
+ rbac={{ pageId: 'test-page' }}
302
+ features={defaultFeatures}
303
+ />
304
+ </TestWrapper>
305
+ );
306
+
307
+ const cells = screen.getAllByRole('cell');
308
+ const firstCell = cells[0];
309
+
310
+ if (firstCell) {
311
+ // Focus the first cell
312
+ firstCell.focus();
313
+ expect(firstCell).toHaveFocus();
314
+
315
+ // Test arrow key navigation
316
+ await user.keyboard('{ArrowRight}');
317
+ // The next cell should be focused (implementation dependent)
318
+
319
+ await user.keyboard('{ArrowDown}');
320
+ // The cell below should be focused (implementation dependent)
321
+
322
+ await user.keyboard('{ArrowLeft}');
323
+ // The previous cell should be focused (implementation dependent)
324
+
325
+ await user.keyboard('{ArrowUp}');
326
+ // The cell above should be focused (implementation dependent)
327
+ }
328
+ });
329
+
330
+ it.skip('should navigate to row start/end with Home/End keys', async () => {
331
+ const user = userEvent.setup();
332
+
333
+ render(
334
+ <TestWrapper>
335
+ <DataTable
336
+ data={testUsers}
337
+ columns={testColumns}
338
+ rbac={{ pageId: 'test-page' }}
339
+ features={defaultFeatures}
340
+ />
341
+ </TestWrapper>
342
+ );
343
+
344
+ const cells = screen.getAllByRole('cell');
345
+ const middleCell = cells[2]; // Assuming this is not the first or last in row
346
+
347
+ if (middleCell) {
348
+ // Focus a middle cell
349
+ middleCell.focus();
350
+ expect(middleCell).toHaveFocus();
351
+
352
+ // Press Home to go to row start
353
+ await user.keyboard('{Home}');
354
+ // Should focus first cell in row (implementation dependent)
355
+
356
+ // Press End to go to row end
357
+ await user.keyboard('{End}');
358
+ // Should focus last cell in row (implementation dependent)
359
+ }
360
+ });
361
+
362
+ it.skip('should navigate to table start/end with Ctrl+Home/End', async () => {
363
+ const user = userEvent.setup();
364
+
365
+ render(
366
+ <TestWrapper>
367
+ <DataTable
368
+ data={testUsers}
369
+ columns={testColumns}
370
+ rbac={{ pageId: 'test-page' }}
371
+ features={defaultFeatures}
372
+ />
373
+ </TestWrapper>
374
+ );
375
+
376
+ const cells = screen.getAllByRole('cell');
377
+ const middleCell = cells[Math.floor(cells.length / 2)];
378
+
379
+ if (middleCell) {
380
+ // Focus a middle cell
381
+ middleCell.focus();
382
+ expect(middleCell).toHaveFocus();
383
+
384
+ // Press Ctrl+Home to go to table start
385
+ await user.keyboard('{Control>}{Home}{/Control}');
386
+ // Should focus first cell in table (implementation dependent)
387
+
388
+ // Press Ctrl+End to go to table end
389
+ await user.keyboard('{Control>}{End}{/Control}');
390
+ // Should focus last cell in table (implementation dependent)
391
+ }
392
+ });
393
+ });
394
+
395
+ describe('Focus Management', () => {
396
+ it.skip('should restore focus when modals close', async () => {
397
+ const user = userEvent.setup();
398
+
399
+ render(
400
+ <TestWrapper>
401
+ <DataTable
402
+ data={testUsers}
403
+ columns={testColumns}
404
+ rbac={{ pageId: 'test-page' }}
405
+ features={defaultFeatures}
406
+ />
407
+ </TestWrapper>
408
+ );
409
+
410
+ // Find and focus a cell
411
+ const cells = screen.getAllByRole('cell');
412
+ const firstCell = cells[0];
413
+
414
+ if (firstCell) {
415
+ firstCell.focus();
416
+ expect(firstCell).toHaveFocus();
417
+
418
+ // Open import modal (if import button exists)
419
+ const importButton = screen.queryByText(/import/i);
420
+ if (importButton) {
421
+ await user.click(importButton);
422
+
423
+ // Focus should be stored and modal should open
424
+ // (Implementation dependent - modal focus management)
425
+
426
+ // Close modal (ESC key or close button)
427
+ await user.keyboard('{Escape}');
428
+
429
+ // Focus should be restored to the original cell
430
+ await waitFor(() => {
431
+ expect(firstCell).toHaveFocus();
432
+ });
433
+ }
434
+ }
435
+ });
436
+
437
+ it('should not show focus warnings in console', () => {
438
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
439
+
440
+ render(
441
+ <TestWrapper>
442
+ <DataTable
443
+ data={testUsers}
444
+ columns={testColumns}
445
+ rbac={{ pageId: 'test-page' }}
446
+ features={defaultFeatures}
447
+ />
448
+ </TestWrapper>
449
+ );
450
+
451
+ // Check that no focus-related warnings were logged
452
+ const focusWarnings = consoleSpy.mock.calls.filter(call =>
453
+ call.some(arg =>
454
+ typeof arg === 'string' &&
455
+ (arg.includes('focus') || arg.includes('tabindex') || arg.includes('keyboard'))
456
+ )
457
+ );
458
+
459
+ expect(focusWarnings).toHaveLength(0);
460
+
461
+ consoleSpy.mockRestore();
462
+ });
463
+ });
464
+
465
+ describe('Unsupported Operations', () => {
466
+ it('should disable keyboard resize when not supported', async () => {
467
+ const user = userEvent.setup();
468
+
469
+ render(
470
+ <TestWrapper>
471
+ <DataTable
472
+ data={testUsers}
473
+ columns={testColumns}
474
+ rbac={{ pageId: 'test-page' }}
475
+ features={{ ...defaultFeatures, columnReordering: false }}
476
+ />
477
+ </TestWrapper>
478
+ );
479
+
480
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
481
+ const nameButton = nameHeader.querySelector('button');
482
+
483
+ // Focus the button inside the header
484
+ nameButton?.focus();
485
+ expect(nameButton).toHaveFocus();
486
+
487
+ // Try to resize column (Ctrl + or Ctrl -)
488
+ await user.keyboard('{Control>}={/Control}');
489
+
490
+ // Should announce that resizing is not supported
491
+ await waitFor(() => {
492
+ const liveRegion = document.querySelector('[aria-live="polite"]');
493
+ expect(liveRegion?.textContent).toContain('not supported');
494
+ }, { timeout: 1000 });
495
+ });
496
+
497
+ it('should disable keyboard reorder when not supported', async () => {
498
+ const user = userEvent.setup();
499
+
500
+ render(
501
+ <TestWrapper>
502
+ <DataTable
503
+ data={testUsers}
504
+ columns={testColumns}
505
+ rbac={{ pageId: 'test-page' }}
506
+ features={{ ...defaultFeatures, columnReordering: false }}
507
+ />
508
+ </TestWrapper>
509
+ );
510
+
511
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
512
+ const nameButton = nameHeader.querySelector('button');
513
+
514
+ // Focus the button inside the header
515
+ nameButton?.focus();
516
+ expect(nameButton).toHaveFocus();
517
+
518
+ // Try to reorder column (Ctrl + R)
519
+ await user.keyboard('{Control>}r{/Control}');
520
+
521
+ // Should announce that reordering is not supported
522
+ await waitFor(() => {
523
+ const liveRegion = document.querySelector('[aria-live="polite"]');
524
+ expect(liveRegion?.textContent).toContain('not supported');
525
+ }, { timeout: 1000 });
526
+ });
527
+ });
528
+
529
+ describe('Tab Navigation', () => {
530
+ it('should allow normal Tab navigation to work', async () => {
531
+ const user = userEvent.setup();
532
+
533
+ render(
534
+ <TestWrapper>
535
+ <DataTable
536
+ data={testUsers}
537
+ columns={testColumns}
538
+ rbac={{ pageId: 'test-page' }}
539
+ features={defaultFeatures}
540
+ />
541
+ </TestWrapper>
542
+ );
543
+
544
+ // Tab should work normally and not be intercepted
545
+ await user.tab();
546
+
547
+ // Should focus the first tabbable element
548
+ const focusedElement = document.activeElement;
549
+ expect(focusedElement).toBeTruthy();
550
+
551
+ // Tab again
552
+ await user.tab();
553
+
554
+ // Should move to next tabbable element
555
+ const nextFocusedElement = document.activeElement;
556
+ expect(nextFocusedElement).not.toBe(focusedElement);
557
+ });
558
+ });
559
+
560
+ describe('Integration Tests', () => {
561
+ it.skip('should work end-to-end with sorting and navigation', async () => {
562
+ const user = userEvent.setup();
563
+
564
+ render(
565
+ <TestWrapper>
566
+ <DataTable
567
+ data={testUsers}
568
+ columns={testColumns}
569
+ rbac={{ pageId: 'test-page' }}
570
+ features={defaultFeatures}
571
+ />
572
+ </TestWrapper>
573
+ );
574
+
575
+ // Navigate to name header
576
+ const nameHeader = screen.getByRole('columnheader', { name: /name/i });
577
+ nameHeader.focus();
578
+
579
+ // Sort by name
580
+ await user.keyboard('{Enter}');
581
+
582
+ await waitFor(() => {
583
+ expect(nameHeader).toHaveAttribute('aria-sort', 'ascending');
584
+ });
585
+
586
+ // Navigate to email header
587
+ await user.keyboard('{ArrowRight}');
588
+
589
+ const emailHeader = screen.getByRole('columnheader', { name: /email/i });
590
+ await waitFor(() => {
591
+ expect(emailHeader).toHaveFocus();
592
+ });
593
+
594
+ // Sort by email
595
+ await user.keyboard(' ');
596
+
597
+ await waitFor(() => {
598
+ expect(emailHeader).toHaveAttribute('aria-sort', 'ascending');
599
+ });
600
+
601
+ // Navigate to first cell
602
+ const cells = screen.getAllByRole('cell');
603
+ if (cells[0]) {
604
+ cells[0].focus();
605
+
606
+ // Navigate around cells
607
+ await user.keyboard('{ArrowRight}');
608
+ await user.keyboard('{ArrowDown}');
609
+ await user.keyboard('{Home}');
610
+
611
+ // Should not cause any errors or warnings
612
+ }
613
+ });
614
+ });
615
+ });