@jmruthers/pace-core 0.5.136 → 0.5.139
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-CYOHOX3O.js → DataTable-JXFCA2BJ.js} +10 -9
- package/dist/{EventLogo-801uofbR.d.ts → EventLogo-rFL_kRjk.d.ts} +73 -1
- package/dist/{UnifiedAuthProvider-5E5TUNMS.js → UnifiedAuthProvider-XIQQ7LVU.js} +4 -5
- package/dist/{chunk-YLKIDTUK.js → chunk-22WKWKRX.js} +4 -4
- package/dist/{chunk-TVYPTYOY.js → chunk-4C7EXCAR.js} +60 -24
- package/dist/chunk-4C7EXCAR.js.map +1 -0
- package/dist/{chunk-NOHEVYVX.js → chunk-5JMOHWDI.js} +417 -319
- package/dist/chunk-5JMOHWDI.js.map +1 -0
- package/dist/{chunk-FHWWBIHA.js → chunk-6DXZ6V5Q.js} +5 -5
- package/dist/{chunk-2TWNJ46Y.js → chunk-6LAAY47Q.js} +2 -2
- package/dist/{chunk-444EZN6N.js → chunk-7QCC6MCP.js} +88 -1
- package/dist/chunk-7QCC6MCP.js.map +1 -0
- package/dist/chunk-BJPBT3CU.js +21 -0
- package/dist/chunk-BJPBT3CU.js.map +1 -0
- package/dist/{chunk-L6PGMCMD.js → chunk-BOOI7GK2.js} +38 -12
- package/dist/chunk-BOOI7GK2.js.map +1 -0
- package/dist/{chunk-XARJS7CD.js → chunk-INQLMHPF.js} +2 -2
- package/dist/chunk-JISYG63F.js +70 -0
- package/dist/chunk-JISYG63F.js.map +1 -0
- package/dist/{chunk-SL2YQDR6.js → chunk-MA6EPSGZ.js} +2 -2
- package/dist/{chunk-5DPZ5EAT.js → chunk-OWAG3GSU.js} +1 -3
- package/dist/{chunk-LTV3XIJJ.js → chunk-T6JN6LH6.js} +4 -4
- package/dist/{chunk-HJGGOMQ6.js → chunk-TLT2ZR3L.js} +147 -103
- package/dist/chunk-TLT2ZR3L.js.map +1 -0
- package/dist/{chunk-4MT5BGGL.js → chunk-YCWDTTUK.js} +4 -6
- package/dist/{chunk-4MT5BGGL.js.map → chunk-YCWDTTUK.js.map} +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +12 -11
- package/dist/components.js.map +1 -1
- package/dist/hooks.js +8 -9
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -14
- package/dist/index.js.map +1 -1
- package/dist/providers.js +3 -4
- package/dist/rbac/index.js +8 -9
- package/dist/schema-DTDZQe2u.d.ts +28 -0
- package/dist/types.d.ts +152 -3
- package/dist/types.js +51 -16
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +89 -4
- package/dist/utils.js +214 -96
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +1 -343
- package/dist/validation.js +3 -100
- 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 +1 -1
- 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 +1 -1
- 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/BadgeProps.md +27 -0
- 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/EventLogoProps.md +1 -1
- 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 +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 +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.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/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/SessionRestorationLoaderProps.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 +84 -15
- package/docs/architecture/README.md +0 -1
- package/docs/styles/README.md +0 -2
- package/examples/RBAC/CompleteRBACExample.tsx +324 -0
- package/examples/RBAC/EventBasedApp.tsx +239 -0
- package/examples/RBAC/PermissionExample.tsx +151 -0
- package/examples/RBAC/index.ts +13 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +301 -0
- package/examples/public-pages/PublicEventPage.tsx +274 -0
- package/examples/public-pages/PublicPageApp.tsx +308 -0
- package/examples/public-pages/PublicPageUsageExample.tsx +216 -0
- package/examples/public-pages/index.ts +14 -0
- package/package.json +1 -10
- package/src/__tests__/TEST_STANDARD.md +92 -0
- package/src/components/Badge/Badge.test.tsx +314 -0
- package/src/components/Badge/Badge.tsx +304 -0
- package/src/components/Badge/index.ts +3 -0
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
- package/src/components/DataTable/__tests__/styles.test.ts +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
- package/src/components/DataTable/components/DataTableBody.tsx +461 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
- package/src/components/DataTable/components/FilterRow.tsx +9 -3
- package/src/components/DataTable/components/PaginationControls.tsx +1 -0
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
- package/src/components/DataTable/core/ActionManager.ts +235 -0
- package/src/components/DataTable/core/ColumnManager.ts +205 -0
- package/src/components/DataTable/core/DataManager.ts +188 -0
- package/src/components/DataTable/core/DataTableContext.tsx +181 -0
- package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
- package/src/components/DataTable/core/PluginRegistry.ts +229 -0
- package/src/components/DataTable/core/StateManager.ts +311 -0
- package/src/components/DataTable/core/interfaces.ts +338 -0
- package/src/components/DataTable/styles.ts +27 -6
- package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
- package/src/components/DataTable/utils/columnUtils.ts +40 -0
- package/src/components/DataTable/utils/debugTools.ts +609 -0
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/Dialog/README.md +804 -0
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
- package/src/components/Dialog/utils/safeHtml.ts +185 -0
- package/src/components/Footer/Footer.test.tsx +1 -1
- package/src/components/Form/Form.test.tsx +1 -1
- package/src/components/Form/FormErrorSummary.tsx +113 -0
- package/src/components/Form/FormFieldset.tsx +127 -0
- package/src/components/Form/FormLiveRegion.tsx +198 -0
- package/src/components/LoginForm/LoginForm.test.tsx +1 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +597 -0
- package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
- package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +20 -8
- package/src/components/Table/__tests__/Table.test.tsx +1 -1
- package/src/components/index.ts +3 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
- package/src/index.ts +4 -0
- package/src/rbac/hooks/useCan.test.ts +24 -0
- package/src/rbac/hooks/usePermissions.ts +49 -12
- package/src/styles/core.css +3 -0
- package/src/utils/appConfig.ts +47 -0
- package/src/utils/appIdResolver.test.ts +499 -0
- package/src/utils/appIdResolver.ts +130 -0
- package/src/utils/appNameResolver.simple.test.ts +212 -0
- package/src/utils/appNameResolver.test.ts +121 -0
- package/src/utils/appNameResolver.ts +191 -0
- package/src/utils/audit.ts +127 -0
- package/src/utils/auth-utils.ts +96 -0
- package/src/utils/bundleAnalysis.ts +129 -0
- package/src/utils/cn.ts +7 -0
- package/src/utils/debugLogger.ts +67 -0
- package/src/utils/deviceFingerprint.ts +215 -0
- package/src/utils/dynamicUtils.ts +105 -0
- package/src/utils/file-reference.test.ts +788 -0
- package/src/utils/file-reference.ts +519 -0
- package/src/utils/formatDate.test.ts +237 -0
- package/src/utils/formatting.ts +133 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/lazyLoad.tsx +44 -0
- package/src/utils/logger.ts +179 -0
- package/src/utils/organisationContext.test.ts +322 -0
- package/src/utils/organisationContext.ts +153 -0
- package/src/utils/performanceBenchmark.ts +64 -0
- package/src/utils/performanceBudgets.ts +110 -0
- package/src/utils/permissionTypes.ts +37 -0
- package/src/utils/permissionUtils.test.ts +393 -0
- package/src/utils/permissionUtils.ts +34 -0
- package/src/utils/sanitization.ts +264 -0
- package/src/utils/schemaUtils.ts +37 -0
- package/src/utils/secureDataAccess.test.ts +711 -0
- package/src/utils/secureDataAccess.ts +377 -0
- package/src/utils/secureErrors.ts +79 -0
- package/src/utils/secureStorage.ts +244 -0
- package/src/utils/security.ts +156 -0
- package/src/utils/securityMonitor.ts +45 -0
- package/src/utils/sessionTracking.ts +126 -0
- package/src/utils/validation.ts +111 -0
- package/src/utils/validationUtils.ts +120 -0
- package/src/validation/index.ts +2 -2
- package/dist/chunk-444EZN6N.js.map +0 -1
- package/dist/chunk-APIBCTL2.js +0 -670
- package/dist/chunk-APIBCTL2.js.map +0 -1
- package/dist/chunk-HJGGOMQ6.js.map +0 -1
- package/dist/chunk-K2WWTH7O.js +0 -94
- package/dist/chunk-K2WWTH7O.js.map +0 -1
- package/dist/chunk-L6PGMCMD.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-NOHEVYVX.js.map +0 -1
- package/dist/chunk-TVYPTYOY.js.map +0 -1
- package/dist/validation-8npbysjg.d.ts +0 -177
- /package/dist/{DataTable-CYOHOX3O.js.map → DataTable-JXFCA2BJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-5E5TUNMS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
- /package/dist/{chunk-YLKIDTUK.js.map → chunk-22WKWKRX.js.map} +0 -0
- /package/dist/{chunk-FHWWBIHA.js.map → chunk-6DXZ6V5Q.js.map} +0 -0
- /package/dist/{chunk-2TWNJ46Y.js.map → chunk-6LAAY47Q.js.map} +0 -0
- /package/dist/{chunk-XARJS7CD.js.map → chunk-INQLMHPF.js.map} +0 -0
- /package/dist/{chunk-SL2YQDR6.js.map → chunk-MA6EPSGZ.js.map} +0 -0
- /package/dist/{chunk-5DPZ5EAT.js.map → chunk-OWAG3GSU.js.map} +0 -0
- /package/dist/{chunk-LTV3XIJJ.js.map → chunk-T6JN6LH6.js.map} +0 -0
- /package/examples/{components → components 2}/DataTable/HierarchicalActionsExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/HierarchicalExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/InitialPageSizeExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/PerformanceExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/index.ts +0 -0
- /package/examples/{components → components 2}/Dialog/BasicHtmlTest.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/DebugHtmlExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/HtmlDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/ScrollableDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/SimpleHtmlTest.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/SmartDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/index.ts +0 -0
- /package/examples/{components → components 2}/index.ts +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Password Reset Form Component
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/PasswordReset
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* A comprehensive password reset form component that handles email-based password recovery
|
|
8
|
+
* with proper validation, loading states, and success feedback.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Email validation and submission
|
|
12
|
+
* - Loading states with disabled form
|
|
13
|
+
* - Success state with confirmation message
|
|
14
|
+
* - Error handling and display
|
|
15
|
+
* - Resend functionality
|
|
16
|
+
* - Accessibility compliant
|
|
17
|
+
* - Responsive design
|
|
18
|
+
* - Integration with UnifiedAuthProvider
|
|
19
|
+
* - Form validation
|
|
20
|
+
* - Success and error callbacks
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* // Basic password reset form
|
|
25
|
+
* <PasswordResetForm
|
|
26
|
+
* onSuccess={() => {
|
|
27
|
+
* toast.success('Password reset email sent!');
|
|
28
|
+
* }}
|
|
29
|
+
* onError={(error) => {
|
|
30
|
+
* toast.error(`Failed to send reset email: ${error.message}`);
|
|
31
|
+
* }}
|
|
32
|
+
* />
|
|
33
|
+
*
|
|
34
|
+
* // Password reset form with custom styling
|
|
35
|
+
* <PasswordResetForm
|
|
36
|
+
* className="max-w-md mx-auto p-6 bg-main-50 rounded-lg shadow-md"
|
|
37
|
+
* onSuccess={() => {
|
|
38
|
+
* console.log('Reset email sent successfully');
|
|
39
|
+
* navigate('/check-email');
|
|
40
|
+
* }}
|
|
41
|
+
* onError={(error) => {
|
|
42
|
+
* console.error('Password reset failed:', error);
|
|
43
|
+
* }}
|
|
44
|
+
* />
|
|
45
|
+
*
|
|
46
|
+
* // Password reset form in a modal
|
|
47
|
+
* <Modal isOpen={showResetForm} onClose={() => setShowResetForm(false)}>
|
|
48
|
+
* <ModalContent>
|
|
49
|
+
* <PasswordResetForm
|
|
50
|
+
* onSuccess={() => {
|
|
51
|
+
* setShowResetForm(false);
|
|
52
|
+
* toast.success('Check your email for reset instructions');
|
|
53
|
+
* }}
|
|
54
|
+
* onError={(error) => {
|
|
55
|
+
* toast.error(error.message);
|
|
56
|
+
* }}
|
|
57
|
+
* />
|
|
58
|
+
* </ModalContent>
|
|
59
|
+
* </Modal>
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @accessibility
|
|
63
|
+
* - WCAG 2.1 AA compliant
|
|
64
|
+
* - Proper form labels and associations
|
|
65
|
+
* - Screen reader friendly error messages
|
|
66
|
+
* - Keyboard navigation support
|
|
67
|
+
* - Focus management
|
|
68
|
+
* - High contrast support
|
|
69
|
+
* - Clear error identification
|
|
70
|
+
* - Role="alert" for error announcements
|
|
71
|
+
*
|
|
72
|
+
* @dependencies
|
|
73
|
+
* - React 18+ - Hooks and state
|
|
74
|
+
* - UnifiedAuthProvider - Authentication context
|
|
75
|
+
* - Button component
|
|
76
|
+
* - Input component
|
|
77
|
+
* - Label component
|
|
78
|
+
* - Tailwind CSS - Styling
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
import React, { useState } from 'react';
|
|
82
|
+
import { Button } from '../Button/Button';
|
|
83
|
+
import { Input } from '../Input/Input';
|
|
84
|
+
import { Label } from '../Label';
|
|
85
|
+
import { cn } from '../../utils/cn';
|
|
86
|
+
import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
|
|
87
|
+
|
|
88
|
+
export interface PasswordResetFormProps {
|
|
89
|
+
onSuccess?: () => void;
|
|
90
|
+
onError?: (error: Error) => void;
|
|
91
|
+
className?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function PasswordResetForm({
|
|
95
|
+
onSuccess,
|
|
96
|
+
onError,
|
|
97
|
+
className
|
|
98
|
+
}: PasswordResetFormProps) {
|
|
99
|
+
const { resetPassword } = useUnifiedAuth();
|
|
100
|
+
const [email, setEmail] = useState('');
|
|
101
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
102
|
+
const [isSuccess, setIsSuccess] = useState(false);
|
|
103
|
+
const [error, setError] = useState<string | null>(null);
|
|
104
|
+
|
|
105
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
|
|
108
|
+
if (!email.trim()) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
setIsLoading(true);
|
|
113
|
+
setError(null);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const { error: resetError } = await resetPassword(email);
|
|
117
|
+
|
|
118
|
+
if (resetError) {
|
|
119
|
+
const errorObj = new Error(resetError.message || 'Failed to send reset email');
|
|
120
|
+
setError(errorObj.message);
|
|
121
|
+
onError?.(errorObj);
|
|
122
|
+
} else {
|
|
123
|
+
setIsSuccess(true);
|
|
124
|
+
onSuccess?.();
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
const errorObj = err instanceof Error ? err : new Error('An unexpected error occurred');
|
|
128
|
+
setError(errorObj.message);
|
|
129
|
+
onError?.(errorObj);
|
|
130
|
+
} finally {
|
|
131
|
+
setIsLoading(false);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleSendAnother = () => {
|
|
136
|
+
setIsSuccess(false);
|
|
137
|
+
setError(null);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
if (isSuccess) {
|
|
141
|
+
return (
|
|
142
|
+
<div className={cn('', className)} role="form">
|
|
143
|
+
<div className="space-y-4 text-center">
|
|
144
|
+
<h2>Check your email</h2>
|
|
145
|
+
<p className="text-sec-600">
|
|
146
|
+
We have sent a password reset link to {email}
|
|
147
|
+
</p>
|
|
148
|
+
<Button
|
|
149
|
+
variant="outline"
|
|
150
|
+
onClick={handleSendAnother}
|
|
151
|
+
className="w-full"
|
|
152
|
+
>
|
|
153
|
+
Send another email
|
|
154
|
+
</Button>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div className={cn('', className)} role="form">
|
|
162
|
+
<div className="space-y-4">
|
|
163
|
+
<div className="space-y-2">
|
|
164
|
+
<h2>Reset Password</h2>
|
|
165
|
+
<p className="text-sec-600">
|
|
166
|
+
Enter your email address and we'll send you a reset link.
|
|
167
|
+
</p>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<form onSubmit={handleSubmit} className="space-y-4">
|
|
171
|
+
<div className="space-y-2">
|
|
172
|
+
<Label htmlFor="email">Email Address</Label>
|
|
173
|
+
<Input
|
|
174
|
+
id="email"
|
|
175
|
+
type="email"
|
|
176
|
+
value={email}
|
|
177
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
178
|
+
placeholder="Enter your email"
|
|
179
|
+
required
|
|
180
|
+
disabled={isLoading}
|
|
181
|
+
/>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
{error && (
|
|
185
|
+
<div className="text-sm text-destructive" role="alert">
|
|
186
|
+
{error}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
|
|
190
|
+
<Button
|
|
191
|
+
type="submit"
|
|
192
|
+
className="w-full"
|
|
193
|
+
disabled={!email.trim() || isLoading}
|
|
194
|
+
>
|
|
195
|
+
{isLoading ? 'Sending...' : 'Send Reset Link'}
|
|
196
|
+
</Button>
|
|
197
|
+
</form>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Public Page Debugger
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/PublicLayout
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* A debugging component that helps identify why authentication context
|
|
8
|
+
* is being triggered in public pages.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { useEffect } from 'react';
|
|
12
|
+
import { usePublicPageContext } from './PublicPageProvider';
|
|
13
|
+
|
|
14
|
+
export interface PublicPageDebuggerProps {
|
|
15
|
+
/** Whether to enable debugging */
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
/** Custom label for this debugger instance */
|
|
18
|
+
label?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Debugger component that logs context information
|
|
23
|
+
*
|
|
24
|
+
* This component helps identify why authentication context
|
|
25
|
+
* is being triggered in public pages.
|
|
26
|
+
*/
|
|
27
|
+
export function PublicPageDebugger({ enabled = true, label = 'PublicPage' }: PublicPageDebuggerProps) {
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!enabled) return;
|
|
30
|
+
|
|
31
|
+
console.log(`[${label}] Component mounted`);
|
|
32
|
+
|
|
33
|
+
// Check if we're in a public page context
|
|
34
|
+
try {
|
|
35
|
+
// This will throw if we're not in PublicPageProvider
|
|
36
|
+
const { isPublicPage } = usePublicPageContext();
|
|
37
|
+
console.log(`[${label}] Public page context detected:`, isPublicPage);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.warn(`[${label}] Not in PublicPageProvider context:`, error instanceof Error ? error.message : String(error));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Check for authentication context
|
|
43
|
+
try {
|
|
44
|
+
// This will throw if we're not in UnifiedAuthProvider
|
|
45
|
+
const { isAuthenticated } = require('../../providers/UnifiedAuthProvider').useUnifiedAuth();
|
|
46
|
+
console.warn(`[${label}] AUTHENTICATION CONTEXT DETECTED! This should not happen in public pages.`);
|
|
47
|
+
console.warn(`[${label}] isAuthenticated:`, isAuthenticated);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.log(`[${label}] No authentication context detected (good for public pages)`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check for organisation context
|
|
53
|
+
try {
|
|
54
|
+
// This will throw if we're not in OrganisationProvider
|
|
55
|
+
const { selectedOrganisation } = require('../../providers/OrganisationProvider').useOrganisations();
|
|
56
|
+
console.warn(`[${label}] ORGANISATION CONTEXT DETECTED! This should not happen in public pages.`);
|
|
57
|
+
console.warn(`[${label}] selectedOrganisation:`, selectedOrganisation);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.log(`[${label}] No organisation context detected (good for public pages)`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check for event context
|
|
63
|
+
try {
|
|
64
|
+
// This will throw if we're not in EventProvider
|
|
65
|
+
const { events } = require('../../providers/EventProvider').useEvents();
|
|
66
|
+
console.warn(`[${label}] EVENT CONTEXT DETECTED! This should not happen in public pages.`);
|
|
67
|
+
console.warn(`[${label}] events:`, events);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.log(`[${label}] No event context detected (good for public pages)`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check environment variables
|
|
73
|
+
const supabaseUrl = (import.meta as any).env?.VITE_SUPABASE_URL;
|
|
74
|
+
const supabaseKey = (import.meta as any).env?.VITE_SUPABASE_ANON_KEY;
|
|
75
|
+
|
|
76
|
+
console.log(`[${label}] Environment variables:`, {
|
|
77
|
+
supabaseUrl: supabaseUrl ? 'Present' : 'Missing',
|
|
78
|
+
supabaseKey: supabaseKey ? 'Present' : 'Missing'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return () => {
|
|
82
|
+
console.log(`[${label}] Component unmounted`);
|
|
83
|
+
};
|
|
84
|
+
}, [enabled, label]);
|
|
85
|
+
|
|
86
|
+
if (!enabled) return null;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div style={{
|
|
90
|
+
position: 'fixed',
|
|
91
|
+
top: 0,
|
|
92
|
+
right: 0,
|
|
93
|
+
background: 'rgba(0,0,0,0.8)',
|
|
94
|
+
color: 'white',
|
|
95
|
+
padding: '8px',
|
|
96
|
+
fontSize: '12px',
|
|
97
|
+
zIndex: 9999,
|
|
98
|
+
fontFamily: 'monospace'
|
|
99
|
+
}}>
|
|
100
|
+
<div>Public Page Debugger</div>
|
|
101
|
+
<div>Check console for context analysis</div>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Public Page Diagnostic Component
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/PublicLayout
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* A diagnostic component that helps identify exactly where authentication
|
|
8
|
+
* context is being triggered in public pages.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { useEffect, useState } from 'react';
|
|
12
|
+
import { usePublicPageContext } from './PublicPageProvider';
|
|
13
|
+
|
|
14
|
+
export interface PublicPageDiagnosticProps {
|
|
15
|
+
/** Whether to enable diagnostics */
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
/** Custom label for this diagnostic instance */
|
|
18
|
+
label?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Diagnostic component that identifies authentication context issues
|
|
23
|
+
*
|
|
24
|
+
* This component will help you identify exactly where the problem is
|
|
25
|
+
* in your public page implementation.
|
|
26
|
+
*/
|
|
27
|
+
export function PublicPageDiagnostic({ enabled = true, label = 'PublicPage' }: PublicPageDiagnosticProps) {
|
|
28
|
+
const [diagnostics, setDiagnostics] = useState<{
|
|
29
|
+
hasPublicPageContext: boolean;
|
|
30
|
+
hasAuthContext: boolean;
|
|
31
|
+
hasOrgContext: boolean;
|
|
32
|
+
hasEventContext: boolean;
|
|
33
|
+
hasEnvironmentVars: boolean;
|
|
34
|
+
routeParams: any;
|
|
35
|
+
}>({
|
|
36
|
+
hasPublicPageContext: false,
|
|
37
|
+
hasAuthContext: false,
|
|
38
|
+
hasOrgContext: false,
|
|
39
|
+
hasEventContext: false,
|
|
40
|
+
hasEnvironmentVars: false,
|
|
41
|
+
routeParams: null
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!enabled) return;
|
|
46
|
+
|
|
47
|
+
const runDiagnostics = () => {
|
|
48
|
+
const newDiagnostics = {
|
|
49
|
+
hasPublicPageContext: false,
|
|
50
|
+
hasAuthContext: false,
|
|
51
|
+
hasOrgContext: false,
|
|
52
|
+
hasEventContext: false,
|
|
53
|
+
hasEnvironmentVars: false,
|
|
54
|
+
routeParams: null
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Check for PublicPageProvider context
|
|
58
|
+
try {
|
|
59
|
+
const { isPublicPage } = usePublicPageContext();
|
|
60
|
+
newDiagnostics.hasPublicPageContext = isPublicPage === true;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
newDiagnostics.hasPublicPageContext = false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check for authentication context
|
|
66
|
+
try {
|
|
67
|
+
const { isAuthenticated } = require('../../providers/UnifiedAuthProvider').useUnifiedAuth();
|
|
68
|
+
newDiagnostics.hasAuthContext = true;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
newDiagnostics.hasAuthContext = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check for organisation context
|
|
74
|
+
try {
|
|
75
|
+
const { selectedOrganisation } = require('../../providers/OrganisationProvider').useOrganisations();
|
|
76
|
+
newDiagnostics.hasOrgContext = true;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
newDiagnostics.hasOrgContext = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check for event context
|
|
82
|
+
try {
|
|
83
|
+
const { events } = require('../../providers/EventProvider').useEvents();
|
|
84
|
+
newDiagnostics.hasEventContext = true;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
newDiagnostics.hasEventContext = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check environment variables
|
|
90
|
+
const supabaseUrl = (import.meta as any).env?.VITE_SUPABASE_URL;
|
|
91
|
+
const supabaseKey = (import.meta as any).env?.VITE_SUPABASE_ANON_KEY;
|
|
92
|
+
newDiagnostics.hasEnvironmentVars = !!(supabaseUrl && supabaseKey);
|
|
93
|
+
|
|
94
|
+
// Check route parameters
|
|
95
|
+
try {
|
|
96
|
+
const { useParams } = require('react-router-dom');
|
|
97
|
+
const params = useParams();
|
|
98
|
+
newDiagnostics.routeParams = params;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
newDiagnostics.routeParams = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setDiagnostics(newDiagnostics);
|
|
104
|
+
|
|
105
|
+
// Log results
|
|
106
|
+
console.group(`🔍 [${label}] Public Page Diagnostics`);
|
|
107
|
+
console.log('✅ Public Page Context:', newDiagnostics.hasPublicPageContext ? 'PRESENT' : 'MISSING');
|
|
108
|
+
console.log('❌ Auth Context:', newDiagnostics.hasAuthContext ? 'PRESENT (BAD!)' : 'ABSENT (GOOD!)');
|
|
109
|
+
console.log('❌ Org Context:', newDiagnostics.hasOrgContext ? 'PRESENT (BAD!)' : 'ABSENT (GOOD!)');
|
|
110
|
+
console.log('❌ Event Context:', newDiagnostics.hasEventContext ? 'PRESENT (BAD!)' : 'ABSENT (GOOD!)');
|
|
111
|
+
console.log('✅ Environment Vars:', newDiagnostics.hasEnvironmentVars ? 'PRESENT' : 'MISSING');
|
|
112
|
+
console.log('✅ Route Params:', newDiagnostics.routeParams);
|
|
113
|
+
console.groupEnd();
|
|
114
|
+
|
|
115
|
+
// Provide specific guidance
|
|
116
|
+
if (newDiagnostics.hasAuthContext || newDiagnostics.hasOrgContext || newDiagnostics.hasEventContext) {
|
|
117
|
+
console.error(`🚨 [${label}] PROBLEM DETECTED: Public page is inside authentication context!`);
|
|
118
|
+
console.error('🔧 SOLUTION: Move public routes outside of UnifiedAuthProvider, OrganisationProvider, and EventProvider');
|
|
119
|
+
console.error('📖 See: packages/core/docs/emergency-public-pages-fix.md');
|
|
120
|
+
} else if (!newDiagnostics.hasPublicPageContext) {
|
|
121
|
+
console.warn(`⚠️ [${label}] WARNING: Not in PublicPageProvider context`);
|
|
122
|
+
console.warn('🔧 SOLUTION: Wrap your public page component in <PublicPageProvider>');
|
|
123
|
+
} else if (!newDiagnostics.hasEnvironmentVars) {
|
|
124
|
+
console.warn(`⚠️ [${label}] WARNING: Missing environment variables`);
|
|
125
|
+
console.warn('🔧 SOLUTION: Set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in your environment');
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`✅ [${label}] All diagnostics passed! Public page should work correctly.`);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
runDiagnostics();
|
|
132
|
+
}, [enabled, label]);
|
|
133
|
+
|
|
134
|
+
if (!enabled) return null;
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<div style={{
|
|
138
|
+
position: 'fixed',
|
|
139
|
+
top: 0,
|
|
140
|
+
left: 0,
|
|
141
|
+
background: 'rgba(0,0,0,0.9)',
|
|
142
|
+
color: 'white',
|
|
143
|
+
padding: '12px',
|
|
144
|
+
fontSize: '11px',
|
|
145
|
+
zIndex: 9999,
|
|
146
|
+
fontFamily: 'monospace',
|
|
147
|
+
maxWidth: '300px',
|
|
148
|
+
borderRadius: '0 0 8px 0'
|
|
149
|
+
}}>
|
|
150
|
+
<div style={{ fontWeight: 'bold', marginBottom: '8px' }}>🔍 Public Page Diagnostics</div>
|
|
151
|
+
<div>Public Context: {diagnostics.hasPublicPageContext ? '✅' : '❌'}</div>
|
|
152
|
+
<div>Auth Context: {diagnostics.hasAuthContext ? '❌ BAD' : '✅ GOOD'}</div>
|
|
153
|
+
<div>Org Context: {diagnostics.hasOrgContext ? '❌ BAD' : '✅ GOOD'}</div>
|
|
154
|
+
<div>Event Context: {diagnostics.hasEventContext ? '❌ BAD' : '✅ GOOD'}</div>
|
|
155
|
+
<div>Env Vars: {diagnostics.hasEnvironmentVars ? '✅' : '❌'}</div>
|
|
156
|
+
<div>Route Params: {diagnostics.routeParams ? '✅' : '❌'}</div>
|
|
157
|
+
<div style={{ marginTop: '8px', fontSize: '10px', opacity: 0.8 }}>
|
|
158
|
+
Check console for detailed analysis
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
@@ -12,7 +12,7 @@ import { PublicPageFooter } from '../PublicPageFooter';
|
|
|
12
12
|
import type { Event } from '../../../types/unified';
|
|
13
13
|
|
|
14
14
|
// Mock the cn utility
|
|
15
|
-
vi.mock('../../../utils/cn', () => ({
|
|
15
|
+
vi.mock('../../../utils/core/cn', () => ({
|
|
16
16
|
cn: vi.fn((...classes) => classes.filter(Boolean).join(' '))
|
|
17
17
|
}));
|
|
18
18
|
|
|
@@ -33,11 +33,13 @@ export interface SelectContextValue extends SelectState {
|
|
|
33
33
|
actions: SelectActions;
|
|
34
34
|
registerItem?: (value: string, text: string) => void;
|
|
35
35
|
unregisterItem?: (value: string) => void;
|
|
36
|
+
direction?: 'up' | 'down';
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export interface SelectProps extends Omit<React.HTMLAttributes<HTMLFormElement>, 'onChange' | 'onKeyDown' | 'onFocus' | 'onBlur'> {
|
|
39
40
|
children: React.ReactNode;
|
|
40
41
|
className?: string;
|
|
42
|
+
direction?: 'up' | 'down';
|
|
41
43
|
// State props are in UseSelectStateProps (via & intersection)
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -168,6 +170,7 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
|
|
|
168
170
|
({
|
|
169
171
|
children,
|
|
170
172
|
className,
|
|
173
|
+
direction = 'down',
|
|
171
174
|
...selectProps
|
|
172
175
|
}, ref) => {
|
|
173
176
|
const internalRef = React.useRef<HTMLFormElement>(null);
|
|
@@ -317,7 +320,8 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
|
|
|
317
320
|
actions,
|
|
318
321
|
registerItem,
|
|
319
322
|
unregisterItem,
|
|
320
|
-
|
|
323
|
+
direction,
|
|
324
|
+
}), [state, actions, registerItem, unregisterItem, direction]);
|
|
321
325
|
|
|
322
326
|
return (
|
|
323
327
|
<form
|
|
@@ -341,7 +345,8 @@ Select.displayName = "Select";
|
|
|
341
345
|
|
|
342
346
|
export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
343
347
|
({ children, className, variant = "outline", size = "default", asChild = false, ...props }, ref) => {
|
|
344
|
-
const { open, disabled, value, actions } = useSelectContext();
|
|
348
|
+
const { open, disabled, value, actions, direction = 'down' } = useSelectContext();
|
|
349
|
+
const opensUpward = direction === 'up';
|
|
345
350
|
|
|
346
351
|
const handleClick = () => {
|
|
347
352
|
actions.setOpen(!open);
|
|
@@ -377,7 +382,8 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
|
|
|
377
382
|
className: cn(
|
|
378
383
|
"!justify-between relative w-full",
|
|
379
384
|
"[&_svg]:pointer-events-none",
|
|
380
|
-
open && "!rounded-b-none !border-b-0",
|
|
385
|
+
open && !opensUpward && "!rounded-b-none !border-b-0",
|
|
386
|
+
open && opensUpward && "!rounded-t-none !border-t-0",
|
|
381
387
|
className
|
|
382
388
|
),
|
|
383
389
|
style: {
|
|
@@ -438,7 +444,8 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
|
|
|
438
444
|
className={cn(
|
|
439
445
|
"!justify-between relative w-full",
|
|
440
446
|
"[&_svg]:pointer-events-none",
|
|
441
|
-
open && "!rounded-b-none !border-b-0",
|
|
447
|
+
open && !opensUpward && "!rounded-b-none !border-b-0",
|
|
448
|
+
open && opensUpward && "!rounded-t-none !border-t-0",
|
|
442
449
|
className
|
|
443
450
|
)}
|
|
444
451
|
style={{
|
|
@@ -493,10 +500,10 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
|
|
|
493
500
|
className,
|
|
494
501
|
searchable = false,
|
|
495
502
|
searchPlaceholder = "Search...",
|
|
496
|
-
maxHeight = "20rem",
|
|
503
|
+
maxHeight = "max(20rem, 50vh)",
|
|
497
504
|
style
|
|
498
505
|
}, ref) => {
|
|
499
|
-
const { open, actions } = useSelectContext();
|
|
506
|
+
const { open, actions, direction = 'down' } = useSelectContext();
|
|
500
507
|
const { searchTerm, setSearchTerm, filteredChildren, searchInputRef } = useSelectSearch({
|
|
501
508
|
children,
|
|
502
509
|
searchable,
|
|
@@ -525,16 +532,21 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
|
|
|
525
532
|
);
|
|
526
533
|
}
|
|
527
534
|
|
|
535
|
+
const opensUpward = direction === 'up';
|
|
536
|
+
|
|
528
537
|
return (
|
|
529
538
|
<ul
|
|
530
539
|
ref={ref}
|
|
531
540
|
className={cn(
|
|
532
|
-
"absolute z-[99999] w-full overflow-y-auto
|
|
541
|
+
"absolute z-[99999] w-full overflow-y-auto border border-main-300 bg-main-50 shadow-lg",
|
|
533
542
|
"list-none p-0 m-0",
|
|
543
|
+
opensUpward
|
|
544
|
+
? "rounded-t-md border-b-0"
|
|
545
|
+
: "rounded-b-md border-t-0",
|
|
534
546
|
className
|
|
535
547
|
)}
|
|
536
548
|
style={{
|
|
537
|
-
top: '100%',
|
|
549
|
+
[opensUpward ? 'bottom' : 'top']: '100%',
|
|
538
550
|
left: 0,
|
|
539
551
|
right: 0,
|
|
540
552
|
maxHeight,
|
package/src/components/index.ts
CHANGED
|
@@ -49,6 +49,9 @@ export type { LabelProps } from './Label';
|
|
|
49
49
|
export { Alert, AlertTitle, AlertDescription } from './Alert';
|
|
50
50
|
export { Avatar, AvatarImage, AvatarFallback } from './Avatar';
|
|
51
51
|
|
|
52
|
+
export { Badge } from './Badge';
|
|
53
|
+
export type { BadgeProps, BadgeVariant } from './Badge';
|
|
54
|
+
|
|
52
55
|
export { Checkbox } from './Checkbox';
|
|
53
56
|
export { Switch } from './Switch';
|
|
54
57
|
export type { SwitchProps } from './Switch';
|