@stack-spot/portal-layout 0.0.64 → 1.0.0-dev.1768482785050
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 +779 -0
- package/dist/Layout.d.ts +60 -8
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +59 -24
- package/dist/Layout.js.map +1 -1
- package/dist/LayoutOverlayManager.d.ts +274 -19
- package/dist/LayoutOverlayManager.d.ts.map +1 -1
- package/dist/LayoutOverlayManager.js +373 -82
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/WelcomeTour.d.ts +2 -0
- package/dist/WelcomeTour.d.ts.map +1 -0
- package/dist/WelcomeTour.js +8 -0
- package/dist/WelcomeTour.js.map +1 -0
- package/dist/components/Backdrop.d.ts +75 -0
- package/dist/components/Backdrop.d.ts.map +1 -0
- package/dist/components/Backdrop.js +69 -0
- package/dist/components/Backdrop.js.map +1 -0
- package/dist/components/Contact/show-contact-modal.d.ts +5 -0
- package/dist/components/Contact/show-contact-modal.d.ts.map +1 -0
- package/dist/components/Contact/show-contact-modal.js +37 -0
- package/dist/components/Contact/show-contact-modal.js.map +1 -0
- package/dist/components/ContactModal.d.ts +1 -0
- package/dist/components/ContactModal.d.ts.map +1 -0
- package/dist/components/ContactModal.js +2 -0
- package/dist/components/ContactModal.js.map +1 -0
- package/dist/components/Dialog.d.ts +54 -7
- package/dist/components/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog.js +8 -2
- package/dist/components/Dialog.js.map +1 -1
- package/dist/components/Header.d.ts +38 -2
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +9 -4
- package/dist/components/Header.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationPanel.d.ts +3 -0
- package/dist/components/NotificationCenter/NotificationPanel.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanel.js +19 -0
- package/dist/components/NotificationCenter/NotificationPanel.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts +3 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.js +16 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts +4 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.js +12 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.js.map +1 -0
- package/dist/components/NotificationCenter/dictionary.d.ts +2 -0
- package/dist/components/NotificationCenter/dictionary.d.ts.map +1 -0
- package/dist/components/NotificationCenter/dictionary.js +43 -0
- package/dist/components/NotificationCenter/dictionary.js.map +1 -0
- package/dist/components/NotificationCenter/index.d.ts +2 -0
- package/dist/components/NotificationCenter/index.d.ts.map +1 -0
- package/dist/components/NotificationCenter/index.js +34 -0
- package/dist/components/NotificationCenter/index.js.map +1 -0
- package/dist/components/NotificationCenter/styled.d.ts +3 -0
- package/dist/components/NotificationCenter/styled.d.ts.map +1 -0
- package/dist/components/NotificationCenter/styled.js +74 -0
- package/dist/components/NotificationCenter/styled.js.map +1 -0
- package/dist/components/NotificationCenter/types.d.ts +21 -0
- package/dist/components/NotificationCenter/types.d.ts.map +1 -0
- package/dist/components/NotificationCenter/types.js.map +1 -0
- package/dist/components/NotificationCenter/utils.d.ts +5 -0
- package/dist/components/NotificationCenter/utils.d.ts.map +1 -0
- package/dist/components/NotificationCenter/utils.js +18 -0
- package/dist/components/NotificationCenter/utils.js.map +1 -0
- package/dist/components/OverlayContent.d.ts +27 -1
- package/dist/components/OverlayContent.d.ts.map +1 -1
- package/dist/components/OverlayContent.js +8 -4
- package/dist/components/OverlayContent.js.map +1 -1
- package/dist/components/PortalSwitcher.d.ts +19 -1
- package/dist/components/PortalSwitcher.d.ts.map +1 -1
- package/dist/components/PortalSwitcher.js +16 -31
- package/dist/components/PortalSwitcher.js.map +1 -1
- package/dist/components/PrivacyPolicyMessage/hooks.d.ts +10 -0
- package/dist/components/PrivacyPolicyMessage/hooks.d.ts.map +1 -0
- package/dist/components/PrivacyPolicyMessage/hooks.js +33 -0
- package/dist/components/PrivacyPolicyMessage/hooks.js.map +1 -0
- package/dist/components/PrivacyPolicyMessage/index.d.ts +7 -0
- package/dist/components/PrivacyPolicyMessage/index.d.ts.map +1 -0
- package/dist/components/PrivacyPolicyMessage/index.js +5 -0
- package/dist/components/PrivacyPolicyMessage/index.js.map +1 -0
- package/dist/components/Rate/FeedbackModal.d.ts +8 -0
- package/dist/components/Rate/FeedbackModal.d.ts.map +1 -0
- package/dist/components/Rate/FeedbackModal.js +52 -0
- package/dist/components/Rate/FeedbackModal.js.map +1 -0
- package/dist/components/Rate/hook.d.ts +3 -0
- package/dist/components/Rate/hook.d.ts.map +1 -0
- package/dist/components/Rate/hook.js +48 -0
- package/dist/components/Rate/hook.js.map +1 -0
- package/dist/components/Rate/index.d.ts +10 -0
- package/dist/components/Rate/index.d.ts.map +1 -0
- package/dist/components/Rate/index.js +16 -0
- package/dist/components/Rate/index.js.map +1 -0
- package/dist/components/Rate/on-nps-submit.d.ts +7 -0
- package/dist/components/Rate/on-nps-submit.d.ts.map +1 -0
- package/dist/components/Rate/on-nps-submit.js +8 -0
- package/dist/components/Rate/on-nps-submit.js.map +1 -0
- package/dist/components/Rate/show-rate-us-modals.d.ts +17 -0
- package/dist/components/Rate/show-rate-us-modals.d.ts.map +1 -0
- package/dist/components/Rate/show-rate-us-modals.js +14 -0
- package/dist/components/Rate/show-rate-us-modals.js.map +1 -0
- package/dist/components/Rate/utils.d.ts +2 -0
- package/dist/components/Rate/utils.d.ts.map +1 -0
- package/dist/components/Rate/utils.js +10 -0
- package/dist/components/Rate/utils.js.map +1 -0
- package/dist/components/Toaster.d.ts +35 -0
- package/dist/components/Toaster.d.ts.map +1 -1
- package/dist/components/Toaster.js +32 -4
- package/dist/components/Toaster.js.map +1 -1
- package/dist/components/TypeForm/hook.d.ts +2 -0
- package/dist/components/TypeForm/hook.d.ts.map +1 -0
- package/dist/components/TypeForm/hook.js +11 -0
- package/dist/components/TypeForm/hook.js.map +1 -0
- package/dist/components/TypeForm/index.d.ts +6 -0
- package/dist/components/TypeForm/index.d.ts.map +1 -0
- package/dist/components/TypeForm/index.js +23 -0
- package/dist/components/TypeForm/index.js.map +1 -0
- package/dist/components/TypeForm/show-typeform-modal.d.ts +5 -0
- package/dist/components/TypeForm/show-typeform-modal.d.ts.map +1 -0
- package/dist/components/TypeForm/show-typeform-modal.js +11 -0
- package/dist/components/TypeForm/show-typeform-modal.js.map +1 -0
- package/dist/components/TypeForm/utils.d.ts +2 -0
- package/dist/components/TypeForm/utils.d.ts.map +1 -0
- package/dist/components/TypeForm/utils.js +9 -0
- package/dist/components/TypeForm/utils.js.map +1 -0
- package/dist/components/UserMenu.d.ts +19 -2
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +12 -6
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +25 -4
- package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/ErrorBoundary.js +10 -1
- package/dist/components/error/ErrorBoundary.js.map +1 -1
- package/dist/components/error/ErrorManager.d.ts +22 -6
- package/dist/components/error/ErrorManager.d.ts.map +1 -1
- package/dist/components/error/ErrorManager.js +21 -1
- package/dist/components/error/ErrorManager.js.map +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +26 -5
- package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/SilentErrorBoundary.js +10 -0
- package/dist/components/error/SilentErrorBoundary.js.map +1 -1
- package/dist/components/menu/MenuContent.d.ts +20 -547
- package/dist/components/menu/MenuContent.d.ts.map +1 -1
- package/dist/components/menu/MenuContent.js +89 -88
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSectionGroup.d.ts +2 -0
- package/dist/components/menu/MenuSectionGroup.d.ts.map +1 -0
- package/dist/components/menu/MenuSectionGroup.js +121 -0
- package/dist/components/menu/MenuSectionGroup.js.map +1 -0
- package/dist/components/menu/MenuSections.d.ts +17 -0
- package/dist/components/menu/MenuSections.d.ts.map +1 -1
- package/dist/components/menu/MenuSections.js +159 -39
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +5 -0
- package/dist/components/menu/PageSelector.d.ts.map +1 -1
- package/dist/components/menu/PageSelector.js +9 -4
- package/dist/components/menu/PageSelector.js.map +1 -1
- package/dist/components/menu/types.d.ts +219 -8
- package/dist/components/menu/types.d.ts.map +1 -1
- package/dist/components/tour/StepContainer.d.ts +37 -0
- package/dist/components/tour/StepContainer.d.ts.map +1 -0
- package/dist/components/tour/StepContainer.js +51 -0
- package/dist/components/tour/StepContainer.js.map +1 -0
- package/dist/components/tour/StepNavigation.d.ts +29 -0
- package/dist/components/tour/StepNavigation.d.ts.map +1 -0
- package/dist/components/tour/StepNavigation.js +37 -0
- package/dist/components/tour/StepNavigation.js.map +1 -0
- package/dist/components/tour/StepTitle.d.ts +17 -0
- package/dist/components/tour/StepTitle.d.ts.map +1 -0
- package/dist/components/tour/StepTitle.js +10 -0
- package/dist/components/tour/StepTitle.js.map +1 -0
- package/dist/components/tour/hook.d.ts +3 -0
- package/dist/components/tour/hook.d.ts.map +1 -0
- package/dist/components/tour/hook.js +10 -0
- package/dist/components/tour/hook.js.map +1 -0
- package/dist/components/tour/index.d.ts +5 -0
- package/dist/components/tour/index.d.ts.map +1 -0
- package/dist/components/tour/index.js +5 -0
- package/dist/components/tour/index.js.map +1 -0
- package/dist/components/tour/manager.d.ts +34 -0
- package/dist/components/tour/manager.d.ts.map +1 -0
- package/dist/components/tour/manager.js +104 -0
- package/dist/components/tour/manager.js.map +1 -0
- package/dist/components/tour/utils.d.ts +66 -8
- package/dist/components/tour/utils.d.ts.map +1 -1
- package/dist/components/tour/utils.js +57 -45
- package/dist/components/tour/utils.js.map +1 -1
- package/dist/components/user-menu-manager.d.ts +13 -0
- package/dist/components/user-menu-manager.d.ts.map +1 -0
- package/dist/components/user-menu-manager.js +36 -0
- package/dist/components/user-menu-manager.js.map +1 -0
- package/dist/dictionary.d.ts +6 -1
- package/dist/dictionary.d.ts.map +1 -1
- package/dist/dictionary.js +7 -2
- package/dist/dictionary.js.map +1 -1
- package/dist/elements.d.ts +7 -0
- package/dist/elements.d.ts.map +1 -1
- package/dist/elements.js +7 -0
- package/dist/elements.js.map +1 -1
- package/dist/index.d.ts +15 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/layout.css +190 -35
- package/dist/svg/StarFillWithGradient.d.ts +6 -0
- package/dist/svg/StarFillWithGradient.d.ts.map +1 -0
- package/dist/svg/StarFillWithGradient.js +4 -0
- package/dist/svg/StarFillWithGradient.js.map +1 -0
- package/dist/toaster.d.ts +55 -9
- package/dist/toaster.d.ts.map +1 -1
- package/dist/toaster.js +34 -6
- package/dist/toaster.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +6 -69
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +9 -130
- package/dist/utils.js.map +1 -1
- package/package.dev.json +3 -0
- package/package.json +26 -15
- package/package.stg.json +3 -0
- package/readme.md +147 -0
- package/src/Layout.tsx +166 -57
- package/src/LayoutOverlayManager.tsx +499 -85
- package/src/WelcomeTour.tsx +8 -0
- package/src/components/Backdrop.tsx +116 -0
- package/src/components/Contact/show-contact-modal.tsx +71 -0
- package/src/components/Dialog.tsx +58 -9
- package/src/components/Header.tsx +53 -5
- package/src/components/NotificationCenter/NotificationPanel.tsx +40 -0
- package/src/components/NotificationCenter/NotificationPanelHeader.tsx +53 -0
- package/src/components/NotificationCenter/NotificationsPanelFooter.tsx +25 -0
- package/src/components/NotificationCenter/dictionary.ts +44 -0
- package/src/components/NotificationCenter/index.tsx +58 -0
- package/src/components/NotificationCenter/styled.ts +75 -0
- package/src/components/NotificationCenter/types.ts +24 -0
- package/src/components/NotificationCenter/utils.ts +20 -0
- package/src/components/OverlayContent.tsx +40 -5
- package/src/components/PortalSwitcher.tsx +33 -39
- package/src/components/PrivacyPolicyMessage/hooks.tsx +49 -0
- package/src/components/PrivacyPolicyMessage/index.tsx +21 -0
- package/src/components/Rate/FeedbackModal.tsx +86 -0
- package/src/components/Rate/hook.tsx +61 -0
- package/src/components/Rate/index.tsx +36 -0
- package/src/components/Rate/on-nps-submit.ts +18 -0
- package/src/components/Rate/show-rate-us-modals.tsx +29 -0
- package/src/components/Rate/utils.ts +11 -0
- package/src/components/Toaster.tsx +82 -3
- package/src/components/TypeForm/hook.tsx +13 -0
- package/src/components/TypeForm/index.tsx +50 -0
- package/src/components/TypeForm/show-typeform-modal.tsx +10 -0
- package/src/components/TypeForm/utils.ts +8 -0
- package/src/components/UserMenu.tsx +32 -8
- package/src/components/error/ErrorBoundary.tsx +11 -2
- package/src/components/error/ErrorManager.ts +22 -6
- package/src/components/error/SilentErrorBoundary.tsx +12 -2
- package/src/components/menu/MenuContent.tsx +102 -110
- package/src/components/menu/MenuSectionGroup.tsx +121 -0
- package/src/components/menu/MenuSections.tsx +342 -93
- package/src/components/menu/PageSelector.tsx +16 -4
- package/src/components/menu/types.ts +221 -9
- package/src/components/tour/StepContainer.tsx +92 -0
- package/src/components/tour/StepNavigation.tsx +72 -0
- package/src/components/tour/StepTitle.tsx +28 -0
- package/src/components/tour/hook.ts +12 -0
- package/src/components/tour/index.ts +6 -0
- package/src/components/tour/manager.tsx +119 -0
- package/src/components/tour/utils.tsx +119 -0
- package/src/components/user-menu-manager.ts +31 -0
- package/src/dictionary.ts +7 -2
- package/src/elements.ts +7 -0
- package/src/index.ts +15 -8
- package/src/layout.css +190 -35
- package/src/svg/StarFillWithGradient.tsx +14 -0
- package/src/toaster.tsx +90 -13
- package/src/types.ts +4 -0
- package/src/utils.ts +9 -142
- package/dist/components/BottomNotification.d.ts +0 -1
- package/dist/components/BottomNotification.d.ts.map +0 -1
- package/dist/components/BottomNotification.js +0 -2
- package/dist/components/BottomNotification.js.map +0 -1
- package/dist/components/BottomPanel.d.ts +0 -1
- package/dist/components/BottomPanel.d.ts.map +0 -1
- package/dist/components/BottomPanel.js +0 -2
- package/dist/components/BottomPanel.js.map +0 -1
- package/dist/components/SelectionList.d.ts +0 -36
- package/dist/components/SelectionList.d.ts.map +0 -1
- package/dist/components/SelectionList.js +0 -140
- package/dist/components/SelectionList.js.map +0 -1
- package/dist/components/error/ErrorDescriptor.d.ts +0 -12
- package/dist/components/error/ErrorDescriptor.d.ts.map +0 -1
- package/dist/components/error/ErrorDescriptor.js +0 -17
- package/dist/components/error/ErrorDescriptor.js.map +0 -1
- package/dist/components/error/ErrorFeedback.d.ts +0 -3
- package/dist/components/error/ErrorFeedback.d.ts.map +0 -1
- package/dist/components/error/ErrorFeedback.js +0 -66
- package/dist/components/error/ErrorFeedback.js.map +0 -1
- package/dist/components/menu/use-check-text-overflow.d.ts +0 -6
- package/dist/components/menu/use-check-text-overflow.d.ts.map +0 -1
- package/dist/components/menu/use-check-text-overflow.js +0 -20
- package/dist/components/menu/use-check-text-overflow.js.map +0 -1
- package/dist/components/menu/use-keyboard-controls.d.ts +0 -23
- package/dist/components/menu/use-keyboard-controls.d.ts.map +0 -1
- package/dist/components/menu/use-keyboard-controls.js +0 -49
- package/dist/components/menu/use-keyboard-controls.js.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.d.ts +0 -6
- package/dist/components/menu/useCheckTextOverflow.d.ts.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.js +0 -20
- package/dist/components/menu/useCheckTextOverflow.js.map +0 -1
- package/dist/components/tour/Navigation.d.ts +0 -8
- package/dist/components/tour/Navigation.d.ts.map +0 -1
- package/dist/components/tour/Navigation.js +0 -15
- package/dist/components/tour/Navigation.js.map +0 -1
- package/dist/components/tour/PortalSwitcherStep.d.ts +0 -3
- package/dist/components/tour/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/PortalSwitcherStep.js +0 -29
- package/dist/components/tour/PortalSwitcherStep.js.map +0 -1
- package/dist/components/tour/config.d.ts +0 -3
- package/dist/components/tour/config.d.ts.map +0 -1
- package/dist/components/tour/config.js +0 -22
- package/dist/components/tour/config.js.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts +0 -3
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.js +0 -30
- package/dist/components/tour/steps/PortalSwitcherStep.js.map +0 -1
- package/dist/components/types.d.ts +0 -15
- package/dist/components/types.d.ts.map +0 -1
- package/dist/components/types.js.map +0 -1
- package/dist/layout-context.d.ts +0 -10
- package/dist/layout-context.d.ts.map +0 -1
- package/dist/layout-context.js +0 -11
- package/dist/layout-context.js.map +0 -1
- package/dist/svg/AI.d.ts +0 -6
- package/dist/svg/AI.d.ts.map +0 -1
- package/dist/svg/AI.js +0 -9
- package/dist/svg/AI.js.map +0 -1
- package/dist/svg/EDP.d.ts +0 -6
- package/dist/svg/EDP.d.ts.map +0 -1
- package/dist/svg/EDP.js +0 -5
- package/dist/svg/EDP.js.map +0 -1
- package/dist/svg/Forbidden.d.ts +0 -6
- package/dist/svg/Forbidden.d.ts.map +0 -1
- package/dist/svg/Forbidden.js +0 -4
- package/dist/svg/Forbidden.js.map +0 -1
- package/dist/svg/HUB.d.ts +0 -6
- package/dist/svg/HUB.d.ts.map +0 -1
- package/dist/svg/HUB.js +0 -5
- package/dist/svg/HUB.js.map +0 -1
- package/dist/svg/Logo.d.ts +0 -2
- package/dist/svg/Logo.d.ts.map +0 -1
- package/dist/svg/Logo.js +0 -4
- package/dist/svg/Logo.js.map +0 -1
- package/dist/svg/NotFound.d.ts +0 -6
- package/dist/svg/NotFound.d.ts.map +0 -1
- package/dist/svg/NotFound.js +0 -4
- package/dist/svg/NotFound.js.map +0 -1
- package/dist/svg/ServerError.d.ts +0 -6
- package/dist/svg/ServerError.d.ts.map +0 -1
- package/dist/svg/ServerError.js +0 -4
- package/dist/svg/ServerError.js.map +0 -1
- package/dist/svg/Unauthenticated.d.ts +0 -6
- package/dist/svg/Unauthenticated.d.ts.map +0 -1
- package/dist/svg/Unauthenticated.js +0 -4
- package/dist/svg/Unauthenticated.js.map +0 -1
- package/src/components/BottomPanel.tsx +0 -0
- package/src/components/SelectionList.tsx +0 -272
- package/src/components/error/ErrorFeedback.tsx +0 -114
- package/src/components/menu/use-check-text-overflow.tsx +0 -26
- package/src/components/menu/use-keyboard-controls.tsx +0 -70
- package/src/components/tour/PortalSwitcherStep.tsx +0 -36
- package/src/components/types.ts +0 -15
- package/src/layout-context.tsx +0 -22
- package/src/svg/AI.tsx +0 -37
- package/src/svg/EDP.tsx +0 -35
- package/src/svg/Forbidden.tsx +0 -22
- package/src/svg/HUB.tsx +0 -35
- package/src/svg/Logo.tsx +0 -35
- package/src/svg/NotFound.tsx +0 -16
- package/src/svg/ServerError.tsx +0 -33
- package/src/svg/Unauthenticated.tsx +0 -16
- /package/dist/components/{types.js → NotificationCenter/types.js} +0 -0
- /package/src/components/{BottomNotification.tsx → ContactModal.tsx} +0 -0
|
@@ -1,32 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
// todo: remove unused code as soon as this is validated by the design team: "remove overlays on hover".
|
|
3
|
+
import { Box, Flex, IconBox, Text } from '@citric/core'
|
|
4
|
+
import { ChevronUpFill, Cog, Collapse, Expand, Support } from '@citric/icons'
|
|
5
|
+
import { ReactTooltip } from '@citric/ui'
|
|
6
|
+
import { useKeyboardControls } from '@stack-spot/portal-components'
|
|
7
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
8
|
+
import { listToClass } from '@stack-spot/portal-theme'
|
|
9
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
10
|
+
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
5
11
|
import { elementIds, getLayoutElements } from '../../elements'
|
|
6
|
-
import {
|
|
12
|
+
import { StarFillWithGradient } from '../../svg/StarFillWithGradient'
|
|
13
|
+
import { isLessThan30Days } from '../Rate/hook'
|
|
7
14
|
import { MenuContent } from './MenuContent'
|
|
15
|
+
import { MenuSectionGroup } from './MenuSectionGroup'
|
|
8
16
|
import { MenuProps, MenuSection } from './types'
|
|
9
|
-
import { useKeyboardControls } from './use-keyboard-controls'
|
|
10
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Amount of time to wait before hiding the menu overlay once the mouse leaves its area.
|
|
20
|
+
*/
|
|
11
21
|
const HIDE_OVERLAY_DELAY_MS = 400
|
|
12
22
|
const MENU_OVERLAY_ID = 'menuContentOverlay'
|
|
13
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Pointer to the latest "hideOverlay" task. This allows the operation to be cancelled.
|
|
26
|
+
*/
|
|
14
27
|
let hideOverlayTask: number | undefined
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Accessibility. Makes the menu overlay accessible through the keyboard.
|
|
31
|
+
*/
|
|
17
32
|
let attachKeyboardListenersForOverlay: () => void
|
|
33
|
+
/**
|
|
34
|
+
* Accessibility. Makes the menu overlay invisible to the keyboard.
|
|
35
|
+
*/
|
|
18
36
|
let detachKeyboardListenersForOverlay: () => void
|
|
19
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Hides the menu overlay after HIDE_OVERLAY_DELAY_MS. This operation may be canceled.
|
|
40
|
+
*
|
|
41
|
+
* This gives the user some time to move the mouse outside the overlay for while before it disappears. If the user moves the mouse out of
|
|
42
|
+
* the overlay and, before HIDE_OVERLAY_DELAY_MS, moves the mouse back, we want the overlay to keep showing.
|
|
43
|
+
*/
|
|
44
|
+
// @ts-ignore: unused (remove when validated by the design team)
|
|
20
45
|
function hideOverlay() {
|
|
21
46
|
if (hideOverlayTask !== undefined) return
|
|
22
47
|
hideOverlayTask = window.setTimeout(hideOverlayImmediately, HIDE_OVERLAY_DELAY_MS)
|
|
23
48
|
}
|
|
24
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Accessibility. Returns the accessibility button of the section with the preview (overlay) currently active.
|
|
52
|
+
*/
|
|
25
53
|
function getAccessibilityButtonOfSectionWithActiveOverlay(): HTMLElement | null | undefined {
|
|
26
54
|
return document.getElementById(elementIds.menuSections)?.querySelector('button[aria-expanded="true"]')
|
|
27
55
|
}
|
|
28
56
|
|
|
29
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Hides the menu overlay without waiting for anything. This is not cancellable.
|
|
59
|
+
*/
|
|
30
60
|
export function hideOverlayImmediately() {
|
|
31
61
|
detachKeyboardListenersForOverlay?.()
|
|
32
62
|
const overlay = document.getElementById(MENU_OVERLAY_ID)
|
|
@@ -36,12 +66,18 @@ export function hideOverlayImmediately() {
|
|
|
36
66
|
getAccessibilityButtonOfSectionWithActiveOverlay()?.setAttribute('aria-expanded', 'false')
|
|
37
67
|
}
|
|
38
68
|
|
|
69
|
+
/**
|
|
70
|
+
* If `hideOverlay` was called and not fulfilled yet, this cancels the task, preventing the overlay from closing.
|
|
71
|
+
*/
|
|
39
72
|
function cancelHideOverlayTask() {
|
|
40
73
|
if (hideOverlayTask === undefined) return
|
|
41
74
|
clearTimeout(hideOverlayTask)
|
|
42
75
|
hideOverlayTask = undefined
|
|
43
76
|
}
|
|
44
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Shows the menu overlay.
|
|
80
|
+
*/
|
|
45
81
|
function showOverlay() {
|
|
46
82
|
cancelHideOverlayTask()
|
|
47
83
|
const overlay = document.getElementById(MENU_OVERLAY_ID)
|
|
@@ -51,10 +87,23 @@ function showOverlay() {
|
|
|
51
87
|
attachKeyboardListenersForOverlay?.()
|
|
52
88
|
}
|
|
53
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Checks if the menu content (2nd menu list from left to right) is visible or not.
|
|
92
|
+
* The menu content is visible if:
|
|
93
|
+
* 1. The menu is not compact (the button at the end of the section list compacts/expands the menu);
|
|
94
|
+
* 2. If the current section has any menu content.
|
|
95
|
+
*/
|
|
54
96
|
function isMenuContentVisible() {
|
|
55
|
-
return !!document.getElementById(
|
|
97
|
+
return !!document.getElementById(elementIds.layout)?.classList?.contains('menu-content-visible')
|
|
56
98
|
}
|
|
57
99
|
|
|
100
|
+
/**
|
|
101
|
+
* A section in the the menu-sections.
|
|
102
|
+
*
|
|
103
|
+
* A section in the menu is responsible for rendering the section icon, label, accessibility button and controlling the menu overlay.
|
|
104
|
+
* @param props React props for the component {@link MenuSection} & { id, setCurrentOverlay }. Id identifies the current section and
|
|
105
|
+
* setCurrentOverlay controls the overlay (preview) content.
|
|
106
|
+
*/
|
|
58
107
|
const Section = ({
|
|
59
108
|
icon,
|
|
60
109
|
label,
|
|
@@ -64,31 +113,32 @@ const Section = ({
|
|
|
64
113
|
active,
|
|
65
114
|
content,
|
|
66
115
|
customContent,
|
|
67
|
-
onOpen,
|
|
68
116
|
setCurrentOverlay,
|
|
69
117
|
id,
|
|
70
|
-
|
|
71
|
-
className,
|
|
118
|
+
badge,
|
|
72
119
|
}: MenuSection & {
|
|
73
|
-
id: number,
|
|
120
|
+
id: number,
|
|
121
|
+
setCurrentOverlay: (id: number | undefined) => void,
|
|
122
|
+
hasContent: boolean,
|
|
74
123
|
}) => {
|
|
75
124
|
const Link = useAnchorTag()
|
|
125
|
+
// const t = useTranslate(dictionary)
|
|
76
126
|
const contentToRender = typeof content === 'function' ? content() : content
|
|
77
|
-
|
|
127
|
+
|
|
78
128
|
function shouldShowOverlay() {
|
|
79
129
|
/* The overlay should appear if:
|
|
80
|
-
* 1. The menu is compacted showing only the icons
|
|
130
|
+
* 1. The menu is compacted showing only the icons
|
|
81
131
|
* 2. The section has some content to render OR:
|
|
82
|
-
* 3.
|
|
132
|
+
* 3. There is a contextual menu for the active page.
|
|
83
133
|
*/
|
|
84
134
|
const { layout } = getLayoutElements()
|
|
85
135
|
const isCompactedOnlyIcons = layout?.classList.contains('menu-compact')
|
|
86
|
-
return isCompactedOnlyIcons && (!!contentToRender || !!customContent
|
|
136
|
+
return isCompactedOnlyIcons && (!!contentToRender || !!customContent)
|
|
87
137
|
}
|
|
88
138
|
|
|
139
|
+
// @ts-ignore: unused (remove when validated by the design team)
|
|
89
140
|
function prepareShowOverlay(event: React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.KeyboardEvent<any>) {
|
|
90
141
|
if (!shouldShowOverlay()) return
|
|
91
|
-
onOpen?.()
|
|
92
142
|
const anchorElement = event.target as HTMLElement
|
|
93
143
|
const accessibilityButton = anchorElement?.parentElement?.querySelector('button') as HTMLElement
|
|
94
144
|
accessibilityButton?.setAttribute('aria-expanded', 'true')
|
|
@@ -99,94 +149,162 @@ const Section = ({
|
|
|
99
149
|
function click() {
|
|
100
150
|
if (onClick) onClick()
|
|
101
151
|
hideOverlayImmediately()
|
|
152
|
+
const classList = document.getElementById(elementIds.layout)?.classList
|
|
153
|
+
if (!classList) return
|
|
154
|
+
classList.remove('menu-manual')
|
|
102
155
|
}
|
|
103
156
|
|
|
104
157
|
const labelText = typeof label === 'string' ? label : label.id
|
|
105
158
|
|
|
106
159
|
return (
|
|
107
160
|
<>
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
{
|
|
161
|
+
<Link
|
|
162
|
+
href={href}
|
|
163
|
+
target={target}
|
|
164
|
+
onClick={click}
|
|
165
|
+
// onMouseEnter={prepareShowOverlay}
|
|
166
|
+
// onMouseLeave={() => shouldShowOverlay() && hideOverlay()}
|
|
167
|
+
aria-label={labelText}
|
|
168
|
+
onKeyDown={onClick ? e => e.key === 'Enter' && onClick() : undefined}
|
|
169
|
+
{...(active ? { 'aria-current': 'page' } : undefined)}
|
|
170
|
+
{...(!href ? { 'tabIndex': 0 } : undefined)}
|
|
171
|
+
>
|
|
172
|
+
<ReactTooltip
|
|
173
|
+
text={labelText}
|
|
174
|
+
position="right"
|
|
175
|
+
tabIndex={-1}
|
|
176
|
+
target={document.getElementById(elementIds.layout)}
|
|
177
|
+
disableTooltip={() => !document.getElementById(elementIds.layout)}
|
|
178
|
+
sx={{ width: 'inherit' }}
|
|
125
179
|
>
|
|
126
|
-
<Flex alignItems="center" justifyContent="center" px={
|
|
127
|
-
<IconBox
|
|
128
|
-
|
|
180
|
+
<Flex alignItems="center" justifyContent="center" flexWrap="nowrap" px={3} w="100%">
|
|
181
|
+
<IconBox className={badge ? 'section-icon-with-badge' : 'section-icon'}>
|
|
182
|
+
{icon}
|
|
183
|
+
</IconBox>
|
|
184
|
+
<Flex alignItems="center" justifyContent="space-between" w="100%" className="section-text">
|
|
185
|
+
{typeof label === 'string' ? (
|
|
186
|
+
<Text appearance="microtext1" className="section-label" ml={3}>
|
|
187
|
+
{label}
|
|
188
|
+
</Text>
|
|
189
|
+
) : (label.element)}
|
|
190
|
+
{badge && <Box className="section-badge">{badge}</Box>}
|
|
191
|
+
</Flex>
|
|
129
192
|
</Flex>
|
|
130
|
-
</
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
193
|
+
</ReactTooltip>
|
|
194
|
+
</Link>
|
|
195
|
+
{/*shouldShowOverlay() &&
|
|
196
|
+
<IconBox size="sm" className="section-submenu-icon"
|
|
197
|
+
as="button"
|
|
198
|
+
aria-label={interpolate(t.menuOptions, label)}
|
|
199
|
+
aria-controls={MENU_OVERLAY_ID}
|
|
200
|
+
aria-expanded={false}
|
|
201
|
+
onKeyDown={(event) => {
|
|
202
|
+
if (event.key === 'Enter') {
|
|
203
|
+
prepareShowOverlay(event)
|
|
204
|
+
}
|
|
205
|
+
}}>
|
|
206
|
+
<ChevronRight />
|
|
207
|
+
</IconBox>
|
|
208
|
+
*/}
|
|
146
209
|
</>
|
|
147
210
|
)
|
|
148
211
|
}
|
|
149
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Renders the overlay content.
|
|
215
|
+
* @param props the content of the overlay, can be either customized (react component), a config object or a function that creates the
|
|
216
|
+
* config object.
|
|
217
|
+
* @returns the content
|
|
218
|
+
*/
|
|
150
219
|
const OverlayRenderer = ({ content, customContent }: Pick<MenuSection, 'content' | 'customContent'>) => {
|
|
151
220
|
if (customContent) {
|
|
152
|
-
return <div id="custom-selectable-item">
|
|
221
|
+
return <div id="custom-selectable-item">{customContent}</div>
|
|
153
222
|
}
|
|
154
223
|
|
|
155
224
|
const data = typeof content === 'function' ? content() : content
|
|
156
225
|
return <MenuContent {...data} />
|
|
157
226
|
}
|
|
158
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Renders a menu-sections interface.
|
|
230
|
+
*
|
|
231
|
+
* Considering the Stackspot UI, this is the "menu sections", not the "menu content", i.e. it's the first menu from left to right, the
|
|
232
|
+
* one with the icons and section names: the main menu.
|
|
233
|
+
*
|
|
234
|
+
* Attention: each section in the menu is identified by its index. To avoid errors, the array passed to this component must never change.
|
|
235
|
+
* To control whether or not to show an item, use the property `hidden`, instead of adding/removing it to the array. Example of error:
|
|
236
|
+
* start the section menu with 5 items, remove the 5th item and add another item. The previous 5th item and the new 5th items are different,
|
|
237
|
+
* but since we identify the item by its index, the two different sections will be rendered as if they were the same, causing a react hook
|
|
238
|
+
* call order problem.
|
|
239
|
+
*
|
|
240
|
+
* @param props the props for the component {@link MenuProps}.
|
|
241
|
+
*/
|
|
159
242
|
export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
|
|
160
243
|
const Link = useAnchorTag()
|
|
244
|
+
const [showSupport, setShowSupport] = useState(true)
|
|
161
245
|
const t = useTranslate(dictionary)
|
|
162
246
|
// this is a mock state only used to force an update on the component.
|
|
163
247
|
const [_, setUpdate] = useState(0)
|
|
164
248
|
|
|
165
|
-
const toggleMenu = useCallback((
|
|
249
|
+
const toggleMenu = useCallback(() => {
|
|
166
250
|
const layout = document.getElementById('layout')
|
|
167
251
|
if (!layout) return
|
|
168
252
|
if (layout.classList.contains('menu-compact')) {
|
|
169
253
|
layout.classList.remove('menu-compact')
|
|
254
|
+
setShowSupport(true)
|
|
170
255
|
} else {
|
|
171
256
|
layout.classList.add('menu-compact')
|
|
257
|
+
setShowSupport(false)
|
|
172
258
|
}
|
|
173
259
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
layout.classList.remove('menu-content-visible')
|
|
177
|
-
} else {
|
|
178
|
-
layout.classList.add('menu-content-visible')
|
|
179
|
-
}
|
|
180
|
-
}
|
|
260
|
+
layout.classList.add('menu-manual')
|
|
261
|
+
|
|
181
262
|
setUpdate(current => current + 1)
|
|
182
263
|
}, [])
|
|
183
264
|
// the current overlay showing, when the user hovers the section icon. This is the index of the item in the sections array.
|
|
184
265
|
const [currentOverlay, setCurrentOverlay] = useState<number | undefined>()
|
|
185
266
|
|
|
267
|
+
//Custom items don't have overlay.
|
|
268
|
+
const sectionsWithoutCustom = useMemo(() => sections.filter((s) => !s.type), [sections]) as MenuSection[]
|
|
269
|
+
const sectionItemsOverlay = useMemo(
|
|
270
|
+
() => sectionsWithoutCustom.flatMap((s: MenuSection) => 'children' in s ? s.children?.map((c) => c) : s), [sectionsWithoutCustom],
|
|
271
|
+
)
|
|
272
|
+
|
|
186
273
|
const sectionItems = useMemo(
|
|
187
|
-
() => sections.
|
|
188
|
-
|
|
189
|
-
|
|
274
|
+
() => sections.reduce<JSX.Element[]>(
|
|
275
|
+
(result, s, i) => {
|
|
276
|
+
if (s.label === t.contactUs && !showSupport) {
|
|
277
|
+
return result
|
|
278
|
+
}
|
|
279
|
+
if (s.type) {
|
|
280
|
+
return (s.hidden ? result : [
|
|
281
|
+
...result, <Box key={`custom-element-${i}`}
|
|
282
|
+
className={s.className || ''}>
|
|
283
|
+
<Flex alignItems="center" justifyContent="center" flexWrap="nowrap" px={3} w="100%">
|
|
284
|
+
<IconBox className="custom-element-icon section-icon" >{s.icon}</IconBox>
|
|
285
|
+
</Flex>
|
|
286
|
+
<Box className="custom-element">
|
|
287
|
+
{s.children}
|
|
288
|
+
</Box>
|
|
289
|
+
</Box>,
|
|
290
|
+
])
|
|
291
|
+
}
|
|
292
|
+
return (s.hidden ? result : [
|
|
293
|
+
...result,
|
|
294
|
+
<li
|
|
295
|
+
role="menuitem"
|
|
296
|
+
key={s.label as string}
|
|
297
|
+
className={listToClass(['section-submenu', 'no-indentation', s.className || undefined, s.active ? 'active' : undefined])}>
|
|
298
|
+
{'children' in s
|
|
299
|
+
? <CollapsibleSection listItems={sectionItemsOverlay} {...s} setCurrentOverlay={setCurrentOverlay} />
|
|
300
|
+
: <Section key={i} id={sectionItemsOverlay.findIndex((sio) => sio?.label === s.label)}
|
|
301
|
+
{...s} setCurrentOverlay={setCurrentOverlay} hasContent={!!props.content || !!props.customContent} />}
|
|
302
|
+
</li>,
|
|
303
|
+
])
|
|
304
|
+
|
|
305
|
+
}, [],
|
|
306
|
+
),
|
|
307
|
+
[sections, showSupport],
|
|
190
308
|
)
|
|
191
309
|
|
|
192
310
|
function onPressEscape() {
|
|
@@ -194,12 +312,14 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
|
|
|
194
312
|
hideOverlayImmediately()
|
|
195
313
|
}
|
|
196
314
|
|
|
315
|
+
// @ts-ignore: unused (remove when validated by the design team)
|
|
197
316
|
const { keyboardControlledElement: overlayRef, attachKeyboardListeners, detachKeyboardListeners } = useKeyboardControls({
|
|
198
317
|
onPressEscape,
|
|
199
318
|
querySelectors: 'li a.action, #custom-selectable-item button, #custom-selectable-item input',
|
|
200
319
|
})
|
|
201
320
|
|
|
202
|
-
//
|
|
321
|
+
// this only works because we have a single section menu in the site. This workaround was created since the keyboard controls were
|
|
322
|
+
// transformed into a hook. This is not ideal and it would be a good idea to rewrite this code without the need for this.
|
|
203
323
|
attachKeyboardListenersForOverlay = attachKeyboardListeners
|
|
204
324
|
detachKeyboardListenersForOverlay = detachKeyboardListeners
|
|
205
325
|
|
|
@@ -208,63 +328,192 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
|
|
|
208
328
|
Below, the key is of extreme importance. It ensures React will consider every section content to be an entirely different
|
|
209
329
|
component. Without this, React would see the content changing every time a new section is hovered. Since the content might be a
|
|
210
330
|
hook, this would cause some serious problems. */
|
|
331
|
+
// @ts-ignore: unused (remove when validated by the design team)
|
|
211
332
|
function renderMenuOverlay() {
|
|
212
333
|
if (currentOverlay === undefined) return null
|
|
213
|
-
const shouldRenderMenuContentInstead = !isMenuContentVisible() &&
|
|
334
|
+
const shouldRenderMenuContentInstead = !isMenuContentVisible() && sectionItemsOverlay[currentOverlay]?.active &&
|
|
214
335
|
(!!props.content || !!props.customContent)
|
|
215
336
|
return shouldRenderMenuContentInstead
|
|
216
337
|
? <OverlayRenderer key={'contentKey' in props ? props.contentKey : undefined} content={props.content}
|
|
217
338
|
customContent={props.customContent} />
|
|
218
|
-
: <OverlayRenderer key={currentOverlay} content={
|
|
219
|
-
customContent={
|
|
339
|
+
: <OverlayRenderer key={currentOverlay} content={sectionItemsOverlay[currentOverlay]?.content}
|
|
340
|
+
customContent={sectionItemsOverlay[currentOverlay]?.customContent} />
|
|
220
341
|
}
|
|
221
342
|
|
|
222
343
|
return (
|
|
223
344
|
<>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
<Flex
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
345
|
+
<MenuSectionGroup className="open root no-indentation">{sectionItems}</MenuSectionGroup>
|
|
346
|
+
|
|
347
|
+
<Flex alignItems="center">
|
|
348
|
+
<RateAndContactUsItem {...props} showSupport={showSupport} />
|
|
349
|
+
<ReactTooltip
|
|
350
|
+
text={t.toggle}
|
|
351
|
+
position="right"
|
|
352
|
+
tabIndex={-1}
|
|
353
|
+
disableTooltip={() => !document.getElementById(elementIds.layout)}
|
|
354
|
+
target={document.getElementById(elementIds.layout)}
|
|
355
|
+
sx={{ width: 'inherit' }}
|
|
356
|
+
>
|
|
357
|
+
<button aria-label={t.toggle} role="menuitem" className="toggle sections-footer" onClick={toggleMenu}>
|
|
358
|
+
<IconBox>
|
|
359
|
+
<Expand className="expand" />
|
|
360
|
+
<Collapse className="collapse" />
|
|
361
|
+
</IconBox>
|
|
362
|
+
<Text appearance="microtext1" ml={8} className="collapse" colorScheme="light.contrastText">{t.hide}</Text>
|
|
363
|
+
</button>
|
|
364
|
+
</ReactTooltip>
|
|
235
365
|
{(props.settings?.show) &&
|
|
236
|
-
<Link
|
|
366
|
+
<Link
|
|
367
|
+
href={props.settings?.href}
|
|
368
|
+
onClick={props.settings?.onClick}
|
|
237
369
|
className="sections-footer toggle"
|
|
238
|
-
{
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
370
|
+
aria-label={t.settings}
|
|
371
|
+
{...(props.settings.active ? { 'aria-current': 'page' } : undefined)}
|
|
372
|
+
>
|
|
373
|
+
<ReactTooltip
|
|
374
|
+
text={t.settings}
|
|
375
|
+
position="right"
|
|
376
|
+
tabIndex={-1}
|
|
377
|
+
disableTooltip={() => !document.getElementById(elementIds.layout)}
|
|
378
|
+
target={document.getElementById(elementIds.layout)}
|
|
379
|
+
sx={{ width: 'inherit' }}
|
|
380
|
+
>
|
|
381
|
+
<IconBox aria-label={t.settingsIcon}>
|
|
382
|
+
<Cog />
|
|
383
|
+
</IconBox>
|
|
384
|
+
<Text appearance="microtext1" ml={8} className="collapse">{t.settings}</Text>
|
|
385
|
+
</ReactTooltip>
|
|
243
386
|
</Link>
|
|
244
387
|
}
|
|
245
388
|
</Flex>
|
|
246
389
|
|
|
247
|
-
<div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={overlayRef}>
|
|
390
|
+
{/* <div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={overlayRef}>
|
|
248
391
|
{renderMenuOverlay()}
|
|
249
|
-
|
|
250
|
-
|
|
392
|
+
</div> */}
|
|
393
|
+
</>
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const RateAndContactUsItem = ({ showSupport, ...props }: Omit<MenuProps, 'sections'> & { showSupport?: boolean }) => {
|
|
398
|
+
const t = useTranslate(dictionary)
|
|
399
|
+
const alreadyAnswered = localStorage.getItem('RATED_US_IN')
|
|
400
|
+
const hasAnsweredLess30Days = alreadyAnswered ? isLessThan30Days(new Date(+alreadyAnswered), new Date(Date.now())) : false
|
|
401
|
+
const Link = useAnchorTag()
|
|
402
|
+
|
|
403
|
+
//This effect is only used to remove from local storage unused keys from
|
|
404
|
+
//previous rate us and contact us versions. We do not want to fill the users storage
|
|
405
|
+
//with things that are not used anymore.
|
|
406
|
+
useEffect(() => {
|
|
407
|
+
localStorage.removeItem('CONTACT_POPOVER')
|
|
408
|
+
localStorage.removeItem('RATE_POPOVER')
|
|
409
|
+
localStorage.removeItem('viewNpsItem')
|
|
410
|
+
}, [])
|
|
411
|
+
|
|
412
|
+
return <>
|
|
413
|
+
{(props.rateUs?.show && !hasAnsweredLess30Days) &&
|
|
414
|
+
<button role="menuitem" className="toggle sections-footer" onClick={props.rateUs?.onClick}
|
|
415
|
+
{...(props.rateUs.active ? { 'aria-current': 'page' } : undefined)}>
|
|
416
|
+
<IconBox aria-label={t.rateUsIcon} sx={{ paddingTop: '2px' }}>
|
|
417
|
+
<StarFillWithGradient id="svg-icon" className="gradient-svg rotate-icon" />
|
|
418
|
+
</IconBox>
|
|
419
|
+
<Text appearance="microtext1" ml={8} sx={{ marginTop: '3px' }}
|
|
420
|
+
className="collapse gradient grow-shrink" colorScheme="light.contrastText">{t.rateUs}</Text>
|
|
421
|
+
</button>
|
|
422
|
+
}
|
|
423
|
+
{(props.contactUs?.show && showSupport) && (
|
|
424
|
+
<Link href={props.contactUs?.href} className="toggle sections-footer" onClick={props.contactUs?.onClick}
|
|
425
|
+
{...(props.contactUs.active ? { 'aria-current': 'page' } : undefined)} target={props.contactUs?.target}>
|
|
426
|
+
<IconBox aria-label={t.contactIcon}>
|
|
427
|
+
<Support />
|
|
428
|
+
</IconBox>
|
|
429
|
+
<Text appearance="microtext1" ml={8} sx={{ marginTop: '3px' }}
|
|
430
|
+
className="collapse" colorScheme="light.contrastText">{t.contactUs}</Text>
|
|
431
|
+
</Link>
|
|
432
|
+
)}
|
|
433
|
+
</>
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* A menu item that is actually a subgroup and can be collapsed/expanded.
|
|
438
|
+
* @param props the props for the component {@link MenuSectionGroup}.
|
|
439
|
+
*/
|
|
440
|
+
const CollapsibleSection = (
|
|
441
|
+
{ label, open: initialValue, children, icon, setCurrentOverlay, listItems, replaceWithChildrenWhenCollapsed = true }: (
|
|
442
|
+
MenuSection & { setCurrentOverlay: (id: number | undefined) => void, listItems: (MenuSection | undefined)[] }
|
|
443
|
+
)) => {
|
|
444
|
+
const [open, setOpen] = useState(initialValue || false)
|
|
445
|
+
const menuGroupId = `menuGroup${label}`
|
|
446
|
+
const items = useMemo(() => children?.filter(i => !i.hidden).map(
|
|
447
|
+
(c) => (
|
|
448
|
+
<li
|
|
449
|
+
role="menuitem"
|
|
450
|
+
key={c.label as string}
|
|
451
|
+
title={c.label as string}
|
|
452
|
+
className={`section-submenu ${c.className} ${c.active ? 'active' : ''}`}>
|
|
453
|
+
<Section
|
|
454
|
+
id={listItems?.findIndex((item) => item?.label === c.label)} key={c.label as string}
|
|
455
|
+
{...c} hasContent={false} setCurrentOverlay={setCurrentOverlay} />
|
|
456
|
+
</li>
|
|
457
|
+
)), [children])
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<>
|
|
461
|
+
<a
|
|
462
|
+
onClick={() => setOpen(!open)}
|
|
463
|
+
onKeyDown={e => e.key === 'Enter' && setOpen(!open)}
|
|
464
|
+
className={listToClass(['item-row', replaceWithChildrenWhenCollapsed && 'hidden-when-collapsed'])}
|
|
465
|
+
tabIndex={0}
|
|
466
|
+
aria-controls={menuGroupId}
|
|
467
|
+
aria-expanded={open}
|
|
468
|
+
>
|
|
469
|
+
<ReactTooltip
|
|
470
|
+
text={label as string}
|
|
471
|
+
position="right"
|
|
472
|
+
tabIndex={-1}
|
|
473
|
+
target={document.getElementById(elementIds.layout)}
|
|
474
|
+
sx={{ width: 'inherit' }}
|
|
475
|
+
>
|
|
476
|
+
<Flex alignItems="center" px={3} style={{ width: '100%' }}>
|
|
477
|
+
<IconBox className="section-icon">{icon}</IconBox>
|
|
478
|
+
<Text appearance="microtext1" className="section-label" ml={3} colorScheme="light.contrastText">
|
|
479
|
+
{label as string}
|
|
480
|
+
</Text>
|
|
481
|
+
<IconBox style={{ marginLeft: 'auto' }} className="chevron-icon-box">
|
|
482
|
+
<ChevronUpFill className={listToClass(['chevron', open ? 'open' : ''])} />
|
|
483
|
+
</IconBox>
|
|
484
|
+
</Flex>
|
|
485
|
+
</ReactTooltip>
|
|
486
|
+
</a>
|
|
487
|
+
<MenuSectionGroup id={menuGroupId}
|
|
488
|
+
className={`${open ? 'open' : ''} root no-indentation`}
|
|
489
|
+
aria-hidden={!open}>
|
|
490
|
+
{items}
|
|
491
|
+
</MenuSectionGroup>
|
|
251
492
|
</>
|
|
252
493
|
)
|
|
253
494
|
}
|
|
254
495
|
|
|
255
496
|
const dictionary = {
|
|
256
497
|
en: {
|
|
257
|
-
toggle: '
|
|
498
|
+
toggle: 'Collapse or expand the menu',
|
|
258
499
|
menuOptions: 'View $0 menu options',
|
|
259
500
|
settings: 'Settings',
|
|
260
501
|
settingsIcon: 'Settings icon',
|
|
261
502
|
hide: 'Hide',
|
|
503
|
+
contactUs: 'Support',
|
|
504
|
+
contactIcon: 'Contact icon',
|
|
505
|
+
rateUs: 'Rate us',
|
|
506
|
+
rateUsIcon: 'Rate us icon',
|
|
262
507
|
},
|
|
263
508
|
pt: {
|
|
264
|
-
toggle: '
|
|
509
|
+
toggle: 'Contrair ou expandir o menu',
|
|
265
510
|
menuOptions: 'Visualizar opções do menu $0',
|
|
266
511
|
settings: 'Configurações',
|
|
267
|
-
settingsIcon: '
|
|
512
|
+
settingsIcon: 'Ícone de configurações',
|
|
268
513
|
hide: 'Esconder',
|
|
514
|
+
contactUs: 'Suporte',
|
|
515
|
+
contactIcon: 'Ícone de contato',
|
|
516
|
+
rateUs: 'Avalie-nos',
|
|
517
|
+
rateUsIcon: 'Avalie-nos icon',
|
|
269
518
|
},
|
|
270
519
|
} satisfies Dictionary
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { IconBox, Text } from '@citric/core'
|
|
2
2
|
import { ArrowRight, Select } from '@citric/icons'
|
|
3
3
|
import { LoadingCircular } from '@citric/ui'
|
|
4
|
+
import { useCheckTextOverflow } from '@stack-spot/portal-components'
|
|
5
|
+
import { ListAction, SelectionList } from '@stack-spot/portal-components/SelectionList'
|
|
6
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
7
|
import { theme } from '@stack-spot/portal-theme'
|
|
5
8
|
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
6
9
|
import { KeyboardEvent, useMemo, useRef, useState } from 'react'
|
|
7
10
|
import { styled } from 'styled-components'
|
|
8
|
-
import { useAnchorTag } from '../../layout-context'
|
|
9
|
-
import { ListAction, SelectionList } from '../SelectionList'
|
|
10
11
|
import { MENU_CONTENT_PADDING as PADDING } from './constants'
|
|
11
12
|
import { Selector } from './types'
|
|
12
|
-
import { useCheckTextOverflow } from './use-check-text-overflow'
|
|
13
13
|
|
|
14
14
|
const SelectorBox = styled.div`
|
|
15
15
|
position: relative;
|
|
@@ -81,6 +81,11 @@ const SelectorBox = styled.div`
|
|
|
81
81
|
}
|
|
82
82
|
`
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* A selector component to render inside a menu-content. Allows the user to select another page.
|
|
86
|
+
*
|
|
87
|
+
* @param props the React props for the component {@link Selector}.
|
|
88
|
+
*/
|
|
84
89
|
export const PageSelector = ({ options, value, button, loading, title }: Selector) => {
|
|
85
90
|
const Link = useAnchorTag()
|
|
86
91
|
const t = useTranslate(dictionary)
|
|
@@ -113,7 +118,13 @@ export const PageSelector = ({ options, value, button, loading, title }: Selecto
|
|
|
113
118
|
? <LoadingCircular />
|
|
114
119
|
: (
|
|
115
120
|
<>
|
|
116
|
-
{title && <Text
|
|
121
|
+
{title && <Text
|
|
122
|
+
colorScheme="light.700"
|
|
123
|
+
sx={{ mb: 3 }}
|
|
124
|
+
id="pageSelectorTitle"
|
|
125
|
+
aria-label={title}>
|
|
126
|
+
{title}
|
|
127
|
+
</Text>}
|
|
117
128
|
<button
|
|
118
129
|
onClick={() => setVisible(true)}
|
|
119
130
|
onKeyDown={(e: KeyboardEvent<HTMLButtonElement>) => e.key === 'Enter' && setVisible(true)}
|
|
@@ -123,6 +134,7 @@ export const PageSelector = ({ options, value, button, loading, title }: Selecto
|
|
|
123
134
|
aria-expanded={visible}
|
|
124
135
|
aria-controls={id.current}
|
|
125
136
|
aria-haspopup="listbox"
|
|
137
|
+
aria-labelledby="pageSelectorTitle"
|
|
126
138
|
>
|
|
127
139
|
{selected?.icon && <IconBox>{selected?.icon}</IconBox>}
|
|
128
140
|
{isTextLabel ?
|