@jmruthers/pace-core 0.5.75 → 0.5.76

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 (226) hide show
  1. package/dist/{DataTable-HWZQGASI.js → DataTable-4GAVPIEG.js} +48 -30
  2. package/dist/{PublicLoadingSpinner-BKNBT6b6.d.ts → PublicLoadingSpinner-BiNER8F5.d.ts} +28 -17
  3. package/dist/{chunk-33PHABLB.js → chunk-AFGTSUAD.js} +10 -127
  4. package/dist/chunk-AFGTSUAD.js.map +1 -0
  5. package/dist/{chunk-2DFZ432F.js → chunk-K34IM5CT.js} +3 -5
  6. package/dist/{chunk-2DFZ432F.js.map → chunk-K34IM5CT.js.map} +1 -1
  7. package/dist/{chunk-2CHATWBF.js → chunk-KHJS6VIA.js} +199 -35
  8. package/dist/chunk-KHJS6VIA.js.map +1 -0
  9. package/dist/{chunk-ZTT2AXMX.js → chunk-KK73ZB4E.js} +2 -2
  10. package/dist/{chunk-CY3AHGO4.js → chunk-M5IWZRBT.js} +1750 -2815
  11. package/dist/chunk-M5IWZRBT.js.map +1 -0
  12. package/dist/{chunk-DAXLNIDY.js → chunk-Y6TXWPJO.js} +6 -4
  13. package/dist/{chunk-DAXLNIDY.js.map → chunk-Y6TXWPJO.js.map} +1 -1
  14. package/dist/{chunk-YNUBMSMV.js → chunk-YCKPEMJA.js} +186 -263
  15. package/dist/chunk-YCKPEMJA.js.map +1 -0
  16. package/dist/components.d.ts +1 -1
  17. package/dist/components.js +7 -6
  18. package/dist/components.js.map +1 -1
  19. package/dist/hooks.d.ts +17 -40
  20. package/dist/hooks.js +6 -6
  21. package/dist/index.d.ts +3 -3
  22. package/dist/index.js +12 -10
  23. package/dist/index.js.map +1 -1
  24. package/dist/rbac/index.d.ts +54 -1
  25. package/dist/rbac/index.js +5 -4
  26. package/dist/utils.js +1 -1
  27. package/docs/TERMINOLOGY.md +231 -0
  28. package/docs/api/classes/ColumnFactory.md +1 -1
  29. package/docs/api/classes/ErrorBoundary.md +1 -1
  30. package/docs/api/classes/InvalidScopeError.md +1 -1
  31. package/docs/api/classes/MissingUserContextError.md +1 -1
  32. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  33. package/docs/api/classes/PermissionDeniedError.md +1 -1
  34. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  35. package/docs/api/classes/RBACAuditManager.md +1 -1
  36. package/docs/api/classes/RBACCache.md +1 -1
  37. package/docs/api/classes/RBACEngine.md +1 -1
  38. package/docs/api/classes/RBACError.md +1 -1
  39. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  40. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  41. package/docs/api/classes/StorageUtils.md +1 -1
  42. package/docs/api/enums/FileCategory.md +1 -1
  43. package/docs/api/interfaces/AggregateConfig.md +1 -1
  44. package/docs/api/interfaces/ButtonProps.md +1 -1
  45. package/docs/api/interfaces/CardProps.md +1 -1
  46. package/docs/api/interfaces/ColorPalette.md +1 -1
  47. package/docs/api/interfaces/ColorShade.md +1 -1
  48. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  49. package/docs/api/interfaces/DataTableAction.md +1 -1
  50. package/docs/api/interfaces/DataTableColumn.md +1 -1
  51. package/docs/api/interfaces/DataTableProps.md +1 -1
  52. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  53. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  54. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  55. package/docs/api/interfaces/EventLogoProps.md +1 -1
  56. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  57. package/docs/api/interfaces/FileMetadata.md +1 -1
  58. package/docs/api/interfaces/FileReference.md +1 -1
  59. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  60. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  61. package/docs/api/interfaces/FileUploadProps.md +1 -1
  62. package/docs/api/interfaces/FooterProps.md +1 -1
  63. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  64. package/docs/api/interfaces/InputProps.md +1 -1
  65. package/docs/api/interfaces/LabelProps.md +1 -1
  66. package/docs/api/interfaces/LoginFormProps.md +1 -1
  67. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  68. package/docs/api/interfaces/NavigationContextType.md +1 -1
  69. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  70. package/docs/api/interfaces/NavigationItem.md +1 -1
  71. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  72. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  73. package/docs/api/interfaces/Organisation.md +1 -1
  74. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  75. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  76. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  77. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  78. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  79. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  80. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  81. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  82. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  83. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  84. package/docs/api/interfaces/PaletteData.md +1 -1
  85. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  86. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  87. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  88. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  89. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  90. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  91. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  92. package/docs/api/interfaces/RBACConfig.md +1 -1
  93. package/docs/api/interfaces/RBACContextType.md +1 -1
  94. package/docs/api/interfaces/RBACLogger.md +1 -1
  95. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  96. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  97. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  98. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  99. package/docs/api/interfaces/RouteConfig.md +1 -1
  100. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  101. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  102. package/docs/api/interfaces/StorageConfig.md +1 -1
  103. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  104. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  105. package/docs/api/interfaces/StorageListOptions.md +1 -1
  106. package/docs/api/interfaces/StorageListResult.md +1 -1
  107. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  108. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  109. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  110. package/docs/api/interfaces/StyleImport.md +1 -1
  111. package/docs/api/interfaces/SwitchProps.md +1 -1
  112. package/docs/api/interfaces/ToastActionElement.md +1 -1
  113. package/docs/api/interfaces/ToastProps.md +1 -1
  114. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  115. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  116. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  117. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  118. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  119. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  120. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  121. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  122. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  123. package/docs/api/interfaces/UseResolvedScopeOptions.md +47 -0
  124. package/docs/api/interfaces/UseResolvedScopeReturn.md +47 -0
  125. package/docs/api/interfaces/UserEventAccess.md +1 -1
  126. package/docs/api/interfaces/UserMenuProps.md +1 -1
  127. package/docs/api/interfaces/UserProfile.md +1 -1
  128. package/docs/api/modules.md +57 -11
  129. package/docs/api-reference/providers.md +26 -7
  130. package/docs/best-practices/README.md +20 -0
  131. package/docs/best-practices/accessibility.md +566 -0
  132. package/docs/best-practices/performance-expansion.md +473 -0
  133. package/docs/core-concepts/authentication.md +15 -7
  134. package/docs/documentation-index.md +1 -1
  135. package/docs/documentation-templates.md +539 -0
  136. package/docs/getting-started/quick-start.md +16 -66
  137. package/docs/implementation-guides/component-styling.md +410 -0
  138. package/docs/implementation-guides/data-tables.md +1 -1
  139. package/docs/style-guide.md +39 -0
  140. package/package.json +1 -1
  141. package/src/__tests__/TEST_GUIDE_CURSOR.md +290 -0
  142. package/src/__tests__/helpers/supabaseMock.ts +48 -2
  143. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +17 -6
  144. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +73 -9
  145. package/src/components/DataTable/components/DataTableCore.tsx +280 -475
  146. package/src/components/DataTable/components/UnifiedTableBody.tsx +120 -153
  147. package/src/components/DataTable/components/index.ts +1 -2
  148. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +208 -275
  149. package/src/components/DataTable/core/index.ts +1 -8
  150. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +525 -0
  151. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +570 -0
  152. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +214 -0
  153. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +224 -0
  154. package/src/components/DataTable/hooks/index.ts +6 -0
  155. package/src/components/DataTable/hooks/useColumnReordering.ts +1 -0
  156. package/src/components/DataTable/hooks/useDataTablePermissions.ts +149 -0
  157. package/src/components/DataTable/hooks/useDataTableState.ts +12 -6
  158. package/src/components/DataTable/hooks/useHierarchicalState.ts +26 -8
  159. package/src/components/DataTable/hooks/useTableColumns.ts +153 -0
  160. package/src/components/DataTable/index.ts +1 -9
  161. package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +89 -0
  162. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +3 -6
  163. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +462 -0
  164. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +247 -0
  165. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +8 -6
  166. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +466 -0
  167. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +265 -0
  168. package/src/components/DataTable/utils/errorHandling.ts +52 -460
  169. package/src/components/DataTable/utils/exportUtils.ts +46 -15
  170. package/src/components/DataTable/utils/hierarchicalSorting.ts +50 -3
  171. package/src/components/DataTable/utils/hierarchicalUtils.ts +167 -34
  172. package/src/components/DataTable/utils/index.ts +5 -0
  173. package/src/components/DataTable/utils/rowUtils.ts +68 -0
  174. package/src/components/EventSelector/EventSelector.test.tsx +672 -0
  175. package/src/components/Label/__tests__/Label.test.tsx +434 -0
  176. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +190 -0
  177. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +185 -0
  178. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +313 -0
  179. package/src/components/Select/Select.test.tsx +143 -120
  180. package/src/components/Select/Select.tsx +47 -212
  181. package/src/components/Select/hooks.ts +36 -1
  182. package/src/components/Select/index.ts +2 -1
  183. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +137 -0
  184. package/src/hooks/useSecureDataAccess.test.ts +32 -29
  185. package/src/providers/__tests__/ProviderLifecycle.test.tsx +341 -0
  186. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +437 -0
  187. package/src/rbac/hooks/index.ts +2 -0
  188. package/src/rbac/hooks/useResolvedScope.ts +232 -0
  189. package/src/services/__tests__/InactivityService.lifecycle.test.ts +411 -0
  190. package/src/services/__tests__/OrganisationService.pagination.test.ts +375 -0
  191. package/src/types/__tests__/README.md +114 -0
  192. package/src/types/__tests__/validation.test.ts +731 -0
  193. package/src/utils/__tests__/file-reference.test.ts +383 -0
  194. package/src/utils/__tests__/performanceBenchmark.test.ts +175 -0
  195. package/src/utils/appNameResolver.test.ts +54 -0
  196. package/src/validation/__tests__/csrf.unit.test.ts +63 -0
  197. package/src/validation/__tests__/passwordSchema.unit.test.ts +105 -0
  198. package/dist/chunk-2CHATWBF.js.map +0 -1
  199. package/dist/chunk-33PHABLB.js.map +0 -1
  200. package/dist/chunk-CY3AHGO4.js.map +0 -1
  201. package/dist/chunk-TYHR5X4W.js +0 -33
  202. package/dist/chunk-TYHR5X4W.js.map +0 -1
  203. package/dist/chunk-YNUBMSMV.js.map +0 -1
  204. package/dist/eventContext-BBA42P6G.js +0 -14
  205. package/dist/eventContext-BBA42P6G.js.map +0 -1
  206. package/docs/documentation-style-checklist.md +0 -294
  207. package/src/components/DataTable/components/DataTableBody.tsx +0 -488
  208. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -144
  209. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -515
  210. package/src/components/DataTable/core/ActionManager.ts +0 -235
  211. package/src/components/DataTable/core/ColumnManager.ts +0 -215
  212. package/src/components/DataTable/core/DataManager.ts +0 -188
  213. package/src/components/DataTable/core/DataTableContext.tsx +0 -181
  214. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -264
  215. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  216. package/src/components/DataTable/core/StateManager.ts +0 -311
  217. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -634
  218. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -193
  219. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -519
  220. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -714
  221. package/src/components/DataTable/core/interfaces.ts +0 -338
  222. package/src/components/DataTable/utils/debugTools.ts +0 -583
  223. package/src/components/Select/Select.bug-test.tsx +0 -69
  224. package/src/components/Select/Select.refactored.tsx +0 -497
  225. /package/dist/{DataTable-HWZQGASI.js.map → DataTable-4GAVPIEG.js.map} +0 -0
  226. /package/dist/{chunk-ZTT2AXMX.js.map → chunk-KK73ZB4E.js.map} +0 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * @file Unit Tests for Hierarchical Sorting Utilities
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Utils/__tests__
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest';
8
+ import {
9
+ sortHierarchicalDataByStructure,
10
+ sortHierarchicalDataWithSorting,
11
+ isHierarchicalSortableColumn,
12
+ getHierarchicalSortConfig
13
+ } from '../hierarchicalSorting';
14
+ import type { HierarchicalDataRow } from '../../types';
15
+ import type { SortingState } from '@tanstack/react-table';
16
+
17
+ interface TestRow extends HierarchicalDataRow {
18
+ name: string;
19
+ value: number;
20
+ date: Date;
21
+ }
22
+
23
+ describe('[unit] hierarchicalSorting', () => {
24
+ const createMockData = (): TestRow[] => [
25
+ { id: '1', name: 'Parent 1', value: 10, date: new Date('2023-01-01'), isParent: true, parentId: null },
26
+ { id: '1-1', name: 'Child A', value: 5, date: new Date('2023-01-05'), isParent: false, parentId: '1' },
27
+ { id: '1-2', name: 'Child B', value: 15, date: new Date('2023-01-03'), isParent: false, parentId: '1' },
28
+ { id: '2', name: 'Parent 2', value: 20, date: new Date('2023-01-02'), isParent: true, parentId: null },
29
+ { id: '2-1', name: 'Child C', value: 8, date: new Date('2023-01-06'), isParent: false, parentId: '2' },
30
+ { id: '3', name: 'Parent 3', value: 5, date: new Date('2023-01-03'), isParent: true, parentId: null },
31
+ ];
32
+
33
+ describe('sortHierarchicalDataByStructure', () => {
34
+ it('sorts data with parents before children', () => {
35
+ const data = createMockData();
36
+ const sorted = sortHierarchicalDataByStructure(data);
37
+
38
+ // First 3 rows should be parents
39
+ expect(sorted[0].id).toBe('1');
40
+ expect(sorted[1].id).toBe('2');
41
+ expect(sorted[2].id).toBe('3');
42
+ expect(sorted[0].isParent).toBe(true);
43
+ expect(sorted[1].isParent).toBe(true);
44
+ expect(sorted[2].isParent).toBe(true);
45
+ });
46
+
47
+ it('includes all children after parents', () => {
48
+ const data = createMockData();
49
+ const sorted = sortHierarchicalDataByStructure(data);
50
+
51
+ const parentCount = sorted.filter(r => r.isParent).length;
52
+ expect(parentCount).toBe(3);
53
+
54
+ const childCount = sorted.filter(r => !r.isParent).length;
55
+ expect(childCount).toBe(3);
56
+ });
57
+
58
+ it('maintains all rows in output', () => {
59
+ const data = createMockData();
60
+ const sorted = sortHierarchicalDataByStructure(data);
61
+
62
+ expect(sorted.length).toBe(data.length);
63
+
64
+ const sortedIds = sorted.map(r => r.id);
65
+ const originalIds = data.map(r => r.id);
66
+
67
+ expect(sortedIds.sort()).toEqual(originalIds.sort());
68
+ });
69
+
70
+ it('handles empty data array', () => {
71
+ const sorted = sortHierarchicalDataByStructure([]);
72
+ expect(sorted).toEqual([]);
73
+ });
74
+
75
+ it('handles data with only parents', () => {
76
+ const data = createMockData().filter(r => r.isParent);
77
+ const sorted = sortHierarchicalDataByStructure(data);
78
+
79
+ expect(sorted.length).toBe(3);
80
+ expect(sorted.every(r => r.isParent)).toBe(true);
81
+ });
82
+ });
83
+
84
+ describe('sortHierarchicalDataWithSorting', () => {
85
+ it('returns original data when no sorting provided', () => {
86
+ const data = createMockData();
87
+ const sorted = sortHierarchicalDataWithSorting(data, []);
88
+
89
+ expect(sorted.map(r => r.id)).toEqual(data.map(r => r.id));
90
+ });
91
+
92
+ it('sorts children within parent groups by name ascending', () => {
93
+ const data = createMockData();
94
+ const sorting: SortingState = [{ id: 'name', desc: false }];
95
+
96
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
97
+
98
+ // Parent 1 with sorted children
99
+ const parent1Index = sorted.findIndex(r => r.id === '1');
100
+ const parent1Children = sorted.slice(parent1Index + 1, parent1Index + 3);
101
+
102
+ expect(parent1Children[0].name).toBe('Child A');
103
+ expect(parent1Children[1].name).toBe('Child B');
104
+ });
105
+
106
+ it('sorts children within parent groups by value descending', () => {
107
+ const data = createMockData();
108
+ const sorting: SortingState = [{ id: 'value', desc: true }];
109
+
110
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
111
+
112
+ // Parent 1 with sorted children (desc)
113
+ const parent1Index = sorted.findIndex(r => r.id === '1');
114
+ const parent1Children = sorted.slice(parent1Index + 1, parent1Index + 3);
115
+
116
+ expect(parent1Children[0].value).toBe(15);
117
+ expect(parent1Children[1].value).toBe(5);
118
+ });
119
+
120
+ it('preserves parent-child relationships', () => {
121
+ const data = createMockData();
122
+ const sorting: SortingState = [{ id: 'name', desc: false }];
123
+
124
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
125
+
126
+ // Parent 1's children should come after Parent 1
127
+ const parent1Index = sorted.findIndex(r => r.id === '1');
128
+ const child1Index = sorted.findIndex(r => r.id === '1-1');
129
+ const child2Index = sorted.findIndex(r => r.id === '1-2');
130
+
131
+ expect(child1Index).toBeGreaterThan(parent1Index);
132
+ expect(child2Index).toBeGreaterThan(parent1Index);
133
+ });
134
+
135
+ it('handles null values in sorting', () => {
136
+ const dataWithNull: TestRow[] = [
137
+ { id: '1', name: 'Parent 1', value: null as any, date: new Date(), isParent: true, parentId: null },
138
+ { id: '1-1', name: 'Child A', value: null as any, date: new Date(), isParent: false, parentId: '1' },
139
+ { id: '1-2', name: 'Child B', value: 10, date: new Date(), isParent: false, parentId: '1' },
140
+ ];
141
+
142
+ const sorting: SortingState = [{ id: 'value', desc: false }];
143
+ const sorted = sortHierarchicalDataWithSorting(dataWithNull, sorting);
144
+
145
+ expect(sorted.length).toBeGreaterThan(0);
146
+ // Null values should sort first (because null < any)
147
+ expect(sorted[0].value).toBeNull();
148
+ });
149
+
150
+ it('handles nested property access', () => {
151
+ const data = [
152
+ {
153
+ id: '1',
154
+ name: 'Parent 1',
155
+ value: 10,
156
+ date: new Date(),
157
+ isParent: true,
158
+ parentId: null,
159
+ nested: { prop: 'B' }
160
+ } as any,
161
+ {
162
+ id: '1-1',
163
+ name: 'Child A',
164
+ value: 5,
165
+ date: new Date(),
166
+ isParent: false,
167
+ parentId: '1',
168
+ nested: { prop: 'A' }
169
+ } as any,
170
+ ];
171
+
172
+ const sorting: SortingState = [{ id: 'nested.prop', desc: false }];
173
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
174
+
175
+ expect(sorted.length).toBe(2);
176
+ expect(sorted[1].id).toBe('1-1'); // Child A sorted first
177
+ });
178
+
179
+ it('handles missing column property gracefully', () => {
180
+ const data = createMockData();
181
+ const sorting: SortingState = [{ id: 'nonExistent', desc: false }];
182
+
183
+ // Should not crash
184
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
185
+
186
+ expect(sorted.length).toBe(data.length);
187
+ });
188
+
189
+ it('handles date sorting', () => {
190
+ const data = createMockData();
191
+ const sorting: SortingState = [{ id: 'date', desc: false }];
192
+
193
+ const sorted = sortHierarchicalDataWithSorting(data, sorting);
194
+
195
+ const parent1Index = sorted.findIndex(r => r.id === '1');
196
+ const parent1Children = sorted.slice(parent1Index + 1, parent1Index + 3);
197
+
198
+ // Should sort by date ascending
199
+ expect(parent1Children[0].date.getTime()).toBeLessThan(parent1Children[1].date.getTime());
200
+ });
201
+ });
202
+
203
+ describe('isHierarchicalSortableColumn', () => {
204
+ const mockColumns = [
205
+ { id: 'name', accessorKey: 'name', hideForParent: false },
206
+ { id: 'value', accessorKey: 'value', hideForParent: true },
207
+ { id: 'date', accessorKey: 'date' },
208
+ ];
209
+
210
+ it('returns true for normal sortable columns', () => {
211
+ expect(isHierarchicalSortableColumn('name', mockColumns)).toBe(true);
212
+ expect(isHierarchicalSortableColumn('date', mockColumns)).toBe(true);
213
+ });
214
+
215
+ it('returns false for parent-hidden columns when specified', () => {
216
+ expect(isHierarchicalSortableColumn('value', mockColumns)).toBe(false);
217
+ });
218
+
219
+ it('returns true for non-existent columns', () => {
220
+ expect(isHierarchicalSortableColumn('nonExistent', mockColumns)).toBe(true);
221
+ });
222
+ });
223
+
224
+ describe('getHierarchicalSortConfig', () => {
225
+ it('returns original sorting state', () => {
226
+ const sorting: SortingState = [{ id: 'name', desc: false }];
227
+ const config = getHierarchicalSortConfig(sorting, []);
228
+
229
+ expect(config).toEqual(sorting);
230
+ });
231
+
232
+ it('returns empty array when no sorting', () => {
233
+ const config = getHierarchicalSortConfig([], []);
234
+
235
+ expect(config).toEqual([]);
236
+ });
237
+
238
+ it('preserves sorting configuration', () => {
239
+ const sorting: SortingState = [{ id: 'value', desc: true }];
240
+ const config = getHierarchicalSortConfig(sorting, []);
241
+
242
+ expect(config[0].id).toBe('value');
243
+ expect(config[0].desc).toBe(true);
244
+ });
245
+ });
246
+ });
247
+
@@ -8,14 +8,16 @@
8
8
  import { describe, it, expect } from 'vitest';
