@telefonica/mistica 17.3.0 → 17.5.0
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/css/blau.css +29 -16
- package/css/esimflag.css +40 -18
- package/css/mistica-common.css +5 -0
- package/css/mistica.css +1 -1
- package/css/movistar.css +34 -18
- package/css/o2.css +31 -18
- package/css/telefonica.css +43 -18
- package/css/vivo-evolution.css +71 -20
- package/css/vivo.css +31 -18
- package/dist/accordion.css-mistica.js +10 -10
- package/dist/align.css-mistica.js +1 -1
- package/dist/autocomplete.css-mistica.js +4 -4
- package/dist/avatar.css-mistica.js +1 -1
- package/dist/badge.css-mistica.js +1 -1
- package/dist/box.css-mistica.js +13 -13
- package/dist/boxed.css-mistica.js +24 -24
- package/dist/boxed.d.ts +9 -0
- package/dist/boxed.js +18 -15
- package/dist/button-group.css-mistica.js +1 -1
- package/dist/button-layout.css-mistica.js +19 -19
- package/dist/button.css-mistica.js +51 -51
- package/dist/callout.css-mistica.js +13 -13
- package/dist/card-internal.css-mistica.js +22 -22
- package/dist/carousel.css-mistica.js +30 -30
- package/dist/checkbox.css-mistica.js +15 -15
- package/dist/chip.css-mistica.js +18 -18
- package/dist/circle.css-mistica.js +2 -2
- package/dist/community/advanced-data-card.css-mistica.js +19 -19
- package/dist/community/ai-card.css-mistica.js +11 -11
- package/dist/community/blocks.css-mistica.js +1 -1
- package/dist/community/cyber/example-component.css-mistica.js +1 -1
- package/dist/community/example-component.css-mistica.js +1 -1
- package/dist/community/skins/cyber-skin.js +19 -17
- package/dist/counter.css-mistica.js +6 -6
- package/dist/cover-hero.css-mistica.js +7 -7
- package/dist/credit-card-number-field.css-mistica.js +3 -3
- package/dist/date-field.css-mistica.js +1 -1
- package/dist/date-time-picker.css-mistica.js +1 -1
- package/dist/dialog.css-mistica.js +10 -10
- package/dist/divider.css-mistica.js +5 -5
- package/dist/double-field.css-mistica.js +2 -2
- package/dist/drawer.css-mistica.js +4 -4
- package/dist/empty-state-card.css-mistica.js +1 -1
- package/dist/empty-state.css-mistica.js +8 -8
- package/dist/fade-in.css-mistica.js +1 -1
- package/dist/fade-out.css-mistica.js +11 -0
- package/dist/fade-out.css.d.ts +1 -0
- package/dist/fade-out.d.ts +11 -0
- package/dist/fade-out.js +88 -0
- package/dist/feedback.css-mistica.js +5 -5
- package/dist/file-upload.css-mistica.js +10 -10
- package/dist/fixed-footer-layout.css-mistica.js +6 -6
- package/dist/form.css-mistica.js +1 -1
- package/dist/generated/mistica-icons/icon-antenna-filled.js +40 -12
- package/dist/generated/mistica-icons/icon-antenna-light.js +37 -17
- package/dist/generated/mistica-icons/icon-antenna-regular.js +42 -14
- package/dist/generated/mistica-icons/icon-arrow-up-down-filled.js +26 -16
- package/dist/generated/mistica-icons/icon-arrow-up-down-light.js +22 -12
- package/dist/generated/mistica-icons/icon-arrow-up-down-regular.js +30 -20
- package/dist/generated/mistica-icons/icon-arrows-left-and-right-filled.js +26 -16
- package/dist/generated/mistica-icons/icon-arrows-left-and-right-light.js +24 -14
- package/dist/generated/mistica-icons/icon-arrows-left-and-right-regular.js +26 -16
- package/dist/generated/mistica-icons/icon-authentication-success-filled.js +31 -11
- package/dist/generated/mistica-icons/icon-authentication-success-light.js +33 -17
- package/dist/generated/mistica-icons/icon-authentication-success-regular.js +29 -13
- package/dist/generated/mistica-icons/icon-blog-filled.js +36 -16
- package/dist/generated/mistica-icons/icon-blog-light.js +34 -14
- package/dist/generated/mistica-icons/icon-blog-regular.js +32 -16
- package/dist/generated/mistica-icons/icon-book-filled.js +19 -9
- package/dist/generated/mistica-icons/icon-book-light.js +25 -15
- package/dist/generated/mistica-icons/icon-book-regular.js +16 -6
- package/dist/generated/mistica-icons/icon-box-filled.js +35 -19
- package/dist/generated/mistica-icons/icon-box-light.js +28 -18
- package/dist/generated/mistica-icons/icon-box-regular.js +26 -16
- package/dist/generated/mistica-icons/icon-box-star-filled.js +37 -17
- package/dist/generated/mistica-icons/icon-box-star-light.js +22 -6
- package/dist/generated/mistica-icons/icon-box-star-regular.js +30 -14
- package/dist/generated/mistica-icons/icon-briefcase-filled.js +28 -12
- package/dist/generated/mistica-icons/icon-briefcase-light.js +21 -11
- package/dist/generated/mistica-icons/icon-briefcase-regular.js +29 -19
- package/dist/generated/mistica-icons/icon-calendar-event-filled.js +23 -12
- package/dist/generated/mistica-icons/icon-calendar-event-light.js +28 -11
- package/dist/generated/mistica-icons/icon-calendar-event-regular.js +30 -13
- package/dist/generated/mistica-icons/icon-calendar-filled.js +32 -22
- package/dist/generated/mistica-icons/icon-calendar-light.js +39 -23
- package/dist/generated/mistica-icons/icon-calendar-month-filled.js +23 -12
- package/dist/generated/mistica-icons/icon-calendar-month-light.js +30 -13
- package/dist/generated/mistica-icons/icon-calendar-month-regular.js +30 -13
- package/dist/generated/mistica-icons/icon-calendar-regular.js +33 -17
- package/dist/generated/mistica-icons/icon-car-filled.js +25 -9
- package/dist/generated/mistica-icons/icon-car-light.js +24 -14
- package/dist/generated/mistica-icons/icon-car-regular.js +24 -14
- package/dist/generated/mistica-icons/icon-care-briefcase-filled.js +23 -12
- package/dist/generated/mistica-icons/icon-care-briefcase-light.js +25 -14
- package/dist/generated/mistica-icons/icon-care-briefcase-regular.js +18 -8
- package/dist/generated/mistica-icons/icon-care-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-care-home-filled.js +24 -13
- package/dist/generated/mistica-icons/icon-care-home-light.js +24 -13
- package/dist/generated/mistica-icons/icon-care-home-regular.js +26 -16
- package/dist/generated/mistica-icons/icon-care-laptop-filled.js +22 -11
- package/dist/generated/mistica-icons/icon-care-laptop-light.js +24 -13
- package/dist/generated/mistica-icons/icon-care-laptop-regular.js +28 -18
- package/dist/generated/mistica-icons/icon-care-light.js +22 -12
- package/dist/generated/mistica-icons/icon-care-mobile-filled.js +22 -11
- package/dist/generated/mistica-icons/icon-care-mobile-light.js +29 -12
- package/dist/generated/mistica-icons/icon-care-mobile-regular.js +33 -17
- package/dist/generated/mistica-icons/icon-care-regular.js +23 -13
- package/dist/generated/mistica-icons/icon-care-shield-filled.js +24 -14
- package/dist/generated/mistica-icons/icon-care-shield-light.js +23 -13
- package/dist/generated/mistica-icons/icon-care-shield-regular.js +26 -16
- package/dist/generated/mistica-icons/icon-change-plan-filled.js +36 -16
- package/dist/generated/mistica-icons/icon-change-plan-light.js +38 -18
- package/dist/generated/mistica-icons/icon-change-plan-regular.js +30 -14
- package/dist/generated/mistica-icons/icon-chip-device-filled.js +32 -16
- package/dist/generated/mistica-icons/icon-chip-device-light.js +33 -17
- package/dist/generated/mistica-icons/icon-chip-device-regular.js +36 -20
- package/dist/generated/mistica-icons/icon-chip-sim-card-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-chip-sim-card-light.js +36 -20
- package/dist/generated/mistica-icons/icon-chip-sim-card-regular.js +42 -26
- package/dist/generated/mistica-icons/icon-credit-card-filled.js +20 -10
- package/dist/generated/mistica-icons/icon-credit-card-light.js +18 -8
- package/dist/generated/mistica-icons/icon-credit-card-regular.js +23 -13
- package/dist/generated/mistica-icons/icon-document-information-filled.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-document-information-light.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-document-information-regular.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-document-other-filled.js +25 -9
- package/dist/generated/mistica-icons/icon-document-other-light.js +33 -17
- package/dist/generated/mistica-icons/icon-document-other-regular.js +25 -9
- package/dist/generated/mistica-icons/icon-dollar-symbol-circle-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-dollar-symbol-circle-light.js +30 -14
- package/dist/generated/mistica-icons/icon-dollar-symbol-circle-regular.js +29 -13
- package/dist/generated/mistica-icons/icon-error-filled.js +33 -17
- package/dist/generated/mistica-icons/icon-error-light.js +29 -13
- package/dist/generated/mistica-icons/icon-error-regular.js +32 -16
- package/dist/generated/mistica-icons/icon-esim-filled.js +33 -17
- package/dist/generated/mistica-icons/icon-esim-light.js +43 -23
- package/dist/generated/mistica-icons/icon-esim-regular.js +29 -9
- package/dist/generated/mistica-icons/icon-eye-filled.js +18 -8
- package/dist/generated/mistica-icons/icon-eye-light.js +31 -15
- package/dist/generated/mistica-icons/icon-eye-regular.js +29 -13
- package/dist/generated/mistica-icons/icon-file-ok-filled.js +30 -14
- package/dist/generated/mistica-icons/icon-file-ok-light.js +29 -13
- package/dist/generated/mistica-icons/icon-file-ok-regular.js +31 -15
- package/dist/generated/mistica-icons/icon-fingerprint-filled.js +36 -15
- package/dist/generated/mistica-icons/icon-fingerprint-light.js +35 -14
- package/dist/generated/mistica-icons/icon-fingerprint-regular.js +29 -9
- package/dist/generated/mistica-icons/icon-home-filled.js +17 -7
- package/dist/generated/mistica-icons/icon-home-light.js +21 -11
- package/dist/generated/mistica-icons/icon-home-regular.js +29 -19
- package/dist/generated/mistica-icons/icon-home-wifi-filled.js +39 -19
- package/dist/generated/mistica-icons/icon-home-wifi-light.js +30 -14
- package/dist/generated/mistica-icons/icon-home-wifi-regular.js +37 -17
- package/dist/generated/mistica-icons/icon-id-card-filled.js +32 -16
- package/dist/generated/mistica-icons/icon-id-card-light.js +27 -11
- package/dist/generated/mistica-icons/icon-id-card-regular.js +31 -15
- package/dist/generated/mistica-icons/icon-information-user-filled.js +32 -12
- package/dist/generated/mistica-icons/icon-information-user-light.js +37 -21
- package/dist/generated/mistica-icons/icon-information-user-regular.js +44 -28
- package/dist/generated/mistica-icons/icon-internet-filled.js +18 -8
- package/dist/generated/mistica-icons/icon-internet-light.js +21 -11
- package/dist/generated/mistica-icons/icon-internet-regular.js +19 -9
- package/dist/generated/mistica-icons/icon-internet-roaming-filled.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-internet-roaming-light.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-internet-roaming-regular.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-key-filled.js +21 -11
- package/dist/generated/mistica-icons/icon-key-light.js +31 -15
- package/dist/generated/mistica-icons/icon-key-regular.js +32 -16
- package/dist/generated/mistica-icons/icon-list-filled.js +23 -12
- package/dist/generated/mistica-icons/icon-list-light.js +31 -15
- package/dist/generated/mistica-icons/icon-list-regular.js +34 -18
- package/dist/generated/mistica-icons/icon-location-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-location-light.js +30 -14
- package/dist/generated/mistica-icons/icon-location-regular.js +30 -14
- package/dist/generated/mistica-icons/icon-lock-closed-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-lock-closed-light.js +31 -15
- package/dist/generated/mistica-icons/icon-lock-closed-regular.js +35 -19
- package/dist/generated/mistica-icons/icon-message-filled.js +23 -12
- package/dist/generated/mistica-icons/icon-message-light.js +28 -11
- package/dist/generated/mistica-icons/icon-message-regular.js +27 -10
- package/dist/generated/mistica-icons/icon-mobile-device-filled.js +25 -15
- package/dist/generated/mistica-icons/icon-mobile-device-light.js +26 -10
- package/dist/generated/mistica-icons/icon-mobile-device-regular.js +32 -16
- package/dist/generated/mistica-icons/icon-mobile-information-filled.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-mobile-information-light.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-mobile-information-regular.d.ts +3 -0
- package/dist/generated/mistica-icons/icon-panel-collapse-regular.js +165 -0
- package/dist/generated/mistica-icons/icon-panel-expand-regular.js +159 -0
- package/dist/generated/mistica-icons/icons-keywords.js +57 -0
- package/dist/grid-layout.css-mistica.js +3 -3
- package/dist/grid.css-mistica.js +120 -120
- package/dist/header.css-mistica.js +1 -1
- package/dist/header.d.ts +3 -1
- package/dist/header.js +81 -73
- package/dist/hero.css-mistica.js +4 -4
- package/dist/horizontal-scroll.css-mistica.js +1 -1
- package/dist/icon-button.css-mistica.js +53 -53
- package/dist/icons/icon-chevron.css-mistica.js +2 -2
- package/dist/icons/icon-error.css-mistica.js +1 -1
- package/dist/image.css-mistica.js +6 -6
- package/dist/index.d.ts +6 -0
- package/dist/index.js +14 -1
- package/dist/inline.css-mistica.js +11 -11
- package/dist/list.css-mistica.js +40 -28
- package/dist/list.css.d.ts +2 -0
- package/dist/list.d.ts +3 -1
- package/dist/list.js +176 -165
- package/dist/loading-bar.css-mistica.js +1 -1
- package/dist/loading-screen.css-mistica.js +12 -12
- package/dist/logo.css-mistica.js +5 -5
- package/dist/menu.css-mistica.js +13 -13
- package/dist/mobile-navigation-menu.d.ts +26 -0
- package/dist/mobile-navigation-menu.js +145 -0
- package/dist/mosaic.css-mistica.js +1 -1
- package/dist/navigation-bar.css-mistica.js +31 -97
- package/dist/navigation-bar.css.d.ts +0 -24
- package/dist/navigation-bar.d.ts +3 -38
- package/dist/navigation-bar.js +399 -586
- package/dist/navigation-breadcrumbs.css-mistica.js +1 -1
- package/dist/navigation-shared.css-mistica.js +79 -0
- package/dist/navigation-shared.css.d.ts +26 -0
- package/dist/navigation-shared.d.ts +66 -0
- package/dist/navigation-shared.js +264 -0
- package/dist/package-version.js +1 -1
- package/dist/pagination.css-mistica.js +22 -22
- package/dist/pin-field.css-mistica.js +4 -4
- package/dist/popover.css-mistica.js +1 -1
- package/dist/portal.d.ts +1 -1
- package/dist/progress-bar.css-mistica.js +7 -7
- package/dist/radio-button.css-mistica.js +27 -27
- package/dist/rating.css-mistica.js +4 -4
- package/dist/responsive-layout.css-mistica.js +6 -6
- package/dist/screen-reader-only.css-mistica.js +1 -1
- package/dist/select.css-mistica.js +21 -21
- package/dist/sheet-action-row.css-mistica.js +1 -1
- package/dist/sheet-common.css-mistica.js +7 -7
- package/dist/sheet-info.css-mistica.js +1 -1
- package/dist/sidenav-bar-context.d.ts +25 -0
- package/dist/sidenav-bar-context.js +72 -0
- package/dist/sidenav-bar-data.d.ts +15 -0
- package/dist/sidenav-bar-data.js +38 -0
- package/dist/sidenav-bar-first-level-item.d.ts +42 -0
- package/dist/sidenav-bar-first-level-item.js +174 -0
- package/dist/sidenav-bar-keyboard.d.ts +13 -0
- package/dist/sidenav-bar-keyboard.js +314 -0
- package/dist/sidenav-bar-layout.css-mistica.js +28 -0
- package/dist/sidenav-bar-layout.css.d.ts +5 -0
- package/dist/sidenav-bar-layout.d.ts +22 -0
- package/dist/sidenav-bar-layout.js +103 -0
- package/dist/sidenav-bar-mobile.d.ts +24 -0
- package/dist/sidenav-bar-mobile.js +332 -0
- package/dist/sidenav-bar-motion.d.ts +32 -0
- package/dist/sidenav-bar-motion.js +84 -0
- package/dist/sidenav-bar-panel.d.ts +31 -0
- package/dist/sidenav-bar-panel.js +208 -0
- package/dist/sidenav-bar-row.d.ts +82 -0
- package/dist/sidenav-bar-row.js +230 -0
- package/dist/sidenav-bar-second-level-item.d.ts +43 -0
- package/dist/sidenav-bar-second-level-item.js +89 -0
- package/dist/sidenav-bar-section.d.ts +23 -0
- package/dist/sidenav-bar-section.js +167 -0
- package/dist/sidenav-bar-types.d.ts +192 -0
- package/dist/sidenav-bar-types.js +11 -0
- package/dist/sidenav-bar.css-mistica.js +325 -0
- package/dist/sidenav-bar.css.d.ts +93 -0
- package/dist/sidenav-bar.d.ts +102 -0
- package/dist/sidenav-bar.js +492 -0
- package/dist/skeletons.css-mistica.js +8 -8
- package/dist/skins/blau.js +23 -8
- package/dist/skins/defaults.js +11 -0
- package/dist/skins/esimflag.js +24 -9
- package/dist/skins/movistar.js +24 -9
- package/dist/skins/o2.js +24 -9
- package/dist/skins/skin-contract.css-mistica.js +740 -731
- package/dist/skins/skin-contract.css.d.ts +9 -0
- package/dist/skins/telefonica.js +24 -9
- package/dist/skins/types/colors.d.ts +2 -0
- package/dist/skins/types/index.d.ts +1 -0
- package/dist/skins/vivo-evolution.js +25 -10
- package/dist/skins/vivo.js +24 -9
- package/dist/skip-link.css-mistica.js +2 -2
- package/dist/slider.css-mistica.js +24 -24
- package/dist/snackbar.css-mistica.js +14 -14
- package/dist/spinner.css-mistica.js +1 -1
- package/dist/square.css-mistica.js +1 -1
- package/dist/stack.css-mistica.js +5 -5
- package/dist/stacking-group.css-mistica.js +1 -1
- package/dist/stepper.css-mistica.js +9 -9
- package/dist/switch-component.css-mistica.js +48 -42
- package/dist/switch-component.css.d.ts +2 -0
- package/dist/switch-component.js +18 -18
- package/dist/table.css-mistica.js +9 -9
- package/dist/tabs.css-mistica.js +22 -22
- package/dist/tag.css-mistica.js +3 -3
- package/dist/text-field-base.css-mistica.js +20 -20
- package/dist/text-field-components.css-mistica.js +10 -10
- package/dist/text-link.css-mistica.js +6 -6
- package/dist/text-tokens.d.ts +6 -0
- package/dist/text-tokens.js +157 -133
- package/dist/text.css-mistica.js +6 -6
- package/dist/timeline.css-mistica.js +11 -11
- package/dist/timer.css-mistica.js +6 -6
- package/dist/tooltip.css-mistica.js +2 -2
- package/dist/touchable.css-mistica.js +4 -4
- package/dist/utils/aspect-ratio-support.css-mistica.js +2 -2
- package/dist/video.css-mistica.js +1 -1
- package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
- package/dist-es/accordion.css-mistica.js +7 -7
- package/dist-es/align.css-mistica.js +1 -1
- package/dist-es/autocomplete.css-mistica.js +2 -2
- package/dist-es/avatar.css-mistica.js +1 -1
- package/dist-es/badge.css-mistica.js +1 -1
- package/dist-es/box.css-mistica.js +13 -13
- package/dist-es/boxed.css-mistica.js +23 -23
- package/dist-es/boxed.js +25 -25
- package/dist-es/button-group.css-mistica.js +1 -1
- package/dist-es/button-layout.css-mistica.js +16 -16
- package/dist-es/button.css-mistica.js +38 -38
- package/dist-es/callout.css-mistica.js +12 -12
- package/dist-es/card-internal.css-mistica.js +17 -17
- package/dist-es/carousel.css-mistica.js +10 -10
- package/dist-es/checkbox.css-mistica.js +13 -13
- package/dist-es/chip.css-mistica.js +17 -17
- package/dist-es/circle.css-mistica.js +2 -2
- package/dist-es/community/advanced-data-card.css-mistica.js +7 -7
- package/dist-es/community/ai-card.css-mistica.js +4 -4
- package/dist-es/community/blocks.css-mistica.js +1 -1
- package/dist-es/community/cyber/example-component.css-mistica.js +1 -1
- package/dist-es/community/example-component.css-mistica.js +1 -1
- package/dist-es/community/skins/cyber-skin.js +19 -17
- package/dist-es/counter.css-mistica.js +2 -2
- package/dist-es/cover-hero.css-mistica.js +4 -4
- package/dist-es/credit-card-number-field.css-mistica.js +3 -3
- package/dist-es/date-field.css-mistica.js +1 -1
- package/dist-es/date-time-picker.css-mistica.js +1 -1
- package/dist-es/dialog.css-mistica.js +5 -5
- package/dist-es/divider.css-mistica.js +5 -5
- package/dist-es/double-field.css-mistica.js +2 -2
- package/dist-es/drawer.css-mistica.js +2 -2
- package/dist-es/empty-state-card.css-mistica.js +1 -1
- package/dist-es/empty-state.css-mistica.js +7 -7
- package/dist-es/fade-in.css-mistica.js +1 -1
- package/dist-es/fade-out.css-mistica.js +2 -0
- package/dist-es/fade-out.js +79 -0
- package/dist-es/feedback.css-mistica.js +2 -2
- package/dist-es/file-upload.css-mistica.js +8 -8
- package/dist-es/fixed-footer-layout.css-mistica.js +3 -3
- package/dist-es/form.css-mistica.js +1 -1
- package/dist-es/generated/mistica-icons/icon-antenna-filled.js +50 -22
- package/dist-es/generated/mistica-icons/icon-antenna-light.js +47 -27
- package/dist-es/generated/mistica-icons/icon-antenna-regular.js +52 -24
- package/dist-es/generated/mistica-icons/icon-arrow-up-down-filled.js +29 -19
- package/dist-es/generated/mistica-icons/icon-arrow-up-down-light.js +26 -16
- package/dist-es/generated/mistica-icons/icon-arrow-up-down-regular.js +34 -24
- package/dist-es/generated/mistica-icons/icon-arrows-left-and-right-filled.js +30 -20
- package/dist-es/generated/mistica-icons/icon-arrows-left-and-right-light.js +32 -22
- package/dist-es/generated/mistica-icons/icon-arrows-left-and-right-regular.js +34 -24
- package/dist-es/generated/mistica-icons/icon-authentication-success-filled.js +42 -22
- package/dist-es/generated/mistica-icons/icon-authentication-success-light.js +44 -28
- package/dist-es/generated/mistica-icons/icon-authentication-success-regular.js +42 -26
- package/dist-es/generated/mistica-icons/icon-blog-filled.js +44 -24
- package/dist-es/generated/mistica-icons/icon-blog-light.js +45 -25
- package/dist-es/generated/mistica-icons/icon-blog-regular.js +45 -29
- package/dist-es/generated/mistica-icons/icon-book-filled.js +23 -13
- package/dist-es/generated/mistica-icons/icon-book-light.js +33 -23
- package/dist-es/generated/mistica-icons/icon-book-regular.js +22 -12
- package/dist-es/generated/mistica-icons/icon-box-filled.js +38 -22
- package/dist-es/generated/mistica-icons/icon-box-light.js +38 -28
- package/dist-es/generated/mistica-icons/icon-box-regular.js +37 -27
- package/dist-es/generated/mistica-icons/icon-box-star-filled.js +49 -29
- package/dist-es/generated/mistica-icons/icon-box-star-light.js +29 -13
- package/dist-es/generated/mistica-icons/icon-box-star-regular.js +33 -17
- package/dist-es/generated/mistica-icons/icon-briefcase-filled.js +32 -16
- package/dist-es/generated/mistica-icons/icon-briefcase-light.js +24 -14
- package/dist-es/generated/mistica-icons/icon-briefcase-regular.js +32 -22
- package/dist-es/generated/mistica-icons/icon-calendar-event-filled.js +28 -17
- package/dist-es/generated/mistica-icons/icon-calendar-event-light.js +34 -17
- package/dist-es/generated/mistica-icons/icon-calendar-event-regular.js +36 -19
- package/dist-es/generated/mistica-icons/icon-calendar-filled.js +42 -32
- package/dist-es/generated/mistica-icons/icon-calendar-light.js +45 -29
- package/dist-es/generated/mistica-icons/icon-calendar-month-filled.js +31 -20
- package/dist-es/generated/mistica-icons/icon-calendar-month-light.js +38 -21
- package/dist-es/generated/mistica-icons/icon-calendar-month-regular.js +38 -21
- package/dist-es/generated/mistica-icons/icon-calendar-regular.js +45 -29
- package/dist-es/generated/mistica-icons/icon-car-filled.js +26 -10
- package/dist-es/generated/mistica-icons/icon-car-light.js +33 -23
- package/dist-es/generated/mistica-icons/icon-car-regular.js +29 -19
- package/dist-es/generated/mistica-icons/icon-care-briefcase-filled.js +30 -19
- package/dist-es/generated/mistica-icons/icon-care-briefcase-light.js +28 -17
- package/dist-es/generated/mistica-icons/icon-care-briefcase-regular.js +24 -14
- package/dist-es/generated/mistica-icons/icon-care-filled.js +29 -19
- package/dist-es/generated/mistica-icons/icon-care-home-filled.js +32 -21
- package/dist-es/generated/mistica-icons/icon-care-home-light.js +31 -20
- package/dist-es/generated/mistica-icons/icon-care-home-regular.js +40 -30
- package/dist-es/generated/mistica-icons/icon-care-laptop-filled.js +29 -18
- package/dist-es/generated/mistica-icons/icon-care-laptop-light.js +31 -20
- package/dist-es/generated/mistica-icons/icon-care-laptop-regular.js +33 -23
- package/dist-es/generated/mistica-icons/icon-care-light.js +24 -14
- package/dist-es/generated/mistica-icons/icon-care-mobile-filled.js +30 -19
- package/dist-es/generated/mistica-icons/icon-care-mobile-light.js +35 -18
- package/dist-es/generated/mistica-icons/icon-care-mobile-regular.js +50 -34
- package/dist-es/generated/mistica-icons/icon-care-regular.js +38 -28
- package/dist-es/generated/mistica-icons/icon-care-shield-filled.js +33 -23
- package/dist-es/generated/mistica-icons/icon-care-shield-light.js +27 -17
- package/dist-es/generated/mistica-icons/icon-care-shield-regular.js +33 -23
- package/dist-es/generated/mistica-icons/icon-change-plan-filled.js +41 -21
- package/dist-es/generated/mistica-icons/icon-change-plan-light.js +42 -22
- package/dist-es/generated/mistica-icons/icon-change-plan-regular.js +35 -19
- package/dist-es/generated/mistica-icons/icon-chip-device-filled.js +37 -21
- package/dist-es/generated/mistica-icons/icon-chip-device-light.js +46 -30
- package/dist-es/generated/mistica-icons/icon-chip-device-regular.js +48 -32
- package/dist-es/generated/mistica-icons/icon-chip-sim-card-filled.js +26 -16
- package/dist-es/generated/mistica-icons/icon-chip-sim-card-light.js +43 -27
- package/dist-es/generated/mistica-icons/icon-chip-sim-card-regular.js +59 -43
- package/dist-es/generated/mistica-icons/icon-credit-card-filled.js +24 -14
- package/dist-es/generated/mistica-icons/icon-credit-card-light.js +19 -9
- package/dist-es/generated/mistica-icons/icon-credit-card-regular.js +26 -16
- package/dist-es/generated/mistica-icons/icon-document-other-filled.js +31 -15
- package/dist-es/generated/mistica-icons/icon-document-other-light.js +42 -26
- package/dist-es/generated/mistica-icons/icon-document-other-regular.js +32 -16
- package/dist-es/generated/mistica-icons/icon-dollar-symbol-circle-filled.js +28 -18
- package/dist-es/generated/mistica-icons/icon-dollar-symbol-circle-light.js +41 -25
- package/dist-es/generated/mistica-icons/icon-dollar-symbol-circle-regular.js +42 -26
- package/dist-es/generated/mistica-icons/icon-error-filled.js +44 -28
- package/dist-es/generated/mistica-icons/icon-error-light.js +37 -21
- package/dist-es/generated/mistica-icons/icon-error-regular.js +40 -24
- package/dist-es/generated/mistica-icons/icon-esim-filled.js +48 -32
- package/dist-es/generated/mistica-icons/icon-esim-light.js +58 -38
- package/dist-es/generated/mistica-icons/icon-esim-regular.js +35 -15
- package/dist-es/generated/mistica-icons/icon-eye-filled.js +24 -14
- package/dist-es/generated/mistica-icons/icon-eye-light.js +43 -27
- package/dist-es/generated/mistica-icons/icon-eye-regular.js +33 -17
- package/dist-es/generated/mistica-icons/icon-file-ok-filled.js +41 -25
- package/dist-es/generated/mistica-icons/icon-file-ok-light.js +37 -21
- package/dist-es/generated/mistica-icons/icon-file-ok-regular.js +41 -25
- package/dist-es/generated/mistica-icons/icon-fingerprint-filled.js +45 -24
- package/dist-es/generated/mistica-icons/icon-fingerprint-light.js +39 -18
- package/dist-es/generated/mistica-icons/icon-fingerprint-regular.js +32 -12
- package/dist-es/generated/mistica-icons/icon-home-filled.js +19 -9
- package/dist-es/generated/mistica-icons/icon-home-light.js +24 -14
- package/dist-es/generated/mistica-icons/icon-home-regular.js +30 -20
- package/dist-es/generated/mistica-icons/icon-home-wifi-filled.js +51 -31
- package/dist-es/generated/mistica-icons/icon-home-wifi-light.js +36 -20
- package/dist-es/generated/mistica-icons/icon-home-wifi-regular.js +51 -31
- package/dist-es/generated/mistica-icons/icon-id-card-filled.js +40 -24
- package/dist-es/generated/mistica-icons/icon-id-card-light.js +38 -22
- package/dist-es/generated/mistica-icons/icon-id-card-regular.js +42 -26
- package/dist-es/generated/mistica-icons/icon-information-user-filled.js +36 -16
- package/dist-es/generated/mistica-icons/icon-information-user-light.js +51 -35
- package/dist-es/generated/mistica-icons/icon-information-user-regular.js +58 -42
- package/dist-es/generated/mistica-icons/icon-internet-filled.js +22 -12
- package/dist-es/generated/mistica-icons/icon-internet-light.js +25 -15
- package/dist-es/generated/mistica-icons/icon-internet-regular.js +22 -12
- package/dist-es/generated/mistica-icons/icon-key-filled.js +23 -13
- package/dist-es/generated/mistica-icons/icon-key-light.js +40 -24
- package/dist-es/generated/mistica-icons/icon-key-regular.js +40 -24
- package/dist-es/generated/mistica-icons/icon-list-filled.js +29 -18
- package/dist-es/generated/mistica-icons/icon-list-light.js +38 -22
- package/dist-es/generated/mistica-icons/icon-list-regular.js +42 -26
- package/dist-es/generated/mistica-icons/icon-location-filled.js +29 -19
- package/dist-es/generated/mistica-icons/icon-location-light.js +37 -21
- package/dist-es/generated/mistica-icons/icon-location-regular.js +37 -21
- package/dist-es/generated/mistica-icons/icon-lock-closed-filled.js +28 -18
- package/dist-es/generated/mistica-icons/icon-lock-closed-light.js +35 -19
- package/dist-es/generated/mistica-icons/icon-lock-closed-regular.js +40 -24
- package/dist-es/generated/mistica-icons/icon-message-filled.js +29 -18
- package/dist-es/generated/mistica-icons/icon-message-light.js +36 -19
- package/dist-es/generated/mistica-icons/icon-message-regular.js +35 -18
- package/dist-es/generated/mistica-icons/icon-mobile-device-filled.js +30 -20
- package/dist-es/generated/mistica-icons/icon-mobile-device-light.js +34 -18
- package/dist-es/generated/mistica-icons/icon-mobile-device-regular.js +37 -21
- package/dist-es/generated/mistica-icons/icon-panel-collapse-regular.js +115 -0
- package/dist-es/generated/mistica-icons/icon-panel-expand-regular.js +109 -0
- package/dist-es/generated/mistica-icons/icons-keywords.js +57 -0
- package/dist-es/grid-layout.css-mistica.js +3 -3
- package/dist-es/grid.css-mistica.js +120 -120
- package/dist-es/header.css-mistica.js +1 -1
- package/dist-es/header.js +113 -105
- package/dist-es/hero.css-mistica.js +3 -3
- package/dist-es/horizontal-scroll.css-mistica.js +1 -1
- package/dist-es/icon-button.css-mistica.js +53 -53
- package/dist-es/icons/icon-chevron.css-mistica.js +2 -2
- package/dist-es/icons/icon-error.css-mistica.js +1 -1
- package/dist-es/image.css-mistica.js +4 -4
- package/dist-es/index.js +2349 -2345
- package/dist-es/inline.css-mistica.js +11 -11
- package/dist-es/list.css-mistica.js +8 -2
- package/dist-es/list.js +275 -264
- package/dist-es/loading-bar.css-mistica.js +1 -1
- package/dist-es/loading-screen.css-mistica.js +5 -5
- package/dist-es/logo.css-mistica.js +5 -5
- package/dist-es/menu.css-mistica.js +13 -13
- package/dist-es/mobile-navigation-menu.js +90 -0
- package/dist-es/mosaic.css-mistica.js +1 -1
- package/dist-es/navigation-bar.css-mistica.js +11 -20
- package/dist-es/navigation-bar.js +469 -656
- package/dist-es/navigation-breadcrumbs.css-mistica.js +1 -1
- package/dist-es/navigation-shared.css-mistica.js +11 -0
- package/dist-es/navigation-shared.js +192 -0
- package/dist-es/package-version.js +1 -1
- package/dist-es/pagination.css-mistica.js +19 -19
- package/dist-es/pin-field.css-mistica.js +2 -2
- package/dist-es/popover.css-mistica.js +1 -1
- package/dist-es/progress-bar.css-mistica.js +7 -7
- package/dist-es/radio-button.css-mistica.js +22 -22
- package/dist-es/rating.css-mistica.js +3 -3
- package/dist-es/responsive-layout.css-mistica.js +6 -6
- package/dist-es/screen-reader-only.css-mistica.js +1 -1
- package/dist-es/select.css-mistica.js +18 -18
- package/dist-es/sheet-action-row.css-mistica.js +1 -1
- package/dist-es/sheet-common.css-mistica.js +2 -2
- package/dist-es/sheet-info.css-mistica.js +1 -1
- package/dist-es/sidenav-bar-context.js +14 -0
- package/dist-es/sidenav-bar-data.js +12 -0
- package/dist-es/sidenav-bar-first-level-item.js +124 -0
- package/dist-es/sidenav-bar-keyboard.js +253 -0
- package/dist-es/sidenav-bar-layout.css-mistica.js +2 -0
- package/dist-es/sidenav-bar-layout.js +86 -0
- package/dist-es/sidenav-bar-mobile.js +277 -0
- package/dist-es/sidenav-bar-motion.js +26 -0
- package/dist-es/sidenav-bar-panel.js +146 -0
- package/dist-es/sidenav-bar-row.js +208 -0
- package/dist-es/sidenav-bar-second-level-item.js +72 -0
- package/dist-es/sidenav-bar-section.js +112 -0
- package/dist-es/sidenav-bar-types.js +2 -0
- package/dist-es/sidenav-bar.css-mistica.js +74 -0
- package/dist-es/sidenav-bar.js +429 -0
- package/dist-es/skeletons.css-mistica.js +7 -7
- package/dist-es/skins/blau.js +23 -8
- package/dist-es/skins/defaults.js +11 -0
- package/dist-es/skins/esimflag.js +24 -9
- package/dist-es/skins/movistar.js +24 -9
- package/dist-es/skins/o2.js +24 -9
- package/dist-es/skins/skin-contract.css-mistica.js +740 -731
- package/dist-es/skins/telefonica.js +24 -9
- package/dist-es/skins/vivo-evolution.js +25 -10
- package/dist-es/skins/vivo.js +24 -9
- package/dist-es/skip-link.css-mistica.js +2 -2
- package/dist-es/slider.css-mistica.js +20 -20
- package/dist-es/snackbar.css-mistica.js +5 -5
- package/dist-es/spinner.css-mistica.js +1 -1
- package/dist-es/square.css-mistica.js +1 -1
- package/dist-es/stack.css-mistica.js +5 -5
- package/dist-es/stacking-group.css-mistica.js +1 -1
- package/dist-es/stepper.css-mistica.js +3 -3
- package/dist-es/style.css +1 -1
- package/dist-es/switch-component.css-mistica.js +37 -37
- package/dist-es/switch-component.js +26 -26
- package/dist-es/table.css-mistica.js +9 -9
- package/dist-es/tabs.css-mistica.js +19 -19
- package/dist-es/tag.css-mistica.js +2 -2
- package/dist-es/text-field-base.css-mistica.js +17 -17
- package/dist-es/text-field-components.css-mistica.js +4 -4
- package/dist-es/text-link.css-mistica.js +6 -6
- package/dist-es/text-tokens.js +82 -67
- package/dist-es/text.css-mistica.js +6 -6
- package/dist-es/timeline.css-mistica.js +10 -10
- package/dist-es/timer.css-mistica.js +6 -6
- package/dist-es/tooltip.css-mistica.js +2 -2
- package/dist-es/touchable.css-mistica.js +2 -2
- package/dist-es/utils/aspect-ratio-support.css-mistica.js +2 -2
- package/dist-es/video.css-mistica.js +1 -1
- package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
- package/package.json +2 -1
- package/src/boxed.css.ts +1 -0
- package/src/boxed.tsx +18 -5
- package/src/callout.css.ts +4 -2
- package/src/community/skins/cyber-skin.tsx +19 -16
- package/src/fade-out.css.ts +12 -0
- package/src/fade-out.tsx +50 -0
- package/src/header.tsx +39 -17
- package/src/index.tsx +15 -0
- package/src/list.css.ts +36 -1
- package/src/list.tsx +370 -344
- package/src/mobile-navigation-menu.tsx +168 -0
- package/src/navigation-bar.css.ts +2 -267
- package/src/navigation-bar.tsx +77 -370
- package/src/navigation-shared.css.ts +289 -0
- package/src/navigation-shared.tsx +262 -0
- package/src/package-version.tsx +1 -1
- package/src/portal.tsx +1 -1
- package/src/sidenav-bar-context.tsx +41 -0
- package/src/sidenav-bar-data.ts +49 -0
- package/src/sidenav-bar-first-level-item.tsx +203 -0
- package/src/sidenav-bar-keyboard.tsx +393 -0
- package/src/sidenav-bar-layout.css.ts +89 -0
- package/src/sidenav-bar-layout.tsx +61 -0
- package/src/sidenav-bar-mobile.tsx +302 -0
- package/src/sidenav-bar-motion.tsx +70 -0
- package/src/sidenav-bar-panel.tsx +269 -0
- package/src/sidenav-bar-row.tsx +272 -0
- package/src/sidenav-bar-second-level-item.tsx +99 -0
- package/src/sidenav-bar-section.tsx +98 -0
- package/src/sidenav-bar-types.ts +224 -0
- package/src/sidenav-bar.css.ts +1018 -0
- package/src/sidenav-bar.tsx +821 -0
- package/src/skins/blau.tsx +17 -8
- package/src/skins/defaults.tsx +5 -0
- package/src/skins/esimflag.tsx +18 -9
- package/src/skins/movistar.tsx +18 -9
- package/src/skins/o2.tsx +18 -9
- package/src/skins/skin-contract.css.ts +3 -0
- package/src/skins/telefonica.tsx +18 -9
- package/src/skins/types/colors.tsx +2 -0
- package/src/skins/types/index.tsx +1 -0
- package/src/skins/vivo-evolution.tsx +19 -10
- package/src/skins/vivo.tsx +18 -9
- package/src/switch-component.css.ts +20 -0
- package/src/switch-component.tsx +9 -1
- package/src/text-tokens.tsx +24 -0
|
@@ -0,0 +1,821 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import classnames from 'classnames';
|
|
4
|
+
import {CSSTransition} from 'react-transition-group';
|
|
5
|
+
import * as styles from './sidenav-bar.css';
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_WIDTH,
|
|
8
|
+
COLLAPSED_WIDTH,
|
|
9
|
+
LOGO_SIZE,
|
|
10
|
+
COLLAPSE_DURATION_MS,
|
|
11
|
+
CONTENT_DURATION_MS,
|
|
12
|
+
} from './sidenav-bar.css';
|
|
13
|
+
import {ThemeVariant, normalizeVariant, useThemeVariant} from './theme-variant-context';
|
|
14
|
+
import {getPrefixedDataAttributes} from './utils/dom';
|
|
15
|
+
import {applyCssVars} from './utils/css';
|
|
16
|
+
import {useScreenSize, useTheme} from './hooks';
|
|
17
|
+
import {IconButton} from './icon-button';
|
|
18
|
+
import {Logo} from './logo';
|
|
19
|
+
import IconPanelExpandRegular from './generated/mistica-icons/icon-panel-expand-regular';
|
|
20
|
+
import IconPanelCollapseRegular from './generated/mistica-icons/icon-panel-collapse-regular';
|
|
21
|
+
import {SidenavFirstLevelItem} from './sidenav-bar-first-level-item';
|
|
22
|
+
import {renderSidenavSecondLevelItem} from './sidenav-bar-second-level-item';
|
|
23
|
+
import {SidenavSection} from './sidenav-bar-section';
|
|
24
|
+
import {SidenavDoublePanel} from './sidenav-bar-panel';
|
|
25
|
+
import {SidenavBarMobile} from './sidenav-bar-mobile';
|
|
26
|
+
import {useIsMotionOff} from './sidenav-bar-motion';
|
|
27
|
+
import {useSidenavRailKeyboard} from './sidenav-bar-keyboard';
|
|
28
|
+
import {SidenavBarContext} from './sidenav-bar-context';
|
|
29
|
+
import {shouldShowBoxedBorder} from './boxed';
|
|
30
|
+
import {
|
|
31
|
+
isSidenavSection,
|
|
32
|
+
getFirstLevelItems,
|
|
33
|
+
getSidenavSectionTitle,
|
|
34
|
+
renderSidenavSlot,
|
|
35
|
+
renderSidenavLogo,
|
|
36
|
+
} from './sidenav-bar-data';
|
|
37
|
+
import * as tokens from './text-tokens';
|
|
38
|
+
import {isSidenavMoving} from './sidenav-bar-types';
|
|
39
|
+
|
|
40
|
+
import type {Variant} from './theme-variant-context';
|
|
41
|
+
import type {ExclusifyUnion} from './utils/utility-types';
|
|
42
|
+
import type {DataAttributes} from './utils/types';
|
|
43
|
+
import type {
|
|
44
|
+
SidenavEntry,
|
|
45
|
+
SidenavFirstLevelItem as SidenavFirstLevelItemData,
|
|
46
|
+
SidenavSecondLevelItem as SidenavSecondLevelItemData,
|
|
47
|
+
SidenavLogo,
|
|
48
|
+
SidenavSlot,
|
|
49
|
+
SidenavSlotRenderProps,
|
|
50
|
+
SidenavCollapseState,
|
|
51
|
+
} from './sidenav-bar-types';
|
|
52
|
+
|
|
53
|
+
type SidenavBarBaseProps = {
|
|
54
|
+
/**
|
|
55
|
+
* First-level entries of the body. Each entry is either a section with items, or a stand-alone item
|
|
56
|
+
* that needs no section.
|
|
57
|
+
* @see SidenavEntry
|
|
58
|
+
* @see SidenavSection
|
|
59
|
+
* @see SidenavFirstLevelItem
|
|
60
|
+
*/
|
|
61
|
+
entries?: ReadonlyArray<SidenavEntry>;
|
|
62
|
+
/** Accessible name of the navigation landmark. Defaults to a localized "Main navigation". */
|
|
63
|
+
'aria-label'?: string;
|
|
64
|
+
/** Color variant (default, brand, alternative, negative, media). @default 'default' */
|
|
65
|
+
variant?: Variant;
|
|
66
|
+
/** Width of expanded sidenav in pixels. The second column takes the same width. @default 240 */
|
|
67
|
+
width?: number;
|
|
68
|
+
/** Opens the children of a parent item in a second column, to the right of the sidenav.
|
|
69
|
+
* @default false */
|
|
70
|
+
doublePanel?: boolean;
|
|
71
|
+
/** Logo of the header. Defaults to the isotype of the skin at 32px, in both the expanded and the
|
|
72
|
+
* collapsed state. It takes true for that same default, false to hide the logo, an element of your
|
|
73
|
+
* own, or a function that receives the collapsed state and returns one logo for each state. The
|
|
74
|
+
* collapsed rail clamps the width of the logo to 32px, and the spot is at least 32px tall: a taller
|
|
75
|
+
* logo of your own makes the spot grow. The mobile top bar matches the main navigation
|
|
76
|
+
* bar: it shows the isotype at 40px, and it reports a collapsed state of false.
|
|
77
|
+
* @see SidenavLogoRenderProps */
|
|
78
|
+
logo?: SidenavLogo;
|
|
79
|
+
/** Custom content below logo/collapse in header. It takes an element, or a function that receives the
|
|
80
|
+
* collapse state and returns the content for that state.
|
|
81
|
+
* @see SidenavSlotRenderProps */
|
|
82
|
+
headerSlot?: SidenavSlot;
|
|
83
|
+
/** Custom background color of the whole sidenav: header, body, footer and second column. Use an
|
|
84
|
+
* opaque color: the header and the footer are sticky over the scrolling body, so a translucent color
|
|
85
|
+
* lets the body content show through them. */
|
|
86
|
+
background?: string;
|
|
87
|
+
/** ID of currently selected item (controlled selection). */
|
|
88
|
+
selectedItemId?: string | null;
|
|
89
|
+
/** Called when selection changes. */
|
|
90
|
+
onSelectedItemIdChange?: (id: string | null) => void;
|
|
91
|
+
dataAttributes?: DataAttributes;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Constraints enforced by the type system:
|
|
96
|
+
*
|
|
97
|
+
* - A boxed sidenav has its own edge, so the vertical right divider does not apply to it:
|
|
98
|
+
* `divider` is only accepted when `boxed` is false.
|
|
99
|
+
* - The collapsed state is either controlled through `collapsed` (requires `onCollapse`)
|
|
100
|
+
* or uncontrolled through `defaultCollapsed` (optional `onCollapse`), never both.
|
|
101
|
+
* - `showCollapseButton: false` removes the built-in collapse button, which is the only control that
|
|
102
|
+
* toggles the state from inside. Without it, the sidenav never changes the state by itself, so
|
|
103
|
+
* `onCollapse` has no event to report and `defaultCollapsed` has no state to seed: both are not
|
|
104
|
+
* allowed. That sidenav takes `collapsed` alone, and mirrors it on every render, so a control of your
|
|
105
|
+
* own (for example in a slot) still collapses it through that prop.
|
|
106
|
+
* - `fixedFooter` is only allowed when `footerSlot` is provided.
|
|
107
|
+
*/
|
|
108
|
+
type SidenavBarProps = SidenavBarBaseProps &
|
|
109
|
+
ExclusifyUnion<
|
|
110
|
+
| {
|
|
111
|
+
/** Renders as a floating box (with own edge). Divider not applicable. */
|
|
112
|
+
boxed: true;
|
|
113
|
+
}
|
|
114
|
+
| {
|
|
115
|
+
/** Renders as full-width. @default false */
|
|
116
|
+
boxed?: false;
|
|
117
|
+
/** Shows vertical right divider (only when boxed=false). @default true */
|
|
118
|
+
divider?: boolean;
|
|
119
|
+
}
|
|
120
|
+
> &
|
|
121
|
+
ExclusifyUnion<
|
|
122
|
+
| {
|
|
123
|
+
/** Controlled collapsed state. */
|
|
124
|
+
collapsed: boolean;
|
|
125
|
+
/** Handler for collapsed state changes (required for controlled mode). */
|
|
126
|
+
onCollapse: (collapsed: boolean) => void;
|
|
127
|
+
/** Renders the built-in collapse button, which lets the user toggle the state. @default true */
|
|
128
|
+
showCollapseButton?: true;
|
|
129
|
+
}
|
|
130
|
+
| {
|
|
131
|
+
/** Initial collapsed state (uncontrolled). @default false */
|
|
132
|
+
defaultCollapsed?: boolean;
|
|
133
|
+
/** Optional handler for collapsed state changes (for logging/effects). */
|
|
134
|
+
onCollapse?: (collapsed: boolean) => void;
|
|
135
|
+
/** Renders the built-in collapse button, which lets the user toggle the state. @default true */
|
|
136
|
+
showCollapseButton?: true;
|
|
137
|
+
}
|
|
138
|
+
| {
|
|
139
|
+
/** Collapsed state. There is no built-in button to toggle it, so the sidenav mirrors this
|
|
140
|
+
* prop on every render. Unlike `defaultCollapsed`, it is not a seed: a later change of it
|
|
141
|
+
* moves the sidenav. @default false */
|
|
142
|
+
collapsed?: boolean;
|
|
143
|
+
/** Hides the built-in collapse button. Only a change of `collapsed` moves the sidenav. */
|
|
144
|
+
showCollapseButton: false;
|
|
145
|
+
}
|
|
146
|
+
> &
|
|
147
|
+
ExclusifyUnion<
|
|
148
|
+
| {
|
|
149
|
+
/** Custom content in footer region (at bottom of sidenav). It takes an element, or a function
|
|
150
|
+
* that receives the collapse state and returns the content for that state.
|
|
151
|
+
* @see SidenavSlotRenderProps */
|
|
152
|
+
footerSlot: SidenavSlot;
|
|
153
|
+
/** Keep footer fixed when scrolling. @default false */
|
|
154
|
+
fixedFooter?: boolean;
|
|
155
|
+
}
|
|
156
|
+
| {
|
|
157
|
+
/** No footer slot. */
|
|
158
|
+
footerSlot?: undefined;
|
|
159
|
+
}
|
|
160
|
+
>;
|
|
161
|
+
|
|
162
|
+
const renderFirstLevelItem = (
|
|
163
|
+
item: SidenavFirstLevelItemData,
|
|
164
|
+
{standalone}: {standalone?: boolean} = {}
|
|
165
|
+
): React.ReactElement => (
|
|
166
|
+
<SidenavFirstLevelItem
|
|
167
|
+
key={item.id}
|
|
168
|
+
id={item.id}
|
|
169
|
+
label={item.label}
|
|
170
|
+
asset={item.asset}
|
|
171
|
+
showAssetWhenExpanded={item.showAssetWhenExpanded}
|
|
172
|
+
rightSlot={item.rightSlot}
|
|
173
|
+
standalone={standalone}
|
|
174
|
+
defaultOpen={item.defaultOpen}
|
|
175
|
+
secondLevelItems={item.children}
|
|
176
|
+
href={item.href}
|
|
177
|
+
to={item.to}
|
|
178
|
+
onPress={item.onPress}
|
|
179
|
+
newTab={item.newTab}
|
|
180
|
+
onNavigate={item.onNavigate}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Finds the first-level item that owns the given child id. The sidenav supports a single nesting
|
|
186
|
+
* level, so the parent of an item is always a first-level item.
|
|
187
|
+
*/
|
|
188
|
+
const findParentOfItem = (
|
|
189
|
+
entries: ReadonlyArray<SidenavEntry>,
|
|
190
|
+
childId: string
|
|
191
|
+
): SidenavFirstLevelItemData | undefined =>
|
|
192
|
+
getFirstLevelItems(entries).find((item) => item.children?.some((child) => child.id === childId));
|
|
193
|
+
|
|
194
|
+
/** Finds a first-level item by id. Only these items can open a panel. */
|
|
195
|
+
const findFirstLevelItem = (
|
|
196
|
+
entries: ReadonlyArray<SidenavEntry>,
|
|
197
|
+
itemId: string
|
|
198
|
+
): SidenavFirstLevelItemData | undefined => getFirstLevelItems(entries).find((item) => item.id === itemId);
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Development-only validation of the entries. It walks the data instead of checking inside each
|
|
202
|
+
* `SidenavItem` render: every item of the sidenav comes from this data, so one walk covers all of
|
|
203
|
+
* them, it reports each problem once, and it does not see the re-renders of the panel.
|
|
204
|
+
*/
|
|
205
|
+
const validateSidenavEntries = (entries: ReadonlyArray<SidenavEntry>): void => {
|
|
206
|
+
const seenIds = new Set<string>();
|
|
207
|
+
const duplicateIds = new Set<string>();
|
|
208
|
+
|
|
209
|
+
const visitItem = (item: SidenavFirstLevelItemData | SidenavSecondLevelItemData, level: number): void => {
|
|
210
|
+
if (seenIds.has(item.id)) {
|
|
211
|
+
duplicateIds.add(item.id);
|
|
212
|
+
} else {
|
|
213
|
+
seenIds.add(item.id);
|
|
214
|
+
}
|
|
215
|
+
if (level > 0 && item.children?.length) {
|
|
216
|
+
console.error(
|
|
217
|
+
`SidenavItem "${item.label}" at level ${level} cannot have children. ` +
|
|
218
|
+
`SidenavItem supports maximum 2 levels of nesting. ` +
|
|
219
|
+
`Only level 0 items can have children.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
item.children?.forEach((child) => visitItem(child, level + 1));
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
getFirstLevelItems(entries).forEach((item) => visitItem(item, 0));
|
|
226
|
+
|
|
227
|
+
if (duplicateIds.size > 0) {
|
|
228
|
+
console.error(
|
|
229
|
+
`SidenavBar: duplicate item IDs found: ${Array.from(duplicateIds).join(', ')}. ` +
|
|
230
|
+
`All SidenavItem ids must be unique within a SidenavBar.`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const renderSidenavEntries = (entries: ReadonlyArray<SidenavEntry>): Array<React.ReactElement> => {
|
|
236
|
+
// Every entry of the first level is one item of the body list, a section as much as a stand-alone
|
|
237
|
+
// item. A section holds a list of its own, and a stand-alone item holds a single row.
|
|
238
|
+
return entries.map((entry, entryIndex) => {
|
|
239
|
+
if (isSidenavSection(entry)) {
|
|
240
|
+
const previousEntry = entries[entryIndex - 1];
|
|
241
|
+
const sharesDividerWithPrevious =
|
|
242
|
+
!!entry.dividerTop &&
|
|
243
|
+
!!previousEntry &&
|
|
244
|
+
isSidenavSection(previousEntry) &&
|
|
245
|
+
!!previousEntry.dividerBottom;
|
|
246
|
+
const isFirstEntry = entryIndex === 0;
|
|
247
|
+
const isLastEntry = entryIndex === entries.length - 1;
|
|
248
|
+
return (
|
|
249
|
+
<div key={`${getSidenavSectionTitle(entry.title).text}-${entryIndex}`} role="listitem">
|
|
250
|
+
<SidenavSection
|
|
251
|
+
title={entry.title}
|
|
252
|
+
dividerTop={entry.dividerTop && !isFirstEntry && !sharesDividerWithPrevious}
|
|
253
|
+
dividerBottom={entry.dividerBottom && !isLastEntry}
|
|
254
|
+
>
|
|
255
|
+
{entry.items.map((item) => renderFirstLevelItem(item))}
|
|
256
|
+
</SidenavSection>
|
|
257
|
+
</div>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div key={entry.id} className={styles.standaloneItem} role="listitem">
|
|
263
|
+
{renderFirstLevelItem(entry as SidenavFirstLevelItemData, {standalone: true})}
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const SidenavBar = ({
|
|
270
|
+
entries,
|
|
271
|
+
'aria-label': ariaLabelProp,
|
|
272
|
+
variant = 'default',
|
|
273
|
+
boxed = false,
|
|
274
|
+
divider = true,
|
|
275
|
+
showCollapseButton = true,
|
|
276
|
+
collapsed: collapsedProp,
|
|
277
|
+
defaultCollapsed = false,
|
|
278
|
+
onCollapse,
|
|
279
|
+
doublePanel = false,
|
|
280
|
+
width = DEFAULT_WIDTH,
|
|
281
|
+
logo,
|
|
282
|
+
headerSlot,
|
|
283
|
+
footerSlot,
|
|
284
|
+
fixedFooter = false,
|
|
285
|
+
background,
|
|
286
|
+
selectedItemId,
|
|
287
|
+
onSelectedItemIdChange,
|
|
288
|
+
dataAttributes,
|
|
289
|
+
}: SidenavBarProps): JSX.Element => {
|
|
290
|
+
const {isTabletOrSmaller} = useScreenSize();
|
|
291
|
+
const {componentProperties, texts, t} = useTheme();
|
|
292
|
+
const ariaLabel = ariaLabelProp ?? (texts.sidenavLandmark || t(tokens.sidenavLandmark));
|
|
293
|
+
const isMotionOff = useIsMotionOff();
|
|
294
|
+
// Read before the `ThemeVariant` of the returned tree, so this is the variant of the page that holds the
|
|
295
|
+
// sidenav, and not the variant of the sidenav itself.
|
|
296
|
+
const pageVariant = normalizeVariant(useThemeVariant());
|
|
297
|
+
const [panelOpenForItemId, setPanelOpenForItemId] = React.useState<string | null>(() =>
|
|
298
|
+
doublePanel && entries && selectedItemId
|
|
299
|
+
? findParentOfItem(entries, selectedItemId)?.id ?? null
|
|
300
|
+
: null
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
const isCollapsedControlled = collapsedProp !== undefined;
|
|
304
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = React.useState(defaultCollapsed);
|
|
305
|
+
// A controlled sidenav (`collapsed` set) reads the prop on every render. An uncontrolled one owns its
|
|
306
|
+
// state, which `defaultCollapsed` seeds once. Without the built-in button nothing toggles that state,
|
|
307
|
+
// so a sidenav that hides the button and omits `collapsed` keeps the seed, which the types pin to false.
|
|
308
|
+
const collapsed = isCollapsedControlled ? Boolean(collapsedProp) : uncontrolledCollapsed;
|
|
309
|
+
const containerRef = React.useRef<HTMLElement>(null);
|
|
310
|
+
|
|
311
|
+
// The second column slides away instead of disappearing, so it still renders while it closes, when the
|
|
312
|
+
// item that opened it is already gone. It therefore keeps the title and the children of that item
|
|
313
|
+
// until a new item replaces them.
|
|
314
|
+
const doublePanelRef = React.useRef<HTMLDivElement>(null);
|
|
315
|
+
const [doublePanelContent, setDoublePanelContent] = React.useState<{
|
|
316
|
+
itemId: string;
|
|
317
|
+
label: string;
|
|
318
|
+
children: ReadonlyArray<SidenavSecondLevelItemData>;
|
|
319
|
+
} | null>(null);
|
|
320
|
+
|
|
321
|
+
// The settled state follows `collapsed` once the rail rests. A user who turned motion down sees no
|
|
322
|
+
// movement, so it follows at once there.
|
|
323
|
+
const [collapsedSettled, setCollapsedSettled] = React.useState(collapsed);
|
|
324
|
+
React.useEffect(() => {
|
|
325
|
+
if (isMotionOff) {
|
|
326
|
+
setCollapsedSettled(collapsed);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const timeoutId = setTimeout(() => setCollapsedSettled(collapsed), COLLAPSE_DURATION_MS);
|
|
330
|
+
return () => clearTimeout(timeoutId);
|
|
331
|
+
}, [collapsed, isMotionOff]);
|
|
332
|
+
const collapseState: SidenavCollapseState = collapsed
|
|
333
|
+
? collapsedSettled
|
|
334
|
+
? 'collapsed'
|
|
335
|
+
: 'collapsing'
|
|
336
|
+
: collapsedSettled
|
|
337
|
+
? 'expanding'
|
|
338
|
+
: 'expanded';
|
|
339
|
+
|
|
340
|
+
// A press on an item of the sidenav closes the panel and moves the selection at the same time.
|
|
341
|
+
// The press records its selection here, so the adjustment below knows the user already dismissed
|
|
342
|
+
// the second column for that selection, and does not reopen it.
|
|
343
|
+
const [dismissedSelection, setDismissedSelection] = React.useState<string | null>(null);
|
|
344
|
+
|
|
345
|
+
const selectItemAndClosePanel = React.useCallback(
|
|
346
|
+
(itemId: string | null) => {
|
|
347
|
+
if (doublePanel) {
|
|
348
|
+
setDismissedSelection(itemId);
|
|
349
|
+
}
|
|
350
|
+
setPanelOpenForItemId(null);
|
|
351
|
+
if (itemId) {
|
|
352
|
+
onSelectedItemIdChange?.(itemId);
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
[doublePanel, onSelectedItemIdChange]
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
// The second column follows the selection, which can also move from outside of the sidenav (a
|
|
359
|
+
// breadcrumb, a card, a button of the app):
|
|
360
|
+
// - a second-level item opens the column on its parent, so that the new selection stays visible;
|
|
361
|
+
// - a first-level item without children closes the column, because it has nothing to show there;
|
|
362
|
+
// - a press inside the sidenav closes the column through `selectItemAndClosePanel`, and that press
|
|
363
|
+
// wins over the selection it carries.
|
|
364
|
+
// The adjustment runs during the render, where the entries and the previous selection are both in
|
|
365
|
+
// scope, so it needs no effect and no refs. React applies the state it sets before it paints.
|
|
366
|
+
const [previousSelection, setPreviousSelection] = React.useState(selectedItemId);
|
|
367
|
+
if (selectedItemId !== previousSelection) {
|
|
368
|
+
setPreviousSelection(selectedItemId);
|
|
369
|
+
if (dismissedSelection !== null) {
|
|
370
|
+
setDismissedSelection(null);
|
|
371
|
+
}
|
|
372
|
+
if (doublePanel && entries && selectedItemId && dismissedSelection !== selectedItemId) {
|
|
373
|
+
const parent = findParentOfItem(entries, selectedItemId);
|
|
374
|
+
if (parent) {
|
|
375
|
+
setPanelOpenForItemId(parent.id);
|
|
376
|
+
} else {
|
|
377
|
+
const firstLevelItem = findFirstLevelItem(entries, selectedItemId);
|
|
378
|
+
if (firstLevelItem && !firstLevelItem.children?.length) {
|
|
379
|
+
setPanelOpenForItemId(null);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// The column closes as soon as the double panel mode goes off. Only the change of the mode closes it:
|
|
386
|
+
// the collapsed rail opens its dialog panel through this same state with the mode off.
|
|
387
|
+
const [previousDoublePanel, setPreviousDoublePanel] = React.useState(doublePanel);
|
|
388
|
+
if (doublePanel !== previousDoublePanel) {
|
|
389
|
+
setPreviousDoublePanel(doublePanel);
|
|
390
|
+
if (!doublePanel) {
|
|
391
|
+
setPanelOpenForItemId(null);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// A change of the entries invalidates the open column, whose parent item may not exist anymore.
|
|
396
|
+
const [previousEntriesLength, setPreviousEntriesLength] = React.useState(entries?.length ?? 0);
|
|
397
|
+
if ((entries?.length ?? 0) !== previousEntriesLength) {
|
|
398
|
+
setPreviousEntriesLength(entries?.length ?? 0);
|
|
399
|
+
setPanelOpenForItemId(null);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Only a press outside of the whole bar, or Escape, dismisses the second column: a press inside the
|
|
403
|
+
// bar that lands on no item keeps it open, and a press on an item closes it through
|
|
404
|
+
// `selectItemAndClosePanel`. A press that also carries a new selection does not race the close: the
|
|
405
|
+
// adjustment above reopens the column for that selection in the same batch of updates.
|
|
406
|
+
React.useEffect(() => {
|
|
407
|
+
if (!doublePanel || !panelOpenForItemId) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const handlePressOutside = (event: MouseEvent) => {
|
|
412
|
+
const container = containerRef.current;
|
|
413
|
+
if (!container) return;
|
|
414
|
+
// The browser builds this path when it dispatches the press, so the path still holds the node
|
|
415
|
+
// that the user pressed and all of its ancestors, even when React replaced them before this
|
|
416
|
+
// listener ran. Reading `event.target` instead counts a press on a control that swaps its own
|
|
417
|
+
// node as a press outside of the bar: the collapse action swaps its icon, and a parent item
|
|
418
|
+
// swaps its whole row, so both of them closed the column that they should have left alone.
|
|
419
|
+
if (event.composedPath().includes(container)) return;
|
|
420
|
+
setPanelOpenForItemId(null);
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const handleEscape = (event: KeyboardEvent) => {
|
|
424
|
+
if (event.key === 'Escape') {
|
|
425
|
+
setPanelOpenForItemId(null);
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
document.addEventListener('click', handlePressOutside);
|
|
430
|
+
document.addEventListener('keydown', handleEscape);
|
|
431
|
+
return () => {
|
|
432
|
+
document.removeEventListener('click', handlePressOutside);
|
|
433
|
+
document.removeEventListener('keydown', handleEscape);
|
|
434
|
+
};
|
|
435
|
+
}, [doublePanel, panelOpenForItemId]);
|
|
436
|
+
|
|
437
|
+
const backgroundStyle = background ? {backgroundColor: background} : undefined;
|
|
438
|
+
|
|
439
|
+
const [showHeaderDivider, setShowHeaderDivider] = React.useState(false);
|
|
440
|
+
const [showFooterDivider, setShowFooterDivider] = React.useState(false);
|
|
441
|
+
// The panel keeps its node while it slides back into the main column, so the column separator stays with
|
|
442
|
+
// it until the movement ends. `isDoublePanelOpen` alone drops the separator when the panel starts to
|
|
443
|
+
// close, and the boundary disappears while the column is still visible.
|
|
444
|
+
const [isDoublePanelMounted, setIsDoublePanelMounted] = React.useState(false);
|
|
445
|
+
const headerDividerSentinelRef = React.useRef<HTMLDivElement>(null);
|
|
446
|
+
const footerDividerSentinelRef = React.useRef<HTMLDivElement>(null);
|
|
447
|
+
const bodyRef = React.useRef<HTMLDivElement>(null);
|
|
448
|
+
|
|
449
|
+
React.useEffect(() => {
|
|
450
|
+
if (!bodyRef.current) return;
|
|
451
|
+
|
|
452
|
+
// The sentinels have no height, and at rest they sit exactly on the edge of the scrollport. A
|
|
453
|
+
// fractional layout (a boxed sidenav measures 100vh minus its margins) can leave them half a
|
|
454
|
+
// pixel outside, and the observer would then paint the divider before any scroll. The 1px root
|
|
455
|
+
// margin counts an edge-adjacent sentinel as inside.
|
|
456
|
+
const headerObserver = new IntersectionObserver(
|
|
457
|
+
([entry]) => {
|
|
458
|
+
setShowHeaderDivider(!entry.isIntersecting);
|
|
459
|
+
},
|
|
460
|
+
{root: bodyRef.current, threshold: 0, rootMargin: '1px 0px 1px 0px'}
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
const footerObserver = new IntersectionObserver(
|
|
464
|
+
([entry]) => {
|
|
465
|
+
setShowFooterDivider(!entry.isIntersecting);
|
|
466
|
+
},
|
|
467
|
+
{root: bodyRef.current, threshold: 0, rootMargin: '1px 0px 1px 0px'}
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
if (headerDividerSentinelRef.current) {
|
|
471
|
+
headerObserver.observe(headerDividerSentinelRef.current);
|
|
472
|
+
}
|
|
473
|
+
if (footerDividerSentinelRef.current) {
|
|
474
|
+
footerObserver.observe(footerDividerSentinelRef.current);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return () => {
|
|
478
|
+
headerObserver.disconnect();
|
|
479
|
+
footerObserver.disconnect();
|
|
480
|
+
};
|
|
481
|
+
}, []);
|
|
482
|
+
|
|
483
|
+
// The rail is travelling between its two widths. See `columnsWhileMoving`.
|
|
484
|
+
const isMoving = isSidenavMoving(collapseState);
|
|
485
|
+
|
|
486
|
+
const toggleCollapsed = React.useCallback(() => {
|
|
487
|
+
// The collapse action keeps the focus while the rail moves, so the pointer rule of
|
|
488
|
+
// `columnsWhileMoving` does not reach a press made with the keyboard. This does.
|
|
489
|
+
if (isMoving) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const next = !collapsed;
|
|
493
|
+
if (!isCollapsedControlled) {
|
|
494
|
+
setUncontrolledCollapsed(next);
|
|
495
|
+
onCollapse?.(next);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
onCollapse?.(next);
|
|
499
|
+
}, [collapsed, isMoving, isCollapsedControlled, onCollapse]);
|
|
500
|
+
|
|
501
|
+
const contextValue = React.useMemo(
|
|
502
|
+
() => ({
|
|
503
|
+
collapsed,
|
|
504
|
+
collapseState,
|
|
505
|
+
isMotionOff,
|
|
506
|
+
doublePanel,
|
|
507
|
+
panelOpenForItemId,
|
|
508
|
+
setPanelOpenForItemId,
|
|
509
|
+
selectItemAndClosePanel,
|
|
510
|
+
containerRef,
|
|
511
|
+
selectedItemId: selectedItemId ?? null,
|
|
512
|
+
}),
|
|
513
|
+
[
|
|
514
|
+
collapsed,
|
|
515
|
+
collapseState,
|
|
516
|
+
isMotionOff,
|
|
517
|
+
doublePanel,
|
|
518
|
+
panelOpenForItemId,
|
|
519
|
+
selectItemAndClosePanel,
|
|
520
|
+
containerRef,
|
|
521
|
+
selectedItemId,
|
|
522
|
+
]
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
const handleRailKeyDown = useSidenavRailKeyboard(containerRef);
|
|
526
|
+
|
|
527
|
+
const currentWidth = collapsed ? COLLAPSED_WIDTH : width;
|
|
528
|
+
|
|
529
|
+
if (process.env.NODE_ENV !== 'production' && entries) {
|
|
530
|
+
validateSidenavEntries(entries);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const normalizedVariant = normalizeVariant(variant);
|
|
534
|
+
|
|
535
|
+
// A tablet has no room for the rail either, so both breakpoints take the mobile treatment.
|
|
536
|
+
if (isTabletOrSmaller) {
|
|
537
|
+
return (
|
|
538
|
+
<SidenavBarMobile
|
|
539
|
+
entries={entries}
|
|
540
|
+
aria-label={ariaLabel}
|
|
541
|
+
variant={normalizedVariant}
|
|
542
|
+
logo={logo}
|
|
543
|
+
headerSlot={headerSlot}
|
|
544
|
+
footerSlot={footerSlot}
|
|
545
|
+
selectedItemId={selectedItemId ?? null}
|
|
546
|
+
onSelectedItemIdChange={onSelectedItemIdChange}
|
|
547
|
+
dataAttributes={dataAttributes}
|
|
548
|
+
/>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const slotRenderProps: SidenavSlotRenderProps = {collapsed, state: collapseState};
|
|
553
|
+
const isDefaultLogo = logo === undefined || logo === true;
|
|
554
|
+
const logoElement = renderSidenavLogo(logo, slotRenderProps, <Logo size={LOGO_SIZE} type="isotype" />);
|
|
555
|
+
|
|
556
|
+
const collapseActionElement = (() => {
|
|
557
|
+
if (!showCollapseButton) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return (
|
|
562
|
+
<IconButton
|
|
563
|
+
Icon={collapsed ? IconPanelExpandRegular : IconPanelCollapseRegular}
|
|
564
|
+
type="neutral"
|
|
565
|
+
backgroundType="transparent"
|
|
566
|
+
small
|
|
567
|
+
onPress={toggleCollapsed}
|
|
568
|
+
aria-label={
|
|
569
|
+
collapsed
|
|
570
|
+
? texts.sidenavExpand || t(tokens.sidenavExpand)
|
|
571
|
+
: texts.sidenavCollapse || t(tokens.sidenavCollapse)
|
|
572
|
+
}
|
|
573
|
+
aria-expanded={!collapsed}
|
|
574
|
+
/>
|
|
575
|
+
);
|
|
576
|
+
})();
|
|
577
|
+
|
|
578
|
+
const headerSlotElement = renderSidenavSlot(headerSlot, slotRenderProps);
|
|
579
|
+
const footerSlotElement = renderSidenavSlot(footerSlot, slotRenderProps);
|
|
580
|
+
const hasHeader = Boolean(logoElement || collapseActionElement || headerSlotElement);
|
|
581
|
+
// todo https://github.com/Telefonica/mistica-design/issues/2827 review Boxed border rendering logic
|
|
582
|
+
const hasBoxedBorder =
|
|
583
|
+
boxed && shouldShowBoxedBorder(normalizedVariant, pageVariant, componentProperties.showBoxedBorder);
|
|
584
|
+
|
|
585
|
+
// The second column belongs to the sidenav, not to the item that opens it, so that it can span the
|
|
586
|
+
// whole height of the sidenav and push the content of the layout.
|
|
587
|
+
const doublePanelItem =
|
|
588
|
+
doublePanel && panelOpenForItemId && entries
|
|
589
|
+
? findFirstLevelItem(entries, panelOpenForItemId)
|
|
590
|
+
: undefined;
|
|
591
|
+
const doublePanelChildren = doublePanelItem?.children;
|
|
592
|
+
const isDoublePanelOpen = Boolean(doublePanelChildren?.length);
|
|
593
|
+
|
|
594
|
+
// This sets state during the render, as the block above does. React then paints once, with the new
|
|
595
|
+
// content. The comparison skips the update when the content did not change, which would loop.
|
|
596
|
+
if (
|
|
597
|
+
doublePanelItem &&
|
|
598
|
+
doublePanelChildren?.length &&
|
|
599
|
+
(doublePanelContent?.label !== doublePanelItem.label ||
|
|
600
|
+
doublePanelContent?.children !== doublePanelChildren)
|
|
601
|
+
) {
|
|
602
|
+
setDoublePanelContent({
|
|
603
|
+
itemId: doublePanelItem.id,
|
|
604
|
+
label: doublePanelItem.label,
|
|
605
|
+
children: doublePanelChildren,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return (
|
|
610
|
+
<ThemeVariant variant={normalizedVariant}>
|
|
611
|
+
<SidenavBarContext.Provider value={contextValue}>
|
|
612
|
+
{/* The rail moves the focus between its items with the arrow keys, so the landmark holds the
|
|
613
|
+
key handler that owns that movement. */}
|
|
614
|
+
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
|
|
615
|
+
<nav
|
|
616
|
+
ref={containerRef}
|
|
617
|
+
aria-label={ariaLabel}
|
|
618
|
+
onKeyDown={handleRailKeyDown}
|
|
619
|
+
className={classnames(styles.container, {
|
|
620
|
+
[styles.withRightDivider[normalizedVariant]]: divider && !boxed,
|
|
621
|
+
[styles.boxed]: boxed,
|
|
622
|
+
[styles.boxedBorder]: hasBoxedBorder,
|
|
623
|
+
[styles.columnsWhileMoving]: isMoving,
|
|
624
|
+
})}
|
|
625
|
+
style={applyCssVars({
|
|
626
|
+
[styles.sidenavWidthVar]: `${currentWidth}px`,
|
|
627
|
+
[styles.sidenavPanelWidthVar]: `${width}px`,
|
|
628
|
+
[styles.collapseDurationVar]: `${isMotionOff ? 0 : COLLAPSE_DURATION_MS}ms`,
|
|
629
|
+
[styles.contentDurationVar]: `${isMotionOff ? 0 : CONTENT_DURATION_MS}ms`,
|
|
630
|
+
})}
|
|
631
|
+
{...getPrefixedDataAttributes({testid: 'SidenavBar', ...dataAttributes})}
|
|
632
|
+
>
|
|
633
|
+
<div
|
|
634
|
+
className={classnames(styles.mainColumn, {
|
|
635
|
+
[styles.columnSeparator[normalizedVariant]]:
|
|
636
|
+
isDoublePanelOpen || isDoublePanelMounted,
|
|
637
|
+
})}
|
|
638
|
+
>
|
|
639
|
+
{hasHeader && (
|
|
640
|
+
<div
|
|
641
|
+
className={classnames(
|
|
642
|
+
styles.headerBase,
|
|
643
|
+
styles.regionBackground[normalizedVariant],
|
|
644
|
+
{
|
|
645
|
+
[styles.headerNegativeBoxedBackground]:
|
|
646
|
+
boxed && normalizedVariant === 'negative',
|
|
647
|
+
}
|
|
648
|
+
)}
|
|
649
|
+
style={backgroundStyle}
|
|
650
|
+
>
|
|
651
|
+
<div
|
|
652
|
+
className={classnames(styles.headerControls, {
|
|
653
|
+
[styles.headerControlsCollapsed]: collapsed,
|
|
654
|
+
})}
|
|
655
|
+
>
|
|
656
|
+
{logoElement && (
|
|
657
|
+
<div
|
|
658
|
+
className={classnames(styles.logo, {
|
|
659
|
+
[styles.logoDefault]: isDefaultLogo,
|
|
660
|
+
[styles.logoCollapsed]: collapsed,
|
|
661
|
+
})}
|
|
662
|
+
// Only the default brand mark leaves the reading order. A logo of
|
|
663
|
+
// the consumer keeps its own accessibility.
|
|
664
|
+
aria-hidden={isDefaultLogo || undefined}
|
|
665
|
+
>
|
|
666
|
+
{logoElement}
|
|
667
|
+
</div>
|
|
668
|
+
)}
|
|
669
|
+
{collapseActionElement}
|
|
670
|
+
</div>
|
|
671
|
+
{headerSlotElement && (
|
|
672
|
+
<div
|
|
673
|
+
className={classnames(styles.headerSlot, {
|
|
674
|
+
[styles.headerSlotCollapsed]: collapsed,
|
|
675
|
+
})}
|
|
676
|
+
>
|
|
677
|
+
{headerSlotElement}
|
|
678
|
+
</div>
|
|
679
|
+
)}
|
|
680
|
+
</div>
|
|
681
|
+
)}
|
|
682
|
+
<div
|
|
683
|
+
ref={bodyRef}
|
|
684
|
+
className={classnames(
|
|
685
|
+
styles.bodyBase,
|
|
686
|
+
styles.regionBackground[normalizedVariant],
|
|
687
|
+
{[styles.bodyWithFixedFooter]: !!footerSlot && fixedFooter}
|
|
688
|
+
)}
|
|
689
|
+
style={backgroundStyle}
|
|
690
|
+
onFocus={(event) => {
|
|
691
|
+
// A row can take the focus while its ring crosses a seam: the row itself
|
|
692
|
+
// is visible, so the browser scrolls nothing, and the scroll padding of
|
|
693
|
+
// the body never engages. The nudge applies it. `nearest` keeps an
|
|
694
|
+
// already-clear row untouched, and the check leaves a pointer focus
|
|
695
|
+
// alone, which draws no ring.
|
|
696
|
+
const target = event.target as HTMLElement;
|
|
697
|
+
try {
|
|
698
|
+
if (target.matches(':focus-visible')) {
|
|
699
|
+
target.scrollIntoView({block: 'nearest'});
|
|
700
|
+
}
|
|
701
|
+
} catch {
|
|
702
|
+
// jsdom implements neither `:focus-visible` nor `scrollIntoView`.
|
|
703
|
+
}
|
|
704
|
+
}}
|
|
705
|
+
>
|
|
706
|
+
<div ref={headerDividerSentinelRef} />
|
|
707
|
+
<div
|
|
708
|
+
className={classnames(styles.headerScrollSpacer, {
|
|
709
|
+
[styles.regionBackground[normalizedVariant]]:
|
|
710
|
+
hasHeader && showHeaderDivider,
|
|
711
|
+
})}
|
|
712
|
+
style={hasHeader && showHeaderDivider ? backgroundStyle : undefined}
|
|
713
|
+
>
|
|
714
|
+
{hasHeader && showHeaderDivider && (
|
|
715
|
+
<div
|
|
716
|
+
className={classnames(
|
|
717
|
+
styles.scrollSpacerDivider,
|
|
718
|
+
styles.scrollDividerVariant[normalizedVariant]
|
|
719
|
+
)}
|
|
720
|
+
/>
|
|
721
|
+
)}
|
|
722
|
+
</div>
|
|
723
|
+
{entries && (
|
|
724
|
+
// The body is the list of the first level. Each entry is one of its items.
|
|
725
|
+
<div className={styles.bodyContent} role="list">
|
|
726
|
+
{renderSidenavEntries(entries)}
|
|
727
|
+
</div>
|
|
728
|
+
)}
|
|
729
|
+
{footerSlot && !fixedFooter && (
|
|
730
|
+
<>
|
|
731
|
+
<div ref={footerDividerSentinelRef} />
|
|
732
|
+
{showFooterDivider && (
|
|
733
|
+
<div
|
|
734
|
+
className={classnames(
|
|
735
|
+
styles.scrollDivider,
|
|
736
|
+
styles.footerScrollDivider,
|
|
737
|
+
styles.scrollDividerVariant[normalizedVariant]
|
|
738
|
+
)}
|
|
739
|
+
/>
|
|
740
|
+
)}
|
|
741
|
+
<div
|
|
742
|
+
className={classnames(
|
|
743
|
+
styles.footerBase,
|
|
744
|
+
styles.regionBackground[normalizedVariant],
|
|
745
|
+
{[styles.footerCollapsed]: collapsed}
|
|
746
|
+
)}
|
|
747
|
+
style={backgroundStyle}
|
|
748
|
+
>
|
|
749
|
+
{footerSlotElement}
|
|
750
|
+
</div>
|
|
751
|
+
</>
|
|
752
|
+
)}
|
|
753
|
+
{footerSlot && fixedFooter && (
|
|
754
|
+
<>
|
|
755
|
+
<div ref={footerDividerSentinelRef} />
|
|
756
|
+
<div
|
|
757
|
+
className={classnames(styles.footerScrollSpacer, {
|
|
758
|
+
[styles.regionBackground[normalizedVariant]]: showFooterDivider,
|
|
759
|
+
})}
|
|
760
|
+
style={showFooterDivider ? backgroundStyle : undefined}
|
|
761
|
+
>
|
|
762
|
+
{showFooterDivider && (
|
|
763
|
+
<div
|
|
764
|
+
className={classnames(
|
|
765
|
+
styles.scrollSpacerDivider,
|
|
766
|
+
styles.scrollDividerVariant[normalizedVariant]
|
|
767
|
+
)}
|
|
768
|
+
/>
|
|
769
|
+
)}
|
|
770
|
+
</div>
|
|
771
|
+
</>
|
|
772
|
+
)}
|
|
773
|
+
</div>
|
|
774
|
+
{footerSlot && fixedFooter && (
|
|
775
|
+
<div
|
|
776
|
+
className={classnames(
|
|
777
|
+
styles.footerBase,
|
|
778
|
+
styles.footerFixed,
|
|
779
|
+
styles.regionBackground[normalizedVariant],
|
|
780
|
+
{[styles.footerCollapsed]: collapsed}
|
|
781
|
+
)}
|
|
782
|
+
style={backgroundStyle}
|
|
783
|
+
>
|
|
784
|
+
{footerSlotElement}
|
|
785
|
+
</div>
|
|
786
|
+
)}
|
|
787
|
+
</div>
|
|
788
|
+
{doublePanelContent && (
|
|
789
|
+
<CSSTransition
|
|
790
|
+
in={isDoublePanelOpen}
|
|
791
|
+
timeout={isMotionOff ? 0 : COLLAPSE_DURATION_MS}
|
|
792
|
+
nodeRef={doublePanelRef}
|
|
793
|
+
classNames={styles.doublePanelTransitionClasses}
|
|
794
|
+
appear
|
|
795
|
+
mountOnEnter
|
|
796
|
+
unmountOnExit
|
|
797
|
+
onEnter={() => setIsDoublePanelMounted(true)}
|
|
798
|
+
onExited={() => setIsDoublePanelMounted(false)}
|
|
799
|
+
>
|
|
800
|
+
<SidenavDoublePanel
|
|
801
|
+
ref={doublePanelRef}
|
|
802
|
+
itemId={doublePanelContent.itemId}
|
|
803
|
+
label={doublePanelContent.label}
|
|
804
|
+
variant={normalizedVariant}
|
|
805
|
+
backgroundColor={background}
|
|
806
|
+
>
|
|
807
|
+
{doublePanelContent.children.map((child) =>
|
|
808
|
+
renderSidenavSecondLevelItem(child, {placement: 'panel'})
|
|
809
|
+
)}
|
|
810
|
+
</SidenavDoublePanel>
|
|
811
|
+
</CSSTransition>
|
|
812
|
+
)}
|
|
813
|
+
</nav>
|
|
814
|
+
</SidenavBarContext.Provider>
|
|
815
|
+
</ThemeVariant>
|
|
816
|
+
);
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
export default SidenavBar;
|
|
820
|
+
export {SidenavBar};
|
|
821
|
+
export type {SidenavBarProps};
|