@jmruthers/pace-core 0.5.136 → 0.5.139

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 (292) hide show
  1. package/dist/{DataTable-CYOHOX3O.js → DataTable-JXFCA2BJ.js} +10 -9
  2. package/dist/{EventLogo-801uofbR.d.ts → EventLogo-rFL_kRjk.d.ts} +73 -1
  3. package/dist/{UnifiedAuthProvider-5E5TUNMS.js → UnifiedAuthProvider-XIQQ7LVU.js} +4 -5
  4. package/dist/{chunk-YLKIDTUK.js → chunk-22WKWKRX.js} +4 -4
  5. package/dist/{chunk-TVYPTYOY.js → chunk-4C7EXCAR.js} +60 -24
  6. package/dist/chunk-4C7EXCAR.js.map +1 -0
  7. package/dist/{chunk-NOHEVYVX.js → chunk-5JMOHWDI.js} +417 -319
  8. package/dist/chunk-5JMOHWDI.js.map +1 -0
  9. package/dist/{chunk-FHWWBIHA.js → chunk-6DXZ6V5Q.js} +5 -5
  10. package/dist/{chunk-2TWNJ46Y.js → chunk-6LAAY47Q.js} +2 -2
  11. package/dist/{chunk-444EZN6N.js → chunk-7QCC6MCP.js} +88 -1
  12. package/dist/chunk-7QCC6MCP.js.map +1 -0
  13. package/dist/chunk-BJPBT3CU.js +21 -0
  14. package/dist/chunk-BJPBT3CU.js.map +1 -0
  15. package/dist/{chunk-L6PGMCMD.js → chunk-BOOI7GK2.js} +38 -12
  16. package/dist/chunk-BOOI7GK2.js.map +1 -0
  17. package/dist/{chunk-XARJS7CD.js → chunk-INQLMHPF.js} +2 -2
  18. package/dist/chunk-JISYG63F.js +70 -0
  19. package/dist/chunk-JISYG63F.js.map +1 -0
  20. package/dist/{chunk-SL2YQDR6.js → chunk-MA6EPSGZ.js} +2 -2
  21. package/dist/{chunk-5DPZ5EAT.js → chunk-OWAG3GSU.js} +1 -3
  22. package/dist/{chunk-LTV3XIJJ.js → chunk-T6JN6LH6.js} +4 -4
  23. package/dist/{chunk-HJGGOMQ6.js → chunk-TLT2ZR3L.js} +147 -103
  24. package/dist/chunk-TLT2ZR3L.js.map +1 -0
  25. package/dist/{chunk-4MT5BGGL.js → chunk-YCWDTTUK.js} +4 -6
  26. package/dist/{chunk-4MT5BGGL.js.map → chunk-YCWDTTUK.js.map} +1 -1
  27. package/dist/components.d.ts +1 -1
  28. package/dist/components.js +12 -11
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.js +8 -9
  31. package/dist/hooks.js.map +1 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +15 -14
  34. package/dist/index.js.map +1 -1
  35. package/dist/providers.js +3 -4
  36. package/dist/rbac/index.js +8 -9
  37. package/dist/schema-DTDZQe2u.d.ts +28 -0
  38. package/dist/types.d.ts +152 -3
  39. package/dist/types.js +51 -16
  40. package/dist/types.js.map +1 -1
  41. package/dist/utils.d.ts +89 -4
  42. package/dist/utils.js +214 -96
  43. package/dist/utils.js.map +1 -1
  44. package/dist/validation.d.ts +1 -343
  45. package/dist/validation.js +3 -100
  46. package/docs/api/classes/ColumnFactory.md +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +1 -1
  49. package/docs/api/classes/MissingUserContextError.md +1 -1
  50. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  51. package/docs/api/classes/PermissionDeniedError.md +1 -1
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +1 -1
  54. package/docs/api/classes/RBACCache.md +1 -1
  55. package/docs/api/classes/RBACEngine.md +1 -1
  56. package/docs/api/classes/RBACError.md +1 -1
  57. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  58. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  59. package/docs/api/classes/StorageUtils.md +1 -1
  60. package/docs/api/enums/FileCategory.md +1 -1
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/BadgeProps.md +27 -0
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/EventLogoProps.md +1 -1
  77. package/docs/api/interfaces/ExportColumn.md +1 -1
  78. package/docs/api/interfaces/ExportOptions.md +1 -1
  79. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  80. package/docs/api/interfaces/FileMetadata.md +1 -1
  81. package/docs/api/interfaces/FileReference.md +1 -1
  82. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  83. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  84. package/docs/api/interfaces/FileUploadProps.md +1 -1
  85. package/docs/api/interfaces/FooterProps.md +1 -1
  86. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  87. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  88. package/docs/api/interfaces/InputProps.md +1 -1
  89. package/docs/api/interfaces/LabelProps.md +1 -1
  90. package/docs/api/interfaces/LoginFormProps.md +1 -1
  91. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  92. package/docs/api/interfaces/NavigationContextType.md +1 -1
  93. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  94. package/docs/api/interfaces/NavigationItem.md +1 -1
  95. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  97. package/docs/api/interfaces/Organisation.md +1 -1
  98. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  99. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  100. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  101. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  102. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  103. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  104. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  105. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  106. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  107. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  108. package/docs/api/interfaces/PaletteData.md +1 -1
  109. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  110. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  111. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  112. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  113. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  114. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  115. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  116. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  117. package/docs/api/interfaces/RBACConfig.md +1 -1
  118. package/docs/api/interfaces/RBACLogger.md +1 -1
  119. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  120. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  121. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  122. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  123. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  124. package/docs/api/interfaces/RouteConfig.md +1 -1
  125. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  126. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  127. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  128. package/docs/api/interfaces/StorageConfig.md +1 -1
  129. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  130. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  131. package/docs/api/interfaces/StorageListOptions.md +1 -1
  132. package/docs/api/interfaces/StorageListResult.md +1 -1
  133. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  134. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  135. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  136. package/docs/api/interfaces/StyleImport.md +1 -1
  137. package/docs/api/interfaces/SwitchProps.md +1 -1
  138. package/docs/api/interfaces/ToastActionElement.md +1 -1
  139. package/docs/api/interfaces/ToastProps.md +1 -1
  140. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  141. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  142. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  143. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  145. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  146. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  147. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  148. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  149. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  150. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  151. package/docs/api/interfaces/UserEventAccess.md +1 -1
  152. package/docs/api/interfaces/UserMenuProps.md +1 -1
  153. package/docs/api/interfaces/UserProfile.md +1 -1
  154. package/docs/api/modules.md +84 -15
  155. package/docs/architecture/README.md +0 -1
  156. package/docs/styles/README.md +0 -2
  157. package/examples/RBAC/CompleteRBACExample.tsx +324 -0
  158. package/examples/RBAC/EventBasedApp.tsx +239 -0
  159. package/examples/RBAC/PermissionExample.tsx +151 -0
  160. package/examples/RBAC/index.ts +13 -0
  161. package/examples/public-pages/CorrectPublicPageImplementation.tsx +301 -0
  162. package/examples/public-pages/PublicEventPage.tsx +274 -0
  163. package/examples/public-pages/PublicPageApp.tsx +308 -0
  164. package/examples/public-pages/PublicPageUsageExample.tsx +216 -0
  165. package/examples/public-pages/index.ts +14 -0
  166. package/package.json +1 -10
  167. package/src/__tests__/TEST_STANDARD.md +92 -0
  168. package/src/components/Badge/Badge.test.tsx +314 -0
  169. package/src/components/Badge/Badge.tsx +304 -0
  170. package/src/components/Badge/index.ts +3 -0
  171. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
  172. package/src/components/DataTable/__tests__/styles.test.ts +1 -1
  173. package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
  174. package/src/components/DataTable/components/DataTableBody.tsx +461 -0
  175. package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
  176. package/src/components/DataTable/components/FilterRow.tsx +9 -3
  177. package/src/components/DataTable/components/PaginationControls.tsx +1 -0
  178. package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
  179. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
  180. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
  181. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
  182. package/src/components/DataTable/core/ActionManager.ts +235 -0
  183. package/src/components/DataTable/core/ColumnManager.ts +205 -0
  184. package/src/components/DataTable/core/DataManager.ts +188 -0
  185. package/src/components/DataTable/core/DataTableContext.tsx +181 -0
  186. package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
  187. package/src/components/DataTable/core/PluginRegistry.ts +229 -0
  188. package/src/components/DataTable/core/StateManager.ts +311 -0
  189. package/src/components/DataTable/core/interfaces.ts +338 -0
  190. package/src/components/DataTable/styles.ts +27 -6
  191. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
  192. package/src/components/DataTable/utils/columnUtils.ts +40 -0
  193. package/src/components/DataTable/utils/debugTools.ts +609 -0
  194. package/src/components/DataTable/utils/index.ts +1 -0
  195. package/src/components/Dialog/README.md +804 -0
  196. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
  197. package/src/components/Dialog/utils/safeHtml.ts +185 -0
  198. package/src/components/Footer/Footer.test.tsx +1 -1
  199. package/src/components/Form/Form.test.tsx +1 -1
  200. package/src/components/Form/FormErrorSummary.tsx +113 -0
  201. package/src/components/Form/FormFieldset.tsx +127 -0
  202. package/src/components/Form/FormLiveRegion.tsx +198 -0
  203. package/src/components/LoginForm/LoginForm.test.tsx +1 -1
  204. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
  205. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
  206. package/src/components/PasswordReset/PasswordResetForm.test.tsx +597 -0
  207. package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
  208. package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
  209. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
  210. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
  211. package/src/components/Select/Select.test.tsx +1 -1
  212. package/src/components/Select/Select.tsx +20 -8
  213. package/src/components/Table/__tests__/Table.test.tsx +1 -1
  214. package/src/components/index.ts +3 -0
  215. package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
  216. package/src/index.ts +4 -0
  217. package/src/rbac/hooks/useCan.test.ts +24 -0
  218. package/src/rbac/hooks/usePermissions.ts +49 -12
  219. package/src/styles/core.css +3 -0
  220. package/src/utils/appConfig.ts +47 -0
  221. package/src/utils/appIdResolver.test.ts +499 -0
  222. package/src/utils/appIdResolver.ts +130 -0
  223. package/src/utils/appNameResolver.simple.test.ts +212 -0
  224. package/src/utils/appNameResolver.test.ts +121 -0
  225. package/src/utils/appNameResolver.ts +191 -0
  226. package/src/utils/audit.ts +127 -0
  227. package/src/utils/auth-utils.ts +96 -0
  228. package/src/utils/bundleAnalysis.ts +129 -0
  229. package/src/utils/cn.ts +7 -0
  230. package/src/utils/debugLogger.ts +67 -0
  231. package/src/utils/deviceFingerprint.ts +215 -0
  232. package/src/utils/dynamicUtils.ts +105 -0
  233. package/src/utils/file-reference.test.ts +788 -0
  234. package/src/utils/file-reference.ts +519 -0
  235. package/src/utils/formatDate.test.ts +237 -0
  236. package/src/utils/formatting.ts +133 -0
  237. package/src/utils/index.ts +7 -0
  238. package/src/utils/lazyLoad.tsx +44 -0
  239. package/src/utils/logger.ts +179 -0
  240. package/src/utils/organisationContext.test.ts +322 -0
  241. package/src/utils/organisationContext.ts +153 -0
  242. package/src/utils/performanceBenchmark.ts +64 -0
  243. package/src/utils/performanceBudgets.ts +110 -0
  244. package/src/utils/permissionTypes.ts +37 -0
  245. package/src/utils/permissionUtils.test.ts +393 -0
  246. package/src/utils/permissionUtils.ts +34 -0
  247. package/src/utils/sanitization.ts +264 -0
  248. package/src/utils/schemaUtils.ts +37 -0
  249. package/src/utils/secureDataAccess.test.ts +711 -0
  250. package/src/utils/secureDataAccess.ts +377 -0
  251. package/src/utils/secureErrors.ts +79 -0
  252. package/src/utils/secureStorage.ts +244 -0
  253. package/src/utils/security.ts +156 -0
  254. package/src/utils/securityMonitor.ts +45 -0
  255. package/src/utils/sessionTracking.ts +126 -0
  256. package/src/utils/validation.ts +111 -0
  257. package/src/utils/validationUtils.ts +120 -0
  258. package/src/validation/index.ts +2 -2
  259. package/dist/chunk-444EZN6N.js.map +0 -1
  260. package/dist/chunk-APIBCTL2.js +0 -670
  261. package/dist/chunk-APIBCTL2.js.map +0 -1
  262. package/dist/chunk-HJGGOMQ6.js.map +0 -1
  263. package/dist/chunk-K2WWTH7O.js +0 -94
  264. package/dist/chunk-K2WWTH7O.js.map +0 -1
  265. package/dist/chunk-L6PGMCMD.js.map +0 -1
  266. package/dist/chunk-LMC26NLJ.js +0 -84
  267. package/dist/chunk-LMC26NLJ.js.map +0 -1
  268. package/dist/chunk-NOHEVYVX.js.map +0 -1
  269. package/dist/chunk-TVYPTYOY.js.map +0 -1
  270. package/dist/validation-8npbysjg.d.ts +0 -177
  271. /package/dist/{DataTable-CYOHOX3O.js.map → DataTable-JXFCA2BJ.js.map} +0 -0
  272. /package/dist/{UnifiedAuthProvider-5E5TUNMS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
  273. /package/dist/{chunk-YLKIDTUK.js.map → chunk-22WKWKRX.js.map} +0 -0
  274. /package/dist/{chunk-FHWWBIHA.js.map → chunk-6DXZ6V5Q.js.map} +0 -0
  275. /package/dist/{chunk-2TWNJ46Y.js.map → chunk-6LAAY47Q.js.map} +0 -0
  276. /package/dist/{chunk-XARJS7CD.js.map → chunk-INQLMHPF.js.map} +0 -0
  277. /package/dist/{chunk-SL2YQDR6.js.map → chunk-MA6EPSGZ.js.map} +0 -0
  278. /package/dist/{chunk-5DPZ5EAT.js.map → chunk-OWAG3GSU.js.map} +0 -0
  279. /package/dist/{chunk-LTV3XIJJ.js.map → chunk-T6JN6LH6.js.map} +0 -0
  280. /package/examples/{components → components 2}/DataTable/HierarchicalActionsExample.tsx +0 -0
  281. /package/examples/{components → components 2}/DataTable/HierarchicalExample.tsx +0 -0
  282. /package/examples/{components → components 2}/DataTable/InitialPageSizeExample.tsx +0 -0
  283. /package/examples/{components → components 2}/DataTable/PerformanceExample.tsx +0 -0
  284. /package/examples/{components → components 2}/DataTable/index.ts +0 -0
  285. /package/examples/{components → components 2}/Dialog/BasicHtmlTest.tsx +0 -0
  286. /package/examples/{components → components 2}/Dialog/DebugHtmlExample.tsx +0 -0
  287. /package/examples/{components → components 2}/Dialog/HtmlDialogExample.tsx +0 -0
  288. /package/examples/{components → components 2}/Dialog/ScrollableDialogExample.tsx +0 -0
  289. /package/examples/{components → components 2}/Dialog/SimpleHtmlTest.tsx +0 -0
  290. /package/examples/{components → components 2}/Dialog/SmartDialogExample.tsx +0 -0
  291. /package/examples/{components → components 2}/Dialog/index.ts +0 -0
  292. /package/examples/{components → components 2}/index.ts +0 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * @file DataTable State Manager
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Architecture/Managers
5
+ * @since 0.3.0
6
+ */
7
+
8
+ import type { StateManager, DataTableState, DataTableObserver, Observable, UIState } from './interfaces';
9
+ import type { DataRecord } from '../types';
10
+
11
+ /**
12
+ * State manager implementation with observer pattern
13
+ * Responsible only for state management
14
+ */
15
+ export class StateManagerImpl<TData extends DataRecord> implements StateManager<TData>, Observable<TData> {
16
+ private state: DataTableState<TData>;
17
+ private observers: Map<string, DataTableObserver<TData>> = new Map();
18
+ private observerIdCounter = 0;
19
+
20
+ constructor(initialState?: Partial<DataTableState<TData>>) {
21
+ this.state = this.createInitialState(initialState);
22
+ }
23
+
24
+ /**
25
+ * Get current state
26
+ */
27
+ getState(): DataTableState<TData> {
28
+ return { ...this.state };
29
+ }
30
+
31
+ /**
32
+ * Set state with updater function
33
+ */
34
+ setState(updater: (state: DataTableState<TData>) => DataTableState<TData>): void {
35
+ const newState = updater(this.getState());
36
+ const oldState = this.state;
37
+ this.state = newState;
38
+
39
+ // Notify observers of state changes
40
+ this.notifyStateChange(oldState, newState);
41
+ }
42
+
43
+ /**
44
+ * Subscribe to state changes
45
+ */
46
+ subscribe(observer: DataTableObserver<TData> | ((state: DataTableState<TData>) => void)): () => void {
47
+ const observerId = `observer-${++this.observerIdCounter}`;
48
+
49
+ let dataTableObserver: DataTableObserver<TData>;
50
+
51
+ if (typeof observer === 'function') {
52
+ dataTableObserver = {
53
+ id: observerId,
54
+ onStateChange: observer,
55
+ };
56
+ } else {
57
+ dataTableObserver = observer;
58
+ }
59
+
60
+ this.observers.set(observerId, dataTableObserver);
61
+
62
+ // Return unsubscribe function
63
+ return () => this.unsubscribe(observerId);
64
+ }
65
+
66
+ /**
67
+ * Subscribe to specific state changes
68
+ */
69
+ subscribeToObserver(observer: DataTableObserver<TData>): () => void {
70
+ this.observers.set(observer.id, observer);
71
+ return () => this.unsubscribe(observer.id);
72
+ }
73
+
74
+ /**
75
+ * Unsubscribe observer
76
+ */
77
+ unsubscribe(observerId: string): void {
78
+ this.observers.delete(observerId);
79
+ }
80
+
81
+ /**
82
+ * Notify all observers of an event
83
+ */
84
+ notify(event: string, data: any): void {
85
+ this.observers.forEach(observer => {
86
+ switch (event) {
87
+ case 'dataChange':
88
+ observer.onDataChange?.(data);
89
+ break;
90
+ case 'columnChange':
91
+ observer.onColumnChange?.(data);
92
+ break;
93
+ case 'stateChange':
94
+ observer.onStateChange?.(data);
95
+ break;
96
+ case 'error':
97
+ observer.onError?.(data);
98
+ break;
99
+ }
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Update data and notify observers
105
+ */
106
+ updateData(data: TData[]): void {
107
+ const oldData = this.state.data;
108
+ this.setState(state => ({ ...state, data }));
109
+
110
+ if (oldData !== data) {
111
+ this.notify('dataChange', data);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Update columns and notify observers
117
+ */
118
+ updateColumns(columns: any[]): void {
119
+ const oldColumns = this.state.columns;
120
+ this.setState(state => ({ ...state, columns }));
121
+
122
+ if (oldColumns !== columns) {
123
+ this.notify('columnChange', columns);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Update actions and notify observers
129
+ */
130
+ updateActions(actions: any[]): void {
131
+ this.setState(state => ({ ...state, actions }));
132
+ }
133
+
134
+ /**
135
+ * Update UI state
136
+ */
137
+ updateUI(uiUpdates: Partial<UIState>): void {
138
+ this.setState(state => ({
139
+ ...state,
140
+ ui: { ...state.ui, ...uiUpdates }
141
+ }));
142
+ }
143
+
144
+ /**
145
+ * Update global filter
146
+ */
147
+ updateGlobalFilter(filter: string): void {
148
+ this.updateUI({ globalFilter: filter });
149
+ }
150
+
151
+ /**
152
+ * Update column filters
153
+ */
154
+ updateColumnFilters(filters: Array<{ id: string; value: any }>): void {
155
+ this.updateUI({ columnFilters: filters });
156
+ }
157
+
158
+ /**
159
+ * Update sorting
160
+ */
161
+ updateSorting(sorting: Array<{ id: string; desc: boolean }>): void {
162
+ this.updateUI({ sorting });
163
+ }
164
+
165
+ /**
166
+ * Update grouping
167
+ */
168
+ updateGrouping(grouping: string[]): void {
169
+ this.updateUI({ grouping });
170
+ }
171
+
172
+ /**
173
+ * Update pagination
174
+ */
175
+ updatePagination(pagination: { pageIndex: number; pageSize: number }): void {
176
+ this.updateUI({ pagination });
177
+ }
178
+
179
+ /**
180
+ * Update row selection
181
+ */
182
+ updateRowSelection(selection: Record<string, boolean>): void {
183
+ this.updateUI({ rowSelection: selection });
184
+ }
185
+
186
+ /**
187
+ * Update editing state
188
+ */
189
+ updateEditing(editing: DataTableState<TData>['ui']['editing']): void {
190
+ this.updateUI({ editing });
191
+ }
192
+
193
+ /**
194
+ * Update modal state
195
+ */
196
+ updateModals(modals: DataTableState<TData>['ui']['modals']): void {
197
+ this.updateUI({ modals });
198
+ }
199
+
200
+ /**
201
+ * Update feature state
202
+ */
203
+ updateFeatureState(featureName: string, state: any): void {
204
+ this.setState(currentState => ({
205
+ ...currentState,
206
+ features: new Map(currentState.features).set(featureName, state)
207
+ }));
208
+ }
209
+
210
+ /**
211
+ * Update plugin state
212
+ */
213
+ updatePluginState(pluginName: string, state: any): void {
214
+ this.setState(currentState => ({
215
+ ...currentState,
216
+ plugins: new Map(currentState.plugins).set(pluginName, state)
217
+ }));
218
+ }
219
+
220
+ /**
221
+ * Set loading state
222
+ */
223
+ setLoading(loading: boolean): void {
224
+ this.setState(state => ({ ...state, isLoading: loading }));
225
+ }
226
+
227
+ /**
228
+ * Set error state
229
+ */
230
+ setError(error: Error | null): void {
231
+ this.setState(state => ({ ...state, error }));
232
+
233
+ if (error) {
234
+ this.notify('error', error);
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Reset state to initial values
240
+ */
241
+ reset(): void {
242
+ this.state = this.createInitialState();
243
+ this.notify('stateChange', this.state);
244
+ }
245
+
246
+ /**
247
+ * Get observer count
248
+ */
249
+ getObserverCount(): number {
250
+ return this.observers.size;
251
+ }
252
+
253
+ /**
254
+ * Create initial state
255
+ */
256
+ private createInitialState(overrides?: Partial<DataTableState<TData>>): DataTableState<TData> {
257
+ const defaultState: DataTableState<TData> = {
258
+ data: [],
259
+ isLoading: false,
260
+ error: null,
261
+ columns: [],
262
+ columnVisibility: {},
263
+ actions: [],
264
+ ui: {
265
+ globalFilter: '',
266
+ columnFilters: [],
267
+ sorting: [],
268
+ grouping: [],
269
+ expanded: {},
270
+ pagination: {
271
+ pageIndex: 0,
272
+ pageSize: 10,
273
+ },
274
+ rowSelection: {},
275
+ editing: {
276
+ rowId: null,
277
+ data: {},
278
+ isCreating: false,
279
+ creationData: {},
280
+ },
281
+ modals: {
282
+ import: false,
283
+ export: false,
284
+ view: false,
285
+ viewData: null,
286
+ },
287
+ },
288
+ features: new Map(),
289
+ plugins: new Map(),
290
+ };
291
+
292
+ return { ...defaultState, ...overrides };
293
+ }
294
+
295
+ /**
296
+ * Notify observers of state changes
297
+ */
298
+ private notifyStateChange(oldState: DataTableState<TData>, newState: DataTableState<TData>): void {
299
+ // Check for specific changes and notify accordingly
300
+ if (oldState.data !== newState.data) {
301
+ this.notify('dataChange', newState.data);
302
+ }
303
+
304
+ if (oldState.columns !== newState.columns) {
305
+ this.notify('columnChange', newState.columns);
306
+ }
307
+
308
+ // Always notify of state change
309
+ this.notify('stateChange', newState);
310
+ }
311
+ }
@@ -0,0 +1,338 @@
1
+ /**
2
+ * @file DataTable Architecture Interfaces
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Architecture
5
+ * @since 0.3.0
6
+ */
7
+
8
+ import React from 'react';
9
+ import type { ColumnDef } from '@tanstack/react-table';
10
+ import type { DataRecord, DataTableAction } from '../types';
11
+
12
+ // ============================================================================
13
+ // CORE RESPONSIBILITY INTERFACES (SRP)
14
+ // ============================================================================
15
+
16
+ /**
17
+ * Data management responsibility
18
+ */
19
+ export interface DataTableDataManager<TData extends DataRecord> {
20
+ getData(): TData[];
21
+ updateData(id: string, data: Partial<TData>): Promise<void>;
22
+ deleteData(id: string): Promise<void>;
23
+ createData(data: Partial<TData>): Promise<TData>;
24
+ isLoading(): boolean;
25
+ getError(): Error | null;
26
+ }
27
+
28
+ /**
29
+ * Column management responsibility
30
+ */
31
+ export interface ColumnManager<TData extends DataRecord> {
32
+ getColumns(): ColumnDef<TData>[];
33
+ addColumn(column: ColumnDef<TData>): void;
34
+ removeColumn(id: string): void;
35
+ updateColumn(id: string, column: Partial<ColumnDef<TData>>): void;
36
+ getColumn(id: string): ColumnDef<TData> | undefined;
37
+ }
38
+
39
+ /**
40
+ * Action management responsibility
41
+ */
42
+ export interface ActionManager<TData extends DataRecord> {
43
+ getActions(): DataTableAction<TData>[];
44
+ addAction(action: DataTableAction<TData>): void;
45
+ removeAction(id: string): void;
46
+ updateAction(id: string, action: Partial<DataTableAction<TData>>): void;
47
+ }
48
+
49
+ /**
50
+ * State management responsibility
51
+ */
52
+ export interface StateManager<TData extends DataRecord> {
53
+ getState(): DataTableState<TData>;
54
+ setState(updater: (state: DataTableState<TData>) => DataTableState<TData>): void;
55
+ subscribe(callback: (state: DataTableState<TData>) => void): () => void;
56
+
57
+ // Additional methods for convenience
58
+ updateData(data: TData[]): void;
59
+ updateColumns(columns: any[]): void;
60
+ updateActions(actions: any[]): void;
61
+ updateUI(uiUpdates: Partial<UIState>): void;
62
+ updateGlobalFilter(filter: string): void;
63
+ updateColumnFilters(filters: Array<{ id: string; value: any }>): void;
64
+ updateSorting(sorting: Array<{ id: string; desc: boolean }>): void;
65
+ updateGrouping(grouping: string[]): void;
66
+ updatePagination(pagination: { pageIndex: number; pageSize: number }): void;
67
+ updateRowSelection(selection: Record<string, boolean>): void;
68
+ updateEditing(editing: DataTableState<TData>['ui']['editing']): void;
69
+ updateModals(modals: DataTableState<TData>['ui']['modals']): void;
70
+ updateFeatureState(featureName: string, state: any): void;
71
+ updatePluginState(pluginName: string, state: any): void;
72
+ setLoading(loading: boolean): void;
73
+ setError(error: Error | null): void;
74
+ reset(): void;
75
+ }
76
+
77
+ // ============================================================================
78
+ // FEATURE STRATEGY INTERFACES (OCP)
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Feature strategy interface for extensible features
83
+ */
84
+ export interface DataTableFeature<TData extends DataRecord = DataRecord> {
85
+ name: string;
86
+ priority: number;
87
+ isEnabled(): boolean;
88
+ initialize(context: DataTableContext<TData>): void;
89
+ render(): React.ReactNode;
90
+ cleanup(): void;
91
+ getState(): any;
92
+ }
93
+
94
+ /**
95
+ * Feature configuration
96
+ */
97
+ export interface FeatureConfig {
98
+ enabled: boolean;
99
+ options?: Record<string, any>;
100
+ }
101
+
102
+ // ============================================================================
103
+ // PLUGIN ARCHITECTURE INTERFACES
104
+ // ============================================================================
105
+
106
+ /**
107
+ * Plugin interface for extensible functionality
108
+ */
109
+ export interface DataTablePlugin<TData extends DataRecord = DataRecord> {
110
+ name: string;
111
+ version: string;
112
+ priority: number;
113
+ dependencies?: string[];
114
+
115
+ initialize(context: DataTableContext<TData>): Promise<void>;
116
+ render(): React.ReactNode;
117
+ cleanup(): Promise<void>;
118
+
119
+ onDataChange?(data: TData[]): void;
120
+ onColumnChange?(columns: ColumnDef<TData>[]): void;
121
+ onStateChange?(state: Partial<DataTableState<TData>>): void;
122
+ }
123
+
124
+ /**
125
+ * Plugin registry for managing plugins
126
+ */
127
+ export interface PluginRegistry<TData extends DataRecord = DataRecord> {
128
+ register(plugin: DataTablePlugin<TData>): void;
129
+ unregister(name: string): void;
130
+ getPlugin(name: string): DataTablePlugin<TData> | undefined;
131
+ getEnabledPlugins(): DataTablePlugin<TData>[];
132
+ getDependencyOrder(): DataTablePlugin<TData>[];
133
+ }
134
+
135
+ // ============================================================================
136
+ // ADAPTER PATTERN INTERFACES (DIP)
137
+ // ============================================================================
138
+
139
+ /**
140
+ * Data adapter interface for different data sources
141
+ */
142
+ export interface DataAdapter<TData extends DataRecord = DataRecord> {
143
+ name: string;
144
+
145
+ fetchData(options: FetchOptions): Promise<TData[]>;
146
+ updateData(id: string, data: Partial<TData>): Promise<void>;
147
+ deleteData(id: string): Promise<void>;
148
+ createData(data: Partial<TData>): Promise<TData>;
149
+ exportData(format: ExportFormat, options?: ExportOptions): Promise<string>;
150
+ importData(data: TData[]): Promise<void>;
151
+
152
+ isConnected(): boolean;
153
+ getError(): Error | null;
154
+ }
155
+
156
+ /**
157
+ * Fetch options for data adapters
158
+ */
159
+ export interface FetchOptions {
160
+ page?: number;
161
+ pageSize?: number;
162
+ sortBy?: string;
163
+ sortDirection?: 'asc' | 'desc';
164
+ filters?: Record<string, any>;
165
+ search?: string;
166
+ }
167
+
168
+ /**
169
+ * Export options
170
+ */
171
+ export interface ExportOptions {
172
+ filename?: string;
173
+ includeHeaders?: boolean;
174
+ dateFormat?: string;
175
+ }
176
+
177
+ /**
178
+ * Export format types
179
+ */
180
+ export type ExportFormat = 'csv' | 'json' | 'xlsx';
181
+
182
+ // ============================================================================
183
+ // OBSERVER PATTERN INTERFACES
184
+ // ============================================================================
185
+
186
+ /**
187
+ * Observer interface for state changes
188
+ */
189
+ export interface DataTableObserver<TData extends DataRecord = DataRecord> {
190
+ id: string;
191
+ onDataChange?(data: TData[]): void;
192
+ onColumnChange?(columns: ColumnDef<TData>[]): void;
193
+ onStateChange?(state: Partial<DataTableState<TData>>): void;
194
+ onError?(error: Error): void;
195
+ }
196
+
197
+ /**
198
+ * Observable interface for state management
199
+ */
200
+ export interface Observable<TData extends DataRecord = DataRecord> {
201
+ subscribe(observer: DataTableObserver<TData> | ((state: DataTableState<TData>) => void)): () => void;
202
+ unsubscribe(observerId: string): void;
203
+ notify(event: string, data: any): void;
204
+ }
205
+
206
+ // ============================================================================
207
+ // STATE INTERFACES
208
+ // ============================================================================
209
+
210
+ /**
211
+ * Core DataTable state
212
+ */
213
+ export interface DataTableState<TData extends DataRecord = DataRecord> {
214
+ // Data state
215
+ data: TData[];
216
+ isLoading: boolean;
217
+ error: Error | null;
218
+
219
+ // Column state
220
+ columns: ColumnDef<TData>[];
221
+ columnVisibility: Record<string, boolean>;
222
+
223
+ // Action state
224
+ actions: DataTableAction<TData>[];
225
+
226
+ // UI state
227
+ ui: UIState;
228
+
229
+ // Feature state
230
+ features: Map<string, any>;
231
+
232
+ // Plugin state
233
+ plugins: Map<string, any>;
234
+ }
235
+
236
+ /**
237
+ * UI-specific state
238
+ */
239
+ export interface UIState {
240
+ // Filtering
241
+ globalFilter: string;
242
+ columnFilters: Array<{ id: string; value: any }>;
243
+
244
+ // Sorting
245
+ sorting: Array<{ id: string; desc: boolean }>;
246
+
247
+ // Grouping
248
+ grouping: string[];
249
+ expanded: Record<string, boolean>;
250
+
251
+ // Pagination
252
+ pagination: {
253
+ pageIndex: number;
254
+ pageSize: number;
255
+ };
256
+
257
+ // Selection
258
+ rowSelection: Record<string, boolean>;
259
+
260
+ // Editing
261
+ editing: {
262
+ rowId: string | null;
263
+ data: Record<string, any>;
264
+ isCreating: boolean;
265
+ creationData: Record<string, any>;
266
+ };
267
+
268
+ // Modals
269
+ modals: {
270
+ import: boolean;
271
+ export: boolean;
272
+ view: boolean;
273
+ viewData: any;
274
+ };
275
+ }
276
+
277
+ // ============================================================================
278
+ // CONTEXT INTERFACES
279
+ // ============================================================================
280
+
281
+ /**
282
+ * DataTable context for sharing state and managers
283
+ */
284
+ export interface DataTableContext<TData extends DataRecord = DataRecord> {
285
+ // Core managers
286
+ dataManager: DataTableDataManager<TData>;
287
+ columnManager: ColumnManager<TData>;
288
+ actionManager: ActionManager<TData>;
289
+ stateManager: StateManager<TData>;
290
+
291
+ // Architecture components
292
+ pluginRegistry: PluginRegistry<TData>;
293
+ adapter: DataAdapter<TData>;
294
+ observable: Observable<TData>;
295
+
296
+ // Configuration
297
+ config: DataTableConfig<TData>;
298
+
299
+ // Utilities
300
+ utils: DataTableUtils<TData>;
301
+ }
302
+
303
+ /**
304
+ * DataTable configuration
305
+ */
306
+ export interface DataTableConfig<TData extends DataRecord = DataRecord> {
307
+ // Core settings
308
+ title?: string;
309
+ description?: string;
310
+ className?: string;
311
+ variant?: 'default' | 'compact' | 'spacious';
312
+
313
+ // Feature flags
314
+ features: Record<string, FeatureConfig>;
315
+
316
+ // Performance settings
317
+ enableVirtualization: boolean;
318
+ enableCaching: boolean;
319
+ cacheTimeout: number;
320
+
321
+ // Accessibility settings
322
+ enableKeyboardNavigation: boolean;
323
+ enableScreenReaderSupport: boolean;
324
+
325
+ // Event handlers
326
+ onDataChange?: (data: TData[]) => void;
327
+ onError?: (error: Error) => void;
328
+ }
329
+
330
+ /**
331
+ * DataTable utilities
332
+ */
333
+ export interface DataTableUtils<TData extends DataRecord = DataRecord> {
334
+ getRowId: (row: TData, index: number) => string;
335
+ formatValue: (value: any, column: ColumnDef<TData>) => string;
336
+ validateData: (data: Partial<TData>) => string[] | null;
337
+ debounce: <T extends (...args: any[]) => any>(func: T, delay: number) => T;
338
+ }
@@ -148,12 +148,33 @@ export const getTableClasses = (options: {
148
148
  } = {}) => {
149
149
  const { isFixed = false, variant = 'default', className } = options;
150
150
 
151
- return cn(
152
- isFixed ? tableStyles.tableFixed : tableStyles.table,
153
- variant === 'compact' && 'text-sm',
154
- variant === 'spacious' && 'text-base',
155
- className
156
- );
151
+ if (isFixed) {
152
+ // For fixed tables, use tableFixed and add variant-specific text size
153
+ return cn(
154
+ tableStyles.tableFixed,
155
+ variant === 'compact' && 'text-sm',
156
+ variant === 'spacious' && 'text-base',
157
+ className
158
+ );
159
+ }
160
+
161
+ // For regular tables, build classes based on variant
162
+ // tableStyles.table includes 'text-sm', so we need to handle variants carefully
163
+ if (variant === 'compact') {
164
+ // Compact uses text-sm (same as default), so just use base table styles
165
+ return cn(tableStyles.table, className);
166
+ }
167
+
168
+ if (variant === 'spacious') {
169
+ // Spacious uses text-base, so replace text-sm with text-base
170
+ return cn(
171
+ tableStyles.table.replace('text-sm', 'text-base'),
172
+ className
173
+ );
174
+ }
175
+
176
+ // Default variant
177
+ return cn(tableStyles.table, className);
157
178
  };
158
179
 
159
180
  /**