@jmruthers/pace-core 0.5.184 → 0.5.185
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/CHANGELOG.md +38 -0
- package/README.md +60 -1
- package/core-usage-manifest.json +312 -0
- package/dist/{DataTable-QAB34V6K.js → DataTable-IX2NBUTP.js} +6 -6
- package/dist/{DataTable-Bz8ffqyA.d.ts → DataTable-Z9NLVJh0.d.ts} +1 -1
- package/dist/{index-Bl--n7-T.d.ts → PublicPageProvider-BABf6JCh.d.ts} +21 -10
- package/dist/{UnifiedAuthProvider-7F6T4B6K.js → UnifiedAuthProvider-A4BCQRJY.js} +4 -2
- package/dist/{UnifiedAuthProvider-F86d7dSi.d.ts → UnifiedAuthProvider-BG0AL5eE.d.ts} +2 -1
- package/dist/{api-ROMBCNKU.js → api-BMFCXVQX.js} +2 -2
- package/dist/{chunk-RA3JUFMW.js → chunk-445GEP27.js} +154 -4
- package/dist/{chunk-RA3JUFMW.js.map → chunk-445GEP27.js.map} +1 -1
- package/dist/{chunk-CSOFYHAG.js → chunk-AISXLWGZ.js} +374 -60
- package/dist/chunk-AISXLWGZ.js.map +1 -0
- package/dist/{chunk-FUEYYMX5.js → chunk-FXFJRTKI.js} +24 -3
- package/dist/chunk-FXFJRTKI.js.map +1 -0
- package/dist/{chunk-NQPMQGS2.js → chunk-HC67NW5K.js} +379 -359
- package/dist/chunk-HC67NW5K.js.map +1 -0
- package/dist/chunk-HESYZWZW.js +388 -0
- package/dist/chunk-HESYZWZW.js.map +1 -0
- package/dist/{chunk-QUVSNGIP.js → chunk-HGPQUCBC.js} +34 -9
- package/dist/{chunk-QUVSNGIP.js.map → chunk-HGPQUCBC.js.map} +1 -1
- package/dist/{chunk-UHNYIBXL.js → chunk-IXSNYUCT.js} +1 -1
- package/dist/chunk-IXSNYUCT.js.map +1 -0
- package/dist/{chunk-MI7HBHN3.js → chunk-MX3EIJGQ.js} +4 -3
- package/dist/{chunk-MI7HBHN3.js.map → chunk-MX3EIJGQ.js.map} +1 -1
- package/dist/{chunk-PWAHJW4G.js → chunk-OKI34GZD.js} +86 -33
- package/dist/chunk-OKI34GZD.js.map +1 -0
- package/dist/{chunk-W22JP75J.js → chunk-STTZQK2I.js} +3 -3
- package/dist/chunk-THRPYOFK.js +215 -0
- package/dist/chunk-THRPYOFK.js.map +1 -0
- package/dist/{chunk-M7W4CP3M.js → chunk-U6WNSFX5.js} +2 -1
- package/dist/chunk-U6WNSFX5.js.map +1 -0
- package/dist/{chunk-QCDXODCA.js → chunk-XAUHJD3L.js} +2 -2
- package/dist/components.d.ts +182 -6
- package/dist/components.js +157 -11
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +406 -0
- package/dist/{file-reference-D06mEEWW.d.ts → file-reference-BjR39ktt.d.ts} +7 -1
- package/dist/hooks.d.ts +7 -14
- package/dist/hooks.js +10 -22
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +79 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +205 -14
- package/dist/rbac/index.js +28 -6
- package/dist/timezone-_pgH8qrY.d.ts +530 -0
- package/dist/{types-_x1f4QBF.d.ts → types-DUyCRSTj.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-JJczomYq.d.ts → usePublicRouteParams-CvnC3d-e.d.ts} +113 -2
- package/dist/utils.d.ts +109 -151
- package/dist/utils.js +128 -138
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +60 -1
- 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/Logger.md +178 -0
- 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/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +5 -5
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +54 -0
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +18 -2
- 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/ComplianceResult.md +30 -0
- 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/DatabaseComplianceResult.md +85 -0
- package/docs/api/interfaces/DatabaseIssue.md +41 -0
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +6 -6
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.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 +24 -8
- package/docs/api/interfaces/FileUploadProps.md +24 -13
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +9 -9
- 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/LoggerConfig.md +62 -0
- 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 +36 -23
- 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 +11 -11
- 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/ProgressProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +52 -0
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +4 -4
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +7 -7
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +5 -5
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/RuntimeComplianceResult.md +55 -0
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +41 -0
- 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/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.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/UseFormDialogOptions.md +62 -0
- package/docs/api/interfaces/UseFormDialogReturn.md +117 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.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 +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.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 +738 -42
- package/docs/api-reference/hooks.md +111 -0
- package/docs/api-reference/rpc-functions.md +1 -1
- package/docs/api-reference/utilities.md +184 -0
- package/docs/getting-started/installation-guide.md +75 -16
- package/docs/getting-started/quick-start.md +61 -11
- package/docs/implementation-guides/authentication.md +88 -12
- package/docs/implementation-guides/file-reference-system.md +2 -1
- package/docs/implementation-guides/file-upload-storage.md +21 -0
- package/docs/rbac/README.md +1 -0
- package/docs/rbac/compliance/compliance-guide.md +544 -0
- package/docs/rbac/getting-started.md +158 -33
- package/docs/standards/pace-core-compliance.md +432 -0
- package/eslint-config-pace-core.cjs +93 -0
- package/package.json +15 -3
- package/scripts/analyze-bundle.js +232 -0
- package/scripts/build-css.js +56 -0
- package/scripts/build-docs-incremental.js +1015 -0
- package/scripts/check-pace-core-compliance.cjs +2353 -0
- package/scripts/generate-docs.js +157 -0
- package/scripts/setup-build-cache.js +73 -0
- package/scripts/utils/command-runner.js +131 -0
- package/scripts/utils/env.js +33 -0
- package/scripts/utils/index.js +10 -0
- package/scripts/utils/logger.js +88 -0
- package/scripts/utils/path-helpers.js +37 -0
- package/scripts/validate-formats.js +133 -0
- package/scripts/validate-master.js +155 -0
- package/scripts/validate-pre-publish.js +140 -0
- package/scripts/validate-theme.js +142 -0
- package/src/components/Calendar/Calendar.tsx +8 -1
- package/src/components/Card/Card.tsx +47 -8
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +314 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +126 -0
- package/src/components/DatePickerWithTimezone/README.md +135 -0
- package/src/components/DatePickerWithTimezone/index.ts +10 -0
- package/src/components/DateTimeField/DateTimeField.test.tsx +358 -0
- package/src/components/DateTimeField/DateTimeField.tsx +232 -0
- package/src/components/DateTimeField/README.md +148 -0
- package/src/components/DateTimeField/index.ts +10 -0
- package/src/components/FileUpload/FileUpload.tsx +3 -0
- package/src/components/Header/Header.test.tsx +47 -18
- package/src/components/Header/Header.tsx +24 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +29 -20
- package/src/components/PaceAppLayout/README.md +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +37 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +12 -4
- package/src/components/index.ts +8 -0
- package/src/eslint-rules/pace-core-compliance.cjs +406 -0
- package/src/eslint-rules/pace-core-compliance.js +640 -0
- package/src/hooks/__tests__/useFormDialog.test.ts +478 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useFileReference.test.ts +1 -0
- package/src/hooks/useFormDialog.ts +147 -0
- package/src/index.ts +27 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +6 -5
- package/src/providers/services/UnifiedAuthProvider.tsx +24 -3
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +3 -0
- package/src/rbac/compliance/database-validator.ts +165 -0
- package/src/rbac/compliance/index.ts +38 -0
- package/src/rbac/compliance/quick-fix-suggestions.ts +209 -0
- package/src/rbac/compliance/runtime-compliance.ts +77 -0
- package/src/rbac/compliance/setup-validator.ts +131 -0
- package/src/rbac/components/PagePermissionGuard.tsx +8 -64
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +35 -21
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/errors.ts +11 -0
- package/src/rbac/hooks/useRoleManagement.ts +292 -12
- package/src/rbac/index.ts +30 -0
- package/src/services/OrganisationService.ts +4 -0
- package/src/types/file-reference.ts +6 -0
- package/src/utils/__tests__/timezone.test.ts +345 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +2 -0
- package/src/utils/file-reference/index.ts +1 -0
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +167 -0
- package/src/utils/formatting/formatting.ts +179 -0
- package/src/utils/index.ts +27 -1
- package/src/utils/location/index.ts +16 -0
- package/src/utils/location/location.test.ts +286 -0
- package/src/utils/location/location.ts +175 -0
- package/src/utils/timezone/index.ts +17 -0
- package/src/utils/timezone/timezone.test.ts +349 -0
- package/src/utils/timezone/timezone.ts +281 -0
- package/dist/chunk-CSOFYHAG.js.map +0 -1
- package/dist/chunk-FUEYYMX5.js.map +0 -1
- package/dist/chunk-HKIT6O7W.js +0 -198
- package/dist/chunk-HKIT6O7W.js.map +0 -1
- package/dist/chunk-KUEN3HFB.js +0 -94
- package/dist/chunk-KUEN3HFB.js.map +0 -1
- package/dist/chunk-M7W4CP3M.js.map +0 -1
- package/dist/chunk-NQPMQGS2.js.map +0 -1
- package/dist/chunk-PWAHJW4G.js.map +0 -1
- package/dist/chunk-UHNYIBXL.js.map +0 -1
- package/dist/formatting-5wETwiGF.d.ts +0 -162
- /package/dist/{DataTable-QAB34V6K.js.map → DataTable-IX2NBUTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-7F6T4B6K.js.map → UnifiedAuthProvider-A4BCQRJY.js.map} +0 -0
- /package/dist/{api-ROMBCNKU.js.map → api-BMFCXVQX.js.map} +0 -0
- /package/dist/{chunk-W22JP75J.js.map → chunk-STTZQK2I.js.map} +0 -0
- /package/dist/{chunk-QCDXODCA.js.map → chunk-XAUHJD3L.js.map} +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file DatePickerWithTimezone Component Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DatePickerWithTimezone/__tests__
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive test suite for DatePickerWithTimezone component.
|
|
8
|
+
* Tests cover all major functionality, edge cases, and accessibility.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
13
|
+
import userEvent from '@testing-library/user-event';
|
|
14
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
15
|
+
import { DatePickerWithTimezone } from './DatePickerWithTimezone';
|
|
16
|
+
import { Calendar } from '../Calendar';
|
|
17
|
+
|
|
18
|
+
// Mock timezone utilities
|
|
19
|
+
vi.mock('../../utils/timezone', () => ({
|
|
20
|
+
getUserTimeZone: vi.fn(() => 'America/New_York')
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Mock Calendar component
|
|
24
|
+
vi.mock('../Calendar', () => ({
|
|
25
|
+
Calendar: vi.fn(({ selected, onSelect, ...props }) => (
|
|
26
|
+
<div data-testid="calendar" {...props}>
|
|
27
|
+
<button
|
|
28
|
+
data-testid="calendar-day"
|
|
29
|
+
onClick={() => onSelect?.(new Date('2024-01-15'))}
|
|
30
|
+
>
|
|
31
|
+
Day 15
|
|
32
|
+
</button>
|
|
33
|
+
{selected && <span data-testid="selected-date">{selected.toISOString()}</span>}
|
|
34
|
+
</div>
|
|
35
|
+
))
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// Mock Button component
|
|
39
|
+
vi.mock('../Button', () => ({
|
|
40
|
+
Button: vi.fn(({ children, onClick, ...props }) => (
|
|
41
|
+
<button data-testid="done-button" onClick={onClick} {...props}>
|
|
42
|
+
{children}
|
|
43
|
+
</button>
|
|
44
|
+
))
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
// Mock lucide-react Clock icon
|
|
48
|
+
vi.mock('lucide-react', () => ({
|
|
49
|
+
Clock: ({ className, 'aria-hidden': ariaHidden, ...props }: any) => (
|
|
50
|
+
<svg
|
|
51
|
+
data-testid="clock-icon"
|
|
52
|
+
className={className}
|
|
53
|
+
aria-hidden={ariaHidden}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
<path d="M12 2v10l4 4" />
|
|
57
|
+
</svg>
|
|
58
|
+
)
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
describe('DatePickerWithTimezone Component', () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
vi.clearAllMocks();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('Rendering', () => {
|
|
67
|
+
it('renders with default props', () => {
|
|
68
|
+
const onSelect = vi.fn();
|
|
69
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
70
|
+
|
|
71
|
+
expect(screen.getByTestId('calendar')).toBeInTheDocument();
|
|
72
|
+
expect(screen.getByText(/Timezone:/)).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('renders with selected date', () => {
|
|
76
|
+
const onSelect = vi.fn();
|
|
77
|
+
const selected = new Date('2024-01-15');
|
|
78
|
+
render(<DatePickerWithTimezone selected={selected} onSelect={onSelect} />);
|
|
79
|
+
|
|
80
|
+
expect(screen.getByTestId('selected-date')).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('renders with custom timezone', () => {
|
|
84
|
+
const onSelect = vi.fn();
|
|
85
|
+
render(
|
|
86
|
+
<DatePickerWithTimezone
|
|
87
|
+
selected={undefined}
|
|
88
|
+
onSelect={onSelect}
|
|
89
|
+
timezone="America/Los_Angeles"
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(screen.getByText('America/Los_Angeles')).toBeInTheDocument();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('displays "Local" when timezone matches user timezone', () => {
|
|
97
|
+
const onSelect = vi.fn();
|
|
98
|
+
render(
|
|
99
|
+
<DatePickerWithTimezone
|
|
100
|
+
selected={undefined}
|
|
101
|
+
onSelect={onSelect}
|
|
102
|
+
timezone="America/New_York"
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(screen.getByText('Local')).toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('renders with Done button when onDone is provided', () => {
|
|
110
|
+
const onSelect = vi.fn();
|
|
111
|
+
const onDone = vi.fn();
|
|
112
|
+
render(
|
|
113
|
+
<DatePickerWithTimezone selected={undefined} onSelect={onSelect} onDone={onDone} />
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(screen.getByTestId('done-button')).toBeInTheDocument();
|
|
117
|
+
expect(screen.getByText('Done')).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('does not render Done button when onDone is not provided', () => {
|
|
121
|
+
const onSelect = vi.fn();
|
|
122
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
123
|
+
|
|
124
|
+
expect(screen.queryByTestId('done-button')).not.toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('renders with custom className', () => {
|
|
128
|
+
const onSelect = vi.fn();
|
|
129
|
+
const { container } = render(
|
|
130
|
+
<DatePickerWithTimezone
|
|
131
|
+
selected={undefined}
|
|
132
|
+
onSelect={onSelect}
|
|
133
|
+
className="custom-class"
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Date Selection', () => {
|
|
142
|
+
it('calls onSelect when date is selected', async () => {
|
|
143
|
+
const onSelect = vi.fn();
|
|
144
|
+
const user = userEvent.setup();
|
|
145
|
+
|
|
146
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
147
|
+
|
|
148
|
+
const dayButton = screen.getByTestId('calendar-day');
|
|
149
|
+
await user.click(dayButton);
|
|
150
|
+
|
|
151
|
+
expect(onSelect).toHaveBeenCalled();
|
|
152
|
+
expect(onSelect).toHaveBeenCalledWith(expect.any(Date));
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('handles date selection with existing selected date', async () => {
|
|
156
|
+
const onSelect = vi.fn();
|
|
157
|
+
const user = userEvent.setup();
|
|
158
|
+
const selected = new Date('2024-01-10');
|
|
159
|
+
|
|
160
|
+
render(<DatePickerWithTimezone selected={selected} onSelect={onSelect} />);
|
|
161
|
+
|
|
162
|
+
const dayButton = screen.getByTestId('calendar-day');
|
|
163
|
+
await user.click(dayButton);
|
|
164
|
+
|
|
165
|
+
expect(onSelect).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('Done Button', () => {
|
|
170
|
+
it('calls onDone when Done button is clicked', async () => {
|
|
171
|
+
const onSelect = vi.fn();
|
|
172
|
+
const onDone = vi.fn();
|
|
173
|
+
const user = userEvent.setup();
|
|
174
|
+
|
|
175
|
+
render(
|
|
176
|
+
<DatePickerWithTimezone selected={undefined} onSelect={onSelect} onDone={onDone} />
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const doneButton = screen.getByTestId('done-button');
|
|
180
|
+
await user.click(doneButton);
|
|
181
|
+
|
|
182
|
+
expect(onDone).toHaveBeenCalledTimes(1);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('does not call onSelect when Done button is clicked', async () => {
|
|
186
|
+
const onSelect = vi.fn();
|
|
187
|
+
const onDone = vi.fn();
|
|
188
|
+
const user = userEvent.setup();
|
|
189
|
+
|
|
190
|
+
render(
|
|
191
|
+
<DatePickerWithTimezone selected={undefined} onSelect={onSelect} onDone={onDone} />
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const doneButton = screen.getByTestId('done-button');
|
|
195
|
+
await user.click(doneButton);
|
|
196
|
+
|
|
197
|
+
expect(onSelect).not.toHaveBeenCalled();
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('Timezone Display', () => {
|
|
202
|
+
it('displays user timezone as "Local" when no timezone provided', () => {
|
|
203
|
+
const onSelect = vi.fn();
|
|
204
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
205
|
+
|
|
206
|
+
expect(screen.getByText('Local')).toBeInTheDocument();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('displays timezone name when different from user timezone', () => {
|
|
210
|
+
const onSelect = vi.fn();
|
|
211
|
+
render(
|
|
212
|
+
<DatePickerWithTimezone
|
|
213
|
+
selected={undefined}
|
|
214
|
+
onSelect={onSelect}
|
|
215
|
+
timezone="Europe/London"
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
expect(screen.getByText('Europe/London')).toBeInTheDocument();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('displays Clock icon', () => {
|
|
223
|
+
const onSelect = vi.fn();
|
|
224
|
+
render(
|
|
225
|
+
<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
expect(screen.getByTestId('clock-icon')).toBeInTheDocument();
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe('Edge Cases', () => {
|
|
233
|
+
it('handles undefined selected date', () => {
|
|
234
|
+
const onSelect = vi.fn();
|
|
235
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
236
|
+
|
|
237
|
+
expect(screen.getByTestId('calendar')).toBeInTheDocument();
|
|
238
|
+
expect(screen.queryByTestId('selected-date')).not.toBeInTheDocument();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('handles null selected date', () => {
|
|
242
|
+
const onSelect = vi.fn();
|
|
243
|
+
// @ts-expect-error - Testing edge case
|
|
244
|
+
render(<DatePickerWithTimezone selected={null} onSelect={onSelect} />);
|
|
245
|
+
|
|
246
|
+
expect(screen.getByTestId('calendar')).toBeInTheDocument();
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
describe('Accessibility', () => {
|
|
251
|
+
it('has proper ARIA labels for timezone', () => {
|
|
252
|
+
const onSelect = vi.fn();
|
|
253
|
+
render(
|
|
254
|
+
<DatePickerWithTimezone
|
|
255
|
+
selected={undefined}
|
|
256
|
+
onSelect={onSelect}
|
|
257
|
+
timezone="America/Los_Angeles"
|
|
258
|
+
/>
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const timezoneLabel = screen.getByLabelText('Timezone America/Los_Angeles');
|
|
262
|
+
expect(timezoneLabel).toBeInTheDocument();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('marks Clock icon as decorative', () => {
|
|
266
|
+
const onSelect = vi.fn();
|
|
267
|
+
render(
|
|
268
|
+
<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const clockIcon = screen.getByTestId('clock-icon');
|
|
272
|
+
expect(clockIcon).toBeInTheDocument();
|
|
273
|
+
expect(clockIcon).toHaveAttribute('aria-hidden', 'true');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('supports keyboard navigation', async () => {
|
|
277
|
+
const onSelect = vi.fn();
|
|
278
|
+
const user = userEvent.setup();
|
|
279
|
+
|
|
280
|
+
render(<DatePickerWithTimezone selected={undefined} onSelect={onSelect} />);
|
|
281
|
+
|
|
282
|
+
const dayButton = screen.getByTestId('calendar-day');
|
|
283
|
+
await user.tab();
|
|
284
|
+
|
|
285
|
+
// Calendar should be keyboard accessible
|
|
286
|
+
expect(dayButton).toBeInTheDocument();
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe('Calendar Integration', () => {
|
|
291
|
+
it('passes correct props to Calendar component', () => {
|
|
292
|
+
const onSelect = vi.fn();
|
|
293
|
+
const selected = new Date('2024-01-15');
|
|
294
|
+
const MockedCalendar = vi.mocked(Calendar);
|
|
295
|
+
|
|
296
|
+
render(<DatePickerWithTimezone selected={selected} onSelect={onSelect} />);
|
|
297
|
+
|
|
298
|
+
expect(MockedCalendar).toHaveBeenCalledWith(
|
|
299
|
+
expect.objectContaining({
|
|
300
|
+
mode: 'single',
|
|
301
|
+
selected: selected,
|
|
302
|
+
onSelect: onSelect,
|
|
303
|
+
initialFocus: true,
|
|
304
|
+
captionLayout: 'dropdown-buttons',
|
|
305
|
+
fromYear: 1900,
|
|
306
|
+
toYear: 2100,
|
|
307
|
+
className: 'p-0'
|
|
308
|
+
}),
|
|
309
|
+
expect.anything()
|
|
310
|
+
);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file DatePickerWithTimezone Component
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DatePickerWithTimezone
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* Date picker component that displays timezone information alongside the calendar.
|
|
8
|
+
* Provides a calendar interface with timezone context for date selection.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Calendar date selection
|
|
12
|
+
* - Timezone display (shows "Local" when matches user timezone)
|
|
13
|
+
* - Optional "Done" button
|
|
14
|
+
* - Accessible date selection
|
|
15
|
+
* - Keyboard navigation support
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { DatePickerWithTimezone } from '@jmruthers/pace-core/components';
|
|
20
|
+
* import { useState } from 'react';
|
|
21
|
+
*
|
|
22
|
+
* function DateSelector() {
|
|
23
|
+
* const [date, setDate] = useState<Date>();
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <DatePickerWithTimezone
|
|
27
|
+
* selected={date}
|
|
28
|
+
* onSelect={setDate}
|
|
29
|
+
* timezone="America/New_York"
|
|
30
|
+
* onDone={() => console.log('Date selected')}
|
|
31
|
+
* />
|
|
32
|
+
* );
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @accessibility
|
|
37
|
+
* - WCAG 2.1 AA compliant
|
|
38
|
+
* - Keyboard navigation support
|
|
39
|
+
* - Screen reader friendly
|
|
40
|
+
* - Focus management
|
|
41
|
+
* - Proper ARIA attributes
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import * as React from 'react';
|
|
45
|
+
import { Calendar } from '../Calendar';
|
|
46
|
+
import { Button } from '../Button';
|
|
47
|
+
import { Clock } from 'lucide-react';
|
|
48
|
+
import { getUserTimeZone } from '../../utils/timezone';
|
|
49
|
+
import { cn } from '../../utils/core/cn';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Props for the DatePickerWithTimezone component
|
|
53
|
+
*/
|
|
54
|
+
export interface DatePickerWithTimezoneProps {
|
|
55
|
+
/**
|
|
56
|
+
* Currently selected date
|
|
57
|
+
*/
|
|
58
|
+
selected?: Date;
|
|
59
|
+
/**
|
|
60
|
+
* Date selection handler
|
|
61
|
+
*/
|
|
62
|
+
onSelect: (date: Date | undefined) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Optional callback when "Done" button is clicked
|
|
65
|
+
*/
|
|
66
|
+
onDone?: () => void;
|
|
67
|
+
/**
|
|
68
|
+
* Timezone to display (defaults to user's timezone)
|
|
69
|
+
*/
|
|
70
|
+
timezone?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Additional CSS classes
|
|
73
|
+
*/
|
|
74
|
+
className?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* DatePickerWithTimezone component
|
|
79
|
+
* Date picker with timezone information display
|
|
80
|
+
*
|
|
81
|
+
* @param props - DatePickerWithTimezone configuration
|
|
82
|
+
* @returns JSX.Element - The rendered date picker with timezone
|
|
83
|
+
*/
|
|
84
|
+
export function DatePickerWithTimezone({
|
|
85
|
+
selected,
|
|
86
|
+
onSelect,
|
|
87
|
+
onDone,
|
|
88
|
+
timezone,
|
|
89
|
+
className
|
|
90
|
+
}: DatePickerWithTimezoneProps) {
|
|
91
|
+
const userTimezone = getUserTimeZone();
|
|
92
|
+
const displayTimezone = timezone || userTimezone;
|
|
93
|
+
const timezoneDisplay = displayTimezone === userTimezone ? 'Local' : displayTimezone;
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div className={cn('flex flex-col', className)}>
|
|
97
|
+
<div className="p-3">
|
|
98
|
+
<Calendar
|
|
99
|
+
mode="single"
|
|
100
|
+
selected={selected}
|
|
101
|
+
onSelect={onSelect}
|
|
102
|
+
initialFocus
|
|
103
|
+
captionLayout="dropdown-buttons"
|
|
104
|
+
fromYear={1900}
|
|
105
|
+
toYear={2100}
|
|
106
|
+
className="p-0"
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div className="flex items-center justify-between border-t border-border px-3 py-2">
|
|
111
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
112
|
+
<Clock className="h-4 w-4" aria-hidden="true" />
|
|
113
|
+
<span>
|
|
114
|
+
Timezone: <span aria-label={`Timezone ${timezoneDisplay}`}>{timezoneDisplay}</span>
|
|
115
|
+
</span>
|
|
116
|
+
</div>
|
|
117
|
+
{onDone && (
|
|
118
|
+
<Button onClick={onDone} size="sm" className="h-8">
|
|
119
|
+
Done
|
|
120
|
+
</Button>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# DatePickerWithTimezone Component
|
|
2
|
+
|
|
3
|
+
Date picker component that displays timezone information alongside the calendar.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `DatePickerWithTimezone` component provides a calendar interface for date selection with timezone context. It displays the timezone information below the calendar and optionally includes a "Done" button.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Calendar date selection
|
|
12
|
+
- Timezone display (shows "Local" when matches user timezone)
|
|
13
|
+
- Optional "Done" button
|
|
14
|
+
- Accessible date selection
|
|
15
|
+
- Keyboard navigation support
|
|
16
|
+
- Integration with pace-core Calendar component
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Example
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { DatePickerWithTimezone } from '@jmruthers/pace-core/components';
|
|
24
|
+
import { useState } from 'react';
|
|
25
|
+
|
|
26
|
+
function DateSelector() {
|
|
27
|
+
const [date, setDate] = useState<Date>();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<DatePickerWithTimezone
|
|
31
|
+
selected={date}
|
|
32
|
+
onSelect={setDate}
|
|
33
|
+
timezone="America/New_York"
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### With Done Button
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<DatePickerWithTimezone
|
|
43
|
+
selected={date}
|
|
44
|
+
onSelect={setDate}
|
|
45
|
+
timezone="America/New_York"
|
|
46
|
+
onDone={() => {
|
|
47
|
+
console.log('Date selected:', date);
|
|
48
|
+
// Close dialog or perform other actions
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Using User's Timezone
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// When timezone is not provided, uses user's browser timezone
|
|
57
|
+
<DatePickerWithTimezone
|
|
58
|
+
selected={date}
|
|
59
|
+
onSelect={setDate}
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
### Props
|
|
66
|
+
|
|
67
|
+
| Prop | Type | Default | Description |
|
|
68
|
+
|------|------|---------|-------------|
|
|
69
|
+
| `selected` | `Date \| undefined` | - | Currently selected date |
|
|
70
|
+
| `onSelect` | `(date: Date \| undefined) => void` | **required** | Date selection handler |
|
|
71
|
+
| `onDone` | `() => void` | - | Optional callback when "Done" button is clicked |
|
|
72
|
+
| `timezone` | `string` | User's timezone | Timezone to display (IANA timezone string) |
|
|
73
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
74
|
+
|
|
75
|
+
## Behavior
|
|
76
|
+
|
|
77
|
+
### Timezone Display
|
|
78
|
+
|
|
79
|
+
- When `timezone` is not provided: Uses the user's browser timezone
|
|
80
|
+
- When `timezone` matches user's timezone: Shows "Local"
|
|
81
|
+
- When `timezone` is different: Shows the timezone name (e.g., "America/New_York")
|
|
82
|
+
|
|
83
|
+
### Date Selection
|
|
84
|
+
|
|
85
|
+
The component uses the pace-core `Calendar` component for date selection. Selected dates are passed directly to `onSelect` without timezone conversion (dates are timezone-agnostic).
|
|
86
|
+
|
|
87
|
+
### Done Button
|
|
88
|
+
|
|
89
|
+
When `onDone` is provided, a "Done" button appears in the footer. Clicking it calls the `onDone` callback without affecting the selected date.
|
|
90
|
+
|
|
91
|
+
## Accessibility
|
|
92
|
+
|
|
93
|
+
- WCAG 2.1 AA compliant
|
|
94
|
+
- Keyboard navigation support (via Calendar component)
|
|
95
|
+
- Screen reader friendly
|
|
96
|
+
- Proper ARIA labels for timezone information
|
|
97
|
+
- Focus management
|
|
98
|
+
|
|
99
|
+
## Integration
|
|
100
|
+
|
|
101
|
+
### With Dialog
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Dialog, DatePickerWithTimezone } from '@jmruthers/pace-core/components';
|
|
105
|
+
|
|
106
|
+
function DatePickerDialog() {
|
|
107
|
+
const [date, setDate] = useState<Date>();
|
|
108
|
+
const [open, setOpen] = useState(false);
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
112
|
+
<DialogContent>
|
|
113
|
+
<DatePickerWithTimezone
|
|
114
|
+
selected={date}
|
|
115
|
+
onSelect={setDate}
|
|
116
|
+
onDone={() => setOpen(false)}
|
|
117
|
+
/>
|
|
118
|
+
</DialogContent>
|
|
119
|
+
</Dialog>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Edge Cases
|
|
125
|
+
|
|
126
|
+
- **Undefined selected date**: Calendar displays with no date selected
|
|
127
|
+
- **Null selected date**: Treated as undefined
|
|
128
|
+
|
|
129
|
+
## Dependencies
|
|
130
|
+
|
|
131
|
+
- `@jmruthers/pace-core/components/Calendar` - Calendar component
|
|
132
|
+
- `@jmruthers/pace-core/components/Button` - Button component
|
|
133
|
+
- `lucide-react` - Clock icon
|
|
134
|
+
- `@jmruthers/pace-core/utils/timezone` - Timezone utilities
|
|
135
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file DatePickerWithTimezone Component Exports
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DatePickerWithTimezone
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { DatePickerWithTimezone } from './DatePickerWithTimezone';
|
|
9
|
+
export type { DatePickerWithTimezoneProps } from './DatePickerWithTimezone';
|
|
10
|
+
|