@shortfuse/materialdesignweb 0.7.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -90
- package/bin/mdw-css.js +1 -1
- package/components/Badge.js +14 -7
- package/components/Body.js +3 -0
- package/components/BottomAppBar.js +4 -13
- package/components/BottomSheet.js +424 -0
- package/components/Box.js +20 -28
- package/components/Button.js +85 -79
- package/components/Button.md +9 -9
- package/components/Card.js +60 -72
- package/components/Checkbox.js +33 -42
- package/components/CheckboxIcon.js +11 -29
- package/components/Chip.js +13 -11
- package/components/Dialog.js +214 -394
- package/components/DialogActions.js +2 -2
- package/components/Display.js +55 -0
- package/components/Divider.js +3 -3
- package/components/Fab.js +83 -18
- package/components/FabContainer.js +48 -0
- package/components/FilterChip.js +35 -33
- package/components/Grid.js +176 -0
- package/components/Headline.js +5 -28
- package/components/Icon.js +61 -76
- package/components/IconButton.js +72 -126
- package/components/Input.js +859 -1
- package/components/InputChip.js +161 -0
- package/components/Label.js +3 -0
- package/components/List.js +4 -6
- package/components/ListItem.js +46 -30
- package/components/ListOption.js +86 -53
- package/components/Listbox.js +248 -0
- package/components/Menu.js +69 -528
- package/components/MenuItem.js +33 -36
- package/components/NavBar.js +49 -86
- package/components/NavDrawer.js +16 -15
- package/components/NavDrawerItem.js +4 -5
- package/components/NavItem.js +58 -41
- package/components/NavRail.js +30 -20
- package/components/NavRailItem.js +8 -3
- package/components/Page.js +105 -0
- package/components/Pane.js +11 -274
- package/components/Popup.js +29 -0
- package/components/Progress.js +24 -23
- package/components/Radio.js +40 -36
- package/components/RadioIcon.js +12 -16
- package/components/Ripple.js +13 -10
- package/components/Root.js +209 -0
- package/components/Scrim.js +87 -0
- package/components/Search.js +77 -0
- package/components/SegmentedButton.js +33 -45
- package/components/SegmentedButtonGroup.js +25 -13
- package/components/Select.js +10 -11
- package/components/Shape.js +5 -65
- package/components/SideSheet.js +308 -0
- package/components/Slider.js +108 -78
- package/components/Snackbar.js +26 -21
- package/components/SnackbarContainer.js +42 -0
- package/components/Surface.js +17 -12
- package/components/Switch.js +45 -24
- package/components/SwitchIcon.js +49 -39
- package/components/Tab.js +64 -43
- package/components/TabContent.js +5 -3
- package/components/TabList.js +62 -34
- package/components/TabPanel.js +11 -8
- package/components/Table.js +116 -0
- package/components/TextArea.js +54 -50
- package/components/Title.js +4 -9
- package/components/Tooltip.js +44 -22
- package/components/TopAppBar.js +68 -172
- package/constants/shapes.js +36 -0
- package/constants/typography.js +127 -0
- package/core/Composition.js +1164 -645
- package/core/CompositionAdapter.js +314 -0
- package/core/CustomElement.js +701 -286
- package/core/css.js +121 -15
- package/core/customTypes.js +157 -40
- package/core/dom.js +17 -11
- package/{utils → core}/jsonMergePatch.js +42 -18
- package/core/observe.js +343 -244
- package/core/optimizations.js +23 -0
- package/core/template.js +19 -56
- package/core/uid.js +13 -0
- package/dist/index.min.js +85 -184
- package/dist/index.min.js.map +4 -4
- package/dist/meta.json +1 -1
- package/dom/HTMLOptionsCollectionProxy.js +106 -0
- package/loaders/palette.js +13 -0
- package/loaders/theme.js +12 -0
- package/mixins/AriaReflectorMixin.js +53 -14
- package/mixins/AriaToolbarMixin.js +5 -3
- package/mixins/ControlMixin.js +92 -41
- package/mixins/DelegatesFocusMixin.js +54 -0
- package/mixins/DensityMixin.js +2 -3
- package/mixins/ElevationMixin.js +62 -0
- package/mixins/FlexableMixin.js +67 -39
- package/mixins/FormAssociatedMixin.js +71 -16
- package/mixins/HyperlinkMixin.js +66 -0
- package/mixins/InputMixin.js +205 -39
- package/mixins/KeyboardNavMixin.js +22 -7
- package/mixins/NavigationListenerMixin.js +33 -0
- package/mixins/PopupMixin.js +725 -0
- package/mixins/RTLObserverMixin.js +0 -1
- package/mixins/ResizeObserverMixin.js +16 -5
- package/mixins/RippleMixin.js +11 -10
- package/mixins/ScrollListenerMixin.js +42 -33
- package/mixins/SemiStickyMixin.js +97 -0
- package/mixins/ShapeMaskedMixin.js +117 -0
- package/mixins/ShapeMixin.js +17 -194
- package/mixins/StateMixin.js +80 -39
- package/mixins/TextFieldMixin.js +139 -183
- package/mixins/ThemableMixin.js +71 -161
- package/mixins/TooltipTriggerMixin.js +292 -366
- package/mixins/TouchTargetMixin.js +5 -4
- package/mixins/TypographyMixin.js +121 -0
- package/package.json +111 -71
- package/services/rtl.js +10 -0
- package/services/svgAlias.js +17 -0
- package/{theming/index.js → services/theme.js} +25 -175
- 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 +73 -0
- package/types/components/BottomAppBar.d.ts.map +1 -0
- package/types/components/BottomSheet.d.ts +109 -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 +714 -0
- package/types/components/Button.d.ts.map +1 -0
- package/types/components/Card.d.ts +412 -0
- package/types/components/Card.d.ts.map +1 -0
- package/types/components/Checkbox.d.ts +205 -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 +1425 -0
- package/types/components/Chip.d.ts.map +1 -0
- package/types/components/Dialog.d.ts +286 -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 +45 -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 +741 -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 +4283 -0
- package/types/components/FilterChip.d.ts.map +1 -0
- package/types/components/Grid.d.ts +37 -0
- package/types/components/Grid.d.ts.map +1 -0
- package/types/components/Headline.d.ts +47 -0
- package/types/components/Headline.d.ts.map +1 -0
- package/types/components/Icon.d.ts +103 -0
- package/types/components/Icon.d.ts.map +1 -0
- package/types/components/IconButton.d.ts +1486 -0
- package/types/components/IconButton.d.ts.map +1 -0
- package/types/components/Input.d.ts +51288 -0
- package/types/components/Input.d.ts.map +1 -0
- package/types/components/InputChip.d.ts +243 -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 +31 -0
- package/types/components/List.d.ts.map +1 -0
- package/types/components/ListItem.d.ts +349 -0
- package/types/components/ListItem.d.ts.map +1 -0
- package/types/components/ListOption.d.ts +1493 -0
- package/types/components/ListOption.d.ts.map +1 -0
- package/types/components/Listbox.d.ts +12012 -0
- package/types/components/Listbox.d.ts.map +1 -0
- package/types/components/Menu.d.ts +119 -0
- package/types/components/Menu.d.ts.map +1 -0
- package/types/components/MenuItem.d.ts +3109 -0
- package/types/components/MenuItem.d.ts.map +1 -0
- package/types/components/NavBar.d.ts +18 -0
- package/types/components/NavBar.d.ts.map +1 -0
- package/types/components/NavBarItem.d.ts +186 -0
- package/types/components/NavBarItem.d.ts.map +1 -0
- package/types/components/NavDrawer.d.ts +108 -0
- package/types/components/NavDrawer.d.ts.map +1 -0
- package/types/components/NavDrawerItem.d.ts +186 -0
- package/types/components/NavDrawerItem.d.ts.map +1 -0
- package/types/components/NavItem.d.ts +190 -0
- package/types/components/NavItem.d.ts.map +1 -0
- package/types/components/NavRail.d.ts +109 -0
- package/types/components/NavRail.d.ts.map +1 -0
- package/types/components/NavRailItem.d.ts +186 -0
- package/types/components/NavRailItem.d.ts.map +1 -0
- package/types/components/Page.d.ts +24 -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 +76 -0
- package/types/components/Popup.d.ts.map +1 -0
- package/types/components/Progress.d.ts +19 -0
- package/types/components/Progress.d.ts.map +1 -0
- package/types/components/Radio.d.ts +199 -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 +34 -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 +16 -0
- package/types/components/Search.d.ts.map +1 -0
- package/types/components/SegmentedButton.d.ts +718 -0
- package/types/components/SegmentedButton.d.ts.map +1 -0
- package/types/components/SegmentedButtonGroup.d.ts +44 -0
- package/types/components/SegmentedButtonGroup.d.ts.map +1 -0
- package/types/components/Select.d.ts +1361 -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 +106 -0
- package/types/components/SideSheet.d.ts.map +1 -0
- package/types/components/Slider.d.ts +382 -0
- package/types/components/Slider.d.ts.map +1 -0
- package/types/components/Snackbar.d.ts +65 -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 +183 -0
- package/types/components/Switch.d.ts.map +1 -0
- package/types/components/SwitchIcon.d.ts +169 -0
- package/types/components/SwitchIcon.d.ts.map +1 -0
- package/types/components/Tab.d.ts +879 -0
- package/types/components/Tab.d.ts.map +1 -0
- package/types/components/TabContent.d.ts +122 -0
- package/types/components/TabContent.d.ts.map +1 -0
- package/types/components/TabList.d.ts +6266 -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 +2 -0
- package/types/components/Table.d.ts.map +1 -0
- package/types/components/TextArea.d.ts +1394 -0
- package/types/components/TextArea.d.ts.map +1 -0
- package/types/components/Title.d.ts +47 -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 +130 -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 +252 -0
- package/types/core/Composition.d.ts.map +1 -0
- package/types/core/CompositionAdapter.d.ts +92 -0
- package/types/core/CompositionAdapter.d.ts.map +1 -0
- package/types/core/CustomElement.d.ts +302 -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 +26 -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 +113 -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 +23 -0
- package/types/mixins/AriaReflectorMixin.d.ts.map +1 -0
- package/types/mixins/AriaToolbarMixin.d.ts +32 -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 +5 -0
- package/types/mixins/DelegatesFocusMixin.d.ts.map +1 -0
- package/types/mixins/DensityMixin.d.ts +5 -0
- package/types/mixins/DensityMixin.d.ts.map +1 -0
- package/types/mixins/ElevationMixin.d.ts +33 -0
- package/types/mixins/ElevationMixin.d.ts.map +1 -0
- package/types/mixins/FlexableMixin.d.ts +13 -0
- package/types/mixins/FlexableMixin.d.ts.map +1 -0
- package/types/mixins/FormAssociatedMixin.d.ts +122 -0
- package/types/mixins/FormAssociatedMixin.d.ts.map +1 -0
- package/types/mixins/HyperlinkMixin.d.ts +22 -0
- package/types/mixins/HyperlinkMixin.d.ts.map +1 -0
- package/types/mixins/InputMixin.d.ts +179 -0
- package/types/mixins/InputMixin.d.ts.map +1 -0
- package/types/mixins/KeyboardNavMixin.d.ts +47 -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 +82 -0
- package/types/mixins/PopupMixin.d.ts.map +1 -0
- package/types/mixins/RTLObserverMixin.d.ts +7 -0
- package/types/mixins/RTLObserverMixin.d.ts.map +1 -0
- package/types/mixins/ResizeObserverMixin.d.ts +12 -0
- package/types/mixins/ResizeObserverMixin.d.ts.map +1 -0
- package/types/mixins/RippleMixin.d.ts +92 -0
- package/types/mixins/RippleMixin.d.ts.map +1 -0
- package/types/mixins/ScrollListenerMixin.d.ts +41 -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 +9 -0
- package/types/mixins/ShapeMaskedMixin.d.ts.map +1 -0
- package/types/mixins/ShapeMixin.d.ts +38 -0
- package/types/mixins/ShapeMixin.d.ts.map +1 -0
- package/types/mixins/StateMixin.d.ts +27 -0
- package/types/mixins/StateMixin.d.ts.map +1 -0
- package/types/mixins/TextFieldMixin.d.ts +1354 -0
- package/types/mixins/TextFieldMixin.d.ts.map +1 -0
- package/types/mixins/ThemableMixin.d.ts +9 -0
- package/types/mixins/ThemableMixin.d.ts.map +1 -0
- package/types/mixins/TooltipTriggerMixin.d.ts +106 -0
- package/types/mixins/TooltipTriggerMixin.d.ts.map +1 -0
- package/types/mixins/TouchTargetMixin.d.ts +3 -0
- package/types/mixins/TouchTargetMixin.d.ts.map +1 -0
- package/types/mixins/TypographyMixin.d.ts +17 -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/{hct → material-color}/blend.js +8 -10
- package/utils/{hct → material-color/hct}/Cam16.js +196 -69
- package/utils/{hct → material-color/hct}/Hct.js +61 -19
- package/utils/{hct → material-color/hct}/ViewingConditions.js +3 -3
- package/utils/{hct → material-color/hct}/hctSolver.js +9 -16
- package/utils/{hct → material-color}/helper.js +11 -18
- package/utils/{hct → material-color/palettes}/CorePalette.js +79 -19
- package/utils/{hct → material-color/palettes}/TonalPalette.js +12 -4
- package/utils/material-color/scheme/Scheme.js +376 -0
- package/utils/{hct/colorUtils.js → material-color/utils/color.js} +61 -1
- package/utils/pixelmatch.js +360 -0
- package/utils/popup.js +127 -30
- package/utils/searchParams.js +19 -0
- package/components/ExtendedFab.js +0 -36
- package/components/Layout.js +0 -35
- package/components/ListSelect.js +0 -220
- package/components/Nav.js +0 -40
- package/components/Option.js +0 -91
- package/core/ICustomElement.d.ts +0 -291
- package/core/ICustomElement.js +0 -1
- package/core/identify.js +0 -40
- package/core/typings.d.ts +0 -136
- package/core/typings.js +0 -1
- package/mixins/SurfaceMixin.js +0 -181
- package/theming/loader.js +0 -22
- package/utils/hct/Scheme.js +0 -587
- /package/{utils/color_keywords.js → constants/colorKeywords.js} +0 -0
- /package/utils/{hct/mathUtils.js → material-color/utils/math.js} +0 -0
package/core/CustomElement.js
CHANGED
|
@@ -1,10 +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
|
+
import { applyMergePatch } from './jsonMergePatch.js';
|
|
6
7
|
import { defineObservableProperty } from './observe.js';
|
|
7
|
-
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
|
+
*/
|
|
8
115
|
|
|
9
116
|
/**
|
|
10
117
|
* @template {abstract new (...args: any) => unknown} T
|
|
@@ -32,57 +139,49 @@ export function cloneAttributeCallback(name, target) {
|
|
|
32
139
|
};
|
|
33
140
|
}
|
|
34
141
|
|
|
35
|
-
const EVENT_PREFIX_REGEX = /^([*1~]+)?(.*)$/;
|
|
36
|
-
|
|
37
142
|
/**
|
|
38
143
|
* Web Component that can cache templates for minification or performance
|
|
39
144
|
*/
|
|
40
|
-
export default class CustomElement extends
|
|
145
|
+
export default class CustomElement extends HTMLElement {
|
|
41
146
|
/** @type {string} */
|
|
42
147
|
static elementName;
|
|
43
148
|
|
|
44
149
|
/** @return {Iterable<string>} */
|
|
45
150
|
static get observedAttributes() {
|
|
46
|
-
|
|
47
|
-
for (const config of this.propList.values()) {
|
|
48
|
-
if (config.reflect === true || config.reflect === 'read') {
|
|
49
|
-
s.add(config.attr);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return s;
|
|
151
|
+
return this.attrList.keys();
|
|
53
152
|
}
|
|
54
153
|
|
|
55
154
|
/** @type {import('./Composition.js').Compositor<?>} */
|
|
56
155
|
compose() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
this.#composition = new Composition();
|
|
61
|
-
return this.#composition;
|
|
156
|
+
// eslint-disable-next-line no-return-assign
|
|
157
|
+
return (this.#composition ??= new Composition());
|
|
62
158
|
}
|
|
63
159
|
|
|
64
160
|
/** @type {Composition<?>} */
|
|
65
161
|
static _composition = null;
|
|
66
162
|
|
|
67
|
-
/** @type {Map<string, import('./
|
|
163
|
+
/** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
|
|
68
164
|
static _props = new Map();
|
|
69
165
|
|
|
166
|
+
/** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
|
|
167
|
+
static _attrs = new Map();
|
|
168
|
+
|
|
70
169
|
/** @type {Map<string, Function[]>} */
|
|
71
170
|
static _propChangedCallbacks = new Map();
|
|
72
171
|
|
|
73
172
|
/** @type {Map<string, Function[]>} */
|
|
74
173
|
static _attributeChangedCallbacks = new Map();
|
|
75
174
|
|
|
76
|
-
/** @type {
|
|
175
|
+
/** @type {((callback: CallbackArguments) => any)[]} */
|
|
77
176
|
static _onComposeCallbacks = [];
|
|
78
177
|
|
|
79
|
-
/** @type {
|
|
178
|
+
/** @type {((callback: CallbackArguments) => any)[]} */
|
|
80
179
|
static _onConnectedCallbacks = [];
|
|
81
180
|
|
|
82
|
-
/** @type {
|
|
181
|
+
/** @type {((callback: CallbackArguments) => any)[]} */
|
|
83
182
|
static _onDisconnectedCallbacks = [];
|
|
84
183
|
|
|
85
|
-
/** @type {
|
|
184
|
+
/** @type {((callback: CallbackArguments) => any)[]} */
|
|
86
185
|
static _onConstructedCallbacks = [];
|
|
87
186
|
|
|
88
187
|
static interpolatesTemplate = true;
|
|
@@ -102,68 +201,189 @@ export default class CustomElement extends ICustomElement {
|
|
|
102
201
|
/** @type {Map<string, typeof CustomElement>} */
|
|
103
202
|
static registrations = new Map();
|
|
104
203
|
|
|
105
|
-
/**
|
|
106
|
-
|
|
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);
|
|
107
271
|
|
|
108
|
-
/** @type {typeof ICustomElement.methods} */
|
|
109
272
|
static methods = this.set;
|
|
110
273
|
|
|
111
|
-
/**
|
|
112
|
-
|
|
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);
|
|
113
309
|
|
|
114
|
-
|
|
115
|
-
static props = this.observe;
|
|
310
|
+
static idl = this.prop;
|
|
116
311
|
|
|
117
312
|
/**
|
|
118
|
-
* @template {typeof CustomElement} T
|
|
119
313
|
* @this T
|
|
314
|
+
* @template {typeof CustomElement} T
|
|
120
315
|
* @template {keyof T} K
|
|
121
316
|
* @param {K} collection
|
|
122
317
|
* @param {T[K] extends (infer R)[] ? R : never} callback
|
|
123
318
|
*/
|
|
124
319
|
static _addCallback(collection, callback) {
|
|
125
320
|
if (!this.hasOwnProperty(collection)) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
321
|
+
// @ts-expect-error not typed
|
|
322
|
+
this[collection] = [...this[collection], callback];
|
|
323
|
+
return;
|
|
129
324
|
}
|
|
325
|
+
// @ts-expect-error any
|
|
130
326
|
this[collection].push(callback);
|
|
131
327
|
}
|
|
132
328
|
|
|
133
329
|
/**
|
|
134
330
|
* Append parts to composition
|
|
135
|
-
* @type {
|
|
331
|
+
* @type {{
|
|
332
|
+
* <
|
|
333
|
+
* T extends typeof CustomElement,
|
|
334
|
+
* >
|
|
335
|
+
* (this: T, ...parts: ConstructorParameters<typeof Composition<InstanceType<T>>>): T;
|
|
336
|
+
* }}
|
|
136
337
|
*/
|
|
137
338
|
static append(...parts) {
|
|
138
|
-
this.
|
|
139
|
-
|
|
140
|
-
// console.debug('onComposed:append', ...parts);
|
|
141
|
-
composition.append(...parts);
|
|
142
|
-
},
|
|
339
|
+
this._addCallback('_onComposeCallbacks', ({ composition }) => {
|
|
340
|
+
composition.append(...parts);
|
|
143
341
|
});
|
|
144
342
|
// @ts-expect-error Can't cast T
|
|
145
343
|
return this;
|
|
146
344
|
}
|
|
147
345
|
|
|
148
346
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
347
|
+
* After composition, invokes callback.
|
|
348
|
+
* May be called multiple times.
|
|
349
|
+
* @type {{
|
|
350
|
+
* <
|
|
351
|
+
* T1 extends typeof CustomElement,
|
|
352
|
+
* T2 extends InstanceType<T1>,
|
|
353
|
+
* T3 extends CompositionCallback<T2, T2>['composed'],
|
|
354
|
+
* >
|
|
355
|
+
* (this: T1, callback: T3): T1
|
|
356
|
+
* }}
|
|
151
357
|
*/
|
|
152
|
-
static
|
|
153
|
-
|
|
154
|
-
// @ts-expect-error Complex cast
|
|
155
|
-
this.append(css(array, ...substitutions));
|
|
156
|
-
} else {
|
|
157
|
-
// @ts-expect-error Complex cast
|
|
158
|
-
this.append(array, ...substitutions);
|
|
159
|
-
}
|
|
358
|
+
static recompose(callback) {
|
|
359
|
+
this._addCallback('_onComposeCallbacks', callback);
|
|
160
360
|
// @ts-expect-error Can't cast T
|
|
161
361
|
return this;
|
|
162
362
|
}
|
|
163
363
|
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
|
|
364
|
+
/**
|
|
365
|
+
* Appends styles to composition
|
|
366
|
+
* @type {{
|
|
367
|
+
* <
|
|
368
|
+
* T1 extends typeof CustomElement,
|
|
369
|
+
* T2 extends TemplateStringsArray|HTMLStyleElement|CSSStyleSheet|string>(
|
|
370
|
+
* this: T1,
|
|
371
|
+
* array: T2,
|
|
372
|
+
* ...rest: T2 extends string ? any : T2 extends TemplateStringsArray ? any[] : (HTMLStyleElement|CSSStyleSheet)[]
|
|
373
|
+
* ): T1
|
|
374
|
+
* }}
|
|
375
|
+
*/
|
|
376
|
+
static css(array, ...substitutions) {
|
|
377
|
+
this._addCallback('_onComposeCallbacks', ({ composition }) => {
|
|
378
|
+
if (typeof array === 'string' || Array.isArray(array)) {
|
|
379
|
+
// @ts-expect-error Complex cast
|
|
380
|
+
composition.append(css(array, ...substitutions));
|
|
381
|
+
} else {
|
|
382
|
+
// @ts-expect-error Complex cast
|
|
383
|
+
composition.append(array, ...substitutions);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
167
387
|
// @ts-expect-error Can't cast T
|
|
168
388
|
return this;
|
|
169
389
|
}
|
|
@@ -172,31 +392,35 @@ export default class CustomElement extends ICustomElement {
|
|
|
172
392
|
* Registers class asynchronously at end of current event loop cycle
|
|
173
393
|
* via `queueMicrotask`. If class is registered before then,
|
|
174
394
|
* does nothing.
|
|
175
|
-
* @type {
|
|
395
|
+
* @type {{
|
|
396
|
+
* <T extends typeof CustomElement>(this: T, elementName: string): T;
|
|
397
|
+
* }}
|
|
176
398
|
*/
|
|
177
399
|
static autoRegister(elementName) {
|
|
178
|
-
if (
|
|
179
|
-
this.elementName
|
|
400
|
+
if (this.hasOwnProperty('defined') && this.defined) {
|
|
401
|
+
console.warn(this.elementName, 'already registered.');
|
|
402
|
+
// @ts-expect-error Can't cast T
|
|
403
|
+
return this;
|
|
180
404
|
}
|
|
181
|
-
|
|
182
|
-
if (this.autoRegistration) {
|
|
183
|
-
this.register();
|
|
184
|
-
}
|
|
185
|
-
});
|
|
405
|
+
this.register(elementName);
|
|
186
406
|
// @ts-expect-error Can't cast T
|
|
187
407
|
return this;
|
|
188
408
|
}
|
|
189
409
|
|
|
190
410
|
/**
|
|
191
411
|
* Appends DocumentFragment to composition
|
|
192
|
-
* @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
|
+
* }}
|
|
193
419
|
*/
|
|
194
420
|
static html(strings, ...substitutions) {
|
|
195
|
-
this.
|
|
196
|
-
composed({ composition }) {
|
|
421
|
+
this._addCallback('_onComposeCallbacks', ({ composition }) => {
|
|
197
422
|
// console.log('onComposed:html', strings);
|
|
198
|
-
|
|
199
|
-
},
|
|
423
|
+
composition.append(html(strings, ...substitutions));
|
|
200
424
|
});
|
|
201
425
|
// @ts-expect-error Can't cast T
|
|
202
426
|
return this;
|
|
@@ -205,28 +429,28 @@ export default class CustomElement extends ICustomElement {
|
|
|
205
429
|
/**
|
|
206
430
|
* Extends base class into a new class.
|
|
207
431
|
* Use to avoid mutating base class.
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// @ts-expect-error Can't cast T
|
|
213
|
-
return class extends this {};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Extends base class into a new class.
|
|
218
|
-
* Use to avoid mutating base class.
|
|
219
|
-
* TODO: Add constructor arguments typing
|
|
220
|
-
* @type {typeof ICustomElement.tsClassFix}
|
|
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
|
+
* }}
|
|
221
436
|
*/
|
|
222
|
-
static
|
|
437
|
+
static extend(customExtender) {
|
|
223
438
|
// @ts-expect-error Can't cast T
|
|
224
|
-
return this;
|
|
439
|
+
return customExtender ? customExtender(this) : class extends this {};
|
|
225
440
|
}
|
|
226
441
|
|
|
227
442
|
/**
|
|
228
443
|
* Assigns static values to class
|
|
229
|
-
* @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
|
+
* }}
|
|
230
454
|
*/
|
|
231
455
|
static setStatic(source) {
|
|
232
456
|
Object.assign(this, source);
|
|
@@ -236,7 +460,15 @@ export default class CustomElement extends ICustomElement {
|
|
|
236
460
|
|
|
237
461
|
/**
|
|
238
462
|
* Assigns values directly to all instances (via prototype)
|
|
239
|
-
* @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
|
+
* }}
|
|
240
472
|
*/
|
|
241
473
|
static readonly(source, options) {
|
|
242
474
|
// @ts-expect-error Can't cast T
|
|
@@ -245,13 +477,21 @@ export default class CustomElement extends ICustomElement {
|
|
|
245
477
|
|
|
246
478
|
/**
|
|
247
479
|
* Assigns values directly to all instances (via prototype)
|
|
248
|
-
* @type {
|
|
480
|
+
* @type {{
|
|
481
|
+
* <
|
|
482
|
+
* CLASS extends typeof CustomElement,
|
|
483
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
484
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
485
|
+
* PROPS extends object>
|
|
486
|
+
* (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
|
|
487
|
+
* : CLASS & Class<PROPS,ARGS>
|
|
488
|
+
* }}
|
|
249
489
|
*/
|
|
250
490
|
static set(source, options) {
|
|
251
491
|
Object.defineProperties(
|
|
252
492
|
this.prototype,
|
|
253
|
-
Object.fromEntries(
|
|
254
|
-
Object.entries(source).map(([name, value]) => {
|
|
493
|
+
Object.fromEntries([
|
|
494
|
+
...Object.entries(source).map(([name, value]) => {
|
|
255
495
|
// Tap into .map() to avoid double iteration
|
|
256
496
|
// Property may be redefined observable
|
|
257
497
|
this.undefine(name);
|
|
@@ -266,7 +506,17 @@ export default class CustomElement extends ICustomElement {
|
|
|
266
506
|
},
|
|
267
507
|
];
|
|
268
508
|
}),
|
|
269
|
-
|
|
509
|
+
...Object.getOwnPropertySymbols(source).map((symbol) => [
|
|
510
|
+
symbol,
|
|
511
|
+
{
|
|
512
|
+
enumerable: false,
|
|
513
|
+
configurable: true,
|
|
514
|
+
value: source[symbol],
|
|
515
|
+
writable: true,
|
|
516
|
+
...options,
|
|
517
|
+
},
|
|
518
|
+
]),
|
|
519
|
+
]),
|
|
270
520
|
);
|
|
271
521
|
// @ts-expect-error Can't cast T
|
|
272
522
|
return this;
|
|
@@ -274,7 +524,14 @@ export default class CustomElement extends ICustomElement {
|
|
|
274
524
|
|
|
275
525
|
/**
|
|
276
526
|
* Returns result of calling mixin with current class
|
|
277
|
-
* @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
|
+
* }}
|
|
278
535
|
*/
|
|
279
536
|
static mixin(mixin) {
|
|
280
537
|
return mixin(this);
|
|
@@ -282,15 +539,11 @@ export default class CustomElement extends ICustomElement {
|
|
|
282
539
|
|
|
283
540
|
/**
|
|
284
541
|
* Registers class with window.customElements synchronously
|
|
285
|
-
* @type {
|
|
542
|
+
* @type {{
|
|
543
|
+
* <T extends typeof CustomElement>(this: T, elementName?: string, force?: boolean): T;
|
|
544
|
+
* }}
|
|
286
545
|
*/
|
|
287
|
-
static register(elementName
|
|
288
|
-
if (this.hasOwnProperty('defined') && this.defined && !force) {
|
|
289
|
-
console.warn(this.elementName, 'already registered.');
|
|
290
|
-
// @ts-expect-error Can't cast T
|
|
291
|
-
return this;
|
|
292
|
-
}
|
|
293
|
-
|
|
546
|
+
static register(elementName) {
|
|
294
547
|
if (elementName) {
|
|
295
548
|
this.elementName = elementName;
|
|
296
549
|
}
|
|
@@ -309,6 +562,13 @@ export default class CustomElement extends ICustomElement {
|
|
|
309
562
|
return this._props;
|
|
310
563
|
}
|
|
311
564
|
|
|
565
|
+
static get attrList() {
|
|
566
|
+
if (!this.hasOwnProperty('_attrs')) {
|
|
567
|
+
this._attrs = new Map(this._attrs);
|
|
568
|
+
}
|
|
569
|
+
return this._attrs;
|
|
570
|
+
}
|
|
571
|
+
|
|
312
572
|
static get propChangedCallbacks() {
|
|
313
573
|
if (!this.hasOwnProperty('_propChangedCallbacks')) {
|
|
314
574
|
// structuredClone()
|
|
@@ -334,55 +594,82 @@ export default class CustomElement extends ICustomElement {
|
|
|
334
594
|
|
|
335
595
|
/**
|
|
336
596
|
* Creates observable property on instances (via prototype)
|
|
337
|
-
* @
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
* )
|
|
597
|
+
* @type {{
|
|
598
|
+
* <
|
|
599
|
+
* CLASS extends typeof CustomElement,
|
|
600
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
601
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
602
|
+
* KEY extends string,
|
|
603
|
+
* OPTIONS extends ObserverPropertyType
|
|
604
|
+
* | ObserverOptions<ObserverPropertyType, unknown, INSTANCE>
|
|
605
|
+
* | ((this:INSTANCE, data:Partial<INSTANCE>, fn?: () => any) => any),
|
|
606
|
+
* VALUE extends Record<KEY, OPTIONS extends (...args2:any[]) => infer R ? R
|
|
607
|
+
* : OPTIONS extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<OPTIONS>
|
|
608
|
+
* : OPTIONS extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
|
|
609
|
+
* : OPTIONS extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<OPTIONS['type']>
|
|
610
|
+
* : OPTIONS extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
|
|
611
|
+
* : never
|
|
612
|
+
* >
|
|
613
|
+
* > (this: CLASS, name: KEY, options: OPTIONS)
|
|
614
|
+
* : CLASS & Class<VALUE,ARGS>
|
|
615
|
+
* }}
|
|
351
616
|
*/
|
|
352
617
|
static prop(name, typeOrOptions) {
|
|
353
618
|
// TODO: Cache and save configuration for reuse (mixins)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const customCallback = options.changedCallback;
|
|
619
|
+
const config = defineObservableProperty(
|
|
620
|
+
/** @type {any} */ (this.prototype),
|
|
621
|
+
name,
|
|
622
|
+
/** @type {any} */ (typeOrOptions),
|
|
623
|
+
);
|
|
360
624
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
625
|
+
const { changedCallback, attr, reflect, watchers } = config;
|
|
626
|
+
if (changedCallback) {
|
|
627
|
+
watchers.push([name, changedCallback]);
|
|
364
628
|
}
|
|
365
|
-
|
|
366
629
|
// TODO: Inspect possible closure bloat
|
|
367
|
-
|
|
630
|
+
config.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
|
|
368
631
|
this._onObserverPropertyChanged.call(this, name, oldValue, newValue, changes);
|
|
369
632
|
};
|
|
370
633
|
|
|
371
|
-
const config = defineObservableProperty(this.prototype, name, options);
|
|
372
|
-
|
|
373
634
|
this.propList.set(name, config);
|
|
374
|
-
|
|
375
|
-
|
|
635
|
+
|
|
636
|
+
if (attr && (reflect === true || reflect === 'read')) {
|
|
637
|
+
this.attrList.set(attr, config);
|
|
376
638
|
}
|
|
377
639
|
|
|
378
|
-
|
|
640
|
+
this.onPropChanged(watchers);
|
|
641
|
+
|
|
642
|
+
// @ts-expect-error Can't cast T
|
|
643
|
+
return this;
|
|
379
644
|
}
|
|
380
645
|
|
|
381
646
|
/**
|
|
382
647
|
* Define properties on instances via Object.defineProperties().
|
|
383
648
|
* Automatically sets property non-enumerable if name begins with `_`.
|
|
384
649
|
* Functions will be remapped as getters
|
|
385
|
-
* @type {
|
|
650
|
+
* @type {{
|
|
651
|
+
* <
|
|
652
|
+
* CLASS extends typeof CustomElement,
|
|
653
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
654
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
655
|
+
* PROPS extends {
|
|
656
|
+
* [P in keyof any] :
|
|
657
|
+
* {
|
|
658
|
+
* enumerable?: boolean;
|
|
659
|
+
* configurable?: boolean;
|
|
660
|
+
* writable?: boolean;
|
|
661
|
+
* value?: any;
|
|
662
|
+
* get?: ((this: INSTANCE) => any);
|
|
663
|
+
* set?: (this: INSTANCE, value: any) => void;
|
|
664
|
+
* } | ((this: INSTANCE, ...args:any[]) => any)
|
|
665
|
+
* },
|
|
666
|
+
* VALUE extends {
|
|
667
|
+
* [KEY in keyof PROPS]: PROPS[KEY] extends (...args2:any[]) => infer R ? R
|
|
668
|
+
* : PROPS[KEY] extends TypedPropertyDescriptor<infer R> ? R : never
|
|
669
|
+
* }>
|
|
670
|
+
* (this: CLASS, props: PROPS & ThisType<PROPS & INSTANCE>): CLASS
|
|
671
|
+
* & Class<VALUE,ARGS>
|
|
672
|
+
* }}
|
|
386
673
|
*/
|
|
387
674
|
static define(props) {
|
|
388
675
|
Object.defineProperties(
|
|
@@ -414,43 +701,68 @@ export default class CustomElement extends ICustomElement {
|
|
|
414
701
|
|
|
415
702
|
static undefine(name) {
|
|
416
703
|
Reflect.deleteProperty(this.prototype, name);
|
|
417
|
-
|
|
418
|
-
|
|
704
|
+
if (!this.propList.has(name)) return this;
|
|
705
|
+
const { watchers, attr, reflect } = this.propList.get(name);
|
|
706
|
+
if (watchers.length && this.propChangedCallbacks.has(name)) {
|
|
419
707
|
const propWatchers = this.propChangedCallbacks.get(name);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
propWatchers.splice(index, 1);
|
|
426
|
-
}
|
|
708
|
+
for (const watcher of watchers) {
|
|
709
|
+
const index = propWatchers.indexOf(watcher);
|
|
710
|
+
if (index !== -1) {
|
|
711
|
+
console.warn('Unwatching', name);
|
|
712
|
+
propWatchers.splice(index, 1);
|
|
427
713
|
}
|
|
428
714
|
}
|
|
429
715
|
}
|
|
716
|
+
if (attr && (reflect === true || reflect === 'read')) {
|
|
717
|
+
this.attrList.delete(attr);
|
|
718
|
+
}
|
|
430
719
|
this.propList.delete(name);
|
|
720
|
+
|
|
431
721
|
return this;
|
|
432
722
|
}
|
|
433
723
|
|
|
434
724
|
/**
|
|
435
725
|
* Creates observable properties on instances
|
|
436
|
-
* @type {
|
|
726
|
+
* @type {{
|
|
727
|
+
* <
|
|
728
|
+
* CLASS extends typeof CustomElement,
|
|
729
|
+
* ARGS extends ConstructorParameters<CLASS>,
|
|
730
|
+
* INSTANCE extends InstanceType<CLASS>,
|
|
731
|
+
* PROPS extends IDLParameter<INSTANCE & VALUE>,
|
|
732
|
+
* VALUE extends {
|
|
733
|
+
* [KEY in keyof PROPS]:
|
|
734
|
+
* PROPS[KEY] extends (...args2:any[]) => infer R ? R
|
|
735
|
+
* : PROPS[KEY] extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]>
|
|
736
|
+
* : PROPS[KEY] extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
|
|
737
|
+
* : PROPS[KEY] extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]['type']>
|
|
738
|
+
* : PROPS[KEY] extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
|
|
739
|
+
* : never
|
|
740
|
+
* },
|
|
741
|
+
* > (this: CLASS, props: PROPS)
|
|
742
|
+
* : CLASS & Class<VALUE,ARGS>
|
|
743
|
+
* }}
|
|
437
744
|
*/
|
|
438
745
|
static observe(props) {
|
|
439
746
|
for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
this.prop(name, typeOrOptions);
|
|
447
|
-
}
|
|
747
|
+
/** @type {any} */
|
|
748
|
+
const options = (typeof typeOrOptions === 'function')
|
|
749
|
+
? { reflect: false, get: typeOrOptions }
|
|
750
|
+
: typeOrOptions;
|
|
751
|
+
|
|
752
|
+
this.prop(name, options);
|
|
448
753
|
}
|
|
449
754
|
// @ts-expect-error Can't cast T
|
|
450
755
|
return this;
|
|
451
756
|
}
|
|
452
757
|
|
|
453
|
-
/**
|
|
758
|
+
/**
|
|
759
|
+
* @type {{
|
|
760
|
+
* <
|
|
761
|
+
* T1 extends typeof CustomElement,
|
|
762
|
+
* T2 extends IDLParameter<T1>>
|
|
763
|
+
* (this: T1, props: T2):T1 & ParsedProps<T2>
|
|
764
|
+
* }}
|
|
765
|
+
*/
|
|
454
766
|
static defineStatic(props) {
|
|
455
767
|
for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
|
|
456
768
|
const options = (typeof typeOrOptions === 'function')
|
|
@@ -467,12 +779,35 @@ export default class CustomElement extends ICustomElement {
|
|
|
467
779
|
return this;
|
|
468
780
|
}
|
|
469
781
|
|
|
470
|
-
/**
|
|
782
|
+
/**
|
|
783
|
+
* @type {{
|
|
784
|
+
* <T extends typeof CustomElement>
|
|
785
|
+
* (
|
|
786
|
+
* this: T,
|
|
787
|
+
* listeners?: import('./Composition').CompositionEventListenerObject<InstanceType<T>>,
|
|
788
|
+
* options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
|
|
789
|
+
* ): T;
|
|
790
|
+
* }}
|
|
791
|
+
*/
|
|
471
792
|
static events(listeners, options) {
|
|
472
793
|
this.on({
|
|
473
794
|
composed({ composition }) {
|
|
474
795
|
for (const [key, listenerOptions] of Object.entries(listeners)) {
|
|
475
|
-
const [, flags, type] = key.match(
|
|
796
|
+
const [, flags, type] = key.match(/^([*1~]+)?(.*)$/);
|
|
797
|
+
// TODO: Make abstract
|
|
798
|
+
let prop;
|
|
799
|
+
/** @type {string[]} */
|
|
800
|
+
let deepProp = [];
|
|
801
|
+
if (typeof listenerOptions === 'string') {
|
|
802
|
+
const parsedProps = listenerOptions.split('.');
|
|
803
|
+
if (parsedProps.length === 1) {
|
|
804
|
+
prop = listenerOptions;
|
|
805
|
+
deepProp = [];
|
|
806
|
+
} else {
|
|
807
|
+
prop = parsedProps[0];
|
|
808
|
+
deepProp = parsedProps;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
476
811
|
composition.addCompositionEventListener({
|
|
477
812
|
type,
|
|
478
813
|
once: flags?.includes('1'),
|
|
@@ -482,7 +817,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
482
817
|
typeof listenerOptions === 'function'
|
|
483
818
|
? { handleEvent: listenerOptions }
|
|
484
819
|
: (typeof listenerOptions === 'string'
|
|
485
|
-
? { prop
|
|
820
|
+
? { prop, deepProp }
|
|
486
821
|
: listenerOptions)
|
|
487
822
|
),
|
|
488
823
|
...(
|
|
@@ -498,11 +833,23 @@ export default class CustomElement extends ICustomElement {
|
|
|
498
833
|
return this;
|
|
499
834
|
}
|
|
500
835
|
|
|
501
|
-
/**
|
|
836
|
+
/**
|
|
837
|
+
* @type {{
|
|
838
|
+
* <T extends typeof CustomElement>
|
|
839
|
+
* (
|
|
840
|
+
* this: T,
|
|
841
|
+
* listenerMap: {
|
|
842
|
+
* [P in keyof any]: import('./Composition').CompositionEventListenerObject<InstanceType<T>>
|
|
843
|
+
* },
|
|
844
|
+
* options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
|
|
845
|
+
* ): T;
|
|
846
|
+
* }}
|
|
847
|
+
*/
|
|
502
848
|
static childEvents(listenerMap, options) {
|
|
503
|
-
for (const [
|
|
849
|
+
for (const [tag, listeners] of Object.entries(listenerMap)) {
|
|
850
|
+
// @ts-expect-error Can't cast T
|
|
504
851
|
this.events(listeners, {
|
|
505
|
-
|
|
852
|
+
tag: attrNameFromPropName(tag),
|
|
506
853
|
...options,
|
|
507
854
|
});
|
|
508
855
|
}
|
|
@@ -511,7 +858,26 @@ export default class CustomElement extends ICustomElement {
|
|
|
511
858
|
return this;
|
|
512
859
|
}
|
|
513
860
|
|
|
514
|
-
/** @type {typeof
|
|
861
|
+
/** @type {typeof CustomElement['events']} */
|
|
862
|
+
static rootEvents(listeners, options) {
|
|
863
|
+
// @ts-expect-error Can't cast T
|
|
864
|
+
return this.events(listeners, {
|
|
865
|
+
tag: Composition.shadowRootTag,
|
|
866
|
+
...options,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* @type {{
|
|
872
|
+
* <
|
|
873
|
+
* T1 extends typeof CustomElement,
|
|
874
|
+
* T2 extends InstanceType<T1>,
|
|
875
|
+
* T3 extends CompositionCallback<T2, T2>,
|
|
876
|
+
* T4 extends keyof T3,
|
|
877
|
+
* >
|
|
878
|
+
* (this: T1, name: T3|T4, callbacks?: T3[T4] & ThisType<T2>): T1
|
|
879
|
+
* }}
|
|
880
|
+
*/
|
|
515
881
|
static on(nameOrCallbacks, callback) {
|
|
516
882
|
const callbacks = typeof nameOrCallbacks === 'string'
|
|
517
883
|
? { [nameOrCallbacks]: callback }
|
|
@@ -545,31 +911,69 @@ export default class CustomElement extends ICustomElement {
|
|
|
545
911
|
return this;
|
|
546
912
|
}
|
|
547
913
|
|
|
548
|
-
/**
|
|
914
|
+
/**
|
|
915
|
+
* @type {{
|
|
916
|
+
* <
|
|
917
|
+
* T1 extends typeof CustomElement,
|
|
918
|
+
* T2 extends InstanceType<T1>
|
|
919
|
+
* >
|
|
920
|
+
* (
|
|
921
|
+
* this: T1,
|
|
922
|
+
* options: ObjectOrObjectEntries<{
|
|
923
|
+
* [P in keyof T2]? : (
|
|
924
|
+
* this: T2,
|
|
925
|
+
* oldValue: T2[P],
|
|
926
|
+
* newValue: T2[P],
|
|
927
|
+
* changes:any,
|
|
928
|
+
* element: T2
|
|
929
|
+
* ) => void
|
|
930
|
+
* }>,
|
|
931
|
+
* ): T1;
|
|
932
|
+
* }}
|
|
933
|
+
*/
|
|
549
934
|
static onPropChanged(options) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
935
|
+
const entries = Array.isArray(options) ? options : Object.entries(options);
|
|
936
|
+
const { propChangedCallbacks } = this;
|
|
937
|
+
for (const [prop, callback] of entries) {
|
|
938
|
+
if (propChangedCallbacks.has(prop)) {
|
|
939
|
+
propChangedCallbacks.get(prop).push(callback);
|
|
940
|
+
} else {
|
|
941
|
+
propChangedCallbacks.set(prop, [callback]);
|
|
555
942
|
}
|
|
556
|
-
array.push(callback);
|
|
557
943
|
}
|
|
558
944
|
|
|
559
945
|
// @ts-expect-error Can't cast T
|
|
560
946
|
return this;
|
|
561
947
|
}
|
|
562
948
|
|
|
563
|
-
/**
|
|
949
|
+
/**
|
|
950
|
+
* @type {{
|
|
951
|
+
* <
|
|
952
|
+
* T1 extends typeof CustomElement,
|
|
953
|
+
* T2 extends InstanceType<T1>
|
|
954
|
+
* >
|
|
955
|
+
* (
|
|
956
|
+
* this: T1,
|
|
957
|
+
* options: {
|
|
958
|
+
* [x:string]: (
|
|
959
|
+
* this: T2,
|
|
960
|
+
* oldValue: string,
|
|
961
|
+
* newValue: string,
|
|
962
|
+
* element: T2
|
|
963
|
+
* ) => void
|
|
964
|
+
* },
|
|
965
|
+
* ): T1;
|
|
966
|
+
* }}
|
|
967
|
+
*/
|
|
564
968
|
static onAttributeChanged(options) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
969
|
+
const entries = Array.isArray(options) ? options : Object.entries(options);
|
|
970
|
+
const { attributeChangedCallbacks } = this;
|
|
971
|
+
for (const [name, callback] of entries) {
|
|
972
|
+
if (attributeChangedCallbacks.has(name)) {
|
|
973
|
+
attributeChangedCallbacks.get(name).push(callback);
|
|
974
|
+
} else {
|
|
975
|
+
attributeChangedCallbacks.set(name, [callback]);
|
|
571
976
|
}
|
|
572
|
-
array.push(callback);
|
|
573
977
|
}
|
|
574
978
|
|
|
575
979
|
// @ts-expect-error Can't cast T
|
|
@@ -588,10 +992,10 @@ export default class CustomElement extends ICustomElement {
|
|
|
588
992
|
/** @type {Composition<?>} */
|
|
589
993
|
#composition;
|
|
590
994
|
|
|
591
|
-
/** @type {Map<string,
|
|
995
|
+
/** @type {Map<string,{stringValue:string, parsedValue:any}>} */
|
|
592
996
|
_propAttributeCache;
|
|
593
997
|
|
|
594
|
-
/** @type {
|
|
998
|
+
/** @type {CallbackArguments} */
|
|
595
999
|
_callbackArguments = null;
|
|
596
1000
|
|
|
597
1001
|
/** @param {any[]} args */
|
|
@@ -604,7 +1008,24 @@ export default class CustomElement extends ICustomElement {
|
|
|
604
1008
|
|
|
605
1009
|
this.attachShadow({ mode: 'open', delegatesFocus: this.delegatesFocus });
|
|
606
1010
|
|
|
607
|
-
|
|
1011
|
+
/**
|
|
1012
|
+
* Updates nodes based on data
|
|
1013
|
+
* Expects data in JSON Merge Patch format
|
|
1014
|
+
* @see https://www.rfc-editor.org/rfc/rfc7386
|
|
1015
|
+
* @param {Partial<?>} changes
|
|
1016
|
+
* @param {any} data
|
|
1017
|
+
* @return {void}
|
|
1018
|
+
*/
|
|
1019
|
+
this.render = this.composition.render(
|
|
1020
|
+
this.constructor.prototype,
|
|
1021
|
+
this,
|
|
1022
|
+
{
|
|
1023
|
+
defaults: this.constructor.prototype,
|
|
1024
|
+
store: this,
|
|
1025
|
+
shadowRoot: this.shadowRoot,
|
|
1026
|
+
context: this,
|
|
1027
|
+
},
|
|
1028
|
+
);
|
|
608
1029
|
|
|
609
1030
|
for (const callback of this.static._onConstructedCallbacks) {
|
|
610
1031
|
callback.call(this, this.callbackArguments);
|
|
@@ -612,25 +1033,26 @@ export default class CustomElement extends ICustomElement {
|
|
|
612
1033
|
}
|
|
613
1034
|
|
|
614
1035
|
/**
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
1036
|
+
* @type {{
|
|
1037
|
+
* <
|
|
1038
|
+
* T extends CustomElement,
|
|
1039
|
+
* K extends string = string,
|
|
1040
|
+
* >(this:T,
|
|
1041
|
+
* name: K,
|
|
1042
|
+
* oldValue: K extends keyof T ? T[K] : unknown,
|
|
1043
|
+
* newValue: K extends keyof T ? T[K] : unknown,
|
|
1044
|
+
* changes?: K extends keyof T ? T[K] extends object ? Partial<T[K]> : T[K] : unknown): void;
|
|
1045
|
+
* }}
|
|
621
1046
|
*/
|
|
622
|
-
render(data, store) {
|
|
623
|
-
// console.log('render', data);
|
|
624
|
-
this.composition.render(this.shadowRoot, data, this, store ? { ...this, store } : this);
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/** @type {InstanceType<typeof ICustomElement>['propChangedCallback']} */
|
|
628
1047
|
propChangedCallback(name, oldValue, newValue, changes = newValue) {
|
|
629
|
-
this.
|
|
1048
|
+
if (!this.patching) {
|
|
1049
|
+
this.render.byProp(name, changes, this);
|
|
1050
|
+
// this.render({ [name]: changes });
|
|
1051
|
+
}
|
|
630
1052
|
|
|
631
|
-
const
|
|
632
|
-
if (
|
|
633
|
-
for (const callback of
|
|
1053
|
+
const { _propChangedCallbacks } = this.static;
|
|
1054
|
+
if (_propChangedCallbacks.has(name)) {
|
|
1055
|
+
for (const callback of _propChangedCallbacks.get(name)) {
|
|
634
1056
|
callback.call(this, oldValue, newValue, changes, this);
|
|
635
1057
|
}
|
|
636
1058
|
}
|
|
@@ -642,48 +1064,53 @@ export default class CustomElement extends ICustomElement {
|
|
|
642
1064
|
* @param {string|null} newValue
|
|
643
1065
|
*/
|
|
644
1066
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
645
|
-
const
|
|
646
|
-
if (
|
|
647
|
-
for (const callback of
|
|
1067
|
+
const { attributeChangedCallbacks } = this.static;
|
|
1068
|
+
if (attributeChangedCallbacks.has(name)) {
|
|
1069
|
+
for (const callback of attributeChangedCallbacks.get(name)) {
|
|
648
1070
|
callback.call(this, oldValue, newValue, this);
|
|
649
1071
|
}
|
|
650
1072
|
}
|
|
651
1073
|
|
|
652
1074
|
// Array.find
|
|
653
|
-
|
|
654
|
-
|
|
1075
|
+
const { attrList } = this.static;
|
|
1076
|
+
if (!attrList.has(name)) return;
|
|
655
1077
|
|
|
656
|
-
|
|
1078
|
+
const config = attrList.get(name);
|
|
657
1079
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1080
|
+
if (config.attributeChangedCallback) {
|
|
1081
|
+
config.attributeChangedCallback.call(this, name, oldValue, newValue);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
662
1084
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
1085
|
+
let cacheEntry;
|
|
1086
|
+
if (this.attributeCache.has(name)) {
|
|
1087
|
+
cacheEntry = this.attributeCache.get(name);
|
|
1088
|
+
if (cacheEntry.stringValue === newValue) return;
|
|
1089
|
+
}
|
|
668
1090
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
1091
|
+
// @ts-expect-error any
|
|
1092
|
+
const previousDataValue = this[config.key];
|
|
1093
|
+
const parsedValue = newValue === null
|
|
1094
|
+
? config.nullParser(/** @type {null} */ (newValue))
|
|
1095
|
+
// Avoid Boolean('') === false
|
|
1096
|
+
: (config.type === 'boolean' ? true : config.parser(newValue));
|
|
675
1097
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
// "Remember" that this attrValue equates to this data value
|
|
681
|
-
// Avoids rewriting attribute later on data change event
|
|
682
|
-
this.attributeCache.set(name, [newValue, parsedValue]);
|
|
683
|
-
// @ts-expect-error any
|
|
684
|
-
this[config.key] = parsedValue;
|
|
1098
|
+
if (parsedValue === previousDataValue) {
|
|
1099
|
+
// No internal value change
|
|
685
1100
|
return;
|
|
686
1101
|
}
|
|
1102
|
+
// "Remember" that this attrValue equates to this data value
|
|
1103
|
+
// Avoids rewriting attribute later on data change event
|
|
1104
|
+
if (cacheEntry) {
|
|
1105
|
+
cacheEntry.stringValue = newValue;
|
|
1106
|
+
cacheEntry.parsedValue = parsedValue;
|
|
1107
|
+
} else {
|
|
1108
|
+
this.attributeCache.set(name, {
|
|
1109
|
+
stringValue: newValue, parsedValue,
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
// @ts-expect-error any
|
|
1113
|
+
this[config.key] = parsedValue;
|
|
687
1114
|
}
|
|
688
1115
|
|
|
689
1116
|
get #template() {
|
|
@@ -697,19 +1124,33 @@ export default class CustomElement extends ICustomElement {
|
|
|
697
1124
|
* @param {any} changes
|
|
698
1125
|
*/
|
|
699
1126
|
_onObserverPropertyChanged(name, oldValue, newValue, changes) {
|
|
700
|
-
const {
|
|
701
|
-
if (
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1127
|
+
const { propList } = this.static;
|
|
1128
|
+
if (propList.has(name)) {
|
|
1129
|
+
const { reflect, attr } = propList.get(name);
|
|
1130
|
+
if (attr && (reflect === true || reflect === 'write')) {
|
|
1131
|
+
/** @type {{stringValue:string, parsedValue:any}} */
|
|
1132
|
+
let cacheEntry;
|
|
1133
|
+
let needsWrite = false;
|
|
1134
|
+
const { attributeCache } = this;
|
|
1135
|
+
if (attributeCache.has(attr)) {
|
|
1136
|
+
cacheEntry = attributeCache.get(attr);
|
|
1137
|
+
needsWrite = (cacheEntry.parsedValue !== newValue);
|
|
711
1138
|
} else {
|
|
712
|
-
|
|
1139
|
+
// @ts-ignore skip cast
|
|
1140
|
+
cacheEntry = {};
|
|
1141
|
+
attributeCache.set(attr, cacheEntry);
|
|
1142
|
+
needsWrite = true;
|
|
1143
|
+
}
|
|
1144
|
+
if (needsWrite) {
|
|
1145
|
+
const stringValue = attrValueFromDataValue(newValue);
|
|
1146
|
+
cacheEntry.parsedValue = newValue;
|
|
1147
|
+
cacheEntry.stringValue = stringValue;
|
|
1148
|
+
// Cache attrValue to ignore attributeChangedCallback later
|
|
1149
|
+
if (stringValue == null) {
|
|
1150
|
+
this.removeAttribute(attr);
|
|
1151
|
+
} else {
|
|
1152
|
+
this.setAttribute(attr, stringValue);
|
|
1153
|
+
}
|
|
713
1154
|
}
|
|
714
1155
|
}
|
|
715
1156
|
}
|
|
@@ -718,8 +1159,15 @@ export default class CustomElement extends ICustomElement {
|
|
|
718
1159
|
this.propChangedCallback(name, oldValue, newValue, changes);
|
|
719
1160
|
}
|
|
720
1161
|
|
|
1162
|
+
patch(patch) {
|
|
1163
|
+
this.patching = true;
|
|
1164
|
+
applyMergePatch(this, patch);
|
|
1165
|
+
this.render(patch);
|
|
1166
|
+
this.patching = false;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
721
1169
|
/**
|
|
722
|
-
* Proxy object that returns shadow DOM elements by
|
|
1170
|
+
* Proxy object that returns shadow DOM elements by tag.
|
|
723
1171
|
* If called before interpolation (eg: on composed), returns from template
|
|
724
1172
|
* @return {Record<string,HTMLElement>}
|
|
725
1173
|
*/
|
|
@@ -728,82 +1176,48 @@ export default class CustomElement extends ICustomElement {
|
|
|
728
1176
|
return (this.#refsProxy ??= new Proxy({}, {
|
|
729
1177
|
/**
|
|
730
1178
|
* @param {any} target
|
|
731
|
-
* @param {string}
|
|
1179
|
+
* @param {string} tag
|
|
732
1180
|
* @return {Element}
|
|
733
1181
|
*/
|
|
734
|
-
get: (target,
|
|
1182
|
+
get: (target, tag) => {
|
|
735
1183
|
if (!this.#composition) {
|
|
736
1184
|
console.warn(this.static.name, 'Attempted to access references before composing!');
|
|
737
1185
|
}
|
|
738
1186
|
const composition = this.composition;
|
|
1187
|
+
let element;
|
|
739
1188
|
if (!composition.interpolated) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
1189
|
+
if (this.#refsCompositionCache.has(tag)) {
|
|
1190
|
+
element = this.#refsCompositionCache.get(tag).deref();
|
|
1191
|
+
if (element) return element;
|
|
1192
|
+
}
|
|
1193
|
+
const formattedTag = attrNameFromPropName(tag);
|
|
743
1194
|
// console.warn(this.tagName, 'Returning template reference');
|
|
744
|
-
element = composition.template.getElementById(
|
|
1195
|
+
element = composition.template.getElementById(formattedTag);
|
|
745
1196
|
if (!element) return null;
|
|
746
|
-
this.#refsCompositionCache.set(
|
|
1197
|
+
this.#refsCompositionCache.set(tag, new WeakRef(element));
|
|
747
1198
|
return element;
|
|
748
1199
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
1200
|
+
if (this.#refsCache.has(tag)) {
|
|
1201
|
+
element = this.#refsCache.get(tag).deref();
|
|
1202
|
+
if (element) {
|
|
1203
|
+
return element;
|
|
1204
|
+
}
|
|
752
1205
|
}
|
|
753
|
-
|
|
754
|
-
|
|
1206
|
+
|
|
1207
|
+
const formattedTag = attrNameFromPropName(tag);
|
|
1208
|
+
const tagIndex = this.composition.tags.indexOf(formattedTag);
|
|
1209
|
+
element = this.render.state.refs[tagIndex];
|
|
1210
|
+
|
|
755
1211
|
if (!element) return null;
|
|
756
|
-
this.#refsCache.set(
|
|
1212
|
+
this.#refsCache.set(tag, new WeakRef(element));
|
|
757
1213
|
return element;
|
|
758
1214
|
},
|
|
759
1215
|
}));
|
|
760
1216
|
}
|
|
761
1217
|
|
|
762
1218
|
get attributeCache() {
|
|
763
|
-
|
|
764
|
-
return this._propAttributeCache;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
get tabIndex() {
|
|
768
|
-
return super.tabIndex;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
set tabIndex(value) {
|
|
772
|
-
if (value === super.tabIndex && value !== -1) {
|
|
773
|
-
// Non -1 value already set
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
if (this.delegatesFocus && document.activeElement === this) {
|
|
778
|
-
if (this.getAttribute('tabindex') === value.toString()) {
|
|
779
|
-
// Skip if possible
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// Chrome blurs on tabindex changes with delegatesFocus
|
|
784
|
-
// Fixed in Chrome 111
|
|
785
|
-
// Remove this code ~June 2023
|
|
786
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1346606
|
|
787
|
-
/** @type {EventListener} */
|
|
788
|
-
const listener = (e) => {
|
|
789
|
-
e.stopImmediatePropagation();
|
|
790
|
-
e.stopPropagation();
|
|
791
|
-
if (e.type === 'blur') {
|
|
792
|
-
console.warn('Chromium bug 1346606: Tabindex change caused blur. Giving focusing back.', this);
|
|
793
|
-
this.focus();
|
|
794
|
-
} else {
|
|
795
|
-
console.warn('Chromium bug 1346606: Blocking focus event.', this);
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
this.addEventListener('blur', listener, { capture: true, once: true });
|
|
799
|
-
this.addEventListener('focus', listener, { capture: true, once: true });
|
|
800
|
-
super.tabIndex = value;
|
|
801
|
-
this.removeEventListener('blur', listener, { capture: true });
|
|
802
|
-
this.removeEventListener('focus', listener, { capture: true });
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
super.tabIndex = value;
|
|
1219
|
+
// eslint-disable-next-line no-return-assign
|
|
1220
|
+
return (this._propAttributeCache ??= new Map());
|
|
807
1221
|
}
|
|
808
1222
|
|
|
809
1223
|
get static() { return /** @type {typeof CustomElement} */ (/** @type {unknown} */ (this.constructor)); }
|
|
@@ -814,6 +1228,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
814
1228
|
// eslint-disable-next-line no-return-assign
|
|
815
1229
|
return this._callbackArguments ??= {
|
|
816
1230
|
composition: this.#composition,
|
|
1231
|
+
refs: this.refs,
|
|
817
1232
|
html: html.bind(this),
|
|
818
1233
|
inline: addInlineFunction,
|
|
819
1234
|
template: this.#template,
|