@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/core/CustomElement.js
CHANGED
|
@@ -1,11 +1,117 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
2
|
|
|
3
3
|
import Composition from './Composition.js';
|
|
4
|
-
import {
|
|
4
|
+
import { css } from './css.js';
|
|
5
5
|
import { attrNameFromPropName, attrValueFromDataValue } from './dom.js';
|
|
6
6
|
import { applyMergePatch } from './jsonMergePatch.js';
|
|
7
7
|
import { defineObservableProperty } from './observe.js';
|
|
8
|
-
import { addInlineFunction,
|
|
8
|
+
import { addInlineFunction, html } from './template.js';
|
|
9
|
+
|
|
10
|
+
/** @typedef {import('./observe.js').ObserverPropertyType} ObserverPropertyType */
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @template {any} T
|
|
14
|
+
* @typedef {{
|
|
15
|
+
* [P in keyof T]:
|
|
16
|
+
* T[P] extends (...args:any[]) => infer T2 ? T2
|
|
17
|
+
* : T[P] extends ObserverPropertyType
|
|
18
|
+
* ? import('./observe.js').ParsedObserverPropertyType<T[P]>
|
|
19
|
+
* : T[P] extends {type: ObserverPropertyType}
|
|
20
|
+
* ? import('./observe.js').ParsedObserverPropertyType<T[P]['type']>
|
|
21
|
+
* : T[P] extends ObserverOptions<null, infer T2>
|
|
22
|
+
* ? unknown extends T2 ? string : T2
|
|
23
|
+
* : never
|
|
24
|
+
* }} ParsedProps
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @template {ObserverPropertyType} T1
|
|
29
|
+
* @template {any} T2
|
|
30
|
+
* @template {Object} [C=any]
|
|
31
|
+
* @typedef {import('./observe.js').ObserverOptions<T1,T2,C>} ObserverOptions
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @template {{ prototype: unknown; }} T
|
|
36
|
+
* @typedef {T} ClassOf<T>
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @template {any} [T=any]
|
|
41
|
+
* @template {any[]} [A=any[]]
|
|
42
|
+
* @typedef {abstract new (...args: A) => T} Class
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @template {any} T1
|
|
47
|
+
* @template {any} [T2=T1]
|
|
48
|
+
* @callback HTMLTemplater
|
|
49
|
+
* @param {TemplateStringsArray} string
|
|
50
|
+
* @param {...(string|DocumentFragment|Element|((this:T1, data:T2) => any))} substitutions
|
|
51
|
+
* @return {DocumentFragment}
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @template {any} [T1=any]
|
|
56
|
+
* @template {any} [T2=T1]
|
|
57
|
+
* @typedef {Object} CallbackArguments
|
|
58
|
+
* @prop {Composition<T1>} composition
|
|
59
|
+
* @prop {Record<string, HTMLElement>} refs
|
|
60
|
+
* @prop {HTMLTemplater<T1, Partial<T2>>} html
|
|
61
|
+
* @prop {(fn: (this:T1, data: T2) => any) => string} inline
|
|
62
|
+
* @prop {DocumentFragment} template
|
|
63
|
+
* @prop {T1} element
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @template {any} T1
|
|
68
|
+
* @template {any} [T2=T1]
|
|
69
|
+
* @typedef {{
|
|
70
|
+
* composed?: (this: T1, options: CallbackArguments<T1, T2>) => any,
|
|
71
|
+
* constructed?: (this: T1, options: CallbackArguments<T1, T2>) => any,
|
|
72
|
+
* connected?: (this: T1, options: CallbackArguments<T1, T2>) => any,
|
|
73
|
+
* disconnected?: (this: T1, options: CallbackArguments<T1, T2>) => any,
|
|
74
|
+
* props?: {
|
|
75
|
+
* [P in keyof T1] : (
|
|
76
|
+
* this: T1,
|
|
77
|
+
* oldValue: T1[P],
|
|
78
|
+
* newValue: T1[P],
|
|
79
|
+
* changes:any,
|
|
80
|
+
* element: T1
|
|
81
|
+
* ) => any
|
|
82
|
+
* },
|
|
83
|
+
* attrs?: {[K in keyof any]: (
|
|
84
|
+
* this: T1,
|
|
85
|
+
* oldValue: string,
|
|
86
|
+
* newValue: string,
|
|
87
|
+
* element: T1
|
|
88
|
+
* ) => unknown
|
|
89
|
+
* },
|
|
90
|
+
* } & {
|
|
91
|
+
* [P in keyof T1 & string as `${P}Changed`]?: (
|
|
92
|
+
* this: T1,
|
|
93
|
+
* oldValue: T1[P],
|
|
94
|
+
* newValue: T1[P],
|
|
95
|
+
* changes:any,
|
|
96
|
+
* element: T1
|
|
97
|
+
* ) => any
|
|
98
|
+
* }} CompositionCallback
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @template {Object} C
|
|
103
|
+
* @typedef {{
|
|
104
|
+
* [P in string] :
|
|
105
|
+
* ObserverPropertyType
|
|
106
|
+
* | ObserverOptions<ObserverPropertyType, unknown, C>
|
|
107
|
+
* | ((this:C, data:Partial<C>, fn?: () => any) => any)
|
|
108
|
+
* }} IDLParameter
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @template T
|
|
113
|
+
* @typedef {(T | Array<[keyof T & string, T[keyof T]]>)} ObjectOrObjectEntries
|
|
114
|
+
*/
|
|
9
115
|
|
|
10
116
|
/**
|
|
11
117
|
* @template {abstract new (...args: any) => unknown} T
|
|
@@ -33,57 +139,49 @@ export function cloneAttributeCallback(name, target) {
|
|
|
33
139
|
};
|
|
34
140
|
}
|
|
35
141
|
|
|
36
|
-
const EVENT_PREFIX_REGEX = /^([*1~]+)?(.*)$/;
|
|
37
|
-
|
|
38
142
|
/**
|
|
39
143
|
* Web Component that can cache templates for minification or performance
|
|
40
144
|
*/
|
|
41
|
-
export default class CustomElement extends
|
|
145
|
+
export default class CustomElement extends HTMLElement {
|
|
42
146
|
/** @type {string} */
|
|
43
147
|
static elementName;
|
|
44
148
|
|
|
45
149
|
/** @return {Iterable<string>} */
|
|
46
150
|
static get observedAttributes() {
|
|
47
|
-
|
|
48
|
-
for (const config of this.propList.values()) {
|
|
49
|
-
if (config.reflect === true || config.reflect === 'read') {
|
|
50
|
-
s.add(config.attr);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return s;
|
|
151
|
+
return this.attrList.keys();
|
|
54
152
|
}
|
|
55
153
|
|
|
56
154
|
/** @type {import('./Composition.js').Compositor<?>} */
|
|
57
155
|
compose() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
this.#composition = new Composition();
|
|
62
|
-
return this.#composition;
|
|
156
|
+
// eslint-disable-next-line no-return-assign
|
|
157
|
+
return (this.#composition ??= new Composition());
|
|
63
158
|
}
|
|
64
159
|
|
|
65
160
|
/** @type {Composition<?>} */
|
|
66
161
|
static _composition = null;
|
|
67
162
|
|
|
68
|
-
/** @type {Map<string, import('./
|
|
163
|
+
/** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
|
|
69
164
|
static _props = new Map();
|
|
70
165
|
|
|
71
|
-
/** @type {Map<string,
|
|
166
|
+
/** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
|
|
167
|
+
static _attrs = new Map();
|
|
168
|
+
|
|
169
|
+
/** @type {Map<string, Array<(this: any, ...args: any[]) => any>>} */
|
|
72
170
|
static _propChangedCallbacks = new Map();
|
|
73
171
|
|
|
74
|
-
/** @type {Map<string,
|
|
172
|
+
/** @type {Map<string, Array<(this: any, ...args: any[]) => any>>} */
|
|
75
173
|
static _attributeChangedCallbacks = new Map();
|
|
76
174
|
|
|
77
|
-
/** @type {
|
|
175
|
+
/** @type {Array<(callback: CallbackArguments) => any>} */
|
|
78
176
|
static _onComposeCallbacks = [];
|
|
79
177
|
|
|
80
|
-
/** @type {
|
|
178
|
+
/** @type {Array<(callback: CallbackArguments) => any>} */
|
|
81
179
|
static _onConnectedCallbacks = [];
|
|
82
180
|
|
|
83
|
-
/** @type {
|
|
181
|
+
/** @type {Array<(callback: CallbackArguments) => any>} */
|
|
84
182
|
static _onDisconnectedCallbacks = [];
|
|
85
183
|
|
|
86
|
-
/** @type {
|
|
184
|
+
/** @type {Array<(callback: CallbackArguments) => any>} */
|
|
87
185
|
static _onConstructedCallbacks = [];
|
|
88
186
|
|
|
89
187
|
static interpolatesTemplate = true;
|
|
@@ -103,127 +201,256 @@ export default class CustomElement extends ICustomElement {
|
|
|
103
201
|
/** @type {Map<string, typeof CustomElement>} */
|
|
104
202
|
static registrations = new Map();
|
|
105
203
|
|
|
106
|
-
/**
|
|
107
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Expressions are idempotent functions that are selectively called whenever
|
|
206
|
+
* a render is requested.
|
|
207
|
+
* Expressions are constructed exactly as methods though differ in expected
|
|
208
|
+
* arguments. The first argument should be destructured to ensure each used
|
|
209
|
+
* property is accessed at least once in order to inspect used properties.
|
|
210
|
+
*
|
|
211
|
+
* The Composition API will inspect this function with a proxy for `this` to
|
|
212
|
+
* catalog what observables are used by the expression. This allows the
|
|
213
|
+
* Composition API to build a cache as well as selective invoke the expression
|
|
214
|
+
* only when needed.
|
|
215
|
+
*
|
|
216
|
+
* When used with in element templates, the element itself will be passed as
|
|
217
|
+
* its first argument.
|
|
218
|
+
* ````js
|
|
219
|
+
* Button
|
|
220
|
+
* .prop('filled', 'boolean')
|
|
221
|
+
* .prop('outlined', 'boolean')
|
|
222
|
+
* .expresssions({
|
|
223
|
+
* _isFilledOrOutlined({filled, outlined}) {
|
|
224
|
+
* return (filled || outlined)
|
|
225
|
+
* },
|
|
226
|
+
* })
|
|
227
|
+
* .html`<div custom={_isFilledOrOutlined}></div>`;
|
|
228
|
+
* ````
|
|
229
|
+
*
|
|
230
|
+
* When used with external data source, that data source
|
|
231
|
+
* will be passed to the expression with all properties being `null` at first
|
|
232
|
+
* inspection.
|
|
233
|
+
* ````js
|
|
234
|
+
* const externalData = {first: 'John', last: 'Doe'};
|
|
235
|
+
* ContactCard
|
|
236
|
+
* .expresssions({
|
|
237
|
+
* _fullName({first, last}) {
|
|
238
|
+
* return [first, last].filter(Boolean).join(' ');
|
|
239
|
+
* },
|
|
240
|
+
* })
|
|
241
|
+
* myButton.render(externalData);
|
|
242
|
+
* ````
|
|
243
|
+
*
|
|
244
|
+
* Expressions may be support argumentless calls by using default
|
|
245
|
+
* parameters with `this`.
|
|
246
|
+
* ````js
|
|
247
|
+
* Button
|
|
248
|
+
* .expresssions({
|
|
249
|
+
* isFilledOrOutlined({filled, outlined} = this) {
|
|
250
|
+
* return (filled || outlined)
|
|
251
|
+
* },
|
|
252
|
+
* });
|
|
253
|
+
* myButton.isFilledorOutlined();
|
|
254
|
+
* ````
|
|
255
|
+
* @type {{
|
|
256
|
+
* <
|
|
257
|
+
* CLASS extends typeof CustomElement,
|
|
258
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
259
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
260
|
+
* PROPS extends {
|
|
261
|
+
* [K in keyof any]: K extends `_${any}` ? ((data: INSTANCE, state?: Record<string, any>) => string|boolean|null)
|
|
262
|
+
* : ((data?: INSTANCE, state?: Record<string, any>) => string|boolean|null)
|
|
263
|
+
* } & ThisType<INSTANCE>
|
|
264
|
+
* >(this: CLASS, expressions: PROPS & ThisType<INSTANCE & PROPS>):
|
|
265
|
+
* CLASS & Class<{
|
|
266
|
+
* [K in keyof PROPS]: K extends `_${any}` ? never : () => ReturnType<PROPS[K]> }
|
|
267
|
+
* ,ARGS>
|
|
268
|
+
* }}
|
|
269
|
+
*/
|
|
270
|
+
static expressions = /** @type {any} */ (this.set);
|
|
108
271
|
|
|
109
|
-
/** @type {typeof ICustomElement.methods} */
|
|
110
272
|
static methods = this.set;
|
|
111
273
|
|
|
112
|
-
/**
|
|
113
|
-
|
|
274
|
+
/**
|
|
275
|
+
* @type {{
|
|
276
|
+
* <
|
|
277
|
+
* CLASS extends typeof CustomElement,
|
|
278
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
279
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
280
|
+
* PROPS extends Partial<INSTANCE>>
|
|
281
|
+
* (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
|
|
282
|
+
* : CLASS & Class<PROPS,ARGS>
|
|
283
|
+
* }}
|
|
284
|
+
*/
|
|
285
|
+
static overrides = /** @type {any} */ (this.set);
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @type {{
|
|
289
|
+
* <
|
|
290
|
+
* CLASS extends typeof CustomElement,
|
|
291
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
292
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
293
|
+
* KEY extends string,
|
|
294
|
+
* OPTIONS extends ObserverPropertyType
|
|
295
|
+
* | ObserverOptions<ObserverPropertyType, unknown, INSTANCE>
|
|
296
|
+
* | ((this:INSTANCE, data:Partial<INSTANCE>, fn?: () => any) => any),
|
|
297
|
+
* VALUE extends Record<KEY, OPTIONS extends (...args2:any[]) => infer R ? R
|
|
298
|
+
* : OPTIONS extends ObserverPropertyType ? import('./observe.js').ParsedObserverPropertyType<OPTIONS>
|
|
299
|
+
* : OPTIONS extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
|
|
300
|
+
* : OPTIONS extends {type: ObserverPropertyType} ? import('./observe.js').ParsedObserverPropertyType<OPTIONS['type']>
|
|
301
|
+
* : OPTIONS extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
|
|
302
|
+
* : never
|
|
303
|
+
* >
|
|
304
|
+
* > (this: CLASS, name: KEY, options: OPTIONS)
|
|
305
|
+
* : CLASS & Class<VALUE,ARGS>;
|
|
306
|
+
* }}
|
|
307
|
+
*/
|
|
308
|
+
static props = /** @type {any} */ (this.observe);
|
|
114
309
|
|
|
115
|
-
|
|
116
|
-
static props = this.observe;
|
|
310
|
+
static idl = this.prop;
|
|
117
311
|
|
|
118
312
|
/**
|
|
119
|
-
* @template {typeof CustomElement} T
|
|
120
313
|
* @this T
|
|
314
|
+
* @template {typeof CustomElement} T
|
|
121
315
|
* @template {keyof T} K
|
|
122
316
|
* @param {K} collection
|
|
123
|
-
* @param {
|
|
317
|
+
* @param {Function} callback
|
|
124
318
|
*/
|
|
125
319
|
static _addCallback(collection, callback) {
|
|
126
320
|
if (!this.hasOwnProperty(collection)) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
321
|
+
// @ts-expect-error not typed
|
|
322
|
+
this[collection] = [...this[collection], callback];
|
|
323
|
+
return;
|
|
130
324
|
}
|
|
325
|
+
// @ts-expect-error any
|
|
131
326
|
this[collection].push(callback);
|
|
132
327
|
}
|
|
133
328
|
|
|
134
329
|
/**
|
|
135
330
|
* Append parts to composition
|
|
136
|
-
* @type {
|
|
331
|
+
* @type {{
|
|
332
|
+
* <
|
|
333
|
+
* T extends typeof CustomElement,
|
|
334
|
+
* >
|
|
335
|
+
* (this: T, ...parts: ConstructorParameters<typeof Composition<InstanceType<T>>>): T;
|
|
336
|
+
* }}
|
|
137
337
|
*/
|
|
138
338
|
static append(...parts) {
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
// console.debug('onComposed:append', ...parts);
|
|
142
|
-
composition.append(...parts);
|
|
143
|
-
},
|
|
339
|
+
this._onComposeCallbacks.push(({ composition }) => {
|
|
340
|
+
composition.append(...parts);
|
|
144
341
|
});
|
|
145
|
-
|
|
342
|
+
|
|
343
|
+
this._addCallback('_onComposeCallbacks', /** @type {(opts: CallbackArguments) => unknown} */ ((opts) => {
|
|
344
|
+
const { composition } = opts;
|
|
345
|
+
composition.append(...parts);
|
|
346
|
+
}));
|
|
146
347
|
return this;
|
|
147
348
|
}
|
|
148
349
|
|
|
149
350
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
351
|
+
* After composition, invokes callback.
|
|
352
|
+
* May be called multiple times.
|
|
353
|
+
* @type {{
|
|
354
|
+
* <
|
|
355
|
+
* T1 extends (typeof CustomElement),
|
|
356
|
+
* T2 extends InstanceType<T1>,
|
|
357
|
+
* T3 extends CompositionCallback<T2, T2>['composed'],
|
|
358
|
+
* >
|
|
359
|
+
* (this: T1, callback: T3): T1
|
|
360
|
+
* }}
|
|
152
361
|
*/
|
|
153
|
-
static
|
|
154
|
-
|
|
155
|
-
// @ts-expect-error Complex cast
|
|
156
|
-
this.append(css(array, ...substitutions));
|
|
157
|
-
} else {
|
|
158
|
-
// @ts-expect-error Complex cast
|
|
159
|
-
this.append(array, ...substitutions);
|
|
160
|
-
}
|
|
161
|
-
// @ts-expect-error Can't cast T
|
|
362
|
+
static recompose(callback) {
|
|
363
|
+
this._addCallback('_onComposeCallbacks', callback);
|
|
162
364
|
return this;
|
|
163
365
|
}
|
|
164
366
|
|
|
165
|
-
/**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
367
|
+
/**
|
|
368
|
+
* Appends styles to composition
|
|
369
|
+
* @type {{
|
|
370
|
+
* <
|
|
371
|
+
* T1 extends (typeof CustomElement),
|
|
372
|
+
* T2 extends TemplateStringsArray|HTMLStyleElement|CSSStyleSheet|string>(
|
|
373
|
+
* this: T1,
|
|
374
|
+
* array: T2,
|
|
375
|
+
* ...rest: T2 extends string ? any : T2 extends TemplateStringsArray ? any[] : (HTMLStyleElement|CSSStyleSheet)[]
|
|
376
|
+
* ): T1
|
|
377
|
+
* }}
|
|
378
|
+
*/
|
|
379
|
+
static css(array, ...substitutions) {
|
|
380
|
+
this._addCallback('_onComposeCallbacks', /** @type {(opts: CallbackArguments) => unknown} */ ((opts) => {
|
|
381
|
+
const { composition } = opts;
|
|
382
|
+
if (typeof array === 'string' || Array.isArray(array)) {
|
|
383
|
+
// @ts-expect-error Complex cast
|
|
384
|
+
composition.append(css(array, ...substitutions));
|
|
385
|
+
} else {
|
|
386
|
+
// @ts-expect-error Complex cast
|
|
387
|
+
composition.append(array, ...substitutions);
|
|
388
|
+
}
|
|
389
|
+
}));
|
|
390
|
+
|
|
169
391
|
return this;
|
|
170
392
|
}
|
|
171
393
|
|
|
172
394
|
/**
|
|
173
|
-
* Registers class
|
|
174
|
-
* via `queueMicrotask`. If class is registered before then,
|
|
395
|
+
* Registers class with customElements. If class is registered before then,
|
|
175
396
|
* does nothing.
|
|
176
|
-
* @type {
|
|
397
|
+
* @type {{
|
|
398
|
+
* <T extends typeof CustomElement>(this: T, elementName: string): T;
|
|
399
|
+
* }}
|
|
177
400
|
*/
|
|
178
401
|
static autoRegister(elementName) {
|
|
179
402
|
if (this.hasOwnProperty('defined') && this.defined) {
|
|
180
403
|
console.warn(this.elementName, 'already registered.');
|
|
181
|
-
// @ts-expect-error Can't cast T
|
|
182
404
|
return this;
|
|
183
405
|
}
|
|
184
406
|
this.register(elementName);
|
|
185
|
-
// @ts-expect-error Can't cast T
|
|
186
407
|
return this;
|
|
187
408
|
}
|
|
188
409
|
|
|
189
410
|
/**
|
|
190
411
|
* Appends DocumentFragment to composition
|
|
191
|
-
* @type {
|
|
412
|
+
* @type {{
|
|
413
|
+
* <T extends typeof CustomElement>(
|
|
414
|
+
* this: T,
|
|
415
|
+
* string: TemplateStringsArray,
|
|
416
|
+
* ...substitutions: (string|Element|((this:InstanceType<T>, data:InstanceType<T>, injections?:any) => any))[]
|
|
417
|
+
* ): T
|
|
418
|
+
* }}
|
|
192
419
|
*/
|
|
193
420
|
static html(strings, ...substitutions) {
|
|
194
|
-
this.
|
|
195
|
-
|
|
421
|
+
this._addCallback('_onComposeCallbacks', /** @type {(opts: CallbackArguments) => unknown} */ ((opts) => {
|
|
422
|
+
const { composition } = opts;
|
|
196
423
|
// console.log('onComposed:html', strings);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
});
|
|
200
|
-
// @ts-expect-error Can't cast T
|
|
424
|
+
composition.append(html(strings, ...substitutions));
|
|
425
|
+
}));
|
|
201
426
|
return this;
|
|
202
427
|
}
|
|
203
428
|
|
|
204
429
|
/**
|
|
205
430
|
* Extends base class into a new class.
|
|
206
431
|
* Use to avoid mutating base class.
|
|
207
|
-
*
|
|
208
|
-
*
|
|
432
|
+
* @type {{
|
|
433
|
+
* <T1 extends typeof CustomElement, T2 extends T1, T3 extends (Base:T1) => T2>
|
|
434
|
+
* (this: T1,customExtender?: T3|null): T3 extends null ? T1 : T2;
|
|
435
|
+
* }}
|
|
209
436
|
*/
|
|
210
|
-
static extend() {
|
|
437
|
+
static extend(customExtender) {
|
|
211
438
|
// @ts-expect-error Can't cast T
|
|
212
|
-
return class extends this {};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Fix for Typescript not parsing constructor params
|
|
217
|
-
* @type {typeof ICustomElement.tsClassFix}
|
|
218
|
-
*/
|
|
219
|
-
static tsClassFix() {
|
|
220
|
-
// @ts-expect-error Can't cast T
|
|
221
|
-
return this;
|
|
439
|
+
return customExtender ? customExtender(this) : class extends this {};
|
|
222
440
|
}
|
|
223
441
|
|
|
224
442
|
/**
|
|
225
443
|
* Assigns static values to class
|
|
226
|
-
* @type {
|
|
444
|
+
* @type {{
|
|
445
|
+
* <
|
|
446
|
+
* T1 extends typeof CustomElement,
|
|
447
|
+
* T2 extends {
|
|
448
|
+
* [K in keyof any]: (
|
|
449
|
+
* ((this:T1, ...args:any[]) => any)
|
|
450
|
+
* |string|number|boolean|any[]|object)}
|
|
451
|
+
* >
|
|
452
|
+
* (this: T1, source: T2 & ThisType<T1 & T2>):T1 & T2;
|
|
453
|
+
* }}
|
|
227
454
|
*/
|
|
228
455
|
static setStatic(source) {
|
|
229
456
|
Object.assign(this, source);
|
|
@@ -233,16 +460,31 @@ export default class CustomElement extends ICustomElement {
|
|
|
233
460
|
|
|
234
461
|
/**
|
|
235
462
|
* Assigns values directly to all instances (via prototype)
|
|
236
|
-
* @type {
|
|
463
|
+
* @type {{
|
|
464
|
+
* <
|
|
465
|
+
* CLASS extends typeof CustomElement,
|
|
466
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
467
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
468
|
+
* PROPS extends object>
|
|
469
|
+
* (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
|
|
470
|
+
* : CLASS & Class<PROPS,ARGS>
|
|
471
|
+
* }}
|
|
237
472
|
*/
|
|
238
473
|
static readonly(source, options) {
|
|
239
|
-
// @ts-expect-error Can't cast T
|
|
240
474
|
return this.set(source, { ...options, writable: false });
|
|
241
475
|
}
|
|
242
476
|
|
|
243
477
|
/**
|
|
244
478
|
* Assigns values directly to all instances (via prototype)
|
|
245
|
-
* @type {
|
|
479
|
+
* @type {{
|
|
480
|
+
* <
|
|
481
|
+
* CLASS extends typeof CustomElement,
|
|
482
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
483
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
484
|
+
* PROPS extends object>
|
|
485
|
+
* (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
|
|
486
|
+
* : CLASS & Class<PROPS,ARGS>
|
|
487
|
+
* }}
|
|
246
488
|
*/
|
|
247
489
|
static set(source, options) {
|
|
248
490
|
Object.defineProperties(
|
|
@@ -268,6 +510,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
268
510
|
{
|
|
269
511
|
enumerable: false,
|
|
270
512
|
configurable: true,
|
|
513
|
+
// @ts-expect-error Can't index by symbol
|
|
271
514
|
value: source[symbol],
|
|
272
515
|
writable: true,
|
|
273
516
|
...options,
|
|
@@ -281,7 +524,14 @@ export default class CustomElement extends ICustomElement {
|
|
|
281
524
|
|
|
282
525
|
/**
|
|
283
526
|
* Returns result of calling mixin with current class
|
|
284
|
-
* @type {
|
|
527
|
+
* @type {{
|
|
528
|
+
* <
|
|
529
|
+
* BASE extends typeof CustomElement,
|
|
530
|
+
* FN extends (...args:any[]) => any,
|
|
531
|
+
* RETURN extends ReturnType<FN>,
|
|
532
|
+
* SUBCLASS extends ClassOf<RETURN>,
|
|
533
|
+
* >(this: BASE, mixin: FN): SUBCLASS & BASE
|
|
534
|
+
* }}
|
|
285
535
|
*/
|
|
286
536
|
static mixin(mixin) {
|
|
287
537
|
return mixin(this);
|
|
@@ -289,7 +539,9 @@ export default class CustomElement extends ICustomElement {
|
|
|
289
539
|
|
|
290
540
|
/**
|
|
291
541
|
* Registers class with window.customElements synchronously
|
|
292
|
-
* @type {
|
|
542
|
+
* @type {{
|
|
543
|
+
* <T extends typeof CustomElement>(this: T, elementName?: string, force?: boolean): T;
|
|
544
|
+
* }}
|
|
293
545
|
*/
|
|
294
546
|
static register(elementName) {
|
|
295
547
|
if (elementName) {
|
|
@@ -299,7 +551,6 @@ export default class CustomElement extends ICustomElement {
|
|
|
299
551
|
customElements.define(this.elementName, this);
|
|
300
552
|
CustomElement.registrations.set(this.elementName, this);
|
|
301
553
|
this.defined = true;
|
|
302
|
-
// @ts-expect-error Can't cast T
|
|
303
554
|
return this;
|
|
304
555
|
}
|
|
305
556
|
|
|
@@ -310,6 +561,13 @@ export default class CustomElement extends ICustomElement {
|
|
|
310
561
|
return this._props;
|
|
311
562
|
}
|
|
312
563
|
|
|
564
|
+
static get attrList() {
|
|
565
|
+
if (!this.hasOwnProperty('_attrs')) {
|
|
566
|
+
this._attrs = new Map(this._attrs);
|
|
567
|
+
}
|
|
568
|
+
return this._attrs;
|
|
569
|
+
}
|
|
570
|
+
|
|
313
571
|
static get propChangedCallbacks() {
|
|
314
572
|
if (!this.hasOwnProperty('_propChangedCallbacks')) {
|
|
315
573
|
// structuredClone()
|
|
@@ -335,55 +593,84 @@ export default class CustomElement extends ICustomElement {
|
|
|
335
593
|
|
|
336
594
|
/**
|
|
337
595
|
* Creates observable property on instances (via prototype)
|
|
338
|
-
* @
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
* )
|
|
596
|
+
* @type {{
|
|
597
|
+
* <
|
|
598
|
+
* CLASS extends typeof CustomElement,
|
|
599
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
600
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
601
|
+
* KEY extends string,
|
|
602
|
+
* OPTIONS extends ObserverPropertyType
|
|
603
|
+
* | ObserverOptions<ObserverPropertyType, unknown, INSTANCE>
|
|
604
|
+
* | ((this:INSTANCE, data:Partial<INSTANCE>, fn?: () => any) => any),
|
|
605
|
+
* VALUE extends Record<KEY, OPTIONS extends (...args2:any[]) => infer R ? R
|
|
606
|
+
* : OPTIONS extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<OPTIONS>
|
|
607
|
+
* : OPTIONS extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
|
|
608
|
+
* : OPTIONS extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<OPTIONS['type']>
|
|
609
|
+
* : OPTIONS extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
|
|
610
|
+
* : never
|
|
611
|
+
* >
|
|
612
|
+
* > (this: CLASS, name: KEY, options: OPTIONS)
|
|
613
|
+
* : CLASS & Class<VALUE,ARGS>
|
|
614
|
+
* }}
|
|
352
615
|
*/
|
|
353
616
|
static prop(name, typeOrOptions) {
|
|
354
617
|
// TODO: Cache and save configuration for reuse (mixins)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const customCallback = options.changedCallback;
|
|
618
|
+
const config = defineObservableProperty(
|
|
619
|
+
/** @type {any} */ (this.prototype),
|
|
620
|
+
name,
|
|
621
|
+
/** @type {any} */ (typeOrOptions),
|
|
622
|
+
);
|
|
361
623
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
624
|
+
const { changedCallback, attr, reflect, watchers } = config;
|
|
625
|
+
if (changedCallback) {
|
|
626
|
+
watchers.push([name, changedCallback]);
|
|
365
627
|
}
|
|
366
|
-
|
|
367
628
|
// TODO: Inspect possible closure bloat
|
|
368
|
-
|
|
629
|
+
config.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
|
|
369
630
|
this._onObserverPropertyChanged.call(this, name, oldValue, newValue, changes);
|
|
370
631
|
};
|
|
371
632
|
|
|
372
|
-
const config = defineObservableProperty(this.prototype, name, options);
|
|
373
|
-
|
|
374
633
|
this.propList.set(name, config);
|
|
375
|
-
|
|
376
|
-
|
|
634
|
+
|
|
635
|
+
if (attr
|
|
636
|
+
&& (reflect === true || reflect === 'read')
|
|
637
|
+
&& (config.enumerable || !this.attrList.has(attr) || !this.attrList.get(attr).enumerable)) {
|
|
638
|
+
this.attrList.set(attr, config);
|
|
377
639
|
}
|
|
378
640
|
|
|
379
|
-
|
|
641
|
+
this.onPropChanged(watchers);
|
|
642
|
+
|
|
643
|
+
// @ts-expect-error Can't cast T
|
|
644
|
+
return this;
|
|
380
645
|
}
|
|
381
646
|
|
|
382
647
|
/**
|
|
383
648
|
* Define properties on instances via Object.defineProperties().
|
|
384
649
|
* Automatically sets property non-enumerable if name begins with `_`.
|
|
385
650
|
* Functions will be remapped as getters
|
|
386
|
-
* @type {
|
|
651
|
+
* @type {{
|
|
652
|
+
* <
|
|
653
|
+
* CLASS extends typeof CustomElement,
|
|
654
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
655
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
656
|
+
* PROPS extends {
|
|
657
|
+
* [P in keyof any] :
|
|
658
|
+
* {
|
|
659
|
+
* enumerable?: boolean;
|
|
660
|
+
* configurable?: boolean;
|
|
661
|
+
* writable?: boolean;
|
|
662
|
+
* value?: any;
|
|
663
|
+
* get?: ((this: INSTANCE) => any);
|
|
664
|
+
* set?: (this: INSTANCE, value: any) => void;
|
|
665
|
+
* } | ((this: INSTANCE, ...args:any[]) => any)
|
|
666
|
+
* },
|
|
667
|
+
* VALUE extends {
|
|
668
|
+
* [KEY in keyof PROPS]: PROPS[KEY] extends (...args2:any[]) => infer R ? R
|
|
669
|
+
* : PROPS[KEY] extends TypedPropertyDescriptor<infer R> ? R : never
|
|
670
|
+
* }>
|
|
671
|
+
* (this: CLASS, props: PROPS & ThisType<PROPS & INSTANCE>): CLASS
|
|
672
|
+
* & Class<VALUE,ARGS>
|
|
673
|
+
* }}
|
|
387
674
|
*/
|
|
388
675
|
static define(props) {
|
|
389
676
|
Object.defineProperties(
|
|
@@ -413,13 +700,26 @@ export default class CustomElement extends ICustomElement {
|
|
|
413
700
|
return this;
|
|
414
701
|
}
|
|
415
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Assigns values directly to all instances (via prototype)
|
|
705
|
+
* @type {{
|
|
706
|
+
* <
|
|
707
|
+
* CLASS extends typeof CustomElement,
|
|
708
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
709
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
710
|
+
* PROP extends string,
|
|
711
|
+
* PROPS extends INSTANCE & Record<PROP, never>
|
|
712
|
+
* >(this: CLASS, name: PROP):
|
|
713
|
+
* CLASS & Class<PROPS,ARGS>
|
|
714
|
+
* }}
|
|
715
|
+
*/
|
|
416
716
|
static undefine(name) {
|
|
417
717
|
Reflect.deleteProperty(this.prototype, name);
|
|
418
718
|
if (this.propList.has(name)) {
|
|
419
|
-
const
|
|
420
|
-
if (
|
|
719
|
+
const { watchers, attr, reflect } = this.propList.get(name);
|
|
720
|
+
if (watchers.length && this.propChangedCallbacks.has(name)) {
|
|
421
721
|
const propWatchers = this.propChangedCallbacks.get(name);
|
|
422
|
-
for (const watcher of
|
|
722
|
+
for (const [prop, watcher] of watchers) {
|
|
423
723
|
const index = propWatchers.indexOf(watcher);
|
|
424
724
|
if (index !== -1) {
|
|
425
725
|
console.warn('Unwatching', name);
|
|
@@ -427,31 +727,58 @@ export default class CustomElement extends ICustomElement {
|
|
|
427
727
|
}
|
|
428
728
|
}
|
|
429
729
|
}
|
|
730
|
+
if (attr && (reflect === true || reflect === 'read')) {
|
|
731
|
+
this.attrList.delete(attr);
|
|
732
|
+
}
|
|
733
|
+
this.propList.delete(name);
|
|
430
734
|
}
|
|
431
|
-
|
|
735
|
+
|
|
736
|
+
// @ts-expect-error Can't cast T
|
|
432
737
|
return this;
|
|
433
738
|
}
|
|
434
739
|
|
|
435
740
|
/**
|
|
436
741
|
* Creates observable properties on instances
|
|
437
|
-
* @type {
|
|
742
|
+
* @type {{
|
|
743
|
+
* <
|
|
744
|
+
* CLASS extends typeof CustomElement,
|
|
745
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
746
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
747
|
+
* PROPS extends IDLParameter<INSTANCE & VALUE>,
|
|
748
|
+
* VALUE extends {
|
|
749
|
+
* [KEY in keyof PROPS]:
|
|
750
|
+
* PROPS[KEY] extends (...args2:any[]) => infer R ? R
|
|
751
|
+
* : PROPS[KEY] extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]>
|
|
752
|
+
* : PROPS[KEY] extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
|
|
753
|
+
* : PROPS[KEY] extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]['type']>
|
|
754
|
+
* : PROPS[KEY] extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
|
|
755
|
+
* : never
|
|
756
|
+
* },
|
|
757
|
+
* > (this: CLASS, props: PROPS)
|
|
758
|
+
* : CLASS & Class<VALUE,ARGS>
|
|
759
|
+
* }}
|
|
438
760
|
*/
|
|
439
761
|
static observe(props) {
|
|
440
762
|
for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
this.prop(name, typeOrOptions);
|
|
448
|
-
}
|
|
763
|
+
/** @type {any} */
|
|
764
|
+
const options = (typeof typeOrOptions === 'function')
|
|
765
|
+
? { reflect: false, get: typeOrOptions }
|
|
766
|
+
: typeOrOptions;
|
|
767
|
+
|
|
768
|
+
this.prop(name, options);
|
|
449
769
|
}
|
|
450
770
|
// @ts-expect-error Can't cast T
|
|
451
771
|
return this;
|
|
452
772
|
}
|
|
453
773
|
|
|
454
|
-
/**
|
|
774
|
+
/**
|
|
775
|
+
* @type {{
|
|
776
|
+
* <
|
|
777
|
+
* T1 extends typeof CustomElement,
|
|
778
|
+
* T2 extends IDLParameter<T1>>
|
|
779
|
+
* (this: T1, props: T2):T1 & ParsedProps<T2>
|
|
780
|
+
* }}
|
|
781
|
+
*/
|
|
455
782
|
static defineStatic(props) {
|
|
456
783
|
for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
|
|
457
784
|
const options = (typeof typeOrOptions === 'function')
|
|
@@ -459,6 +786,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
459
786
|
: (typeof typeOrOptions === 'string'
|
|
460
787
|
? { type: typeOrOptions }
|
|
461
788
|
: typeOrOptions);
|
|
789
|
+
// @ts-expect-error Adding property to this
|
|
462
790
|
defineObservableProperty(this, name, {
|
|
463
791
|
reflect: false,
|
|
464
792
|
...options,
|
|
@@ -468,12 +796,21 @@ export default class CustomElement extends ICustomElement {
|
|
|
468
796
|
return this;
|
|
469
797
|
}
|
|
470
798
|
|
|
471
|
-
/**
|
|
799
|
+
/**
|
|
800
|
+
* @type {{
|
|
801
|
+
* <T extends typeof CustomElement>
|
|
802
|
+
* (
|
|
803
|
+
* this: T,
|
|
804
|
+
* listeners?: import('./Composition').CompositionEventListenerObject<InstanceType<T>>,
|
|
805
|
+
* options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
|
|
806
|
+
* ): T;
|
|
807
|
+
* }}
|
|
808
|
+
*/
|
|
472
809
|
static events(listeners, options) {
|
|
473
810
|
this.on({
|
|
474
811
|
composed({ composition }) {
|
|
475
812
|
for (const [key, listenerOptions] of Object.entries(listeners)) {
|
|
476
|
-
const [, flags, type] = key.match(
|
|
813
|
+
const [, flags, type] = key.match(/^([*1~]+)?(.*)$/);
|
|
477
814
|
// TODO: Make abstract
|
|
478
815
|
let prop;
|
|
479
816
|
/** @type {string[]} */
|
|
@@ -509,34 +846,51 @@ export default class CustomElement extends ICustomElement {
|
|
|
509
846
|
},
|
|
510
847
|
});
|
|
511
848
|
|
|
512
|
-
// @ts-expect-error Can't cast T
|
|
513
849
|
return this;
|
|
514
850
|
}
|
|
515
851
|
|
|
516
|
-
/**
|
|
852
|
+
/**
|
|
853
|
+
* @type {{
|
|
854
|
+
* <T extends typeof CustomElement>
|
|
855
|
+
* (
|
|
856
|
+
* this: T,
|
|
857
|
+
* listenerMap: {
|
|
858
|
+
* [P in keyof any]: import('./Composition').CompositionEventListenerObject<InstanceType<T>>
|
|
859
|
+
* },
|
|
860
|
+
* options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
|
|
861
|
+
* ): T;
|
|
862
|
+
* }}
|
|
863
|
+
*/
|
|
517
864
|
static childEvents(listenerMap, options) {
|
|
518
865
|
for (const [tag, listeners] of Object.entries(listenerMap)) {
|
|
519
|
-
// @ts-expect-error Can't cast T
|
|
520
866
|
this.events(listeners, {
|
|
521
867
|
tag: attrNameFromPropName(tag),
|
|
522
868
|
...options,
|
|
523
869
|
});
|
|
524
870
|
}
|
|
525
871
|
|
|
526
|
-
// @ts-expect-error Can't cast T
|
|
527
872
|
return this;
|
|
528
873
|
}
|
|
529
874
|
|
|
530
|
-
/** @type {typeof
|
|
875
|
+
/** @type {typeof CustomElement['events']} */
|
|
531
876
|
static rootEvents(listeners, options) {
|
|
532
|
-
// @ts-expect-error Can't cast T
|
|
533
877
|
return this.events(listeners, {
|
|
534
878
|
tag: Composition.shadowRootTag,
|
|
535
879
|
...options,
|
|
536
880
|
});
|
|
537
881
|
}
|
|
538
882
|
|
|
539
|
-
/**
|
|
883
|
+
/**
|
|
884
|
+
* @type {{
|
|
885
|
+
* <
|
|
886
|
+
* T1 extends typeof CustomElement,
|
|
887
|
+
* T2 extends InstanceType<T1>,
|
|
888
|
+
* T3 extends CompositionCallback<T2, T2>,
|
|
889
|
+
* T4 extends keyof T3,
|
|
890
|
+
* >
|
|
891
|
+
* (this: T1, name: T3|T4, callbacks?: T3[T4] & ThisType<T2>): T1
|
|
892
|
+
* }}
|
|
893
|
+
*/
|
|
540
894
|
static on(nameOrCallbacks, callback) {
|
|
541
895
|
const callbacks = typeof nameOrCallbacks === 'string'
|
|
542
896
|
? { [nameOrCallbacks]: callback }
|
|
@@ -558,6 +912,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
558
912
|
default:
|
|
559
913
|
if (name.endsWith('Changed')) {
|
|
560
914
|
const prop = name.slice(0, name.length - 'Changed'.length);
|
|
915
|
+
// @ts-expect-error Computed key
|
|
561
916
|
this.onPropChanged({ [prop]: fn });
|
|
562
917
|
continue;
|
|
563
918
|
}
|
|
@@ -566,36 +921,73 @@ export default class CustomElement extends ICustomElement {
|
|
|
566
921
|
this._addCallback(arrayPropName, fn);
|
|
567
922
|
}
|
|
568
923
|
|
|
569
|
-
// @ts-expect-error Can't cast T
|
|
570
924
|
return this;
|
|
571
925
|
}
|
|
572
926
|
|
|
573
|
-
/**
|
|
927
|
+
/**
|
|
928
|
+
* @type {{
|
|
929
|
+
* <
|
|
930
|
+
* T1 extends typeof CustomElement,
|
|
931
|
+
* T2 extends InstanceType<T1>
|
|
932
|
+
* >
|
|
933
|
+
* (
|
|
934
|
+
* this: T1,
|
|
935
|
+
* options: ObjectOrObjectEntries<{
|
|
936
|
+
* [P in keyof T2]? : (
|
|
937
|
+
* this: T2,
|
|
938
|
+
* oldValue: T2[P],
|
|
939
|
+
* newValue: T2[P],
|
|
940
|
+
* changes:any,
|
|
941
|
+
* element: T2
|
|
942
|
+
* ) => void
|
|
943
|
+
* }>,
|
|
944
|
+
* ): T1;
|
|
945
|
+
* }}
|
|
946
|
+
*/
|
|
574
947
|
static onPropChanged(options) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
948
|
+
const entries = Array.isArray(options) ? options : Object.entries(options);
|
|
949
|
+
const { propChangedCallbacks } = this;
|
|
950
|
+
for (const [prop, callback] of entries) {
|
|
951
|
+
if (propChangedCallbacks.has(prop)) {
|
|
952
|
+
propChangedCallbacks.get(prop).push(callback);
|
|
578
953
|
} else {
|
|
579
|
-
|
|
954
|
+
propChangedCallbacks.set(prop, [callback]);
|
|
580
955
|
}
|
|
581
956
|
}
|
|
582
957
|
|
|
583
|
-
// @ts-expect-error Can't cast T
|
|
584
958
|
return this;
|
|
585
959
|
}
|
|
586
960
|
|
|
587
|
-
/**
|
|
961
|
+
/**
|
|
962
|
+
* @type {{
|
|
963
|
+
* <
|
|
964
|
+
* T1 extends typeof CustomElement,
|
|
965
|
+
* T2 extends InstanceType<T1>
|
|
966
|
+
* >
|
|
967
|
+
* (
|
|
968
|
+
* this: T1,
|
|
969
|
+
* options: {
|
|
970
|
+
* [x:string]: (
|
|
971
|
+
* this: T2,
|
|
972
|
+
* oldValue: string,
|
|
973
|
+
* newValue: string,
|
|
974
|
+
* element: T2
|
|
975
|
+
* ) => void
|
|
976
|
+
* },
|
|
977
|
+
* ): T1;
|
|
978
|
+
* }}
|
|
979
|
+
*/
|
|
588
980
|
static onAttributeChanged(options) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
981
|
+
const entries = Array.isArray(options) ? options : Object.entries(options);
|
|
982
|
+
const { attributeChangedCallbacks } = this;
|
|
983
|
+
for (const [name, callback] of entries) {
|
|
984
|
+
if (attributeChangedCallbacks.has(name)) {
|
|
985
|
+
attributeChangedCallbacks.get(name).push(callback);
|
|
593
986
|
} else {
|
|
594
|
-
|
|
987
|
+
attributeChangedCallbacks.set(name, [callback]);
|
|
595
988
|
}
|
|
596
989
|
}
|
|
597
990
|
|
|
598
|
-
// @ts-expect-error Can't cast T
|
|
599
991
|
return this;
|
|
600
992
|
}
|
|
601
993
|
|
|
@@ -611,10 +1003,15 @@ export default class CustomElement extends ICustomElement {
|
|
|
611
1003
|
/** @type {Composition<?>} */
|
|
612
1004
|
#composition;
|
|
613
1005
|
|
|
1006
|
+
#patching = false;
|
|
1007
|
+
|
|
1008
|
+
/** @type {Array<[string, any, CustomElement]>} */
|
|
1009
|
+
#pendingPatchRenders = [];
|
|
1010
|
+
|
|
614
1011
|
/** @type {Map<string,{stringValue:string, parsedValue:any}>} */
|
|
615
1012
|
_propAttributeCache;
|
|
616
1013
|
|
|
617
|
-
/** @type {
|
|
1014
|
+
/** @type {CallbackArguments} */
|
|
618
1015
|
_callbackArguments = null;
|
|
619
1016
|
|
|
620
1017
|
/** @param {any[]} args */
|
|
@@ -636,11 +1033,12 @@ export default class CustomElement extends ICustomElement {
|
|
|
636
1033
|
* @return {void}
|
|
637
1034
|
*/
|
|
638
1035
|
this.render = this.composition.render(
|
|
639
|
-
this,
|
|
1036
|
+
this.constructor.prototype,
|
|
640
1037
|
this,
|
|
641
1038
|
{
|
|
1039
|
+
defaults: this.constructor.prototype,
|
|
642
1040
|
store: this,
|
|
643
|
-
|
|
1041
|
+
shadowRoot: this.shadowRoot,
|
|
644
1042
|
context: this,
|
|
645
1043
|
},
|
|
646
1044
|
);
|
|
@@ -650,15 +1048,29 @@ export default class CustomElement extends ICustomElement {
|
|
|
650
1048
|
}
|
|
651
1049
|
}
|
|
652
1050
|
|
|
653
|
-
/**
|
|
1051
|
+
/**
|
|
1052
|
+
* @type {{
|
|
1053
|
+
* <
|
|
1054
|
+
* T extends CustomElement,
|
|
1055
|
+
* K extends string = string,
|
|
1056
|
+
* >(this:T,
|
|
1057
|
+
* name: K,
|
|
1058
|
+
* oldValue: K extends keyof T ? T[K] : unknown,
|
|
1059
|
+
* newValue: K extends keyof T ? T[K] : unknown,
|
|
1060
|
+
* changes?: K extends keyof T ? T[K] extends object ? Partial<T[K]> : T[K] : unknown): void;
|
|
1061
|
+
* }}
|
|
1062
|
+
*/
|
|
654
1063
|
propChangedCallback(name, oldValue, newValue, changes = newValue) {
|
|
655
|
-
if (
|
|
1064
|
+
if (this.#patching) {
|
|
1065
|
+
this.#pendingPatchRenders.push([name, changes, this]);
|
|
1066
|
+
} else {
|
|
656
1067
|
this.render.byProp(name, changes, this);
|
|
657
1068
|
// this.render({ [name]: changes });
|
|
658
1069
|
}
|
|
659
1070
|
|
|
660
|
-
|
|
661
|
-
|
|
1071
|
+
const { _propChangedCallbacks } = this.static;
|
|
1072
|
+
if (_propChangedCallbacks.has(name)) {
|
|
1073
|
+
for (const callback of _propChangedCallbacks.get(name)) {
|
|
662
1074
|
callback.call(this, oldValue, newValue, changes, this);
|
|
663
1075
|
}
|
|
664
1076
|
}
|
|
@@ -670,55 +1082,53 @@ export default class CustomElement extends ICustomElement {
|
|
|
670
1082
|
* @param {string|null} newValue
|
|
671
1083
|
*/
|
|
672
1084
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
673
|
-
const
|
|
674
|
-
if (
|
|
675
|
-
for (const callback of
|
|
1085
|
+
const { attributeChangedCallbacks } = this.static;
|
|
1086
|
+
if (attributeChangedCallbacks.has(name)) {
|
|
1087
|
+
for (const callback of attributeChangedCallbacks.get(name)) {
|
|
676
1088
|
callback.call(this, oldValue, newValue, this);
|
|
677
1089
|
}
|
|
678
1090
|
}
|
|
679
1091
|
|
|
680
1092
|
// Array.find
|
|
681
|
-
|
|
682
|
-
|
|
1093
|
+
const { attrList } = this.static;
|
|
1094
|
+
if (!attrList.has(name)) return;
|
|
683
1095
|
|
|
684
|
-
|
|
1096
|
+
const config = attrList.get(name);
|
|
685
1097
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
1098
|
+
if (config.attributeChangedCallback) {
|
|
1099
|
+
config.attributeChangedCallback.call(this, name, oldValue, newValue);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
690
1102
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1103
|
+
let cacheEntry;
|
|
1104
|
+
if (this.attributeCache.has(name)) {
|
|
1105
|
+
cacheEntry = this.attributeCache.get(name);
|
|
1106
|
+
if (cacheEntry.stringValue === newValue) return;
|
|
1107
|
+
}
|
|
696
1108
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1109
|
+
// @ts-expect-error any
|
|
1110
|
+
const previousDataValue = this[config.key];
|
|
1111
|
+
const parsedValue = newValue === null
|
|
1112
|
+
? config.nullParser(/** @type {null} */ (newValue))
|
|
1113
|
+
// Avoid Boolean('') === false
|
|
1114
|
+
: (config.type === 'boolean' ? true : config.parser(newValue));
|
|
703
1115
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
return;
|
|
707
|
-
}
|
|
708
|
-
// "Remember" that this attrValue equates to this data value
|
|
709
|
-
// Avoids rewriting attribute later on data change event
|
|
710
|
-
if (cacheEntry) {
|
|
711
|
-
cacheEntry.stringValue = newValue;
|
|
712
|
-
cacheEntry.parsedValue = parsedValue;
|
|
713
|
-
} else {
|
|
714
|
-
this.attributeCache.set(lcName, {
|
|
715
|
-
stringValue: newValue, parsedValue,
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
// @ts-expect-error any
|
|
719
|
-
this[config.key] = parsedValue;
|
|
1116
|
+
if (parsedValue === previousDataValue) {
|
|
1117
|
+
// No internal value change
|
|
720
1118
|
return;
|
|
721
1119
|
}
|
|
1120
|
+
// "Remember" that this attrValue equates to this data value
|
|
1121
|
+
// Avoids rewriting attribute later on data change event
|
|
1122
|
+
if (cacheEntry) {
|
|
1123
|
+
cacheEntry.stringValue = newValue;
|
|
1124
|
+
cacheEntry.parsedValue = parsedValue;
|
|
1125
|
+
} else {
|
|
1126
|
+
this.attributeCache.set(name, {
|
|
1127
|
+
stringValue: newValue, parsedValue,
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
// @ts-expect-error any
|
|
1131
|
+
this[config.key] = parsedValue;
|
|
722
1132
|
}
|
|
723
1133
|
|
|
724
1134
|
get #template() {
|
|
@@ -732,20 +1142,21 @@ export default class CustomElement extends ICustomElement {
|
|
|
732
1142
|
* @param {any} changes
|
|
733
1143
|
*/
|
|
734
1144
|
_onObserverPropertyChanged(name, oldValue, newValue, changes) {
|
|
735
|
-
|
|
736
|
-
|
|
1145
|
+
const { propList } = this.static;
|
|
1146
|
+
if (propList.has(name)) {
|
|
1147
|
+
const { reflect, attr } = propList.get(name);
|
|
737
1148
|
if (attr && (reflect === true || reflect === 'write')) {
|
|
738
|
-
const lcName = attr.toLowerCase();
|
|
739
1149
|
/** @type {{stringValue:string, parsedValue:any}} */
|
|
740
1150
|
let cacheEntry;
|
|
741
1151
|
let needsWrite = false;
|
|
742
|
-
|
|
743
|
-
|
|
1152
|
+
const { attributeCache } = this;
|
|
1153
|
+
if (attributeCache.has(attr)) {
|
|
1154
|
+
cacheEntry = attributeCache.get(attr);
|
|
744
1155
|
needsWrite = (cacheEntry.parsedValue !== newValue);
|
|
745
1156
|
} else {
|
|
746
1157
|
// @ts-ignore skip cast
|
|
747
1158
|
cacheEntry = {};
|
|
748
|
-
|
|
1159
|
+
attributeCache.set(attr, cacheEntry);
|
|
749
1160
|
needsWrite = true;
|
|
750
1161
|
}
|
|
751
1162
|
if (needsWrite) {
|
|
@@ -766,11 +1177,17 @@ export default class CustomElement extends ICustomElement {
|
|
|
766
1177
|
this.propChangedCallback(name, oldValue, newValue, changes);
|
|
767
1178
|
}
|
|
768
1179
|
|
|
1180
|
+
/** @param {any} patch */
|
|
769
1181
|
patch(patch) {
|
|
770
|
-
this
|
|
1182
|
+
this.#patching = true;
|
|
771
1183
|
applyMergePatch(this, patch);
|
|
1184
|
+
for (const [name, changes, state] of this.#pendingPatchRenders) {
|
|
1185
|
+
if (name in patch) continue;
|
|
1186
|
+
this.render.byProp(name, changes, state);
|
|
1187
|
+
}
|
|
1188
|
+
this.#pendingPatchRenders.slice(0, this.#pendingPatchRenders.length);
|
|
772
1189
|
this.render(patch);
|
|
773
|
-
this
|
|
1190
|
+
this.#patching = false;
|
|
774
1191
|
}
|
|
775
1192
|
|
|
776
1193
|
/**
|
|
@@ -823,60 +1240,23 @@ export default class CustomElement extends ICustomElement {
|
|
|
823
1240
|
}
|
|
824
1241
|
|
|
825
1242
|
get attributeCache() {
|
|
826
|
-
|
|
827
|
-
return this._propAttributeCache;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
get tabIndex() {
|
|
831
|
-
return super.tabIndex;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
set tabIndex(value) {
|
|
835
|
-
if (value === super.tabIndex && value !== -1) {
|
|
836
|
-
// Non -1 value already set
|
|
837
|
-
return;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
if (this.delegatesFocus && document.activeElement === this) {
|
|
841
|
-
if (this.getAttribute('tabindex') === value.toString()) {
|
|
842
|
-
// Skip if possible
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// Chrome blurs on tabindex changes with delegatesFocus
|
|
847
|
-
// Fixed in Chrome 111
|
|
848
|
-
// Remove this code ~June 2023
|
|
849
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1346606
|
|
850
|
-
/** @type {EventListener} */
|
|
851
|
-
const listener = (e) => {
|
|
852
|
-
e.stopImmediatePropagation();
|
|
853
|
-
e.stopPropagation();
|
|
854
|
-
if (e.type === 'blur') {
|
|
855
|
-
console.warn('Chromium bug 1346606: Tabindex change caused blur. Giving focusing back.', this);
|
|
856
|
-
this.focus();
|
|
857
|
-
} else {
|
|
858
|
-
console.warn('Chromium bug 1346606: Blocking focus event.', this);
|
|
859
|
-
}
|
|
860
|
-
};
|
|
861
|
-
this.addEventListener('blur', listener, { capture: true, once: true });
|
|
862
|
-
this.addEventListener('focus', listener, { capture: true, once: true });
|
|
863
|
-
super.tabIndex = value;
|
|
864
|
-
this.removeEventListener('blur', listener, { capture: true });
|
|
865
|
-
this.removeEventListener('focus', listener, { capture: true });
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
super.tabIndex = value;
|
|
1243
|
+
// eslint-disable-next-line no-return-assign
|
|
1244
|
+
return (this._propAttributeCache ??= new Map());
|
|
870
1245
|
}
|
|
871
1246
|
|
|
872
1247
|
get static() { return /** @type {typeof CustomElement} */ (/** @type {unknown} */ (this.constructor)); }
|
|
873
1248
|
|
|
874
1249
|
get unique() { return false; }
|
|
875
1250
|
|
|
1251
|
+
/**
|
|
1252
|
+
* @template {CustomElement} T
|
|
1253
|
+
* @this {T}
|
|
1254
|
+
*/
|
|
876
1255
|
get callbackArguments() {
|
|
877
1256
|
// eslint-disable-next-line no-return-assign
|
|
878
1257
|
return this._callbackArguments ??= {
|
|
879
1258
|
composition: this.#composition,
|
|
1259
|
+
refs: this.refs,
|
|
880
1260
|
html: html.bind(this),
|
|
881
1261
|
inline: addInlineFunction,
|
|
882
1262
|
template: this.#template,
|