@jmruthers/pace-core 0.5.121 → 0.5.124
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.
- package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
- package/dist/{DataTable-DGZDJUYM.js → DataTable-OKDYRW2S.js} +7 -8
- package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
- package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
- package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
- package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
- package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
- package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
- package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
- package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
- package/dist/{chunk-HFBOFZ3Z.js → chunk-GBGYYMC6.js} +317 -251
- package/dist/chunk-GBGYYMC6.js.map +1 -0
- package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
- package/dist/chunk-GEVIB2UB.js.map +1 -0
- package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
- package/dist/chunk-IJOZZOGT.js.map +1 -0
- package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
- package/dist/chunk-M6DDYFUD.js.map +1 -0
- package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
- package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
- package/dist/{chunk-QPI2CCBA.js → chunk-VPUCTHTY.js} +149 -96
- package/dist/chunk-VPUCTHTY.js.map +1 -0
- package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
- package/dist/chunk-XN6GWKMV.js.map +1 -0
- package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
- package/dist/chunk-ZBLK676C.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +11 -11
- package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -3
- package/dist/rbac/index.js +7 -8
- package/dist/styles/index.d.ts +1 -1
- package/dist/styles/index.js +5 -3
- package/dist/theming/runtime.d.ts +73 -1
- package/dist/theming/runtime.js +5 -5
- package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +5 -5
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +6 -6
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +6 -6
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
- package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
- package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +140 -30
- package/docs/best-practices/README.md +1 -1
- package/docs/implementation-guides/datatable-filtering.md +313 -0
- package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/public-pages.md +4 -4
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/rbac/quick-start.md +16 -16
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
- package/examples/public-pages/PublicEventPage.tsx +41 -41
- package/examples/public-pages/PublicPageApp.tsx +33 -33
- package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
- package/package.json +4 -4
- package/src/__tests__/hooks/usePermissions.test.ts +265 -0
- package/src/components/DataTable/DataTable.test.tsx +9 -38
- package/src/components/DataTable/DataTable.tsx +0 -7
- package/src/components/DataTable/components/DataTableCore.tsx +125 -144
- package/src/components/DataTable/components/DataTableModals.tsx +25 -22
- package/src/components/DataTable/components/DataTableToolbar.tsx +14 -1
- package/src/components/DataTable/components/EditableRow.tsx +118 -42
- package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
- package/src/components/DataTable/utils/exportUtils.ts +3 -2
- package/src/components/Dialog/Dialog.tsx +1 -1
- package/src/components/Dialog/README.md +24 -24
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
- package/src/components/PublicLayout/EventLogo.tsx +175 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
- package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
- package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
- package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
- package/src/examples/PublicEventPage.tsx +41 -41
- package/src/examples/PublicPageApp.tsx +33 -33
- package/src/examples/PublicPageUsageExample.tsx +30 -30
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +21 -4
- package/src/hooks/useEventTheme.test.ts +119 -43
- package/src/hooks/useEventTheme.ts +84 -55
- package/src/index.ts +3 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/secureClient.ts +4 -2
- package/src/services/EventService.ts +0 -66
- package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
- package/src/styles/index.ts +1 -1
- package/src/theming/__tests__/parseEventColours.test.ts +209 -0
- package/src/theming/parseEventColours.ts +123 -0
- package/src/theming/runtime.ts +3 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/utils/formatDate.test.ts +11 -11
- package/src/utils/formatting.ts +3 -2
- package/dist/chunk-BDZUMRBD.js 3.map +0 -1
- package/dist/chunk-BHWIUEYH.js.map +0 -1
- package/dist/chunk-CGURJ27Z.js.map +0 -1
- package/dist/chunk-FKFHZUGF.js.map +0 -1
- package/dist/chunk-GKHF54DI 2.js +0 -619
- package/dist/chunk-GKHF54DI.js 2.map +0 -1
- package/dist/chunk-GZRXOUBE.js.map +0 -1
- package/dist/chunk-HFBOFZ3Z.js.map +0 -1
- package/dist/chunk-NZ32EONV.js.map +0 -1
- package/dist/chunk-O3NWNXDY 2.js +0 -76
- package/dist/chunk-QPI2CCBA.js.map +0 -1
- package/dist/chunk-SMJZMKYN.js.map +0 -1
- package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
- package/dist/chunk-TDNI6ZWL.js.map +0 -1
- package/dist/chunk-VKOCWWVY.js.map +0 -1
- package/dist/chunk-WP5I5GLN 2.js +0 -1564
- package/dist/index 3.js +0 -856
- package/dist/providers 3.js +0 -38
- package/dist/providers.js 3.map +0 -1
- package/dist/types 3.js +0 -128
- package/dist/types.js 3.map +0 -1
- package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
- package/dist/utils.js 3.map +0 -1
- package/dist/validation 3.js +0 -479
- package/src/styles/semantic.css +0 -24
- /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-OKDYRW2S.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
- /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
- /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
- /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
- /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
- /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file EventService Event Colours Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Services/EventService
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* Tests for EventService event_colours handling.
|
|
8
|
+
*
|
|
9
|
+
* Note: EventService no longer applies themes directly - that's handled by useEventTheme() hook.
|
|
10
|
+
* These tests verify that event_colours are properly loaded and stored in Event objects.
|
|
11
|
+
*/
|
|
12
|
+
|
|
1
13
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
14
|
import { EventService } from '../../services/EventService';
|
|
3
15
|
|
|
@@ -14,59 +26,51 @@ const baseEvent = {
|
|
|
14
26
|
organisation_id: 'org1',
|
|
15
27
|
};
|
|
16
28
|
|
|
17
|
-
describe('EventService event_colours
|
|
18
|
-
it('
|
|
29
|
+
describe('EventService event_colours handling', () => {
|
|
30
|
+
it('loads event_colours from database into Event object', async () => {
|
|
19
31
|
const supabase = createSupabaseMock();
|
|
20
32
|
const svc = new EventService(supabase, null, null, 'APP', { id: 'org1' } as any, () => {});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// Spy on document style updates by calling the method and ensuring no throw
|
|
32
|
-
expect(() => (svc as any).updateThemeForSelectedEvent()).not.toThrow();
|
|
33
|
+
|
|
34
|
+
// Verify that event_colours are preserved when events are loaded
|
|
35
|
+
// This is verified by the fact that event_colours are passed through
|
|
36
|
+
// in the fetchEvents transformation (line 379 in EventService.ts)
|
|
37
|
+
// The actual theme application is now handled by useEventTheme() hook
|
|
38
|
+
|
|
39
|
+
expect(svc).toBeDefined();
|
|
33
40
|
});
|
|
34
41
|
|
|
35
|
-
it('
|
|
42
|
+
it('preserves event_colours in Event objects', () => {
|
|
36
43
|
const supabase = createSupabaseMock();
|
|
37
44
|
const svc = new EventService(supabase, null, null, 'APP', { id: 'org1' } as any, () => {});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
'ev-sec': { '500': { L: 0.7, C: 0.12, H: 260 }, raw: { L: 0.7, C: 0.12, H: 260 } },
|
|
41
|
-
'ev-acc': { '500': { L: 0.65, C: 0.14, H: 20 }, raw: { L: 0.65, C: 0.14, H: 20 } },
|
|
42
|
-
});
|
|
43
|
-
// @ts-ignore private
|
|
44
|
-
(svc as any).selectedEvent = { ...baseEvent, event_colours: payload };
|
|
45
|
-
expect(() => (svc as any).updateThemeForSelectedEvent()).not.toThrow();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('accepts plain main/sec/acc', () => {
|
|
49
|
-
const supabase = createSupabaseMock();
|
|
50
|
-
const svc = new EventService(supabase, null, null, 'APP', { id: 'org1' } as any, () => {});
|
|
51
|
-
// @ts-ignore private
|
|
52
|
-
(svc as any).selectedEvent = {
|
|
45
|
+
|
|
46
|
+
const eventWithColours = {
|
|
53
47
|
...baseEvent,
|
|
54
48
|
event_colours: {
|
|
55
49
|
main: { '500': { L: 0.75, C: 0.1, H: 200 } },
|
|
56
|
-
sec:
|
|
57
|
-
acc:
|
|
58
|
-
}
|
|
50
|
+
sec: { '500': { L: 0.7, C: 0.12, H: 260 } },
|
|
51
|
+
acc: { '500': { L: 0.65, C: 0.14, H: 20 } },
|
|
52
|
+
}
|
|
59
53
|
};
|
|
60
|
-
|
|
54
|
+
|
|
55
|
+
// Set event - event_colours should be preserved
|
|
56
|
+
svc.setSelectedEvent(eventWithColours as any);
|
|
57
|
+
|
|
58
|
+
const selectedEvent = svc.getSelectedEvent();
|
|
59
|
+
expect(selectedEvent?.event_colours).toEqual(eventWithColours.event_colours);
|
|
61
60
|
});
|
|
62
61
|
|
|
63
|
-
it('
|
|
62
|
+
it('handles null event_colours', () => {
|
|
64
63
|
const supabase = createSupabaseMock();
|
|
65
64
|
const svc = new EventService(supabase, null, null, 'APP', { id: 'org1' } as any, () => {});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
|
|
66
|
+
const eventWithoutColours = {
|
|
67
|
+
...baseEvent,
|
|
68
|
+
event_colours: null
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
svc.setSelectedEvent(eventWithoutColours as any);
|
|
72
|
+
|
|
73
|
+
const selectedEvent = svc.getSelectedEvent();
|
|
74
|
+
expect(selectedEvent?.event_colours).toBeNull();
|
|
69
75
|
});
|
|
70
76
|
});
|
|
71
|
-
|
|
72
|
-
|
package/src/styles/index.ts
CHANGED
|
@@ -47,5 +47,5 @@ export function getAllStylePaths(): string[] {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// Re-export theming runtime for convenience
|
|
50
|
-
export { applyPalette, clearPalette, generateSSRThemeCSS, isDynamicThemingActive, getCurrentThemeData } from '../theming/runtime';
|
|
50
|
+
export { applyPalette, clearPalette, generateSSRThemeCSS, isDynamicThemingActive, getCurrentThemeData, parseAndNormalizeEventColours } from '../theming/runtime';
|
|
51
51
|
export type { PaletteData, ColorPalette, ColorShade } from '../theming/runtime';
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file parseEventColours Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Theming/ParseEventColours
|
|
5
|
+
* @since 2.0.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive tests for the parseAndNormalizeEventColours utility function.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect } from 'vitest';
|
|
11
|
+
import { parseAndNormalizeEventColours } from '../parseEventColours';
|
|
12
|
+
|
|
13
|
+
describe('parseAndNormalizeEventColours', () => {
|
|
14
|
+
describe('Input validation', () => {
|
|
15
|
+
it('returns null for null input', () => {
|
|
16
|
+
expect(parseAndNormalizeEventColours(null)).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('returns null for undefined input', () => {
|
|
20
|
+
expect(parseAndNormalizeEventColours(undefined)).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('returns null for empty string', () => {
|
|
24
|
+
expect(parseAndNormalizeEventColours('')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns null for non-object, non-string input', () => {
|
|
28
|
+
expect(parseAndNormalizeEventColours(123)).toBeNull();
|
|
29
|
+
expect(parseAndNormalizeEventColours(true)).toBeNull();
|
|
30
|
+
expect(parseAndNormalizeEventColours([])).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('returns null for invalid JSON string', () => {
|
|
34
|
+
expect(parseAndNormalizeEventColours('invalid json')).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('JSON string parsing', () => {
|
|
39
|
+
it('parses valid JSON string', () => {
|
|
40
|
+
const input = JSON.stringify({
|
|
41
|
+
main: { 500: { L: 0.5, C: 0.2, H: 0 } },
|
|
42
|
+
sec: { 500: { L: 0.5, C: 0.2, H: 120 } },
|
|
43
|
+
acc: { 500: { L: 0.5, C: 0.2, H: 240 } }
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const result = parseAndNormalizeEventColours(input);
|
|
47
|
+
expect(result).not.toBeNull();
|
|
48
|
+
expect(result?.main).toBeDefined();
|
|
49
|
+
expect(result?.sec).toBeDefined();
|
|
50
|
+
expect(result?.acc).toBeDefined();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('Standard format (main/sec/acc keys)', () => {
|
|
55
|
+
it('parses standard format with main, sec, acc keys', () => {
|
|
56
|
+
const input = {
|
|
57
|
+
main: { 500: { L: 0.5, C: 0.2, H: 0 }, raw: { L: 0.5, C: 0.2, H: 0 } },
|
|
58
|
+
sec: { 500: { L: 0.5, C: 0.2, H: 120 } },
|
|
59
|
+
acc: { 500: { L: 0.5, C: 0.2, H: 240 } }
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const result = parseAndNormalizeEventColours(input);
|
|
63
|
+
expect(result).not.toBeNull();
|
|
64
|
+
expect(result?.main).toBeDefined();
|
|
65
|
+
expect(result?.sec).toBeDefined();
|
|
66
|
+
expect(result?.acc).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('only includes explicitly defined shades', () => {
|
|
70
|
+
const input = {
|
|
71
|
+
main: {
|
|
72
|
+
500: { L: 0.5, C: 0.2, H: 0 },
|
|
73
|
+
raw: { L: 0.5, C: 0.2, H: 0 }
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const result = parseAndNormalizeEventColours(input);
|
|
78
|
+
expect(result).not.toBeNull();
|
|
79
|
+
|
|
80
|
+
// Should only include explicitly defined shades (500 and raw)
|
|
81
|
+
expect(result?.main[500]).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
82
|
+
expect(result?.main.raw).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
83
|
+
|
|
84
|
+
// Should not include undefined shades
|
|
85
|
+
expect(result?.main[50]).toBeUndefined();
|
|
86
|
+
expect(result?.main[100]).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('Legacy format (ev-main/ev-sec/ev-acc keys)', () => {
|
|
91
|
+
it('parses legacy format with ev-main, ev-sec, ev-acc keys', () => {
|
|
92
|
+
const input = {
|
|
93
|
+
'ev-main': { 500: { L: 0.5, C: 0.2, H: 0 } },
|
|
94
|
+
'ev-sec': { 500: { L: 0.5, C: 0.2, H: 120 } },
|
|
95
|
+
'ev-acc': { 500: { L: 0.5, C: 0.2, H: 240 } }
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const result = parseAndNormalizeEventColours(input);
|
|
99
|
+
expect(result).not.toBeNull();
|
|
100
|
+
expect(result?.main).toBeDefined();
|
|
101
|
+
expect(result?.sec).toBeDefined();
|
|
102
|
+
expect(result?.acc).toBeDefined();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('prefers standard keys over legacy keys when both exist', () => {
|
|
106
|
+
const input = {
|
|
107
|
+
main: { 500: { L: 0.5, C: 0.2, H: 0 } },
|
|
108
|
+
'ev-main': { 500: { L: 0.7, C: 0.3, H: 10 } }
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const result = parseAndNormalizeEventColours(input);
|
|
112
|
+
expect(result).not.toBeNull();
|
|
113
|
+
// Implementation prefers standard keys ('main') over legacy keys ('ev-main')
|
|
114
|
+
// So when both exist, 'main' is used
|
|
115
|
+
expect(result?.main[500]).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('Empty/invalid palette handling', () => {
|
|
120
|
+
it('returns null when no palette keys are present', () => {
|
|
121
|
+
const input = { something: 'else' };
|
|
122
|
+
expect(parseAndNormalizeEventColours(input)).toBeNull();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('handles empty palette objects', () => {
|
|
126
|
+
const input = {
|
|
127
|
+
main: {},
|
|
128
|
+
sec: {},
|
|
129
|
+
acc: {}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const result = parseAndNormalizeEventColours(input);
|
|
133
|
+
// Should return null or empty palettes depending on implementation
|
|
134
|
+
// The current implementation returns empty objects, which is valid
|
|
135
|
+
expect(result).not.toBeNull();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('Shade inclusion behavior', () => {
|
|
140
|
+
it('uses existing shade value when present', () => {
|
|
141
|
+
const input = {
|
|
142
|
+
main: {
|
|
143
|
+
50: { L: 0.95, C: 0.01, H: 0 },
|
|
144
|
+
500: { L: 0.5, C: 0.2, H: 0 },
|
|
145
|
+
950: { L: 0.05, C: 0.01, H: 0 },
|
|
146
|
+
raw: { L: 0.5, C: 0.2, H: 0 }
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const result = parseAndNormalizeEventColours(input);
|
|
151
|
+
expect(result?.main[50]).toEqual({ L: 0.95, C: 0.01, H: 0 });
|
|
152
|
+
expect(result?.main[500]).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
153
|
+
expect(result?.main[950]).toEqual({ L: 0.05, C: 0.01, H: 0 });
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('only includes raw when explicitly defined', () => {
|
|
157
|
+
const input = {
|
|
158
|
+
main: {
|
|
159
|
+
raw: { L: 0.5, C: 0.2, H: 0 }
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const result = parseAndNormalizeEventColours(input);
|
|
164
|
+
// Should only include raw, not fill other shades
|
|
165
|
+
expect(result?.main.raw).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
166
|
+
expect(result?.main[50]).toBeUndefined();
|
|
167
|
+
expect(result?.main[500]).toBeUndefined();
|
|
168
|
+
expect(result?.main[950]).toBeUndefined();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('only includes 500 when explicitly defined', () => {
|
|
172
|
+
const input = {
|
|
173
|
+
main: {
|
|
174
|
+
500: { L: 0.5, C: 0.2, H: 0 }
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const result = parseAndNormalizeEventColours(input);
|
|
179
|
+
// Should only include 500, not fill other shades
|
|
180
|
+
expect(result?.main[500]).toEqual({ L: 0.5, C: 0.2, H: 0 });
|
|
181
|
+
expect(result?.main[50]).toBeUndefined();
|
|
182
|
+
expect(result?.main[100]).toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('preserves raw color when present', () => {
|
|
186
|
+
const input = {
|
|
187
|
+
main: {
|
|
188
|
+
500: { L: 0.5, C: 0.2, H: 0 },
|
|
189
|
+
raw: { L: 0.55, C: 0.25, H: 5 }
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const result = parseAndNormalizeEventColours(input);
|
|
194
|
+
expect(result?.main.raw).toEqual({ L: 0.55, C: 0.25, H: 5 });
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('Error handling', () => {
|
|
199
|
+
it('handles malformed color objects gracefully', () => {
|
|
200
|
+
const input = {
|
|
201
|
+
main: { 500: 'invalid' }
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Should not throw, but may return null or handle gracefully
|
|
205
|
+
expect(() => parseAndNormalizeEventColours(input)).not.toThrow();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Event Colours Parser
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Theming/ParseEventColours
|
|
5
|
+
* @since 2.0.0
|
|
6
|
+
*
|
|
7
|
+
* Shared utility for parsing and normalizing event_colours from database.
|
|
8
|
+
* Handles multiple input formats and ensures consistent palette structure.
|
|
9
|
+
*
|
|
10
|
+
* Supports:
|
|
11
|
+
* - Object format: { main: {...}, sec: {...}, acc: {...} }
|
|
12
|
+
* - String format: JSON string that will be parsed
|
|
13
|
+
* - Legacy format: { "ev-main": {...}, "ev-sec": {...}, "ev-acc": {...} }
|
|
14
|
+
*
|
|
15
|
+
* The function only includes explicitly defined color values, ensuring
|
|
16
|
+
* that undefined shades are not included in the palette.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { parseAndNormalizeEventColours } from '@jmruthers/pace-core/theming/parseEventColours';
|
|
21
|
+
*
|
|
22
|
+
* const palette = parseAndNormalizeEventColours(event.event_colours);
|
|
23
|
+
* if (palette) {
|
|
24
|
+
* applyPalette(palette);
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse and normalize event_colours to PaletteData
|
|
31
|
+
*
|
|
32
|
+
* Supports multiple input formats:
|
|
33
|
+
* - Object with 'main', 'sec', 'acc' keys
|
|
34
|
+
* - Object with 'ev-main', 'ev-sec', 'ev-acc' keys (legacy)
|
|
35
|
+
* - JSON string that will be parsed
|
|
36
|
+
*
|
|
37
|
+
* Only includes explicitly defined color values. Does not fill
|
|
38
|
+
* missing shades - only shades that are present in the input will
|
|
39
|
+
* be included in the output.
|
|
40
|
+
*
|
|
41
|
+
* @param input - Event colours from database (JSONB field)
|
|
42
|
+
* @returns Normalized palette data with main, sec, acc palettes, or null if invalid
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // Standard format
|
|
47
|
+
* const colours = {
|
|
48
|
+
* main: { 500: { L: 0.5, C: 0.2, H: 0 }, raw: { L: 0.5, C: 0.2, H: 0 } },
|
|
49
|
+
* sec: { 500: { L: 0.5, C: 0.2, H: 120 } },
|
|
50
|
+
* acc: { 500: { L: 0.5, C: 0.2, H: 240 } }
|
|
51
|
+
* };
|
|
52
|
+
* const palette = parseAndNormalizeEventColours(colours);
|
|
53
|
+
* // Returns: { main: { 500: {...}, raw: {...} }, sec: { 500: {...} }, acc: { 500: {...} } }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* // Legacy format with ev-* keys
|
|
59
|
+
* const colours = {
|
|
60
|
+
* "ev-main": { 500: { L: 0.5, C: 0.2, H: 0 } },
|
|
61
|
+
* "ev-sec": { 500: { L: 0.5, C: 0.2, H: 120 } },
|
|
62
|
+
* "ev-acc": { 500: { L: 0.5, C: 0.2, H: 240 } }
|
|
63
|
+
* };
|
|
64
|
+
* const palette = parseAndNormalizeEventColours(colours);
|
|
65
|
+
* // Returns normalized palette with only defined shades included
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function parseAndNormalizeEventColours(input: unknown): { main: any; sec: any; acc: any } | null {
|
|
69
|
+
try {
|
|
70
|
+
if (!input) return null;
|
|
71
|
+
let obj: any = input;
|
|
72
|
+
|
|
73
|
+
// Handle string input (JSON string from database)
|
|
74
|
+
if (typeof input === 'string') {
|
|
75
|
+
try {
|
|
76
|
+
obj = JSON.parse(input);
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
} else if (typeof input !== 'object') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Support both 'ev-main'/'ev-sec'/'ev-acc' (legacy) and 'main'/'sec'/'acc' (standard) keys
|
|
85
|
+
// Prefer standard keys over legacy keys when both exist
|
|
86
|
+
const pick = (o: any, standard: string, legacy: string) => (o?.[standard] ?? o?.[legacy]) || null;
|
|
87
|
+
const main = pick(obj, 'main', 'ev-main');
|
|
88
|
+
const sec = pick(obj, 'sec', 'ev-sec');
|
|
89
|
+
const acc = pick(obj, 'acc', 'ev-acc');
|
|
90
|
+
|
|
91
|
+
// If no palette data found, return null
|
|
92
|
+
if (!main && !sec && !acc) return null;
|
|
93
|
+
|
|
94
|
+
// Helper: only include explicitly defined color values
|
|
95
|
+
// This ensures we don't include undefined shades in the palette
|
|
96
|
+
const fill = (p: any) => {
|
|
97
|
+
if (!p || typeof p !== 'object') return {} as any;
|
|
98
|
+
const out: any = {};
|
|
99
|
+
|
|
100
|
+
// Only include shades that are explicitly defined in the input
|
|
101
|
+
// Iterate over all keys in the palette object
|
|
102
|
+
for (const key in p) {
|
|
103
|
+
// Only include the key if it has a defined value (not null, undefined, or empty)
|
|
104
|
+
const value = p[key];
|
|
105
|
+
if (value !== null && value !== undefined && value !== '') {
|
|
106
|
+
out[key] = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return out;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
main: fill(main),
|
|
115
|
+
sec: fill(sec),
|
|
116
|
+
acc: fill(acc)
|
|
117
|
+
};
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.warn('[parseEventColours] Failed to parse/normalize event colours:', error);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
package/src/theming/runtime.ts
CHANGED
|
@@ -228,3 +228,6 @@ export function getCurrentThemeData(): PaletteData | null {
|
|
|
228
228
|
// For now, we'll return null as the theme data isn't easily extractable
|
|
229
229
|
return null;
|
|
230
230
|
}
|
|
231
|
+
|
|
232
|
+
// Re-export parseEventColours utility for convenience
|
|
233
|
+
export { parseAndNormalizeEventColours } from './parseEventColours';
|