@shortfuse/materialdesignweb 0.8.0 → 0.9.1
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/README.md +50 -198
- package/bin/mdw-css.js +1 -1
- package/components/Badge.js +15 -5
- package/components/Body.js +7 -0
- package/components/BottomAppBar.js +7 -10
- package/components/BottomSheet.js +472 -0
- package/components/Box.js +11 -49
- package/components/Button.js +81 -82
- package/components/Card.js +74 -62
- package/components/Checkbox.js +15 -25
- package/components/CheckboxIcon.js +19 -31
- package/components/Chip.js +18 -13
- package/components/Dialog.js +70 -100
- package/components/DialogActions.js +4 -0
- package/components/Display.js +64 -0
- package/components/Divider.js +5 -0
- package/components/Fab.js +94 -17
- package/components/FabContainer.js +57 -0
- package/components/FilterChip.js +43 -32
- package/components/Grid.js +187 -0
- package/components/Headline.js +9 -28
- package/components/Icon.js +80 -71
- package/components/IconButton.js +77 -120
- package/components/Input.js +745 -86
- package/components/InputChip.js +193 -0
- package/components/Label.js +7 -0
- package/components/List.js +11 -5
- package/components/ListItem.js +92 -23
- package/components/ListOption.js +143 -65
- package/components/Listbox.js +57 -17
- package/components/Menu.js +39 -27
- package/components/MenuItem.js +49 -36
- package/components/NavBar.js +66 -21
- package/components/NavBarItem.js +5 -0
- package/components/NavDrawer.js +33 -16
- package/components/NavDrawerItem.js +7 -4
- package/components/NavItem.js +61 -34
- package/components/NavRail.js +32 -21
- package/components/NavRailItem.js +10 -2
- package/components/Page.js +119 -0
- package/components/Pane.js +24 -0
- package/components/Popup.js +23 -8
- package/components/Progress.js +25 -5
- package/components/Radio.js +8 -7
- package/components/RadioIcon.js +24 -15
- package/components/Ripple.js +25 -7
- package/components/Root.js +225 -0
- package/components/Scrim.js +95 -0
- package/components/Search.js +30 -25
- package/components/SegmentedButton.js +53 -40
- package/components/SegmentedButtonGroup.js +15 -12
- package/components/Select.js +19 -10
- package/components/Shape.js +10 -66
- package/components/SideSheet.js +337 -0
- package/components/Slider.js +93 -36
- package/components/Snackbar.js +52 -20
- package/components/SnackbarContainer.js +51 -0
- package/components/Surface.js +20 -10
- package/components/Switch.js +21 -18
- package/components/SwitchIcon.js +62 -33
- package/components/Tab.js +78 -38
- package/components/TabContent.js +33 -12
- package/components/TabList.js +95 -34
- package/components/TabPanel.js +10 -1
- package/components/Table.js +151 -0
- package/components/TextArea.js +48 -16
- package/components/Title.js +8 -9
- package/components/Tooltip.js +51 -22
- package/components/TopAppBar.js +71 -78
- package/constants/shapes.js +36 -0
- package/constants/typography.js +127 -0
- package/core/Composition.js +391 -201
- package/core/CompositionAdapter.js +35 -18
- package/core/CustomElement.js +634 -254
- package/core/css.js +117 -12
- package/core/customTypes.js +161 -49
- package/core/dom.js +18 -11
- package/core/jsonMergePatch.js +27 -11
- package/core/observe.js +308 -256
- package/core/optimizations.js +9 -9
- package/core/template.js +14 -57
- package/dist/CustomElement.min.js +2 -0
- package/dist/CustomElement.min.js.map +7 -0
- package/dist/core/CustomElement.min.js +2 -0
- package/dist/core/CustomElement.min.js.map +7 -0
- package/dist/index.min.js +85 -115
- package/dist/index.min.js.map +4 -4
- package/dist/meta.json +1 -1
- package/dom/HTMLOptionsCollectionProxy.js +108 -0
- package/{theming/themableMixinLoader.js → loaders/palette.js} +4 -3
- package/loaders/theme.js +12 -0
- package/mixins/AriaReflectorMixin.js +64 -15
- package/mixins/AriaToolbarMixin.js +6 -0
- package/mixins/ControlMixin.js +79 -33
- package/mixins/DelegatesFocusMixin.js +62 -0
- package/mixins/DensityMixin.js +7 -3
- package/mixins/ElevationMixin.js +61 -0
- package/mixins/FlexableMixin.js +87 -39
- package/mixins/FormAssociatedMixin.js +76 -10
- package/mixins/HyperlinkMixin.js +76 -0
- package/mixins/InputMixin.js +227 -32
- package/mixins/KeyboardNavMixin.js +11 -7
- package/mixins/NavigationListenerMixin.js +33 -0
- package/mixins/PopupMixin.js +216 -219
- package/mixins/RTLObserverMixin.js +2 -0
- package/mixins/ResizeObserverMixin.js +18 -4
- package/mixins/RippleMixin.js +11 -7
- package/mixins/ScrollListenerMixin.js +14 -2
- package/mixins/SemiStickyMixin.js +51 -98
- package/mixins/ShapeMaskedMixin.js +125 -0
- package/mixins/ShapeMixin.js +30 -203
- package/mixins/StateMixin.js +74 -34
- package/mixins/TextFieldMixin.js +128 -145
- package/mixins/ThemableMixin.js +57 -56
- package/mixins/TooltipTriggerMixin.js +305 -359
- package/mixins/TouchTargetMixin.js +5 -2
- package/mixins/TypographyMixin.js +128 -0
- package/package.json +125 -81
- package/services/rtl.js +10 -0
- package/services/svgAlias.js +17 -0
- package/{theming/index.js → services/theme.js} +25 -176
- package/types/bin/mdw-css.d.ts +3 -0
- package/types/bin/mdw-css.d.ts.map +1 -0
- package/types/components/Badge.d.ts +39 -0
- package/types/components/Badge.d.ts.map +1 -0
- package/types/components/Body.d.ts +29 -0
- package/types/components/Body.d.ts.map +1 -0
- package/types/components/BottomAppBar.d.ts +72 -0
- package/types/components/BottomAppBar.d.ts.map +1 -0
- package/types/components/BottomSheet.d.ts +135 -0
- package/types/components/BottomSheet.d.ts.map +1 -0
- package/types/components/Box.d.ts +16 -0
- package/types/components/Box.d.ts.map +1 -0
- package/types/components/Button.d.ts +245 -0
- package/types/components/Button.d.ts.map +1 -0
- package/types/components/Card.d.ts +147 -0
- package/types/components/Card.d.ts.map +1 -0
- package/types/components/Checkbox.d.ts +207 -0
- package/types/components/Checkbox.d.ts.map +1 -0
- package/types/components/CheckboxIcon.d.ts +44 -0
- package/types/components/CheckboxIcon.d.ts.map +1 -0
- package/types/components/Chip.d.ts +248 -0
- package/types/components/Chip.d.ts.map +1 -0
- package/types/components/Dialog.d.ts +103 -0
- package/types/components/Dialog.d.ts.map +1 -0
- package/types/components/DialogActions.d.ts +4 -0
- package/types/components/DialogActions.d.ts.map +1 -0
- package/types/components/Display.d.ts +46 -0
- package/types/components/Display.d.ts.map +1 -0
- package/types/components/Divider.d.ts +10 -0
- package/types/components/Divider.d.ts.map +1 -0
- package/types/components/Fab.d.ts +273 -0
- package/types/components/Fab.d.ts.map +1 -0
- package/types/components/FabContainer.d.ts +10 -0
- package/types/components/FabContainer.d.ts.map +1 -0
- package/types/components/FilterChip.d.ts +256 -0
- package/types/components/FilterChip.d.ts.map +1 -0
- package/types/components/Grid.d.ts +38 -0
- package/types/components/Grid.d.ts.map +1 -0
- package/types/components/Headline.d.ts +46 -0
- package/types/components/Headline.d.ts.map +1 -0
- package/types/components/Icon.d.ts +55 -0
- package/types/components/Icon.d.ts.map +1 -0
- package/types/components/IconButton.d.ts +284 -0
- package/types/components/IconButton.d.ts.map +1 -0
- package/types/components/Input.d.ts +2528 -0
- package/types/components/Input.d.ts.map +1 -0
- package/types/components/InputChip.d.ts +85 -0
- package/types/components/InputChip.d.ts.map +1 -0
- package/types/components/Label.d.ts +29 -0
- package/types/components/Label.d.ts.map +1 -0
- package/types/components/List.d.ts +35 -0
- package/types/components/List.d.ts.map +1 -0
- package/types/components/ListItem.d.ts +124 -0
- package/types/components/ListItem.d.ts.map +1 -0
- package/types/components/ListOption.d.ts +158 -0
- package/types/components/ListOption.d.ts.map +1 -0
- package/types/components/Listbox.d.ts +763 -0
- package/types/components/Listbox.d.ts.map +1 -0
- package/types/components/Menu.d.ts +130 -0
- package/types/components/Menu.d.ts.map +1 -0
- package/types/components/MenuItem.d.ts +232 -0
- package/types/components/MenuItem.d.ts.map +1 -0
- package/types/components/NavBar.d.ts +20 -0
- package/types/components/NavBar.d.ts.map +1 -0
- package/types/components/NavBarItem.d.ts +97 -0
- package/types/components/NavBarItem.d.ts.map +1 -0
- package/types/components/NavDrawer.d.ts +107 -0
- package/types/components/NavDrawer.d.ts.map +1 -0
- package/types/components/NavDrawerItem.d.ts +97 -0
- package/types/components/NavDrawerItem.d.ts.map +1 -0
- package/types/components/NavItem.d.ts +99 -0
- package/types/components/NavItem.d.ts.map +1 -0
- package/types/components/NavRail.d.ts +108 -0
- package/types/components/NavRail.d.ts.map +1 -0
- package/types/components/NavRailItem.d.ts +97 -0
- package/types/components/NavRailItem.d.ts.map +1 -0
- package/types/components/Page.d.ts +25 -0
- package/types/components/Page.d.ts.map +1 -0
- package/types/components/Pane.d.ts +44 -0
- package/types/components/Pane.d.ts.map +1 -0
- package/types/components/Popup.d.ts +78 -0
- package/types/components/Popup.d.ts.map +1 -0
- package/types/components/Progress.d.ts +21 -0
- package/types/components/Progress.d.ts.map +1 -0
- package/types/components/Radio.d.ts +201 -0
- package/types/components/Radio.d.ts.map +1 -0
- package/types/components/RadioIcon.d.ts +46 -0
- package/types/components/RadioIcon.d.ts.map +1 -0
- package/types/components/Ripple.d.ts +35 -0
- package/types/components/Ripple.d.ts.map +1 -0
- package/types/components/Root.d.ts +68 -0
- package/types/components/Root.d.ts.map +1 -0
- package/types/components/Scrim.d.ts +6 -0
- package/types/components/Scrim.d.ts.map +1 -0
- package/types/components/Search.d.ts +516 -0
- package/types/components/Search.d.ts.map +1 -0
- package/types/components/SegmentedButton.d.ts +252 -0
- package/types/components/SegmentedButton.d.ts.map +1 -0
- package/types/components/SegmentedButtonGroup.d.ts +43 -0
- package/types/components/SegmentedButtonGroup.d.ts.map +1 -0
- package/types/components/Select.d.ts +158 -0
- package/types/components/Select.d.ts.map +1 -0
- package/types/components/Shape.d.ts +10 -0
- package/types/components/Shape.d.ts.map +1 -0
- package/types/components/SideSheet.d.ts +111 -0
- package/types/components/SideSheet.d.ts.map +1 -0
- package/types/components/Slider.d.ts +203 -0
- package/types/components/Slider.d.ts.map +1 -0
- package/types/components/Snackbar.d.ts +73 -0
- package/types/components/Snackbar.d.ts.map +1 -0
- package/types/components/SnackbarContainer.d.ts +6 -0
- package/types/components/SnackbarContainer.d.ts.map +1 -0
- package/types/components/Surface.d.ts +45 -0
- package/types/components/Surface.d.ts.map +1 -0
- package/types/components/Switch.d.ts +187 -0
- package/types/components/Switch.d.ts.map +1 -0
- package/types/components/SwitchIcon.d.ts +61 -0
- package/types/components/SwitchIcon.d.ts.map +1 -0
- package/types/components/Tab.d.ts +139 -0
- package/types/components/Tab.d.ts.map +1 -0
- package/types/components/TabContent.d.ts +124 -0
- package/types/components/TabContent.d.ts.map +1 -0
- package/types/components/TabList.d.ts +1111 -0
- package/types/components/TabList.d.ts.map +1 -0
- package/types/components/TabPanel.d.ts +28 -0
- package/types/components/TabPanel.d.ts.map +1 -0
- package/types/components/Table.d.ts +25 -0
- package/types/components/Table.d.ts.map +1 -0
- package/types/components/TextArea.d.ts +201 -0
- package/types/components/TextArea.d.ts.map +1 -0
- package/types/components/Title.d.ts +46 -0
- package/types/components/Title.d.ts.map +1 -0
- package/types/components/Tooltip.d.ts +49 -0
- package/types/components/Tooltip.d.ts.map +1 -0
- package/types/components/TopAppBar.d.ts +129 -0
- package/types/components/TopAppBar.d.ts.map +1 -0
- package/types/constants/colorKeywords.d.ts +2 -0
- package/types/constants/colorKeywords.d.ts.map +1 -0
- package/types/constants/shapes.d.ts +38 -0
- package/types/constants/shapes.d.ts.map +1 -0
- package/types/constants/typography.d.ts +212 -0
- package/types/constants/typography.d.ts.map +1 -0
- package/types/core/Composition.d.ts +260 -0
- package/types/core/Composition.d.ts.map +1 -0
- package/types/core/CompositionAdapter.d.ts +114 -0
- package/types/core/CompositionAdapter.d.ts.map +1 -0
- package/types/core/CustomElement.d.ts +304 -0
- package/types/core/CustomElement.d.ts.map +1 -0
- package/types/core/css.d.ts +44 -0
- package/types/core/css.d.ts.map +1 -0
- package/types/core/customTypes.d.ts +22 -0
- package/types/core/customTypes.d.ts.map +1 -0
- package/types/core/dom.d.ts +32 -0
- package/types/core/dom.d.ts.map +1 -0
- package/types/core/jsonMergePatch.d.ts +31 -0
- package/types/core/jsonMergePatch.d.ts.map +1 -0
- package/types/core/observe.d.ts +114 -0
- package/types/core/observe.d.ts.map +1 -0
- package/types/core/optimizations.d.ts +7 -0
- package/types/core/optimizations.d.ts.map +1 -0
- package/types/core/template.d.ts +47 -0
- package/types/core/template.d.ts.map +1 -0
- package/types/core/uid.d.ts +6 -0
- package/types/core/uid.d.ts.map +1 -0
- package/types/dom/HTMLOptionsCollectionProxy.d.ts +18 -0
- package/types/dom/HTMLOptionsCollectionProxy.d.ts.map +1 -0
- package/types/index.d.ts +88 -0
- package/types/index.d.ts.map +1 -0
- package/types/loaders/palette.d.ts +2 -0
- package/types/loaders/palette.d.ts.map +1 -0
- package/types/loaders/theme.d.ts +2 -0
- package/types/loaders/theme.d.ts.map +1 -0
- package/types/mixins/AriaReflectorMixin.d.ts +31 -0
- package/types/mixins/AriaReflectorMixin.d.ts.map +1 -0
- package/types/mixins/AriaToolbarMixin.d.ts +34 -0
- package/types/mixins/AriaToolbarMixin.d.ts.map +1 -0
- package/types/mixins/ControlMixin.d.ts +124 -0
- package/types/mixins/ControlMixin.d.ts.map +1 -0
- package/types/mixins/DelegatesFocusMixin.d.ts +13 -0
- package/types/mixins/DelegatesFocusMixin.d.ts.map +1 -0
- package/types/mixins/DensityMixin.d.ts +8 -0
- package/types/mixins/DensityMixin.d.ts.map +1 -0
- package/types/mixins/ElevationMixin.d.ts +32 -0
- package/types/mixins/ElevationMixin.d.ts.map +1 -0
- package/types/mixins/FlexableMixin.d.ts +14 -0
- package/types/mixins/FlexableMixin.d.ts.map +1 -0
- package/types/mixins/FormAssociatedMixin.d.ts +123 -0
- package/types/mixins/FormAssociatedMixin.d.ts.map +1 -0
- package/types/mixins/HyperlinkMixin.d.ts +25 -0
- package/types/mixins/HyperlinkMixin.d.ts.map +1 -0
- package/types/mixins/InputMixin.d.ts +173 -0
- package/types/mixins/InputMixin.d.ts.map +1 -0
- package/types/mixins/KeyboardNavMixin.d.ts +46 -0
- package/types/mixins/KeyboardNavMixin.d.ts.map +1 -0
- package/types/mixins/NavigationListenerMixin.d.ts +8 -0
- package/types/mixins/NavigationListenerMixin.d.ts.map +1 -0
- package/types/mixins/PopupMixin.d.ts +98 -0
- package/types/mixins/PopupMixin.d.ts.map +1 -0
- package/types/mixins/RTLObserverMixin.d.ts +8 -0
- package/types/mixins/RTLObserverMixin.d.ts.map +1 -0
- package/types/mixins/ResizeObserverMixin.d.ts +13 -0
- package/types/mixins/ResizeObserverMixin.d.ts.map +1 -0
- package/types/mixins/RippleMixin.d.ts +94 -0
- package/types/mixins/RippleMixin.d.ts.map +1 -0
- package/types/mixins/ScrollListenerMixin.d.ts +46 -0
- package/types/mixins/ScrollListenerMixin.d.ts.map +1 -0
- package/types/mixins/SemiStickyMixin.d.ts +50 -0
- package/types/mixins/SemiStickyMixin.d.ts.map +1 -0
- package/types/mixins/ShapeMaskedMixin.d.ts +12 -0
- package/types/mixins/ShapeMaskedMixin.d.ts.map +1 -0
- package/types/mixins/ShapeMixin.d.ts +39 -0
- package/types/mixins/ShapeMixin.d.ts.map +1 -0
- package/types/mixins/StateMixin.d.ts +29 -0
- package/types/mixins/StateMixin.d.ts.map +1 -0
- package/types/mixins/TextFieldMixin.d.ts +153 -0
- package/types/mixins/TextFieldMixin.d.ts.map +1 -0
- package/types/mixins/ThemableMixin.d.ts +10 -0
- package/types/mixins/ThemableMixin.d.ts.map +1 -0
- package/types/mixins/TooltipTriggerMixin.d.ts +114 -0
- package/types/mixins/TooltipTriggerMixin.d.ts.map +1 -0
- package/types/mixins/TouchTargetMixin.d.ts +6 -0
- package/types/mixins/TouchTargetMixin.d.ts.map +1 -0
- package/types/mixins/TypographyMixin.d.ts +20 -0
- package/types/mixins/TypographyMixin.d.ts.map +1 -0
- package/types/services/rtl.d.ts +3 -0
- package/types/services/rtl.d.ts.map +1 -0
- package/types/services/svgAlias.d.ts +13 -0
- package/types/services/svgAlias.d.ts.map +1 -0
- package/types/services/theme.d.ts +45 -0
- package/types/services/theme.d.ts.map +1 -0
- package/types/utils/cli.d.ts +3 -0
- package/types/utils/cli.d.ts.map +1 -0
- package/types/utils/function.d.ts +3 -0
- package/types/utils/function.d.ts.map +1 -0
- package/types/utils/jsx-runtime.d.ts +20 -0
- package/types/utils/jsx-runtime.d.ts.map +1 -0
- package/types/utils/material-color/blend.d.ts +34 -0
- package/types/utils/material-color/blend.d.ts.map +1 -0
- package/types/utils/material-color/hct/Cam16.d.ts +142 -0
- package/types/utils/material-color/hct/Cam16.d.ts.map +1 -0
- package/types/utils/material-color/hct/Hct.d.ts +93 -0
- package/types/utils/material-color/hct/Hct.d.ts.map +1 -0
- package/types/utils/material-color/hct/ViewingConditions.d.ts +69 -0
- package/types/utils/material-color/hct/ViewingConditions.d.ts.map +1 -0
- package/types/utils/material-color/hct/hctSolver.d.ts +30 -0
- package/types/utils/material-color/hct/hctSolver.d.ts.map +1 -0
- package/types/utils/material-color/helper.d.ts +8 -0
- package/types/utils/material-color/helper.d.ts.map +1 -0
- package/types/utils/material-color/palettes/CorePalette.d.ts +75 -0
- package/types/utils/material-color/palettes/CorePalette.d.ts.map +1 -0
- package/types/utils/material-color/palettes/TonalPalette.d.ts +38 -0
- package/types/utils/material-color/palettes/TonalPalette.d.ts.map +1 -0
- package/types/utils/material-color/scheme/Scheme.d.ts +264 -0
- package/types/utils/material-color/scheme/Scheme.d.ts.map +1 -0
- package/types/utils/material-color/utils/color.d.ts +172 -0
- package/types/utils/material-color/utils/color.d.ts.map +1 -0
- package/types/utils/material-color/utils/math.d.ts +94 -0
- package/types/utils/material-color/utils/math.d.ts.map +1 -0
- package/types/utils/pixelmatch.d.ts +22 -0
- package/types/utils/pixelmatch.d.ts.map +1 -0
- package/types/utils/popup.d.ts +106 -0
- package/types/utils/popup.d.ts.map +1 -0
- package/types/utils/searchParams.d.ts +3 -0
- package/types/utils/searchParams.d.ts.map +1 -0
- package/types/utils/svg.d.ts +7 -0
- package/types/utils/svg.d.ts.map +1 -0
- package/utils/jsx-runtime.js +9 -4
- package/utils/material-color/scheme/Scheme.js +1 -1
- package/utils/pixelmatch.js +363 -0
- package/utils/popup.js +86 -10
- package/utils/searchParams.js +22 -0
- package/components/Button.md +0 -61
- package/components/ExtendedFab.js +0 -32
- package/components/Layout.js +0 -504
- package/components/Nav.js +0 -38
- package/core/DomAdapter.js +0 -586
- package/core/ICustomElement.d.ts +0 -291
- package/core/ICustomElement.js +0 -1
- package/core/test.js +0 -126
- package/core/typings.d.ts +0 -142
- package/core/typings.js +0 -1
- package/mixins/SurfaceMixin.js +0 -127
- package/theming/loader.js +0 -22
- /package/{utils/color_keywords.js → constants/colorKeywords.js} +0 -0
package/components/ListOption.js
CHANGED
|
@@ -1,27 +1,64 @@
|
|
|
1
1
|
// https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
|
|
2
2
|
|
|
3
|
+
import DelegatesFocusMixin from '../mixins/DelegatesFocusMixin.js';
|
|
4
|
+
|
|
3
5
|
import ListItem from './ListItem.js';
|
|
4
6
|
|
|
5
7
|
// https://html.spec.whatwg.org/multipage/form-elements.html#htmloptionelement
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* List options represent selectable choices within a `mdw-listbox` or list.
|
|
11
|
+
* @see https://m3.material.io/components/lists/specs
|
|
12
|
+
*/
|
|
13
|
+
export default ListItem
|
|
8
14
|
.extend()
|
|
15
|
+
.mixin(DelegatesFocusMixin)
|
|
9
16
|
.setStatic({
|
|
10
17
|
formAssociated: true,
|
|
11
18
|
})
|
|
12
19
|
.set({
|
|
20
|
+
/** ARIA role applied to the option container (anchor receives role 'option'). */
|
|
13
21
|
_ariaRole: 'none',
|
|
14
|
-
|
|
22
|
+
|
|
23
|
+
/** Index of this option within its list/listbox (managed externally). */
|
|
15
24
|
_index: -1,
|
|
25
|
+
|
|
26
|
+
/** Internal flag indicating selection was modified via API rather than default. */
|
|
16
27
|
_selectedDirty: false,
|
|
28
|
+
|
|
29
|
+
/** Whether this option behaves as an interactive selectable item. */
|
|
17
30
|
isInteractive: true,
|
|
18
31
|
})
|
|
19
32
|
.observe({
|
|
20
33
|
// ListOption.prototype._form = ListOption.prop('_form');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Explicit label for accessibility. Reflected to attribute `label`.
|
|
37
|
+
* Falls back to `textContent` when not provided.
|
|
38
|
+
*/
|
|
21
39
|
_label: { attr: 'label', reflect: true, nullParser: String },
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Explicit text content for the option. Reflected to attribute `text`.
|
|
43
|
+
*/
|
|
44
|
+
_text: { attr: 'text', reflect: true, nullParser: String },
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Initial/default selection state (reflected to `selected` attribute).
|
|
48
|
+
* Use `selected` property to control runtime selection.
|
|
49
|
+
*/
|
|
22
50
|
defaultSelected: { attr: 'selected', reflect: true, type: 'boolean' },
|
|
51
|
+
|
|
52
|
+
/** Internal boolean representing the current selected state. */
|
|
23
53
|
_selected: 'boolean',
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Underlying option value (reflected to `value` attribute). Defaults to
|
|
57
|
+
* the option's text content when not provided.
|
|
58
|
+
*/
|
|
24
59
|
_value: { attr: 'value', reflect: true },
|
|
60
|
+
|
|
61
|
+
/** Set when form association disables the option. */
|
|
25
62
|
_formDisabled: 'boolean',
|
|
26
63
|
})
|
|
27
64
|
.observe({
|
|
@@ -44,19 +81,45 @@ export default class ListOption extends ListItem
|
|
|
44
81
|
},
|
|
45
82
|
})
|
|
46
83
|
.define({
|
|
84
|
+
/** Numeric index of the option inside the parent listbox. */
|
|
47
85
|
index() { return this._index; },
|
|
48
|
-
|
|
86
|
+
|
|
87
|
+
/** Associated form owner (if any) for form-associated behavior. */
|
|
88
|
+
form() { return /** @type {HTMLInputElement} */ (this.parentElement)?.form; },
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Text content for the option; setting updates the internal `_text` field.
|
|
92
|
+
* If not provided, the getter falls back to element textContent.
|
|
93
|
+
*/
|
|
94
|
+
text: {
|
|
95
|
+
// Incomplete
|
|
96
|
+
get() { return this._text ?? this.textContent; },
|
|
97
|
+
/** @param {string} value */
|
|
98
|
+
set(value) {
|
|
99
|
+
this._text = value;
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Accessible label for the option. Falls back to `text` or the element
|
|
105
|
+
* content when not explicitly set.
|
|
106
|
+
*/
|
|
49
107
|
label: {
|
|
50
|
-
get() { return this._label ?? this.textContent; },
|
|
108
|
+
get() { return this._label ?? this._text ?? this.textContent; },
|
|
51
109
|
/** @param {string} value */
|
|
52
110
|
set(value) {
|
|
53
111
|
this._label = value;
|
|
54
112
|
},
|
|
55
113
|
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Option `value` used when the option is selected in a form. Defaults to
|
|
117
|
+
* the option's text when not explicitly defined.
|
|
118
|
+
*/
|
|
56
119
|
value: {
|
|
57
120
|
get() { return this._value ?? this.textContent; },
|
|
58
121
|
/** @param {string} value */
|
|
59
|
-
set(value) { this.
|
|
122
|
+
set(value) { this._value = value; },
|
|
60
123
|
},
|
|
61
124
|
})
|
|
62
125
|
.methods({
|
|
@@ -69,38 +132,48 @@ export default class ListOption extends ListItem
|
|
|
69
132
|
this.refs.anchor.focus(...options);
|
|
70
133
|
},
|
|
71
134
|
})
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Form Associated elements cannot receive focus unless using delegatesFocus
|
|
77
|
-
// Workaround by redirecting focus to an inner element
|
|
78
|
-
// Reuse HTMLAnchorElement with no HREF
|
|
79
|
-
// Issues: Siblings (images) are not contained within tree
|
|
80
|
-
|
|
81
|
-
anchor.setAttribute('disabled', '{disabledState}');
|
|
82
|
-
anchor.setAttribute('role', 'option');
|
|
83
|
-
anchor.setAttribute('aria-disabled', inline(({ disabledState }) => `${disabledState}`));
|
|
84
|
-
anchor.setAttribute('tabindex', '0');
|
|
85
|
-
anchor.setAttribute('aria-selected', inline(({ selected }) => `${selected}`));
|
|
86
|
-
anchor.setAttribute('selected', '{selected}');
|
|
87
|
-
anchor.removeAttribute('href');
|
|
88
|
-
anchor.removeAttribute('mdw-if');
|
|
89
|
-
|
|
90
|
-
content.setAttribute('selected', '{selected}');
|
|
91
|
-
|
|
92
|
-
state.setAttribute('state-disabled', 'focus');
|
|
135
|
+
.expressions({
|
|
136
|
+
anchorAriaLabelledBy({ _label }) {
|
|
137
|
+
return _label ? null : 'content';
|
|
93
138
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (current == null) {
|
|
97
|
-
anchor.setAttribute('aria-labelledby', 'content');
|
|
98
|
-
anchor.removeAttribute('aria-label');
|
|
99
|
-
} else {
|
|
100
|
-
anchor.setAttribute('aria-label', current);
|
|
101
|
-
anchor.removeAttribute('aria-labelledby');
|
|
102
|
-
}
|
|
139
|
+
anchorAriaDescribedBy({ _label }) {
|
|
140
|
+
return _label ? 'content' : null;
|
|
103
141
|
},
|
|
142
|
+
computedIconVariation({ iconVariation, selected }) {
|
|
143
|
+
if (iconVariation != null) return iconVariation;
|
|
144
|
+
return selected ? 'filled' : null;
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
.recompose(({ inline, refs: { checkbox, radio, anchor, state, content } }) => {
|
|
148
|
+
// Form Associated elements cannot receive focus unless using delegatesFocus
|
|
149
|
+
// Workaround by redirecting focus to an inner element
|
|
150
|
+
// Reuse HTMLAnchorElement with no HREF
|
|
151
|
+
// Issues: Siblings (images) are not contained within tree
|
|
152
|
+
|
|
153
|
+
anchor.setAttribute('disabled', '{disabledState}');
|
|
154
|
+
anchor.setAttribute('role', 'option');
|
|
155
|
+
anchor.setAttribute('aria-disabled', inline(({ disabledState }) => `${disabledState}`));
|
|
156
|
+
anchor.setAttribute('tabindex', '0');
|
|
157
|
+
anchor.setAttribute('aria-selected', inline(({ selected }) => `${selected}`));
|
|
158
|
+
anchor.setAttribute('selected', '{selected}');
|
|
159
|
+
anchor.setAttribute('aria-labelledby', '{anchorAriaLabelledBy}');
|
|
160
|
+
anchor.setAttribute('aria-describedby', '{anchorAriaDescribedBy}');
|
|
161
|
+
anchor.setAttribute('aria-label', '{_label}');
|
|
162
|
+
anchor.removeAttribute('href');
|
|
163
|
+
anchor.removeAttribute('mdw-if');
|
|
164
|
+
|
|
165
|
+
// eslint-disable-next-line no-shadow
|
|
166
|
+
checkbox.setAttribute('mdw-if', inline(({ checkbox, icon }) => !icon && checkbox));
|
|
167
|
+
|
|
168
|
+
// eslint-disable-next-line no-shadow
|
|
169
|
+
radio.setAttribute('mdw-if', inline(({ radio, icon }) => !icon && radio));
|
|
170
|
+
|
|
171
|
+
content.setAttribute('aria-hidden', 'true');
|
|
172
|
+
content.setAttribute('selected', '{selected}');
|
|
173
|
+
|
|
174
|
+
state.setAttribute('state-disabled', 'focus');
|
|
175
|
+
})
|
|
176
|
+
.on({
|
|
104
177
|
selectedChanged(previous, current) {
|
|
105
178
|
// Used by HTMLCollection
|
|
106
179
|
this.classList.toggle('mdw-list-option__selected', current);
|
|
@@ -115,7 +188,11 @@ export default class ListOption extends ListItem
|
|
|
115
188
|
|
|
116
189
|
z-index: 0;
|
|
117
190
|
}
|
|
118
|
-
|
|
191
|
+
|
|
192
|
+
:host([hidden]) {
|
|
193
|
+
display: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
119
196
|
:host([href]) {
|
|
120
197
|
cursor: pointer;
|
|
121
198
|
}
|
|
@@ -128,6 +205,7 @@ export default class ListOption extends ListItem
|
|
|
128
205
|
#content {
|
|
129
206
|
-webkit-user-select: none;
|
|
130
207
|
user-select: none;
|
|
208
|
+
pointer-events: none;
|
|
131
209
|
}
|
|
132
210
|
|
|
133
211
|
#content[selected] {
|
|
@@ -142,35 +220,35 @@ export default class ListOption extends ListItem
|
|
|
142
220
|
background-color: rgb(var(--mdw-bg));
|
|
143
221
|
color: rgb(var(--mdw-ink));
|
|
144
222
|
}
|
|
145
|
-
`
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
223
|
+
`
|
|
224
|
+
.extend((BaseClass) => class extends BaseClass {
|
|
225
|
+
/**
|
|
226
|
+
* @param {string} [text]
|
|
227
|
+
* @param {string} [value]
|
|
228
|
+
* @param {boolean} [defaultSelected]
|
|
229
|
+
* @param {boolean} [selected]
|
|
230
|
+
*/
|
|
231
|
+
constructor(text, value, defaultSelected, selected) {
|
|
232
|
+
super();
|
|
233
|
+
if (text !== undefined) {
|
|
234
|
+
this.text = text;
|
|
235
|
+
}
|
|
236
|
+
if (value !== undefined) {
|
|
237
|
+
this._value = value;
|
|
238
|
+
}
|
|
239
|
+
if (defaultSelected !== undefined) {
|
|
240
|
+
this.defaultSelected = defaultSelected;
|
|
241
|
+
}
|
|
242
|
+
if (selected !== undefined) {
|
|
243
|
+
this._selected = selected;
|
|
244
|
+
}
|
|
167
245
|
}
|
|
168
|
-
}
|
|
169
246
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
247
|
+
connectedCallback() {
|
|
248
|
+
super.connectedCallback();
|
|
249
|
+
if (!this.hasAttribute('tabindex')) {
|
|
250
|
+
this.tabIndex = 0;
|
|
251
|
+
}
|
|
174
252
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
253
|
+
})
|
|
254
|
+
.autoRegister('mdw-list-option');
|
package/components/Listbox.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { constructHTMLOptionsCollectionProxy } from '../dom/HTMLOptionsCollectionProxy.js';
|
|
2
|
+
import DelegatesFocusMixin from '../mixins/DelegatesFocusMixin.js';
|
|
2
3
|
import FormAssociatedMixin from '../mixins/FormAssociatedMixin.js';
|
|
3
4
|
import KeyboardNavMixin from '../mixins/KeyboardNavMixin.js';
|
|
4
5
|
import StateMixin from '../mixins/StateMixin.js';
|
|
@@ -6,32 +7,53 @@ import StateMixin from '../mixins/StateMixin.js';
|
|
|
6
7
|
import List from './List.js';
|
|
7
8
|
import ListOption from './ListOption.js';
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Listbox: a selectable list of options, used for autocompletes and selects.
|
|
12
|
+
* implements {HTMLSelectElement}
|
|
13
|
+
* @see https://m3.material.io/components/lists/specs
|
|
14
|
+
*/
|
|
11
15
|
export default List
|
|
12
16
|
.extend()
|
|
13
17
|
.mixin(StateMixin)
|
|
14
18
|
.mixin(FormAssociatedMixin)
|
|
15
19
|
.mixin(KeyboardNavMixin)
|
|
20
|
+
.mixin(DelegatesFocusMixin)
|
|
16
21
|
.observe({
|
|
22
|
+
/** When true, multiple options may be selected (select-multiple semantics). */
|
|
17
23
|
multiple: 'boolean',
|
|
24
|
+
|
|
25
|
+
/** Visible size (number of rows) for the listbox; 0 means auto. */
|
|
18
26
|
size: { type: 'integer', empty: 0 },
|
|
19
27
|
})
|
|
20
28
|
.set({
|
|
29
|
+
/** ARIA role applied to the host element (default: 'listbox'). */
|
|
21
30
|
_ariaRole: 'listbox',
|
|
22
|
-
|
|
23
|
-
/**
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Lazily-constructed options collection proxy exposing `add`, indexed
|
|
34
|
+
* access, and other `HTMLOptionsCollection` semantics.
|
|
35
|
+
* @type {HTMLCollectionOf<InstanceType<typeof ListOption>> & HTMLOptionsCollection}
|
|
36
|
+
*/
|
|
24
37
|
_optionsCollection: null,
|
|
25
|
-
|
|
38
|
+
|
|
39
|
+
/** Cached collection of selected options (HTMLCollection). */
|
|
26
40
|
_selectedOptionsCollection: null,
|
|
41
|
+
|
|
42
|
+
/** Internal guard to avoid reentrant selectedness updates. */
|
|
27
43
|
_handlingSelectedness: false,
|
|
44
|
+
|
|
45
|
+
/** When true, form resets are honored; toggled when form association changes. */
|
|
46
|
+
_handleFormReset: true,
|
|
28
47
|
})
|
|
29
48
|
.define({
|
|
30
49
|
options() {
|
|
31
50
|
if (!this._optionsCollection) {
|
|
51
|
+
// eslint-disable-next-line operator-linebreak
|
|
52
|
+
const collection = /** @type {HTMLCollectionOf<InstanceType<typeof ListOption>>} */
|
|
53
|
+
(this.getElementsByTagName(ListOption.elementName));
|
|
32
54
|
this._optionsCollection = constructHTMLOptionsCollectionProxy({
|
|
33
55
|
host: this,
|
|
34
|
-
collection
|
|
56
|
+
collection,
|
|
35
57
|
OptionConstructor: ListOption,
|
|
36
58
|
GroupConstructor: ListOption,
|
|
37
59
|
});
|
|
@@ -39,36 +61,46 @@ export default List
|
|
|
39
61
|
return this._optionsCollection;
|
|
40
62
|
},
|
|
41
63
|
|
|
42
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Returns a live HTMLCollection of selected `mdw-list-option` elements.
|
|
66
|
+
* @return {HTMLCollectionOf<InstanceType<typeof ListOption>>}
|
|
67
|
+
*/
|
|
43
68
|
selectedOptions() {
|
|
44
69
|
// eslint-disable-next-line no-return-assign
|
|
45
70
|
return (this._selectedOptionsCollection
|
|
46
71
|
??= (
|
|
47
|
-
/** @type {HTMLCollectionOf<ListOption
|
|
72
|
+
/** @type {HTMLCollectionOf<InstanceType<typeof ListOption>>} */
|
|
48
73
|
(this.getElementsByClassName('mdw-list-option__selected')))
|
|
49
74
|
);
|
|
50
75
|
},
|
|
51
76
|
|
|
52
|
-
type
|
|
77
|
+
/** Returns the control type string compatible with `input`/`select` semantics. */
|
|
78
|
+
type() { return this.multiple ? 'select-multiple' : 'select-one'; },
|
|
53
79
|
|
|
80
|
+
/** Query selector used by keyboard navigation mixin to find focusable options. */
|
|
54
81
|
kbdNavQuery() { return ListOption.elementName; },
|
|
55
82
|
|
|
83
|
+
/** Allow keyboard navigation to focus disabled options in some patterns. */
|
|
56
84
|
kbdNavFocusableWhenDisabled() { return true; },
|
|
57
85
|
})
|
|
58
86
|
.define({
|
|
59
87
|
length() { return this.options.length; },
|
|
60
88
|
|
|
61
89
|
selectedIndex: {
|
|
90
|
+
/** @return {number} */
|
|
62
91
|
get() {
|
|
63
92
|
const [selectedItem] = this.selectedOptions;
|
|
64
93
|
if (!selectedItem) return -1;
|
|
65
94
|
return Array.prototype.indexOf.call(this.options, selectedItem);
|
|
66
95
|
},
|
|
96
|
+
/** @param {number} value */
|
|
67
97
|
set(value) {
|
|
68
98
|
const itemToSelect = this.options[value];
|
|
99
|
+
this._handlingSelectedness = true;
|
|
69
100
|
for (const option of this.options) {
|
|
70
101
|
option.selected = (option === itemToSelect);
|
|
71
102
|
}
|
|
103
|
+
this._handlingSelectedness = false;
|
|
72
104
|
this._value = this.value;
|
|
73
105
|
},
|
|
74
106
|
},
|
|
@@ -80,11 +112,13 @@ export default List
|
|
|
80
112
|
set(v) {
|
|
81
113
|
let newValue = '';
|
|
82
114
|
const vString = `${v}`;
|
|
115
|
+
this._handlingSelectedness = true;
|
|
83
116
|
for (const option of this.options) {
|
|
84
117
|
if ((option.selected = (option.value === vString))) {
|
|
85
118
|
newValue = vString;
|
|
86
119
|
}
|
|
87
120
|
}
|
|
121
|
+
this._handlingSelectedness = false;
|
|
88
122
|
this._value = newValue;
|
|
89
123
|
},
|
|
90
124
|
},
|
|
@@ -99,7 +133,9 @@ export default List
|
|
|
99
133
|
this.updateAriaProperty('ariaMultiSelectable', newValue ? 'true' : 'false');
|
|
100
134
|
},
|
|
101
135
|
_formResetChanged(oldValue, newValue) {
|
|
102
|
-
|
|
136
|
+
if (!newValue) return;
|
|
137
|
+
if (!this._handleFormReset) return;
|
|
138
|
+
this.value = this.defaultValue;
|
|
103
139
|
},
|
|
104
140
|
connected() {
|
|
105
141
|
if (!this.hasAttribute('tabindex')) {
|
|
@@ -124,12 +160,12 @@ export default List
|
|
|
124
160
|
},
|
|
125
161
|
/**
|
|
126
162
|
* @param {number} index
|
|
127
|
-
* @return {ListOption
|
|
163
|
+
* @return {InstanceType<typeof ListOption>|null}
|
|
128
164
|
*/
|
|
129
165
|
item(index) { return this.options[index]; },
|
|
130
166
|
/**
|
|
131
167
|
* @param {string} name ID of ListOption
|
|
132
|
-
* @return {ListOption
|
|
168
|
+
* @return {InstanceType<typeof ListOption>|null}
|
|
133
169
|
*/
|
|
134
170
|
namedItem(name) {
|
|
135
171
|
for (const option of this.options) {
|
|
@@ -143,18 +179,21 @@ export default List
|
|
|
143
179
|
onListboxClick(event) {
|
|
144
180
|
const target = event.target;
|
|
145
181
|
if (!(target instanceof ListOption)) return;
|
|
182
|
+
event.stopImmediatePropagation();
|
|
146
183
|
event.stopPropagation();
|
|
147
|
-
|
|
184
|
+
|
|
185
|
+
const listOption = /** @type {InstanceType<ListOption>} */ (target);
|
|
186
|
+
if (listOption.disabledState) return;
|
|
148
187
|
|
|
149
188
|
let sendUpdateNotifications = false;
|
|
150
189
|
this._handlingSelectedness = true;
|
|
151
190
|
|
|
152
191
|
// Perform unselect
|
|
153
|
-
if (
|
|
192
|
+
if (listOption.selected) {
|
|
154
193
|
// Unselect condition
|
|
155
194
|
if (!this.required || (this.multiple && this.selectedOptions.length > 1)) {
|
|
156
195
|
sendUpdateNotifications = true;
|
|
157
|
-
|
|
196
|
+
listOption.selected = false;
|
|
158
197
|
}
|
|
159
198
|
} else {
|
|
160
199
|
if (!this.multiple) {
|
|
@@ -164,12 +203,13 @@ export default List
|
|
|
164
203
|
}
|
|
165
204
|
}
|
|
166
205
|
|
|
167
|
-
|
|
206
|
+
listOption.selected = true;
|
|
168
207
|
sendUpdateNotifications = true;
|
|
169
208
|
}
|
|
170
209
|
|
|
171
210
|
this._value = this.value;
|
|
172
211
|
this._handlingSelectedness = false;
|
|
212
|
+
this._updateFormAssociatedValue();
|
|
173
213
|
|
|
174
214
|
if (sendUpdateNotifications) {
|
|
175
215
|
this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
@@ -194,7 +234,7 @@ export default List
|
|
|
194
234
|
if (this.multiple) return;
|
|
195
235
|
if (this._handlingSelectedness) return;
|
|
196
236
|
|
|
197
|
-
const target = /** @type {ListOption} */ (
|
|
237
|
+
const target = /** @type {InstanceType<typeof ListOption>} */ (event.target);
|
|
198
238
|
if (target.selected) return;
|
|
199
239
|
this._handlingSelectedness = true;
|
|
200
240
|
|
package/components/Menu.js
CHANGED
|
@@ -1,30 +1,43 @@
|
|
|
1
|
-
// https://www.w3.org/TR/wai-aria-practices/#menu
|
|
2
|
-
|
|
3
|
-
import './Surface.js';
|
|
4
1
|
import CustomElement from '../core/CustomElement.js';
|
|
5
2
|
import { attemptFocus } from '../core/dom.js';
|
|
6
3
|
import DensityMixin from '../mixins/DensityMixin.js';
|
|
4
|
+
import ElevationMixin from '../mixins/ElevationMixin.js';
|
|
7
5
|
import KeyboardNavMixin from '../mixins/KeyboardNavMixin.js';
|
|
8
6
|
import PopupMixin from '../mixins/PopupMixin.js';
|
|
9
7
|
import ShapeMixin from '../mixins/ShapeMixin.js';
|
|
10
|
-
import SurfaceMixin from '../mixins/SurfaceMixin.js';
|
|
11
8
|
import ThemableMixin from '../mixins/ThemableMixin.js';
|
|
12
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Menus provide a list of choices or actions in a temporary surface.
|
|
12
|
+
* @see https://m3.material.io/components/menus/specs
|
|
13
|
+
* @see https://www.w3.org/TR/wai-aria-practices/#menu
|
|
14
|
+
*/
|
|
13
15
|
export default CustomElement
|
|
14
16
|
.extend()
|
|
15
17
|
.mixin(ThemableMixin)
|
|
16
|
-
.mixin(
|
|
18
|
+
.mixin(ElevationMixin)
|
|
17
19
|
.mixin(ShapeMixin)
|
|
18
20
|
.mixin(PopupMixin)
|
|
19
21
|
.mixin(DensityMixin)
|
|
20
22
|
.mixin(KeyboardNavMixin)
|
|
21
23
|
.set({
|
|
22
|
-
|
|
24
|
+
/** Placement strategy for the popup ('corner'). */
|
|
23
25
|
flow: 'corner',
|
|
26
|
+
|
|
27
|
+
/** When true, show a scrim behind the menu (used by `showModal`). */
|
|
24
28
|
_useScrim: false,
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Weak reference to the element that requested a submenu cascade. Stored
|
|
32
|
+
* as a WeakRef to avoid retaining DOM nodes.
|
|
33
|
+
* @type {WeakRef<HTMLElement>}
|
|
34
|
+
*/
|
|
26
35
|
_cascader: null,
|
|
27
|
-
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Weak reference to the currently opened submenu (if any).
|
|
39
|
+
* @type {WeakRef<HTMLElement>}
|
|
40
|
+
*/
|
|
28
41
|
_submenu: null,
|
|
29
42
|
})
|
|
30
43
|
.define({
|
|
@@ -34,9 +47,11 @@ export default CustomElement
|
|
|
34
47
|
const submenuItems = [...this.querySelectorAll(':scope mdw-menu mdw-menu-item')];
|
|
35
48
|
return items.filter((el) => !submenuItems.includes(el));
|
|
36
49
|
},
|
|
50
|
+
/** Return the internal dialog element used for popup rendering (if any). */
|
|
37
51
|
_dialog() {
|
|
38
52
|
return /** @type {HTMLDialogElement} */ (this.refs.dialog);
|
|
39
53
|
},
|
|
54
|
+
/** Element that cascaded this submenu (if present). */
|
|
40
55
|
cascader: {
|
|
41
56
|
get() {
|
|
42
57
|
return this._cascader?.deref();
|
|
@@ -48,6 +63,7 @@ export default CustomElement
|
|
|
48
63
|
this._cascader = value ? new WeakRef(value) : null;
|
|
49
64
|
},
|
|
50
65
|
},
|
|
66
|
+
/** Currently opened submenu element (if any). */
|
|
51
67
|
submenu: {
|
|
52
68
|
get() {
|
|
53
69
|
return this._submenu?.deref();
|
|
@@ -60,15 +76,9 @@ export default CustomElement
|
|
|
60
76
|
},
|
|
61
77
|
},
|
|
62
78
|
})
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
surface.append(shape);
|
|
67
|
-
dialog.prepend(surface);
|
|
68
|
-
scrim.setAttribute('invisible', '');
|
|
69
|
-
|
|
70
|
-
// Wrap slot in scroller
|
|
71
|
-
},
|
|
79
|
+
.recompose(({ refs: { scrim } }) => {
|
|
80
|
+
scrim.setAttribute('invisible', '');
|
|
81
|
+
// Wrap slot in scroller
|
|
72
82
|
})
|
|
73
83
|
.css`
|
|
74
84
|
/* https://m3.material.io/components/menus/specs */
|
|
@@ -77,17 +87,14 @@ export default CustomElement
|
|
|
77
87
|
--mdw-shape__size: var(--mdw-shape__extra-small);
|
|
78
88
|
--mdw-bg: var(--mdw-color__surface-container);
|
|
79
89
|
--mdw-ink: var(--mdw-color__on-surface);
|
|
80
|
-
|
|
81
|
-
--mdw-surface__shadow__resting: var(--mdw-surface__shadow__2);
|
|
82
|
-
--mdw-surface__shadow__raised: var(--mdw-surface__shadow__resting);
|
|
83
90
|
display: block;
|
|
84
91
|
|
|
85
92
|
inline-size: auto;
|
|
86
93
|
min-inline-size: calc(var(--mdw-menu__inline-base) * 2);
|
|
87
94
|
max-inline-size: 100vw;
|
|
88
|
-
}
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
filter: var(--mdw-elevation__drop-shadow__2);
|
|
97
|
+
|
|
91
98
|
background-color: rgb(var(--mdw-bg));
|
|
92
99
|
}
|
|
93
100
|
|
|
@@ -96,6 +103,7 @@ export default CustomElement
|
|
|
96
103
|
}
|
|
97
104
|
`
|
|
98
105
|
.methods({
|
|
106
|
+
/** @param {Parameters<InstanceType<ReturnType<PopupMixin>>['showPopup']>} args */
|
|
99
107
|
showModal(...args) {
|
|
100
108
|
this._useScrim = true;
|
|
101
109
|
const result = this.showPopup(...args);
|
|
@@ -118,16 +126,18 @@ export default CustomElement
|
|
|
118
126
|
})
|
|
119
127
|
.events({
|
|
120
128
|
'mdw-menu-item:cascade'(event) {
|
|
121
|
-
const menuItem = event.target;
|
|
122
|
-
const subMenuId = event.detail;
|
|
129
|
+
const menuItem = /** @type {HTMLElement} */ (event.target);
|
|
130
|
+
const subMenuId = /** @type {CustomEvent<string>} */ (event).detail;
|
|
123
131
|
event.stopPropagation();
|
|
124
132
|
|
|
125
|
-
const
|
|
133
|
+
const root = /** @type {DocumentFragment|Document} */ (this.getRootNode());
|
|
134
|
+
const submenu = /** @type {typeof this} */ (root.getElementById(subMenuId));
|
|
126
135
|
this.submenu = submenu;
|
|
127
136
|
submenu.cascade(menuItem);
|
|
128
137
|
},
|
|
129
138
|
'mdw-menu-item:cascader-blur'() {
|
|
130
|
-
const submenu = this.submenu;
|
|
139
|
+
const submenu = /** @type {typeof this} */ (this.submenu);
|
|
140
|
+
if (!submenu) return;
|
|
131
141
|
// Wait for focus event (if mouse focus on sub menu item)
|
|
132
142
|
queueMicrotask(() => {
|
|
133
143
|
// Stay open if submenu is focused
|
|
@@ -163,7 +173,9 @@ export default CustomElement
|
|
|
163
173
|
// if (!this.submenu) break;
|
|
164
174
|
if (getComputedStyle(this).direction === 'rtl') {
|
|
165
175
|
if (event.key === 'ArrowLeft') break;
|
|
166
|
-
} else if (event.key === 'ArrowRight')
|
|
176
|
+
} else if (event.key === 'ArrowRight') {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
167
179
|
// Fallthrough;
|
|
168
180
|
case 'Escape':
|
|
169
181
|
case 'Esc':
|