@jmruthers/pace-core 0.5.193 → 0.6.1

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 (191) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +372 -0
  4. package/cursor-rules/01-standards-compliance.mdc +275 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +341 -0
  7. package/cursor-rules/04-testing-standards.mdc +315 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +392 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +309 -0
  11. package/cursor-rules/CHANGELOG.md +101 -0
  12. package/cursor-rules/README.md +191 -0
  13. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-CH1U5Tpy.d.ts} +1 -1
  14. package/dist/{DataTable-5FU7IESH.js → DataTable-DQ7RSOHE.js} +6 -6
  15. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-ce4xlHYA.d.ts} +34 -155
  16. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-ATAP5UTR.js} +2 -2
  17. package/dist/{chunk-6C4YBBJM 5.js → chunk-3QRJFVBR.js} +1 -1
  18. package/dist/chunk-3QRJFVBR.js.map +1 -0
  19. package/dist/{chunk-IIELH4DL.js → chunk-3XTALGJF.js} +2 -2
  20. package/dist/{chunk-IIELH4DL.js.map → chunk-3XTALGJF.js.map} +1 -1
  21. package/dist/{chunk-HWIIPPNI.js → chunk-4N5C5XZU.js} +20 -20
  22. package/dist/chunk-4N5C5XZU.js.map +1 -0
  23. package/dist/{chunk-7EQTDTTJ.js → chunk-4ZC4GX36.js} +5 -5
  24. package/dist/{chunk-7EQTDTTJ.js 2.map → chunk-4ZC4GX36.js.map} +1 -1
  25. package/dist/{chunk-7FLMSG37.js → chunk-BYFSK72L.js} +22 -22
  26. package/dist/chunk-BYFSK72L.js.map +1 -0
  27. package/dist/{chunk-LFNCN2SP.js → chunk-EXUD6RNJ.js} +46 -7
  28. package/dist/chunk-EXUD6RNJ.js.map +1 -0
  29. package/dist/{chunk-NOAYCWCX 5.js → chunk-GLK6VM3F.js} +167 -169
  30. package/dist/chunk-GLK6VM3F.js.map +1 -0
  31. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  32. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  33. package/dist/{chunk-BC4IJKSL.js → chunk-JBKQ3SAO.js} +2 -2
  34. package/dist/{chunk-QWWZ5CAQ.js → chunk-LXQLPRQ2.js} +2 -2
  35. package/dist/{chunk-E3SPN4VZ 5.js → chunk-T33XF5ZC.js} +119 -114
  36. package/dist/chunk-T33XF5ZC.js.map +1 -0
  37. package/dist/{chunk-XNXXZ43G.js → chunk-XM25TVIE.js} +27 -4
  38. package/dist/chunk-XM25TVIE.js.map +1 -0
  39. package/dist/components.d.ts +3 -3
  40. package/dist/components.js +8 -8
  41. package/dist/hooks.d.ts +6 -6
  42. package/dist/hooks.js +17 -22
  43. package/dist/hooks.js.map +1 -1
  44. package/dist/index.d.ts +7 -7
  45. package/dist/index.js +15 -16
  46. package/dist/index.js.map +1 -1
  47. package/dist/providers.js +1 -1
  48. package/dist/rbac/index.d.ts +1 -1
  49. package/dist/rbac/index.js +5 -5
  50. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-BJAlWfuJ.d.ts} +3 -3
  51. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  52. package/dist/utils.d.ts +1 -1
  53. package/dist/utils.js +3 -3
  54. package/docs/getting-started/cursor-rules.md +262 -0
  55. package/docs/getting-started/installation-guide.md +6 -1
  56. package/docs/getting-started/quick-start.md +6 -1
  57. package/docs/migration/MIGRATION_GUIDE.md +4 -4
  58. package/docs/migration/REACT_19_MIGRATION.md +227 -0
  59. package/docs/standards/README.md +39 -0
  60. package/docs/troubleshooting/migration.md +4 -4
  61. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  62. package/package.json +11 -6
  63. package/scripts/audit-consuming-app.cjs +961 -0
  64. package/scripts/check-pace-core-compliance.cjs +34 -15
  65. package/scripts/install-cursor-rules.cjs +236 -0
  66. package/src/__tests__/helpers/test-providers.tsx +1 -1
  67. package/src/__tests__/helpers/test-utils.tsx +1 -1
  68. package/src/components/Badge/Badge.tsx +2 -4
  69. package/src/components/Button/Button.tsx +5 -4
  70. package/src/components/Calendar/Calendar.tsx +1 -1
  71. package/src/components/DataTable/DataTable.test.tsx +57 -93
  72. package/src/components/DataTable/DataTable.tsx +2 -2
  73. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +13 -5
  74. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  75. package/src/components/DataTable/components/AccessDeniedPage.tsx +1 -1
  76. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  77. package/src/components/DataTable/components/DataTableCore.tsx +4 -7
  78. package/src/components/DataTable/components/DataTableModals.tsx +1 -1
  79. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  80. package/src/components/DataTable/components/UnifiedTableBody.tsx +6 -8
  81. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  82. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  83. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  84. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  85. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  86. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  87. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  88. package/src/components/DataTable/hooks/useColumnReordering.ts +2 -2
  89. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  90. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  91. package/src/components/Dialog/Dialog.tsx +6 -5
  92. package/src/components/ErrorBoundary/ErrorBoundary.tsx +1 -1
  93. package/src/components/EventSelector/EventSelector.tsx +1 -1
  94. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  95. package/src/components/Footer/Footer.tsx +1 -1
  96. package/src/components/Form/Form.test.tsx +36 -15
  97. package/src/components/Form/Form.tsx +30 -26
  98. package/src/components/Header/Header.tsx +1 -1
  99. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  100. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  101. package/src/components/Input/Input.tsx +28 -30
  102. package/src/components/Label/Label.tsx +1 -1
  103. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  104. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  105. package/src/components/LoginForm/LoginForm.tsx +8 -8
  106. package/src/components/NavigationMenu/NavigationMenu.tsx +1 -1
  107. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  108. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +50 -50
  109. package/src/components/PaceAppLayout/PaceAppLayout.tsx +1 -1
  110. package/src/components/PaceAppLayout/README.md +1 -1
  111. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
  112. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  113. package/src/components/PasswordChange/PasswordChangeForm.tsx +1 -1
  114. package/src/components/Progress/Progress.tsx +1 -1
  115. package/src/components/PublicLayout/PublicPageLayout.tsx +1 -1
  116. package/src/components/Select/Select.tsx +33 -22
  117. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +1 -1
  118. package/src/components/Table/Table.tsx +1 -1
  119. package/src/components/Textarea/Textarea.tsx +27 -29
  120. package/src/components/Toast/Toast.tsx +1 -1
  121. package/src/components/Tooltip/Tooltip.tsx +1 -1
  122. package/src/components/UserMenu/UserMenu.tsx +1 -1
  123. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  124. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  125. package/src/hooks/public/usePublicEvent.ts +1 -1
  126. package/src/hooks/public/usePublicEventLogo.ts +1 -1
  127. package/src/hooks/public/usePublicRouteParams.ts +1 -1
  128. package/src/hooks/useDataTableState.ts +8 -18
  129. package/src/hooks/useFocusManagement.ts +2 -2
  130. package/src/hooks/useFocusTrap.ts +4 -4
  131. package/src/hooks/useFormDialog.ts +8 -7
  132. package/src/hooks/useInactivityTracker.ts +1 -1
  133. package/src/hooks/usePermissionCache.ts +1 -1
  134. package/src/hooks/useSecureDataAccess.ts +19 -4
  135. package/src/hooks/useToast.ts +2 -2
  136. package/src/providers/__tests__/OrganisationProvider.test.tsx +57 -13
  137. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  138. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  139. package/src/providers/services/UnifiedAuthProvider.tsx +22 -22
  140. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +13 -3
  141. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +24 -24
  142. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  143. package/src/rbac/components/NavigationGuard.tsx +1 -1
  144. package/src/rbac/components/NavigationProvider.tsx +1 -1
  145. package/src/rbac/components/PagePermissionGuard.tsx +1 -1
  146. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  147. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  148. package/src/rbac/components/RoleBasedRouter.tsx +1 -1
  149. package/src/rbac/components/SecureDataProvider.tsx +1 -1
  150. package/src/rbac/secureClient.ts +12 -0
  151. package/src/utils/security/secureDataAccess.test.ts +31 -20
  152. package/src/utils/security/secureDataAccess.ts +4 -3
  153. package/dist/chunk-6C4YBBJM.js +0 -628
  154. package/dist/chunk-6C4YBBJM.js.map +0 -1
  155. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  156. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  157. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  158. package/dist/chunk-7FLMSG37.js.map +0 -1
  159. package/dist/chunk-E3SPN4VZ.js +0 -12917
  160. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  161. package/dist/chunk-E66EQZE6 5.js +0 -37
  162. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  163. package/dist/chunk-HWIIPPNI.js.map +0 -1
  164. package/dist/chunk-I7PSE6JW 5.js +0 -191
  165. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  166. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  167. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  168. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  169. package/dist/chunk-LFNCN2SP.js.map +0 -1
  170. package/dist/chunk-LMC26NLJ 2.js +0 -84
  171. package/dist/chunk-NOAYCWCX.js +0 -4993
  172. package/dist/chunk-NOAYCWCX.js.map +0 -1
  173. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  174. package/dist/chunk-QXHPKYJV 3.js +0 -113
  175. package/dist/chunk-R77UEZ4E 3.js +0 -68
  176. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  177. package/dist/chunk-XNXXZ43G.js.map +0 -1
  178. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  179. package/dist/components.js 5.map +0 -1
  180. package/dist/styles/index 2.js +0 -12
  181. package/dist/styles/index.js 5.map +0 -1
  182. package/dist/theming/runtime 5.js +0 -19
  183. package/dist/theming/runtime.js 5.map +0 -1
  184. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-DQ7RSOHE.js.map} +0 -0
  185. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-ATAP5UTR.js.map} +0 -0
  186. /package/dist/{chunk-BC4IJKSL.js.map → chunk-JBKQ3SAO.js.map} +0 -0
  187. /package/dist/{chunk-QWWZ5CAQ.js 3.map → chunk-LXQLPRQ2.js.map} +0 -0
  188. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  189. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  190. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  191. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -166,7 +166,7 @@ describe('[component] UnifiedTableBody', () => {
166
166
  return result.current;
167
167
  };
168
168
 
169
- const defaultProps = {
169
+ const baseProps = {
170
170
  table: createMockTable(),
171
171
  isCreating: false,
172
172
  creationData: {},
@@ -213,7 +213,7 @@ describe('[component] UnifiedTableBody', () => {
213
213
  const table = createMockTable();
214
214
  render(
215
215
  <table>
216
- <UnifiedTableBody {...defaultProps} table={table} />
216
+ <UnifiedTableBody {...baseProps} table={table} />
217
217
  </table>
218
218
  );
219
219
 
@@ -225,7 +225,7 @@ describe('[component] UnifiedTableBody', () => {
225
225
  const table = createMockTable([]);
226
226
  render(
227
227
  <table>
228
- <UnifiedTableBody {...defaultProps} table={table} dataLength={0} />
228
+ <UnifiedTableBody {...baseProps} table={table} dataLength={0} />
229
229
  </table>
230
230
  );
231
231
 
@@ -241,7 +241,7 @@ describe('[component] UnifiedTableBody', () => {
241
241
  render(
242
242
  <table>
243
243
  <UnifiedTableBody
244
- {...defaultProps}
244
+ {...baseProps}
245
245
  table={table}
246
246
  dataLength={0}
247
247
  emptyState={emptyState}
@@ -258,7 +258,7 @@ describe('[component] UnifiedTableBody', () => {
258
258
  render(
259
259
  <table>
260
260
  <UnifiedTableBody
261
- {...defaultProps}
261
+ {...baseProps}
262
262
  table={table}
263
263
  enableFiltering={true}
264
264
  showFilterRow={true}
@@ -276,7 +276,7 @@ describe('[component] UnifiedTableBody', () => {
276
276
  render(
277
277
  <table>
278
278
  <UnifiedTableBody
279
- {...defaultProps}
279
+ {...baseProps}
280
280
  table={table}
281
281
  isCreating={true}
282
282
  creationData={{ name: 'New User', email: 'new@example.com' }}
@@ -297,7 +297,7 @@ describe('[component] UnifiedTableBody', () => {
297
297
  render(
298
298
  <table>
299
299
  <UnifiedTableBody
300
- {...defaultProps}
300
+ {...baseProps}
301
301
  table={table}
302
302
  isCreating={true}
303
303
  creationData={{ name: '' }}
@@ -321,7 +321,7 @@ describe('[component] UnifiedTableBody', () => {
321
321
  render(
322
322
  <table>
323
323
  <UnifiedTableBody
324
- {...defaultProps}
324
+ {...baseProps}
325
325
  table={table}
326
326
  isCreating={true}
327
327
  creationData={{ name: 'New User' }}
@@ -344,7 +344,7 @@ describe('[component] UnifiedTableBody', () => {
344
344
  render(
345
345
  <table>
346
346
  <UnifiedTableBody
347
- {...defaultProps}
347
+ {...baseProps}
348
348
  table={table}
349
349
  isCreating={true}
350
350
  creationData={{ name: 'New User' }}
@@ -377,7 +377,7 @@ describe('[component] UnifiedTableBody', () => {
377
377
  render(
378
378
  <table>
379
379
  <UnifiedTableBody
380
- {...defaultProps}
380
+ {...baseProps}
381
381
  table={table}
382
382
  isCreating={true}
383
383
  creationData={{ status: 'active' }}
@@ -402,7 +402,7 @@ describe('[component] UnifiedTableBody', () => {
402
402
  render(
403
403
  <table>
404
404
  <UnifiedTableBody
405
- {...defaultProps}
405
+ {...baseProps}
406
406
  table={table}
407
407
  isCreating={true}
408
408
  creationData={{ age: '25' }}
@@ -429,7 +429,7 @@ describe('[component] UnifiedTableBody', () => {
429
429
  render(
430
430
  <table>
431
431
  <UnifiedTableBody
432
- {...defaultProps}
432
+ {...baseProps}
433
433
  table={table}
434
434
  isCreating={true}
435
435
  creationData={{ createdAt: '2024-01-01' }}
@@ -451,7 +451,7 @@ describe('[component] UnifiedTableBody', () => {
451
451
  render(
452
452
  <table>
453
453
  <UnifiedTableBody
454
- {...defaultProps}
454
+ {...baseProps}
455
455
  table={table}
456
456
  editingRowId={rowId}
457
457
  editingData={{ name: 'Edited Name' }}
@@ -471,7 +471,7 @@ describe('[component] UnifiedTableBody', () => {
471
471
  render(
472
472
  <table>
473
473
  <UnifiedTableBody
474
- {...defaultProps}
474
+ {...baseProps}
475
475
  table={table}
476
476
  editingRowId={rowId}
477
477
  editingData={{ name: 'Current Name' }}
@@ -496,7 +496,7 @@ describe('[component] UnifiedTableBody', () => {
496
496
  render(
497
497
  <table>
498
498
  <UnifiedTableBody
499
- {...defaultProps}
499
+ {...baseProps}
500
500
  table={table}
501
501
  editingRowId={rowId}
502
502
  editingData={{ name: 'Edited Name' }}
@@ -520,7 +520,7 @@ describe('[component] UnifiedTableBody', () => {
520
520
  render(
521
521
  <table>
522
522
  <UnifiedTableBody
523
- {...defaultProps}
523
+ {...baseProps}
524
524
  table={table}
525
525
  editingRowId={rowId}
526
526
  editingData={{ name: 'Edited Name' }}
@@ -559,7 +559,7 @@ describe('[component] UnifiedTableBody', () => {
559
559
  render(
560
560
  <table>
561
561
  <UnifiedTableBody
562
- {...defaultProps}
562
+ {...baseProps}
563
563
  table={tableWithGrouped as any}
564
564
  grouping={['department']}
565
565
  />
@@ -593,7 +593,7 @@ describe('[component] UnifiedTableBody', () => {
593
593
  render(
594
594
  <table>
595
595
  <UnifiedTableBody
596
- {...defaultProps}
596
+ {...baseProps}
597
597
  table={tableWithGrouped as any}
598
598
  grouping={['department']}
599
599
  />
@@ -625,7 +625,7 @@ describe('[component] UnifiedTableBody', () => {
625
625
  render(
626
626
  <table>
627
627
  <UnifiedTableBody
628
- {...defaultProps}
628
+ {...baseProps}
629
629
  table={table}
630
630
  hierarchical={{
631
631
  enabled: true,
@@ -656,7 +656,7 @@ describe('[component] UnifiedTableBody', () => {
656
656
  render(
657
657
  <table>
658
658
  <UnifiedTableBody
659
- {...defaultProps}
659
+ {...baseProps}
660
660
  table={table}
661
661
  hierarchical={{
662
662
  enabled: true,
@@ -693,7 +693,7 @@ describe('[component] UnifiedTableBody', () => {
693
693
  render(
694
694
  <table>
695
695
  <UnifiedTableBody
696
- {...defaultProps}
696
+ {...baseProps}
697
697
  table={table}
698
698
  actions={actions}
699
699
  />
@@ -728,7 +728,7 @@ describe('[component] UnifiedTableBody', () => {
728
728
  render(
729
729
  <table>
730
730
  <UnifiedTableBody
731
- {...defaultProps}
731
+ {...baseProps}
732
732
  table={table}
733
733
  actions={actions}
734
734
  />
@@ -754,7 +754,7 @@ describe('[component] UnifiedTableBody', () => {
754
754
  render(
755
755
  <table>
756
756
  <UnifiedTableBody
757
- {...defaultProps}
757
+ {...baseProps}
758
758
  table={table}
759
759
  dataLength={0}
760
760
  isFiltered={true}
@@ -777,7 +777,7 @@ describe('[component] UnifiedTableBody', () => {
777
777
  render(
778
778
  <table>
779
779
  <UnifiedTableBody
780
- {...defaultProps}
780
+ {...baseProps}
781
781
  table={table}
782
782
  dataLength={5}
783
783
  forceVirtualization={false}
@@ -796,7 +796,7 @@ describe('[component] UnifiedTableBody', () => {
796
796
  render(
797
797
  <table>
798
798
  <UnifiedTableBody
799
- {...defaultProps}
799
+ {...baseProps}
800
800
  table={table}
801
801
  dataLength={1500}
802
802
  forceVirtualization={false}
@@ -814,7 +814,7 @@ describe('[component] UnifiedTableBody', () => {
814
814
  render(
815
815
  <table>
816
816
  <UnifiedTableBody
817
- {...defaultProps}
817
+ {...baseProps}
818
818
  table={table}
819
819
  dataLength={5}
820
820
  forceVirtualization={true}
@@ -833,7 +833,7 @@ describe('[component] UnifiedTableBody', () => {
833
833
  render(
834
834
  <table>
835
835
  <UnifiedTableBody
836
- {...defaultProps}
836
+ {...baseProps}
837
837
  table={table}
838
838
  isCreating={true}
839
839
  creationData={{ name: null as any, email: null as any }}
@@ -850,7 +850,7 @@ describe('[component] UnifiedTableBody', () => {
850
850
  render(
851
851
  <table>
852
852
  <UnifiedTableBody
853
- {...defaultProps}
853
+ {...baseProps}
854
854
  table={table}
855
855
  getRowId={undefined}
856
856
  />
@@ -866,7 +866,7 @@ describe('[component] UnifiedTableBody', () => {
866
866
  render(
867
867
  <table>
868
868
  <UnifiedTableBody
869
- {...defaultProps}
869
+ {...baseProps}
870
870
  table={table}
871
871
  actions={[]}
872
872
  />
@@ -891,7 +891,7 @@ describe('[component] UnifiedTableBody', () => {
891
891
  render(
892
892
  <table>
893
893
  <UnifiedTableBody
894
- {...defaultProps}
894
+ {...baseProps}
895
895
  table={table}
896
896
  isCreating={true}
897
897
  creationData={{ fullName: 'New Name' }}
@@ -925,7 +925,7 @@ describe('[component] UnifiedTableBody', () => {
925
925
  render(
926
926
  <table>
927
927
  <UnifiedTableBody
928
- {...defaultProps}
928
+ {...baseProps}
929
929
  table={table}
930
930
  isCreating={true}
931
931
  creationData={{ status: '' }}
@@ -960,7 +960,7 @@ describe('[component] UnifiedTableBody', () => {
960
960
  render(
961
961
  <table>
962
962
  <UnifiedTableBody
963
- {...defaultProps}
963
+ {...baseProps}
964
964
  table={table}
965
965
  isCreating={true}
966
966
  creationData={{ category: '' }}
@@ -989,7 +989,7 @@ describe('[component] UnifiedTableBody', () => {
989
989
  render(
990
990
  <table>
991
991
  <UnifiedTableBody
992
- {...defaultProps}
992
+ {...baseProps}
993
993
  table={table}
994
994
  isCreating={true}
995
995
  creationData={{ status: '' }}
@@ -76,7 +76,7 @@ describe('[component] ViewRowModal', () => {
76
76
  createdAt: new Date('2024-01-01'),
77
77
  };
78
78
 
79
- const defaultProps = {
79
+ const baseProps = {
80
80
  isOpen: true,
81
81
  onClose: vi.fn(),
82
82
  data: mockData,
@@ -93,20 +93,20 @@ describe('[component] ViewRowModal', () => {
93
93
  describe('Rendering', () => {
94
94
  it('returns null when data is null', () => {
95
95
  const { container } = render(
96
- <ViewRowModal {...defaultProps} data={null} />
96
+ <ViewRowModal {...baseProps} data={null} />
97
97
  );
98
98
  expect(container.firstChild).toBeNull();
99
99
  });
100
100
 
101
101
  it('returns null when modal is closed', () => {
102
102
  const { container } = render(
103
- <ViewRowModal {...defaultProps} isOpen={false} />
103
+ <ViewRowModal {...baseProps} isOpen={false} />
104
104
  );
105
105
  expect(container.firstChild).toBeNull();
106
106
  });
107
107
 
108
108
  it('renders modal when open with data', () => {
109
- render(<ViewRowModal {...defaultProps} />);
109
+ render(<ViewRowModal {...baseProps} />);
110
110
 
111
111
  // Dialog renders with role="dialog" from Radix UI
112
112
  expect(screen.getByRole('dialog')).toBeInTheDocument();
@@ -116,21 +116,21 @@ describe('[component] ViewRowModal', () => {
116
116
  });
117
117
 
118
118
  it('renders default title when title prop is not provided', () => {
119
- render(<ViewRowModal {...defaultProps} />);
119
+ render(<ViewRowModal {...baseProps} />);
120
120
 
121
121
  // DialogTitle renders as h2, check for text content
122
122
  expect(screen.getByText('Row Details')).toBeInTheDocument();
123
123
  });
124
124
 
125
125
  it('renders custom title when title prop is provided', () => {
126
- render(<ViewRowModal {...defaultProps} title="Custom Title" />);
126
+ render(<ViewRowModal {...baseProps} title="Custom Title" />);
127
127
 
128
128
  // DialogTitle renders as h2, check for text content
129
129
  expect(screen.getByText('Custom Title')).toBeInTheDocument();
130
130
  });
131
131
 
132
132
  it('renders all data fields', () => {
133
- render(<ViewRowModal {...defaultProps} />);
133
+ render(<ViewRowModal {...baseProps} />);
134
134
 
135
135
  expect(screen.getByText(/id/i)).toBeInTheDocument();
136
136
  expect(screen.getByText(/name/i)).toBeInTheDocument();
@@ -140,7 +140,7 @@ describe('[component] ViewRowModal', () => {
140
140
  });
141
141
 
142
142
  it('renders field values correctly', () => {
143
- render(<ViewRowModal {...defaultProps} />);
143
+ render(<ViewRowModal {...baseProps} />);
144
144
 
145
145
  expect(screen.getByText('1')).toBeInTheDocument();
146
146
  expect(screen.getByText('John Doe')).toBeInTheDocument();
@@ -150,7 +150,7 @@ describe('[component] ViewRowModal', () => {
150
150
  });
151
151
 
152
152
  it('formats Date values as locale date strings', () => {
153
- render(<ViewRowModal {...defaultProps} />);
153
+ render(<ViewRowModal {...baseProps} />);
154
154
 
155
155
  const dateValue = screen.getByText(new Date('2024-01-01').toLocaleDateString());
156
156
  expect(dateValue).toBeInTheDocument();
@@ -162,7 +162,7 @@ describe('[component] ViewRowModal', () => {
162
162
  metadata: { key: 'value', nested: { data: 'test' } },
163
163
  };
164
164
 
165
- render(<ViewRowModal {...defaultProps} data={dataWithObject} />);
165
+ render(<ViewRowModal {...baseProps} data={dataWithObject} />);
166
166
 
167
167
  // JSON stringified objects contain the key parts
168
168
  expect(screen.getByText(/key/i)).toBeInTheDocument();
@@ -176,7 +176,7 @@ describe('[component] ViewRowModal', () => {
176
176
  nullableField: null,
177
177
  };
178
178
 
179
- render(<ViewRowModal {...defaultProps} data={dataWithNull} />);
179
+ render(<ViewRowModal {...baseProps} data={dataWithNull} />);
180
180
 
181
181
  // Check that the field label is rendered
182
182
  expect(screen.getByText(/nullable field/i)).toBeInTheDocument();
@@ -189,7 +189,7 @@ describe('[component] ViewRowModal', () => {
189
189
  lastName: 'Doe',
190
190
  };
191
191
 
192
- render(<ViewRowModal {...defaultProps} data={dataWithCamelCase} />);
192
+ render(<ViewRowModal {...baseProps} data={dataWithCamelCase} />);
193
193
 
194
194
  expect(screen.getByText(/first name/i)).toBeInTheDocument();
195
195
  expect(screen.getByText(/last name/i)).toBeInTheDocument();
@@ -201,7 +201,7 @@ describe('[component] ViewRowModal', () => {
201
201
  const user = userEvent.setup();
202
202
  const handleClose = vi.fn();
203
203
 
204
- render(<ViewRowModal {...defaultProps} onClose={handleClose} />);
204
+ render(<ViewRowModal {...baseProps} onClose={handleClose} />);
205
205
 
206
206
  // Get the main "Close" button (not the X icon button)
207
207
  const closeButtons = screen.getAllByRole('button', { name: /close/i });
@@ -217,7 +217,7 @@ describe('[component] ViewRowModal', () => {
217
217
  const user = userEvent.setup();
218
218
  const handleClose = vi.fn();
219
219
 
220
- render(<ViewRowModal {...defaultProps} onClose={handleClose} />);
220
+ render(<ViewRowModal {...baseProps} onClose={handleClose} />);
221
221
 
222
222
  // Get the X icon button specifically (first button with X icon)
223
223
  const xButtons = screen.getAllByTestId('x-icon');
@@ -235,7 +235,7 @@ describe('[component] ViewRowModal', () => {
235
235
 
236
236
  render(
237
237
  <ViewRowModal
238
- {...defaultProps}
238
+ {...baseProps}
239
239
  onClose={handleOpenChange}
240
240
  />
241
241
  );
@@ -253,7 +253,7 @@ describe('[component] ViewRowModal', () => {
253
253
 
254
254
  describe('Edge Cases', () => {
255
255
  it('handles empty data object', () => {
256
- render(<ViewRowModal {...defaultProps} data={{}} />);
256
+ render(<ViewRowModal {...baseProps} data={{}} />);
257
257
 
258
258
  expect(screen.getByRole('dialog')).toBeInTheDocument();
259
259
  expect(screen.getAllByRole('button', { name: /close/i }).length).toBeGreaterThan(0);
@@ -265,7 +265,7 @@ describe('[component] ViewRowModal', () => {
265
265
  optionalField: undefined,
266
266
  };
267
267
 
268
- render(<ViewRowModal {...defaultProps} data={dataWithUndefined} />);
268
+ render(<ViewRowModal {...baseProps} data={dataWithUndefined} />);
269
269
 
270
270
  expect(screen.getByRole('dialog')).toBeInTheDocument();
271
271
  });
@@ -276,7 +276,7 @@ describe('[component] ViewRowModal', () => {
276
276
  tags: ['tag1', 'tag2', 'tag3'],
277
277
  };
278
278
 
279
- render(<ViewRowModal {...defaultProps} data={dataWithArray} />);
279
+ render(<ViewRowModal {...baseProps} data={dataWithArray} />);
280
280
 
281
281
  // Check that array values are displayed (they'll be JSON stringified)
282
282
  expect(screen.getByText(/tag1/i)).toBeInTheDocument();
@@ -294,7 +294,7 @@ describe('[component] ViewRowModal', () => {
294
294
  },
295
295
  };
296
296
 
297
- render(<ViewRowModal {...defaultProps} data={dataWithNested} />);
297
+ render(<ViewRowModal {...baseProps} data={dataWithNested} />);
298
298
 
299
299
  // JSON stringified objects contain the key parts
300
300
  expect(screen.getByText(/street/i)).toBeInTheDocument();
@@ -309,7 +309,7 @@ describe('[component] ViewRowModal', () => {
309
309
  description: longString,
310
310
  };
311
311
 
312
- render(<ViewRowModal {...defaultProps} data={dataWithLongString} />);
312
+ render(<ViewRowModal {...baseProps} data={dataWithLongString} />);
313
313
 
314
314
  expect(screen.getByText(longString)).toBeInTheDocument();
315
315
  });
@@ -320,7 +320,7 @@ describe('[component] ViewRowModal', () => {
320
320
  'field-with-special-chars!@#': 'value',
321
321
  };
322
322
 
323
- render(<ViewRowModal {...defaultProps} data={dataWithSpecial} />);
323
+ render(<ViewRowModal {...baseProps} data={dataWithSpecial} />);
324
324
 
325
325
  // The component only handles camelCase, not special characters
326
326
  // Special characters remain in the field name, so check for parts of the name
@@ -334,7 +334,7 @@ describe('[component] ViewRowModal', () => {
334
334
  count: 0,
335
335
  };
336
336
 
337
- render(<ViewRowModal {...defaultProps} data={dataWithZero} />);
337
+ render(<ViewRowModal {...baseProps} data={dataWithZero} />);
338
338
 
339
339
  // Zero should render as "0" - check for it in the value cell
340
340
  const countLabel = screen.getByText(/count:/i);
@@ -348,7 +348,7 @@ describe('[component] ViewRowModal', () => {
348
348
  active: false,
349
349
  };
350
350
 
351
- render(<ViewRowModal {...defaultProps} data={dataWithFalse} />);
351
+ render(<ViewRowModal {...baseProps} data={dataWithFalse} />);
352
352
 
353
353
  // Boolean false should render as "false" - check for it in the value cell
354
354
  const activeLabel = screen.getByText(/active:/i);
@@ -359,21 +359,21 @@ describe('[component] ViewRowModal', () => {
359
359
 
360
360
  describe('Accessibility', () => {
361
361
  it('provides close button with aria-label', () => {
362
- render(<ViewRowModal {...defaultProps} />);
362
+ render(<ViewRowModal {...baseProps} />);
363
363
 
364
364
  const buttons = screen.getAllByRole('button');
365
365
  expect(buttons.length).toBeGreaterThan(0);
366
366
  });
367
367
 
368
368
  it('provides main close button with accessible text', () => {
369
- render(<ViewRowModal {...defaultProps} />);
369
+ render(<ViewRowModal {...baseProps} />);
370
370
 
371
371
  const closeButtons = screen.getAllByRole('button', { name: /close/i });
372
372
  expect(closeButtons.length).toBeGreaterThan(0);
373
373
  });
374
374
 
375
375
  it('renders dialog with proper structure', () => {
376
- render(<ViewRowModal {...defaultProps} />);
376
+ render(<ViewRowModal {...baseProps} />);
377
377
 
378
378
  expect(screen.getByRole('dialog')).toBeInTheDocument();
379
379
  // Check for content structure instead of testids
@@ -384,7 +384,7 @@ describe('[component] ViewRowModal', () => {
384
384
 
385
385
  describe('Layout and Styling', () => {
386
386
  it('applies max-width and max-height classes to dialog content', () => {
387
- render(<ViewRowModal {...defaultProps} />);
387
+ render(<ViewRowModal {...baseProps} />);
388
388
 
389
389
  // DialogContent receives className prop, check if dialog has the classes
390
390
  const dialog = screen.getByRole('dialog');
@@ -394,7 +394,7 @@ describe('[component] ViewRowModal', () => {
394
394
  });
395
395
 
396
396
  it('renders field labels with proper styling classes', () => {
397
- render(<ViewRowModal {...defaultProps} />);
397
+ render(<ViewRowModal {...baseProps} />);
398
398
 
399
399
  // Check that field labels are rendered (they should have specific classes)
400
400
  const nameLabel = screen.getByText(/name/i);
@@ -402,7 +402,7 @@ describe('[component] ViewRowModal', () => {
402
402
  });
403
403
 
404
404
  it('renders close button in header with proper styling', () => {
405
- render(<ViewRowModal {...defaultProps} />);
405
+ render(<ViewRowModal {...baseProps} />);
406
406
 
407
407
  const xIcons = screen.getAllByTestId('x-icon');
408
408
  expect(xIcons.length).toBeGreaterThan(0);
@@ -29,8 +29,8 @@ export function useColumnReordering<TData>({
29
29
  });
30
30
 
31
31
  // Update column order when columns change
32
- // Using useMemo to prevent infinite loops
33
- useMemo(() => {
32
+ // Using useEffect for side effects (state updates)
33
+ useEffect(() => {
34
34
  if (enableReordering) {
35
35
  const newOrder = columns.map(col => col.id);
36
36
  setColumnOrder(prevOrder => {
@@ -23,7 +23,7 @@ export interface KeyboardNavigationOptions {
23
23
  /** Callback when focus moves to a new cell */
24
24
  onFocusChange?: (rowIndex: number, columnIndex: number) => void;
25
25
  /** Table ref for DOM queries */
26
- tableRef?: React.RefObject<HTMLTableElement>;
26
+ tableRef?: React.RefObject<HTMLTableElement | null>;
27
27
  }
28
28
 
29
29
  export interface KeyboardNavigationState {
@@ -105,7 +105,7 @@ export function useKeyboardNavigation(
105
105
  const internalTableRef = useRef<HTMLTableElement>(null);
106
106
  const tableRef = externalTableRef || internalTableRef;
107
107
  const storedFocusRef = useRef<{ rowIndex: number; columnIndex: number } | null>(null);
108
- const navigationTimeoutRef = useRef<NodeJS.Timeout>();
108
+ const navigationTimeoutRef = useRef<NodeJS.Timeout>(undefined);
109
109
 
110
110
  // Helper to get cell element
111
111
  const getCellElement = useCallback((rowIndex: number, columnIndex: number): HTMLElement | null => {
@@ -295,24 +295,18 @@ describe('DatePickerWithTimezone Component', () => {
295
295
 
296
296
  render(<DatePickerWithTimezone selected={selected} onSelect={onSelect} />);
297
297
 
298
- expect(MockedCalendar).toHaveBeenCalledWith(
299
- expect.objectContaining({
300
- mode: 'single',
301
- selected: selected,
302
- onSelect: onSelect,
303
- initialFocus: true,
304
- captionLayout: 'dropdown',
305
- startMonth: expect.any(Date),
306
- endMonth: expect.any(Date),
307
- className: 'p-0'
308
- }),
309
- expect.anything()
310
- );
298
+ expect(MockedCalendar).toHaveBeenCalled();
311
299
 
312
- // Verify the date range is correct
300
+ // Verify the props are correct
313
301
  const callArgs = MockedCalendar.mock.calls[0][0];
302
+ expect(callArgs.mode).toBe('single');
303
+ expect(callArgs.selected).toEqual(selected);
304
+ expect(callArgs.onSelect).toBe(onSelect);
305
+ expect(callArgs.initialFocus).toBe(true);
306
+ expect(callArgs.captionLayout).toBe('dropdown');
314
307
  expect(callArgs.startMonth).toEqual(new Date(1900, 0));
315
308
  expect(callArgs.endMonth).toEqual(new Date(2100, 11));
309
+ expect(callArgs.className).toBe('p-0');
316
310
  });
317
311
  });
318
312
  });
@@ -149,7 +149,7 @@
149
149
  * @dependencies
150
150
  * - @radix-ui/react-dialog - Core dialog functionality
151
151
  * - lucide-react - Icons
152
- * - React 18+ - Hooks and refs
152
+ * - React 19+ - Hooks and refs
153
153
  * - Tailwind CSS - Styling and animations
154
154
  */
155
155
 
@@ -465,17 +465,18 @@ const DialogContent = React.forwardRef<
465
465
  enableScrolling
466
466
  });
467
467
 
468
- const handleEscapeKeyDown = React.useCallback((event: KeyboardEvent) => {
468
+ // React Compiler handles memoization automatically
469
+ const handleEscapeKeyDown = (event: KeyboardEvent) => {
469
470
  if (preventCloseOnEscape) {
470
471
  event.preventDefault();
471
472
  }
472
- }, [preventCloseOnEscape]);
473
+ };
473
474
 
474
- const handlePointerDownOutside = React.useCallback((event: Event) => {
475
+ const handlePointerDownOutside = (event: Event) => {
475
476
  if (preventCloseOnOutsideClick) {
476
477
  event.preventDefault();
477
478
  }
478
- }, [preventCloseOnOutsideClick]);
479
+ };
479
480
 
480
481
  // Merge smart dimensions with provided style
481
482
  const mergedStyle = React.useMemo(() => {
@@ -75,7 +75,7 @@
75
75
  * - Configurable error reporting
76
76
  *
77
77
  * @dependencies
78
- * - React 18+ - Component lifecycle
78
+ * - React 19+ - Component lifecycle
79
79
  * - Performance monitoring utilities
80
80
  * - Tailwind CSS - Styling
81
81
  */
@@ -80,7 +80,7 @@
80
80
  * - Button component - Retry functionality
81
81
  * - Alert component - Error display
82
82
  * - LoadingSpinner - Loading states
83
- * - React 18+ - Hooks and effects
83
+ * - React 19+ - Hooks and effects
84
84
  * - Tailwind CSS - Styling
85
85
  */
86
86
 
@@ -49,7 +49,7 @@ vi.mock('../../utils/storage/helpers', () => ({
49
49
  }));
50
50
 
51
51
  // Helper to render with UnifiedAuthProvider
52
- const renderWithUnifiedAuth = (ui: React.ReactElement) => {
52
+ const renderWithUnifiedAuth = (ui: React.ReactElement<any>) => {
53
53
  return renderWithProviders(
54
54
  <UnifiedAuthProvider
55
55
  supabaseClient={supabase}
@@ -64,7 +64,7 @@ const renderWithUnifiedAuth = (ui: React.ReactElement) => {
64
64
  );
65
65
  };
66
66
 
67
- const renderWithPublicContext = (ui: React.ReactElement, value: any = null) => {
67
+ const renderWithPublicContext = (ui: React.ReactElement<any>, value: any = null) => {
68
68
  const Context = publicPageContextStore.value ?? React.createContext(null);
69
69
 
70
70
  return renderWithProviders(
@@ -81,7 +81,7 @@
81
81
  * - Clear link identification
82
82
  *
83
83
  * @dependencies
84
- * - React 18+ - Component framework
84
+ * - React 19+ - Component framework
85
85
  * - Tailwind CSS - Styling
86
86
  */
87
87
  import React from 'react';