9
9
  import {
10
10
  validateHierarchicalData,
11
- sortHierarchicalData,
12
11
  groupHierarchicalData,
13
12
  getRowDepth,
13
+ calculateAllDepths,
14
14
  shouldShowColumnForRow,
15
15
  getCellRenderer,
16
16
  calculateIndentation,
17
+ calculateAllIndentation,
17
18
  createHierarchicalStructure
18
19
  } from '../hierarchicalUtils';
20
+ import { sortHierarchicalDataByStructure } from '../hierarchicalSorting';
19
21
  import type { HierarchicalDataRow, DataTableColumn, DataRecord } from '../../types';
20
22
 
21
23
  interface TestHierarchicalData extends HierarchicalDataRow {
@@ -141,7 +143,7 @@ describe('[unit] sortHierarchicalData', () => {
141
143
  { id: 'child2', name: 'Child 2', value: 75, parentId: 'parent1', isParent: false }
142
144
  ];
143
145
 
144
- const result = sortHierarchicalData(unsortedData);
146
+ const result = sortHierarchicalDataByStructure(unsortedData);
145
147
 
146
148
  expect(result[0].isParent).toBe(true);
147
149
  expect(result[0].id).toBe('parent1');
@@ -150,7 +152,7 @@ describe('[unit] sortHierarchicalData', () => {
150
152
  });
151
153
 
152
154
  it('handles data that is already sorted', () => {
153
- const result = sortHierarchicalData(validHierarchicalData);
155
+ const result = sortHierarchicalDataByStructure(validHierarchicalData);
154
156
 
155
157
  // The function should maintain the order but group parents before children
156
158
  expect(result[0].isParent).toBe(true);
@@ -161,7 +163,7 @@ describe('[unit] sortHierarchicalData', () => {
161
163
  });
162
164
 
163
165
  it('handles empty data array', () => {
164
- const result = sortHierarchicalData([]);
166
+ const result = sortHierarchicalDataByStructure([]);
165
167
 
166
168
  expect(result).toEqual([]);
167
169
  });
@@ -172,7 +174,7 @@ describe('[unit] sortHierarchicalData', () => {
172
174
  { id: 'parent2', name: 'Parent 2', value: 200, isParent: true }
173
175
  ];
174
176
 
175
- const result = sortHierarchicalData(parentOnlyData);
177
+ const result = sortHierarchicalDataByStructure(parentOnlyData);
176
178
 
177
179
  expect(result).toEqual(parentOnlyData);
178
180
  });
@@ -183,7 +185,7 @@ describe('[unit] sortHierarchicalData', () => {
183
185
  { id: 'child2', name: 'Child 2', value: 75, parentId: 'parent1', isParent: false }
184
186
  ];
185
187
 
186
- const result = sortHierarchicalData(childOnlyData);
188
+ const result = sortHierarchicalDataByStructure(childOnlyData);
187
189
 
188
190
  expect(result).toEqual(childOnlyData);
189
191
  });