@universal-material/web 3.7.2 → 3.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/.claude-plugin/plugin.json +12 -0
- package/README.md +12 -0
- package/app-bar/top-app-bar.d.ts +20 -4
- package/app-bar/top-app-bar.d.ts.map +1 -1
- package/app-bar/top-app-bar.js +84 -33
- package/app-bar/top-app-bar.js.map +1 -1
- package/app-bar/top-app-bar.styles.d.ts.map +1 -1
- package/app-bar/top-app-bar.styles.js +18 -1
- package/app-bar/top-app-bar.styles.js.map +1 -1
- package/badge/badge.d.ts +5 -2
- package/badge/badge.d.ts.map +1 -1
- package/badge/badge.js +9 -6
- package/badge/badge.js.map +1 -1
- package/badge/badge.styles.d.ts.map +1 -1
- package/badge/badge.styles.js +1 -0
- package/badge/badge.styles.js.map +1 -1
- package/bundle.min.js +5480 -2170
- package/button/button-base.d.ts +9 -2
- package/button/button-base.d.ts.map +1 -1
- package/button/button-base.js +12 -5
- package/button/button-base.js.map +1 -1
- package/button/button-set.d.ts +3 -3
- package/button/button-set.d.ts.map +1 -1
- package/button/button-set.js +7 -7
- package/button/button-set.js.map +1 -1
- package/button/button.d.ts +10 -7
- package/button/button.d.ts.map +1 -1
- package/button/button.js +17 -14
- package/button/button.js.map +1 -1
- package/button/fab-menu-color-context.d.ts +2 -2
- package/button/fab-menu-color-context.d.ts.map +1 -1
- package/button/fab-menu-color-context.js.map +1 -1
- package/button/fab-menu-item.d.ts +3 -3
- package/button/fab-menu-item.d.ts.map +1 -1
- package/button/fab-menu-item.js +11 -11
- package/button/fab-menu-item.js.map +1 -1
- package/button/fab-menu.d.ts +20 -5
- package/button/fab-menu.d.ts.map +1 -1
- package/button/fab-menu.js +48 -11
- package/button/fab-menu.js.map +1 -1
- package/button/fab.d.ts +22 -7
- package/button/fab.d.ts.map +1 -1
- package/button/fab.js +49 -11
- package/button/fab.js.map +1 -1
- package/button/icon-button.d.ts +13 -7
- package/button/icon-button.d.ts.map +1 -1
- package/button/icon-button.js +14 -8
- package/button/icon-button.js.map +1 -1
- package/button/toggle-button.d.ts +6 -6
- package/button/toggle-button.d.ts.map +1 -1
- package/button/toggle-button.js +10 -10
- package/button/toggle-button.js.map +1 -1
- package/button-field/button-field.d.ts +6 -3
- package/button-field/button-field.d.ts.map +1 -1
- package/button-field/button-field.js +12 -9
- package/button-field/button-field.js.map +1 -1
- package/calendar/calendar-adapter.d.ts +3 -0
- package/calendar/calendar-adapter.d.ts.map +1 -1
- package/calendar/calendar-adapter.js.map +1 -1
- package/calendar/calendar-base.d.ts +18 -1
- package/calendar/calendar-base.d.ts.map +1 -1
- package/calendar/calendar-base.js +188 -25
- package/calendar/calendar-base.js.map +1 -1
- package/calendar/calendar.d.ts +6 -2
- package/calendar/calendar.d.ts.map +1 -1
- package/calendar/calendar.js +12 -8
- package/calendar/calendar.js.map +1 -1
- package/calendar/default-calendar-adapter.d.ts +3 -0
- package/calendar/default-calendar-adapter.d.ts.map +1 -1
- package/calendar/default-calendar-adapter.js +17 -5
- package/calendar/default-calendar-adapter.js.map +1 -1
- package/calendar/range-calendar.d.ts +2 -2
- package/calendar/range-calendar.d.ts.map +1 -1
- package/calendar/range-calendar.js +9 -9
- package/calendar/range-calendar.js.map +1 -1
- package/card/card-content.d.ts +7 -2
- package/card/card-content.d.ts.map +1 -1
- package/card/card-content.js +10 -5
- package/card/card-content.js.map +1 -1
- package/card/card-media.d.ts +5 -2
- package/card/card-media.d.ts.map +1 -1
- package/card/card-media.js +8 -5
- package/card/card-media.js.map +1 -1
- package/card/card.d.ts +4 -4
- package/card/card.d.ts.map +1 -1
- package/card/card.js +5 -5
- package/card/card.js.map +1 -1
- package/checkbox/checkbox-list-item.d.ts +4 -4
- package/checkbox/checkbox-list-item.d.ts.map +1 -1
- package/checkbox/checkbox-list-item.js +5 -5
- package/checkbox/checkbox-list-item.js.map +1 -1
- package/checkbox/checkbox.d.ts +10 -3
- package/checkbox/checkbox.d.ts.map +1 -1
- package/checkbox/checkbox.js +14 -7
- package/checkbox/checkbox.js.map +1 -1
- package/chip/chip-set.d.ts +3 -3
- package/chip/chip-set.d.ts.map +1 -1
- package/chip/chip-set.js +6 -6
- package/chip/chip-set.js.map +1 -1
- package/chip/chip.d.ts +8 -5
- package/chip/chip.d.ts.map +1 -1
- package/chip/chip.js +23 -20
- package/chip/chip.js.map +1 -1
- package/chip-field/chip-field.d.ts +6 -3
- package/chip-field/chip-field.d.ts.map +1 -1
- package/chip-field/chip-field.js +9 -9
- package/chip-field/chip-field.js.map +1 -1
- package/collapse/collapse.d.ts +26 -0
- package/collapse/collapse.d.ts.map +1 -0
- package/collapse/collapse.js +62 -0
- package/collapse/collapse.js.map +1 -0
- package/collapse/collapse.styles.d.ts +2 -0
- package/collapse/collapse.styles.d.ts.map +1 -0
- package/collapse/collapse.styles.js +8 -0
- package/collapse/collapse.styles.js.map +1 -0
- package/config.js.map +1 -1
- package/css/universal-material.css +2 -1
- package/css/universal-material.min.css +2 -1
- package/custom-elements.json +17175 -9684
- package/datepicker/datepicker.d.ts +54 -3
- package/datepicker/datepicker.d.ts.map +1 -1
- package/datepicker/datepicker.js +202 -6
- package/datepicker/datepicker.js.map +1 -1
- package/datepicker/datepicker.styles.d.ts.map +1 -1
- package/datepicker/datepicker.styles.js +25 -0
- package/datepicker/datepicker.styles.js.map +1 -1
- package/datepicker/format.d.ts +19 -0
- package/datepicker/format.d.ts.map +1 -0
- package/datepicker/format.js +47 -0
- package/datepicker/format.js.map +1 -0
- package/datepicker/range-datepicker.d.ts +58 -0
- package/datepicker/range-datepicker.d.ts.map +1 -0
- package/datepicker/range-datepicker.js +212 -0
- package/datepicker/range-datepicker.js.map +1 -0
- package/dialog/confirm-dialog-builder.d.ts +3 -3
- package/dialog/confirm-dialog-builder.d.ts.map +1 -1
- package/dialog/confirm-dialog-builder.js.map +1 -1
- package/dialog/dialog-builder.d.ts +5 -4
- package/dialog/dialog-builder.d.ts.map +1 -1
- package/dialog/dialog-builder.js +10 -3
- package/dialog/dialog-builder.js.map +1 -1
- package/dialog/dialog-button-def.d.ts +3 -3
- package/dialog/dialog-button-def.d.ts.map +1 -1
- package/dialog/dialog-button-def.js.map +1 -1
- package/dialog/dialog.d.ts +10 -2
- package/dialog/dialog.d.ts.map +1 -1
- package/dialog/dialog.js +22 -14
- package/dialog/dialog.js.map +1 -1
- package/dialog/message-dialog-builder.d.ts +2 -2
- package/dialog/message-dialog-builder.d.ts.map +1 -1
- package/dialog/message-dialog-builder.js.map +1 -1
- package/elevation/elevation.d.ts +2 -2
- package/elevation/elevation.d.ts.map +1 -1
- package/elevation/elevation.js +4 -4
- package/elevation/elevation.js.map +1 -1
- package/expansion-panel/expansion-panel-container.d.ts +24 -0
- package/expansion-panel/expansion-panel-container.d.ts.map +1 -0
- package/expansion-panel/expansion-panel-container.js +54 -0
- package/expansion-panel/expansion-panel-container.js.map +1 -0
- package/expansion-panel/expansion-panel-container.styles.d.ts +2 -0
- package/expansion-panel/expansion-panel-container.styles.d.ts.map +1 -0
- package/expansion-panel/expansion-panel-container.styles.js +9 -0
- package/expansion-panel/expansion-panel-container.styles.js.map +1 -0
- package/expansion-panel/expansion-panel.d.ts +37 -0
- package/expansion-panel/expansion-panel.d.ts.map +1 -0
- package/expansion-panel/expansion-panel.js +89 -0
- package/expansion-panel/expansion-panel.js.map +1 -0
- package/expansion-panel/expansion-panel.styles.d.ts +2 -0
- package/expansion-panel/expansion-panel.styles.d.ts.map +1 -0
- package/expansion-panel/expansion-panel.styles.js +66 -0
- package/expansion-panel/expansion-panel.styles.js.map +1 -0
- package/field/field-base.d.ts +17 -3
- package/field/field-base.d.ts.map +1 -1
- package/field/field-base.js +30 -20
- package/field/field-base.js.map +1 -1
- package/field/field-defaults-context.d.ts +2 -2
- package/field/field-defaults-context.d.ts.map +1 -1
- package/field/field-defaults-context.js.map +1 -1
- package/field/field-defaults.d.ts +3 -3
- package/field/field-defaults.d.ts.map +1 -1
- package/field/field-defaults.js.map +1 -1
- package/field/field-variant.d.ts +1 -1
- package/field/field-variant.d.ts.map +1 -1
- package/field/field-variant.js.map +1 -1
- package/field/field.d.ts +7 -3
- package/field/field.d.ts.map +1 -1
- package/field/field.js +10 -6
- package/field/field.js.map +1 -1
- package/icon/icon.d.ts +2 -2
- package/icon/icon.d.ts.map +1 -1
- package/icon/icon.js +4 -4
- package/icon/icon.js.map +1 -1
- package/index.d.ts +29 -1
- package/index.d.ts.map +1 -1
- package/index.js +29 -1
- package/index.js.map +1 -1
- package/list/list-item.d.ts +19 -2
- package/list/list-item.d.ts.map +1 -1
- package/list/list-item.js +29 -6
- package/list/list-item.js.map +1 -1
- package/list/list-item.styles.d.ts.map +1 -1
- package/list/list-item.styles.js +13 -0
- package/list/list-item.styles.js.map +1 -1
- package/list/list.d.ts +2 -2
- package/list/list.d.ts.map +1 -1
- package/list/list.js +4 -4
- package/list/list.js.map +1 -1
- package/menu/menu-item.d.ts +9 -3
- package/menu/menu-item.d.ts.map +1 -1
- package/menu/menu-item.js +16 -10
- package/menu/menu-item.js.map +1 -1
- package/menu/menu.d.ts +18 -2
- package/menu/menu.d.ts.map +1 -1
- package/menu/menu.js +37 -18
- package/menu/menu.js.map +1 -1
- package/menu/menu.styles.d.ts.map +1 -1
- package/menu/menu.styles.js +5 -0
- package/menu/menu.styles.js.map +1 -1
- package/navigation/drawer-headline.d.ts +2 -2
- package/navigation/drawer-headline.d.ts.map +1 -1
- package/navigation/drawer-headline.js +6 -6
- package/navigation/drawer-headline.js.map +1 -1
- package/navigation/drawer-headline.styles.js +1 -1
- package/navigation/drawer-headline.styles.js.map +1 -1
- package/navigation/drawer-item.d.ts +3 -3
- package/navigation/drawer-item.d.ts.map +1 -1
- package/navigation/drawer-item.js +17 -12
- package/navigation/drawer-item.js.map +1 -1
- package/navigation/drawer.d.ts +2 -2
- package/navigation/drawer.d.ts.map +1 -1
- package/navigation/drawer.js +4 -4
- package/navigation/drawer.js.map +1 -1
- package/navigation/side-navigation.d.ts +9 -2
- package/navigation/side-navigation.d.ts.map +1 -1
- package/navigation/side-navigation.js +15 -8
- package/navigation/side-navigation.js.map +1 -1
- package/navigation-bar/navigation-bar-item.d.ts +40 -0
- package/navigation-bar/navigation-bar-item.d.ts.map +1 -0
- package/navigation-bar/navigation-bar-item.js +113 -0
- package/navigation-bar/navigation-bar-item.js.map +1 -0
- package/navigation-bar/navigation-bar-item.styles.d.ts +2 -0
- package/navigation-bar/navigation-bar-item.styles.d.ts.map +1 -0
- package/navigation-bar/navigation-bar-item.styles.js +101 -0
- package/navigation-bar/navigation-bar-item.styles.js.map +1 -0
- package/navigation-bar/navigation-bar.d.ts +40 -0
- package/navigation-bar/navigation-bar.d.ts.map +1 -0
- package/navigation-bar/navigation-bar.js +85 -0
- package/navigation-bar/navigation-bar.js.map +1 -0
- package/navigation-bar/navigation-bar.styles.d.ts +2 -0
- package/navigation-bar/navigation-bar.styles.d.ts.map +1 -0
- package/navigation-bar/navigation-bar.styles.js +44 -0
- package/navigation-bar/navigation-bar.styles.js.map +1 -0
- package/navigation-rail/navigation-rail-headline.d.ts +23 -0
- package/navigation-rail/navigation-rail-headline.d.ts.map +1 -0
- package/navigation-rail/navigation-rail-headline.js +28 -0
- package/navigation-rail/navigation-rail-headline.js.map +1 -0
- package/navigation-rail/navigation-rail-headline.styles.d.ts +2 -0
- package/navigation-rail/navigation-rail-headline.styles.d.ts.map +1 -0
- package/navigation-rail/navigation-rail-headline.styles.js +19 -0
- package/navigation-rail/navigation-rail-headline.styles.js.map +1 -0
- package/navigation-rail/navigation-rail-item.d.ts +58 -0
- package/navigation-rail/navigation-rail-item.d.ts.map +1 -0
- package/navigation-rail/navigation-rail-item.js +160 -0
- package/navigation-rail/navigation-rail-item.js.map +1 -0
- package/navigation-rail/navigation-rail-item.styles.d.ts +2 -0
- package/navigation-rail/navigation-rail-item.styles.d.ts.map +1 -0
- package/navigation-rail/navigation-rail-item.styles.js +182 -0
- package/navigation-rail/navigation-rail-item.styles.js.map +1 -0
- package/navigation-rail/navigation-rail.d.ts +66 -0
- package/navigation-rail/navigation-rail.d.ts.map +1 -0
- package/navigation-rail/navigation-rail.js +223 -0
- package/navigation-rail/navigation-rail.js.map +1 -0
- package/navigation-rail/navigation-rail.styles.d.ts +2 -0
- package/navigation-rail/navigation-rail.styles.d.ts.map +1 -0
- package/navigation-rail/navigation-rail.styles.js +220 -0
- package/navigation-rail/navigation-rail.styles.js.map +1 -0
- package/overflow-menu/overflow-menu-item.d.ts +8 -0
- package/overflow-menu/overflow-menu-item.d.ts.map +1 -1
- package/overflow-menu/overflow-menu-item.js +8 -0
- package/overflow-menu/overflow-menu-item.js.map +1 -1
- package/overflow-menu/overflow-menu.d.ts +8 -2
- package/overflow-menu/overflow-menu.d.ts.map +1 -1
- package/overflow-menu/overflow-menu.js +10 -1
- package/overflow-menu/overflow-menu.js.map +1 -1
- package/package.json +21 -5
- package/progress/circular-progress.d.ts +9 -2
- package/progress/circular-progress.d.ts.map +1 -1
- package/progress/circular-progress.js +9 -6
- package/progress/circular-progress.js.map +1 -1
- package/progress/progress-bar.d.ts +9 -2
- package/progress/progress-bar.d.ts.map +1 -1
- package/progress/progress-bar.js +9 -6
- package/progress/progress-bar.js.map +1 -1
- package/radio/radio-list-item.d.ts +4 -4
- package/radio/radio-list-item.d.ts.map +1 -1
- package/radio/radio-list-item.js +5 -5
- package/radio/radio-list-item.js.map +1 -1
- package/radio/radio.d.ts +6 -3
- package/radio/radio.d.ts.map +1 -1
- package/radio/radio.js +9 -6
- package/radio/radio.js.map +1 -1
- package/ripple/ripple.d.ts +2 -2
- package/ripple/ripple.d.ts.map +1 -1
- package/ripple/ripple.js +9 -9
- package/ripple/ripple.js.map +1 -1
- package/scaffold/pane.d.ts +127 -0
- package/scaffold/pane.d.ts.map +1 -0
- package/scaffold/pane.js +220 -0
- package/scaffold/pane.js.map +1 -0
- package/scaffold/pane.styles.d.ts +2 -0
- package/scaffold/pane.styles.d.ts.map +1 -0
- package/scaffold/pane.styles.js +1909 -0
- package/scaffold/pane.styles.js.map +1 -0
- package/scaffold/scaffold.d.ts +45 -0
- package/scaffold/scaffold.d.ts.map +1 -0
- package/scaffold/scaffold.js +170 -0
- package/scaffold/scaffold.js.map +1 -0
- package/scaffold/scaffold.styles.d.ts +2 -0
- package/scaffold/scaffold.styles.d.ts.map +1 -0
- package/scaffold/scaffold.styles.js +69 -0
- package/scaffold/scaffold.styles.js.map +1 -0
- package/scaffold/scroll-container-context.d.ts +4 -0
- package/scaffold/scroll-container-context.d.ts.map +1 -0
- package/scaffold/scroll-container-context.js +3 -0
- package/scaffold/scroll-container-context.js.map +1 -0
- package/scss/utilities/_divider.scss +4 -0
- package/search/search.d.ts +6 -3
- package/search/search.d.ts.map +1 -1
- package/search/search.js +10 -7
- package/search/search.js.map +1 -1
- package/search/search.styles.d.ts.map +1 -1
- package/search/search.styles.js +7 -2
- package/search/search.styles.js.map +1 -1
- package/select/option.d.ts +9 -3
- package/select/option.d.ts.map +1 -1
- package/select/option.js +14 -8
- package/select/option.js.map +1 -1
- package/select/select-navigation-controller.d.ts +4 -4
- package/select/select-navigation-controller.d.ts.map +1 -1
- package/select/select-navigation-controller.js.map +1 -1
- package/select/select.d.ts +22 -12
- package/select/select.d.ts.map +1 -1
- package/select/select.js +81 -31
- package/select/select.js.map +1 -1
- package/shared/button-wrapper.d.ts +4 -1
- package/shared/button-wrapper.d.ts.map +1 -1
- package/shared/button-wrapper.js +8 -8
- package/shared/button-wrapper.js.map +1 -1
- package/shared/char-count-text-field/native-text-field-wrapper.d.ts +15 -2
- package/shared/char-count-text-field/native-text-field-wrapper.d.ts.map +1 -1
- package/shared/char-count-text-field/native-text-field-wrapper.js +16 -6
- package/shared/char-count-text-field/native-text-field-wrapper.js.map +1 -1
- package/shared/menu-field/menu-field-navigation-controller.d.ts +3 -3
- package/shared/menu-field/menu-field-navigation-controller.d.ts.map +1 -1
- package/shared/menu-field/menu-field-navigation-controller.js.map +1 -1
- package/shared/menu-field/menu-field.d.ts +5 -5
- package/shared/menu-field/menu-field.d.ts.map +1 -1
- package/shared/menu-field/menu-field.js.map +1 -1
- package/shared/selection-control/selection-control-list-item.d.ts +2 -2
- package/shared/selection-control/selection-control-list-item.d.ts.map +1 -1
- package/shared/selection-control/selection-control-list-item.js +14 -1
- package/shared/selection-control/selection-control-list-item.js.map +1 -1
- package/shared/selection-control/selection-control.d.ts +10 -1
- package/shared/selection-control/selection-control.d.ts.map +1 -1
- package/shared/selection-control/selection-control.js +24 -7
- package/shared/selection-control/selection-control.js.map +1 -1
- package/shared/sets/set-base.d.ts +1 -1
- package/shared/sets/set-base.d.ts.map +1 -1
- package/shared/sets/set-base.js +2 -2
- package/shared/sets/set-base.js.map +1 -1
- package/shared/text-field-base/text-field-base.d.ts +37 -2
- package/shared/text-field-base/text-field-base.d.ts.map +1 -1
- package/shared/text-field-base/text-field-base.js +66 -4
- package/shared/text-field-base/text-field-base.js.map +1 -1
- package/skills/badge/SKILL.md +43 -0
- package/skills/buttons/SKILL.md +115 -0
- package/skills/card/SKILL.md +162 -0
- package/skills/chips/SKILL.md +95 -0
- package/skills/collapse/SKILL.md +37 -0
- package/skills/datepicker/SKILL.md +110 -0
- package/skills/dialog/SKILL.md +92 -0
- package/skills/drawer/SKILL.md +94 -0
- package/skills/expansion-panel/SKILL.md +65 -0
- package/skills/fab/SKILL.md +79 -0
- package/skills/list/SKILL.md +105 -0
- package/skills/menu/SKILL.md +120 -0
- package/skills/navigation-bar/SKILL.md +87 -0
- package/skills/navigation-rail/SKILL.md +127 -0
- package/skills/overview/SKILL.md +44 -0
- package/skills/progress/SKILL.md +63 -0
- package/skills/scaffold/SKILL.md +392 -0
- package/skills/search/SKILL.md +65 -0
- package/skills/select/SKILL.md +120 -0
- package/skills/selection-controls/SKILL.md +88 -0
- package/skills/setup/SKILL.md +58 -0
- package/skills/slider/SKILL.md +119 -0
- package/skills/snackbar/SKILL.md +70 -0
- package/skills/tab-bar/SKILL.md +55 -0
- package/skills/text-field/SKILL.md +114 -0
- package/skills/theming/SKILL.md +80 -0
- package/skills/top-app-bar/SKILL.md +64 -0
- package/skills/typeahead/SKILL.md +113 -0
- package/slider/slider.d.ts +73 -0
- package/slider/slider.d.ts.map +1 -0
- package/slider/slider.js +506 -0
- package/slider/slider.js.map +1 -0
- package/slider/slider.styles.d.ts +2 -0
- package/slider/slider.styles.d.ts.map +1 -0
- package/slider/slider.styles.js +292 -0
- package/slider/slider.styles.js.map +1 -0
- package/snackbar/snackbar.d.ts +13 -4
- package/snackbar/snackbar.d.ts.map +1 -1
- package/snackbar/snackbar.js +37 -28
- package/snackbar/snackbar.js.map +1 -1
- package/snackbar/snackbar.styles.js +1 -1
- package/snackbar/snackbar.styles.js.map +1 -1
- package/switch/switch-list-item.d.ts +4 -4
- package/switch/switch-list-item.d.ts.map +1 -1
- package/switch/switch-list-item.js +5 -5
- package/switch/switch-list-item.js.map +1 -1
- package/switch/switch.d.ts +3 -3
- package/switch/switch.d.ts.map +1 -1
- package/switch/switch.js +5 -5
- package/switch/switch.js.map +1 -1
- package/tab-bar/tab-bar.d.ts +9 -6
- package/tab-bar/tab-bar.d.ts.map +1 -1
- package/tab-bar/tab-bar.js +43 -23
- package/tab-bar/tab-bar.js.map +1 -1
- package/tab-bar/tab.d.ts +10 -5
- package/tab-bar/tab.d.ts.map +1 -1
- package/tab-bar/tab.js +14 -9
- package/tab-bar/tab.js.map +1 -1
- package/text-area/text-area.d.ts +6 -3
- package/text-area/text-area.d.ts.map +1 -1
- package/text-area/text-area.js +12 -9
- package/text-area/text-area.js.map +1 -1
- package/text-field/text-field.d.ts +31 -3
- package/text-field/text-field.d.ts.map +1 -1
- package/text-field/text-field.js +53 -13
- package/text-field/text-field.js.map +1 -1
- package/typeahead/highlight.d.ts +2 -2
- package/typeahead/highlight.d.ts.map +1 -1
- package/typeahead/highlight.js +7 -7
- package/typeahead/highlight.js.map +1 -1
- package/typeahead/typeahead-template-render.d.ts +4 -0
- package/typeahead/typeahead-template-render.d.ts.map +1 -1
- package/typeahead/typeahead-template-render.js +4 -0
- package/typeahead/typeahead-template-render.js.map +1 -1
- package/typeahead/typeahead.d.ts +14 -7
- package/typeahead/typeahead.d.ts.map +1 -1
- package/typeahead/typeahead.js +29 -18
- package/typeahead/typeahead.js.map +1 -1
- package/vscode.html-custom-data.json +1146 -326
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set up @universal-material/web in an app — install the package, import components, wire the Material Symbols font, and the optional CSS reset.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Setting up @universal-material/web
|
|
6
|
+
|
|
7
|
+
Use this whenever the user is bootstrapping a project (adding a new app, scaffolding a page from scratch) and hasn't yet imported the library.
|
|
8
|
+
|
|
9
|
+
## 1. Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @universal-material/web
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 2. Import the components you need
|
|
16
|
+
|
|
17
|
+
A single side-effect import registers every custom element and exposes the imperative APIs (`ThemeBuilder`, `Snackbar`, `Dialog`):
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import '@universal-material/web';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For tree-shaken builds, import the components individually:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import '@universal-material/web/button/button.js';
|
|
27
|
+
import '@universal-material/web/dialog/dialog.js';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 3. Add the Material Symbols font
|
|
31
|
+
|
|
32
|
+
All icons (`<span class="material-symbols-outlined">…</span>`) require the Google Material Symbols font in the document head:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0" />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Add a system font (Roboto recommended) for the components themselves:
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,400;0,500;0,700&display=swap" />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 4. Optional CSS reset / typography helpers
|
|
45
|
+
|
|
46
|
+
The library ships an opinionated stylesheet with utility classes (`u-headline-l`, `u-label-m`, `u-container`, `u-grid`, etc.):
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<link rel="stylesheet" href="node_modules/@universal-material/web/css/universal-material.min.css" />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
You can also `@import` the SCSS sources from `node_modules/@universal-material/web/scss/universal-material.scss` to opt into theme tokens at build time.
|
|
53
|
+
|
|
54
|
+
## Caveats
|
|
55
|
+
|
|
56
|
+
- Custom elements must be defined before they appear in HTML. If you parse HTML before the JS bundle loads, elements upgrade afterwards (Lit handles this gracefully, but property assignments before upgrade are not reactive).
|
|
57
|
+
- The library uses Lit context. **Provider components must register before their consumers** — `import '@universal-material/web'` already orders them correctly; if you cherry-pick imports, register `scaffold` before `top-app-bar`/`fab`.
|
|
58
|
+
- For the `<input type="date">` mask handling and `<dialog>` ergonomics, modern Chromium/Safari/Firefox are required.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-slider for single-thumb or two-thumb range value selection; wraps a native input[type=range] for keyboard, pointer, and form integration.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Slider
|
|
6
|
+
|
|
7
|
+
Material 3 Expressive slider with optional tick marks, floating value label, and range mode. Form-associated — set `name` to participate in `<form>` submission.
|
|
8
|
+
|
|
9
|
+
## Continuous
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-slider min="0" max="100" value="40" aria-label="Volume"></u-slider>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Discrete (ticks + value indicator while dragging)
|
|
16
|
+
|
|
17
|
+
The 44dp circular value indicator appears centered above the active handle while the user drags.
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<u-slider discrete min="0" max="10" step="1" value="6" aria-label="Rating"></u-slider>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Use `discrete` only when the number of stops is small enough to see.** The number of ticks rendered is `(max - min) / step`. Above ~15-20 stops the ticks crowd together, the track turns into a solid bar of dots, and the value indicator becomes the only readable signal — at that point you should drop `discrete` and use a continuous slider instead.
|
|
24
|
+
|
|
25
|
+
Rule of thumb:
|
|
26
|
+
- ✅ `min="0" max="10" step="1"` — 10 stops, ticks readable
|
|
27
|
+
- ✅ `min="0" max="20" step="2"` — 10 stops
|
|
28
|
+
- ⚠️ `min="0" max="100" step="5"` — 20 stops, borderline
|
|
29
|
+
- ❌ `min="0" max="100" step="1"` — 100 stops, ticks become noise
|
|
30
|
+
- ❌ `min="0" max="12000" step="100"` — 120 stops, looks broken
|
|
31
|
+
|
|
32
|
+
For wide ranges where the **value** is what matters (price, MRR, score 0-100), use a continuous slider and render the current value separately:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<u-slider id="preco" min="0" max="12000" step="100" value="3000" aria-label="Preço"></u-slider>
|
|
36
|
+
<span id="preco-label" class="u-label-l">R$ 3.000</span>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
const s = document.getElementById('preco');
|
|
40
|
+
const l = document.getElementById('preco-label');
|
|
41
|
+
s.addEventListener('input', () => l.textContent = `R$ ${Number(s.value).toLocaleString('pt-BR')}`);
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or use `slider.labelFormat` for the floating indicator (only visible while dragging — still helps for discrete sliders with ≤ ~15 stops, doesn't render the dense ticks):
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
slider.labelFormat = (v) => `R$ ${v.toLocaleString('pt-BR')}`;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Range (two thumbs)
|
|
52
|
+
|
|
53
|
+
Set both `value-start` and `value-end` to enable range mode automatically. The handles clamp to each other so `value-start` cannot exceed `value-end`.
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<u-slider min="0" max="100" value-start="25" value-end="75" aria-label="Price range"></u-slider>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Sizes
|
|
60
|
+
|
|
61
|
+
Five M3 expressive size variants. The track height, handle height, state-layer size, and value-indicator typography scale together.
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<u-slider size="extra-small" value="40"></u-slider>
|
|
65
|
+
<u-slider size="small" value="40"></u-slider>
|
|
66
|
+
<u-slider size="medium" value="40"></u-slider>
|
|
67
|
+
<u-slider size="large" value="40"></u-slider>
|
|
68
|
+
<u-slider size="extra-large" value="40"></u-slider>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| size | track | handle | state-layer | typography |
|
|
72
|
+
| --- | --- | --- | --- | --- |
|
|
73
|
+
| `extra-small` (default) | 16dp | 4×44 | 40 | label-large |
|
|
74
|
+
| `small` | 24dp | 4×52 | 48 | label-large |
|
|
75
|
+
| `medium` | 40dp | 6×64 | 56 | title-medium |
|
|
76
|
+
| `large` | 56dp | 6×80 | 68 | title-medium |
|
|
77
|
+
| `extra-large` | 96dp | 8×120 | 96 | title-large |
|
|
78
|
+
|
|
79
|
+
## Form integration
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<form>
|
|
83
|
+
<u-slider name="volume" min="0" max="100" value="40"></u-slider>
|
|
84
|
+
<u-slider name="price" range value-start="20" value-end="80"></u-slider>
|
|
85
|
+
</form>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Range mode submits two entries: `price-start` and `price-end`.
|
|
89
|
+
|
|
90
|
+
## Events
|
|
91
|
+
|
|
92
|
+
- `input` — fires continuously while dragging (or on each keyboard step).
|
|
93
|
+
- `change` — fires on commit (pointer up, blur).
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const slider = document.querySelector('u-slider')!;
|
|
97
|
+
slider.addEventListener('input', () => console.log(slider.value));
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Attributes
|
|
101
|
+
|
|
102
|
+
- `min`, `max`, `step` — value bounds. Use `step="0"` for fully continuous values.
|
|
103
|
+
- `value` — single-thumb mode.
|
|
104
|
+
- `value-start`, `value-end` — range mode.
|
|
105
|
+
- `range` — force range mode (auto-enabled when both `value-start` and `value-end` are present).
|
|
106
|
+
- `discrete` — show ticks + floating label while dragging.
|
|
107
|
+
- `ticks` — show ticks without enabling the label.
|
|
108
|
+
- `disabled` — disable interaction (dims to 38% opacity).
|
|
109
|
+
- `name` — form-association name.
|
|
110
|
+
- `size` — `extra-small` (default), `small`, `medium`, `large`, `extra-large`.
|
|
111
|
+
|
|
112
|
+
## Caveats
|
|
113
|
+
|
|
114
|
+
- Range mode places two `<input type="range">` elements on top of each other. The handles are clamped via `min`/`max` on each input, so dragging beyond the other thumb is impossible by design.
|
|
115
|
+
- The handle in M3 Expressive is a thin **bar** (4–8dp wide depending on size), not a circle. There is a 6dp gap between the handle and each adjacent track segment, and the track ends facing the handle have a 2dp inner corner radius. The gap collapses at min/max so the active bar always fills to the edge.
|
|
116
|
+
- The handle does **not** narrow on press. The spec's narrow-on-press effect causes a 1-2dp jiggle in the bars when the press visual animates, which the project intentionally avoids — press feedback is the value indicator alone.
|
|
117
|
+
- Hit area: the handle's hitbox matches the state-layer size (40–96dp depending on size). In range mode, the focused / hovered / actively-dragged handle is z-index-raised above the other so overlapping hitboxes resolve to the right one.
|
|
118
|
+
- Exposed parts: `track`, `track-active`, `track-inactive-start` (range only), `track-inactive-end`, `thumb`, `thumb-end` (range only), `value-indicator`, `stop-indicator`.
|
|
119
|
+
- Custom value formatting: assign a function to `slider.labelFormat`, e.g. `(v) => v.toFixed(1) + 'kg'`. Not settable via attribute.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show a snackbar (toast) imperatively via Snackbar.show — message, optional action button, duration, and close affordance.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Snackbar
|
|
6
|
+
|
|
7
|
+
Brief, transient messages shown at the bottom of the screen. Created imperatively — no markup needed.
|
|
8
|
+
|
|
9
|
+
## Show a message
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Snackbar } from '@universal-material/web';
|
|
13
|
+
|
|
14
|
+
Snackbar.show({
|
|
15
|
+
message: 'Your changes have been saved.',
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## With an action
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const sb = Snackbar.show({ message: 'Item deleted.', action: 'Undo' });
|
|
23
|
+
// The action button fires an `actionClick` event on the returned snackbar.
|
|
24
|
+
// There is NO `onAction` config option — passing one is silently ignored.
|
|
25
|
+
sb.addEventListener('actionClick', () => undoDelete());
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Clicking the action button fires `actionClick` and closes the snackbar.
|
|
29
|
+
|
|
30
|
+
## Duration
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { Snackbar, SnackbarDuration } from '@universal-material/web';
|
|
34
|
+
|
|
35
|
+
Snackbar.show({
|
|
36
|
+
message: 'Saved as draft',
|
|
37
|
+
duration: SnackbarDuration.long, // 5000ms — this is the default when omitted
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
Snackbar.show({
|
|
41
|
+
message: 'Quick toast',
|
|
42
|
+
duration: SnackbarDuration.short, // 2500ms
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
Snackbar.show({
|
|
46
|
+
message: 'Custom 6s',
|
|
47
|
+
duration: 6000, // any ms value
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Pass `duration: 0` (or `Infinity`) for a sticky snackbar that only closes on action or via the close button.
|
|
52
|
+
|
|
53
|
+
## Close affordance
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
Snackbar.show({
|
|
57
|
+
message: 'Network request failed',
|
|
58
|
+
showClose: true,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Multiple snackbars
|
|
63
|
+
|
|
64
|
+
Calling `.show()` while another snackbar is visible queues the new one — only one renders at a time.
|
|
65
|
+
|
|
66
|
+
## Caveats
|
|
67
|
+
|
|
68
|
+
- The snackbar mounts itself at the document level (escapes any scrim/dialog). To override its anchoring (e.g. inside a scaffold), customize `--u-snackbar-bottom-offset` on `:root`.
|
|
69
|
+
- Don't use snackbars for errors that require user attention — use `<u-dialog>` (`Dialog.message()`/`.confirm()`) instead.
|
|
70
|
+
- The snackbar API is imperative; for declarative usage, mount the element manually and toggle visibility, but it's almost never what you want.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-tab-bar and u-tab for horizontally arranged content tabs with an animated underline indicator.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tab bar
|
|
6
|
+
|
|
7
|
+
`<u-tab-bar>` groups a row of `<u-tab>`s and animates an underline indicator under the active tab.
|
|
8
|
+
|
|
9
|
+
## Basic
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-tab-bar>
|
|
13
|
+
<u-tab active>Overview</u-tab>
|
|
14
|
+
<u-tab>Activity</u-tab>
|
|
15
|
+
<u-tab>Files</u-tab>
|
|
16
|
+
<u-tab>Members</u-tab>
|
|
17
|
+
</u-tab-bar>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Tracking the selected tab
|
|
21
|
+
|
|
22
|
+
The bar fires a **`change`** event on user selection and exposes **`activeTabIndex`** / **`activeTab`** (read + write). Use these to switch the body view — more robust than reading `click` + `textContent`:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const bar = document.querySelector('u-tab-bar')!;
|
|
26
|
+
bar.addEventListener('change', () => {
|
|
27
|
+
showPanel(bar.activeTabIndex); // 0-based index of the selected tab
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
bar.activeTabIndex = 2; // select programmatically (does NOT fire `change`)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
There's also a cancelable `changing` event — call `preventDefault()` to block the switch. (`variant="primary" | "secondary"` chooses the indicator style.)
|
|
34
|
+
|
|
35
|
+
## With icons
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<u-tab-bar>
|
|
39
|
+
<u-tab active>
|
|
40
|
+
<span class="material-symbols-outlined" slot="icon">home</span>
|
|
41
|
+
Home
|
|
42
|
+
</u-tab>
|
|
43
|
+
<u-tab>
|
|
44
|
+
<span class="material-symbols-outlined" slot="icon">search</span>
|
|
45
|
+
Search
|
|
46
|
+
</u-tab>
|
|
47
|
+
</u-tab-bar>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Caveats
|
|
51
|
+
|
|
52
|
+
- The bar is meant for **content** tabs (switching the body view). For top-level navigation between pages, use `<u-navigation-bar>` (mobile) or `<u-drawer>` items.
|
|
53
|
+
- `active` in markup sets the **initial** selection — put it on any `<u-tab>` (`<u-tab active>` on the second tab starts there). With no `active`, the first tab is selected. `tab.active` is read-only at runtime (derived from `bar.activeTab`); switch with `bar.activeTabIndex = n`.
|
|
54
|
+
- Don't manually toggle `active` on multiple tabs at once — only one should be active. The bar enforces this on click but not on attribute writes.
|
|
55
|
+
- The underline indicator animates between tabs via CSS. If you toggle `active` programmatically very fast, the indicator may skip frames.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-text-field and u-text-area for text input — filled/outlined variants, validation, supporting text, char counter, prefix/suffix slots.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Text field & text area
|
|
6
|
+
|
|
7
|
+
Both `<u-text-field>` and `<u-text-area>` are form-associated, support M3 filled and outlined variants, and share the same field chrome (floating label, supporting text, error text, leading/trailing icons).
|
|
8
|
+
|
|
9
|
+
## Basic text field
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-text-field label="Name"></u-text-field>
|
|
13
|
+
<u-text-field label="Email" type="email" placeholder="you@example.com"></u-text-field>
|
|
14
|
+
<u-text-field label="Password" type="password"></u-text-field>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Variants
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<u-text-field label="Filled (default)"></u-text-field>
|
|
21
|
+
<u-text-field label="Outlined" variant="outlined"></u-text-field>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Set a global default with `FieldBase.setDefaults(rootElement, { variant: 'outlined' })`.
|
|
25
|
+
|
|
26
|
+
## Icons
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<u-text-field label="Search">
|
|
30
|
+
<span class="material-symbols-outlined" slot="leading-icon">search</span>
|
|
31
|
+
<u-icon-button slot="trailing-icon" type="button">
|
|
32
|
+
<span class="material-symbols-outlined">close</span>
|
|
33
|
+
</u-icon-button>
|
|
34
|
+
</u-text-field>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Prefix / suffix (text-field only)
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<u-text-field label="Amount" prefix-text="$" suffix-text="USD"></u-text-field>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Supporting text, error text, char counter
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<u-text-field
|
|
47
|
+
label="Bio"
|
|
48
|
+
supporting-text="Tell us about yourself"
|
|
49
|
+
[maxlength]="120">
|
|
50
|
+
</u-text-field>
|
|
51
|
+
|
|
52
|
+
<u-text-field
|
|
53
|
+
label="Username"
|
|
54
|
+
error-text="Already taken"
|
|
55
|
+
invalid>
|
|
56
|
+
</u-text-field>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `supporting-text` — small caption under the field.
|
|
60
|
+
- `error-text` + `invalid` — replaces the supporting text and tints the chrome red.
|
|
61
|
+
- `maxlength` — drives an automatic `N/MAX` counter.
|
|
62
|
+
- `hide-counter` — suppress the counter even when `maxlength` is set.
|
|
63
|
+
|
|
64
|
+
## Multi-line
|
|
65
|
+
|
|
66
|
+
`<u-text-area>` is the textarea equivalent; same API plus `rows`:
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<u-text-area label="Description" rows="4" maxlength="500"></u-text-area>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Read-only / disabled
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<u-text-field label="ID" value="abc-123" readOnly></u-text-field>
|
|
76
|
+
<u-text-field label="Locked" disabled></u-text-field>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Validation
|
|
80
|
+
|
|
81
|
+
`required`, `pattern`, `minlength` and `maxlength` are forwarded to the inner input and participate in **constraint validation** — they block native `<form>` submit and feed `checkValidity()` / `reportValidity()`:
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<u-text-field label="Email" type="email" required></u-text-field>
|
|
85
|
+
<u-text-field label="ZIP" pattern="[0-9]{5}" minlength="5"></u-text-field>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
field.checkValidity(); // boolean; fires `invalid` if not valid
|
|
90
|
+
field.reportValidity(); // also shows the native bubble + sets the visual `invalid` state
|
|
91
|
+
field.validity.patternMismatch; // live ValidityState
|
|
92
|
+
field.validationMessage; // localized message
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For custom errors, keep driving `invalid` + `error-text` yourself (`field.invalid = true; field.errorText = 'Already taken'`).
|
|
96
|
+
|
|
97
|
+
## Reading and writing the value
|
|
98
|
+
|
|
99
|
+
Form integration via `ElementInternals` — the field participates in `<form>` submission and `FormData`. From JS:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
const field = document.querySelector('u-text-field')!;
|
|
103
|
+
field.value = 'hello';
|
|
104
|
+
console.log(field.value);
|
|
105
|
+
|
|
106
|
+
field.addEventListener('input', () => console.log(field.value));
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Caveats
|
|
110
|
+
|
|
111
|
+
- The placeholder is hidden visually while the field is empty AND not focused so it doesn't collide with the floating label. Don't fight this with custom CSS — that's the M3 behavior.
|
|
112
|
+
- For `type="date"` use `<u-datepicker>` (not `<u-text-field type="date">`) — the datepicker handles the calendar popover, the M3 chrome and the native browser-mask hiding.
|
|
113
|
+
- Wrap inside `<form>` for native submit; `Enter` in the input triggers `form.requestSubmit()` automatically.
|
|
114
|
+
- Constraint validation covers `required` / `pattern` / `minlength` / `maxlength`. Number `min` / `max` / `step` and `inputmode` are **not** forwarded yet — for those, validate in script and drive `invalid` + `error-text` yourself.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Configure the app's Material 3 color theme via ThemeBuilder — seed color, dark mode, custom colors.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Theming
|
|
6
|
+
|
|
7
|
+
Use this when the user wants to set the app's primary color, switch dark/light mode, or customize Material 3 color tokens.
|
|
8
|
+
|
|
9
|
+
## Seeding a theme from a single source color
|
|
10
|
+
|
|
11
|
+
`ThemeBuilder.create(seed)` derives an entire M3 color palette (primary, secondary, tertiary, surface, etc.) from one hex color:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { ThemeBuilder } from '@universal-material/web';
|
|
15
|
+
|
|
16
|
+
const css = ThemeBuilder.create('#4f46e5').build();
|
|
17
|
+
|
|
18
|
+
const style = document.createElement('style');
|
|
19
|
+
style.id = 'theme-styles';
|
|
20
|
+
style.textContent = css;
|
|
21
|
+
document.head.appendChild(style);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The generated CSS sets variables on `:root` like `--u-color-primary`, `--u-color-on-primary`, `--u-color-secondary-container`, etc. Every component reads from these.
|
|
25
|
+
|
|
26
|
+
## Reacting to a new color at runtime
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
function setTheme(hex: string): void {
|
|
30
|
+
const css = ThemeBuilder.create(hex).build();
|
|
31
|
+
document.getElementById('theme-styles')!.textContent = css;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Dark mode
|
|
36
|
+
|
|
37
|
+
`ThemeBuilder` emits each token as a CSS `light-dark(<light>, <dark>)` value, so every color follows the document's **`color-scheme`**. With no override, that tracks the OS via `prefers-color-scheme`.
|
|
38
|
+
|
|
39
|
+
To force a scheme, add the library's utility class to the **`<body>`** — `u-dark` or `u-light`. No class = follow the system:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<body class="u-dark">…</body> <!-- force dark -->
|
|
43
|
+
<body class="u-light">…</body> <!-- force light -->
|
|
44
|
+
<body>…</body> <!-- system default -->
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// runtime toggle
|
|
49
|
+
document.body.classList.remove('u-dark', 'u-light');
|
|
50
|
+
document.body.classList.add(scheme === 'dark' ? 'u-dark' : 'u-light'); // add neither for "system"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`u-dark` / `u-light` set `color-scheme: dark/light !important` (plus the body text color), which is what `light-dark()` resolves against. There is **no** `theme` attribute hook — use these classes. For a "system / light / dark" toggle, persist the choice and apply the class at boot, before first paint.
|
|
54
|
+
|
|
55
|
+
## Reading current token values
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const primary = getComputedStyle(document.documentElement)
|
|
59
|
+
.getPropertyValue('--u-color-primary').trim();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This is useful when integrating non-component visuals (charts, illustrations) that need to follow the theme.
|
|
63
|
+
|
|
64
|
+
## Overriding individual tokens
|
|
65
|
+
|
|
66
|
+
You can override any token after the generated theme by setting the variable yourself:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
:root {
|
|
70
|
+
--u-color-primary: #2e7d32; /* override seed-derived primary */
|
|
71
|
+
--u-shape-corner-large: 24px; /* tune shape tokens */
|
|
72
|
+
--u-top-app-bar-container-color: transparent; /* component-specific */
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Caveats
|
|
77
|
+
|
|
78
|
+
- Call `ThemeBuilder` once at boot, before the first paint, to avoid a flash of unstyled colors.
|
|
79
|
+
- The library reads tokens via CSS variables, so changing them at runtime updates every component live — no re-render needed.
|
|
80
|
+
- Do **not** hardcode hex values in component CSS — always reference tokens (`var(--u-color-primary)`) so the theme controls the look.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Add a top app bar to a screen — small/medium/large sizes, leading and trailing icons, scroll-driven collapse.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Top app bar
|
|
6
|
+
|
|
7
|
+
`<u-top-app-bar>` is the Material 3 top app bar: persistent strip at the top of a screen with headline, leading icon (menu/back), and trailing actions.
|
|
8
|
+
|
|
9
|
+
## Basic small bar
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-top-app-bar headline="Inbox">
|
|
13
|
+
<u-icon-button slot="leading-icon">
|
|
14
|
+
<span class="material-symbols-outlined">menu</span>
|
|
15
|
+
</u-icon-button>
|
|
16
|
+
<u-icon-button slot="trailing-icon">
|
|
17
|
+
<span class="material-symbols-outlined">search</span>
|
|
18
|
+
</u-icon-button>
|
|
19
|
+
</u-top-app-bar>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Size variants
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<u-top-app-bar size="small" headline="Small"></u-top-app-bar>
|
|
26
|
+
<u-top-app-bar size="medium" headline="Medium"></u-top-app-bar>
|
|
27
|
+
<u-top-app-bar size="large" headline="Large"></u-top-app-bar>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `small` (64dp) — default.
|
|
31
|
+
- `medium` (112dp) and `large` (152dp) — render an "extended" headline area that fades out as the user scrolls.
|
|
32
|
+
|
|
33
|
+
## Positioning
|
|
34
|
+
|
|
35
|
+
| Mode | Anchored to | When to use |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `fixed` (default) | Viewport top. Slides with `--u-app-bar-offset` when a `u-side-navigation` drawer opens. | Standalone pages, side-navigation layouts. |
|
|
38
|
+
| `absolute` | Nearest positioned ancestor. | Inside a `u-scaffold` (auto-set), or any custom container. |
|
|
39
|
+
| `static` | In-flow, no special positioning. | Rare — when the bar should scroll with content. |
|
|
40
|
+
|
|
41
|
+
Inside a `<u-scaffold>` the scaffold flips `position` to `absolute` automatically and feeds the bar its scroll container via context, so the scroll-driven collapse works without manual wiring.
|
|
42
|
+
|
|
43
|
+
## Scroll-driven collapse
|
|
44
|
+
|
|
45
|
+
For `medium`/`large` bars, the extended headline fades out as the user scrolls past it. The bar finds its scroll target in this order:
|
|
46
|
+
|
|
47
|
+
1. Explicit `scrollContainer` attribute (`HTMLElement`, element id, `"window"`, or `"none"` to disable).
|
|
48
|
+
2. The scroll container provided by an ancestor `<u-scaffold>` via Lit context.
|
|
49
|
+
3. `window` (default).
|
|
50
|
+
|
|
51
|
+
## Customizing colors
|
|
52
|
+
|
|
53
|
+
```css
|
|
54
|
+
u-top-app-bar {
|
|
55
|
+
--u-top-app-bar-container-color: var(--u-color-surface);
|
|
56
|
+
--u-top-app-bar-on-scroll-container-color: var(--u-color-surface-container);
|
|
57
|
+
--u-top-app-bar-text-color: var(--u-color-on-surface);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Caveats
|
|
62
|
+
|
|
63
|
+
- Don't put the headline inside the `leading-icon` / `trailing-icon` slots — those are reserved for `<u-icon-button>`s. Use the `headline` attribute or the default slot.
|
|
64
|
+
- When inside `<u-scaffold>`, do **not** set `position="fixed"` — the scaffold's container clips the bar to itself, and fixed-to-viewport would escape the layout.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Build an autocomplete / typeahead with u-typeahead — a controller attached to a text field via target-id, with sync/async sources, object results, custom item templates, and match highlighting.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Typeahead
|
|
6
|
+
|
|
7
|
+
`<u-typeahead>` is **not** a field — it's a controller that attaches to a separate input (`<u-text-field>` or a native input) and opens a popover of suggestions as the user types. You give it a `source`; it renders the dropdown and emits a `selected` event.
|
|
8
|
+
|
|
9
|
+
> **Key shape (easy to get wrong):** the typeahead has no label/field of its own. Pair it with a field via `target-id`. A standalone `<u-typeahead label="…">` renders nothing.
|
|
10
|
+
|
|
11
|
+
## Simple string suggestions
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<u-text-field id="country-input" label="Country"></u-text-field>
|
|
15
|
+
<u-typeahead target-id="country-input"></u-typeahead>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
const countries = ['Argentina', 'Brazil', 'Chile', 'Spain', 'United States'];
|
|
19
|
+
const ta = document.querySelector('u-typeahead');
|
|
20
|
+
// `source` = an array, or a (term) => Array | Promise<Array>
|
|
21
|
+
ta.source = (term) => countries.filter(c => c.toLowerCase().includes(term.toLowerCase()));
|
|
22
|
+
</script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
When `source` is a plain array, the component filters it internally by case-insensitive substring. When it's a function, you do the filtering and may return a `Promise`.
|
|
26
|
+
|
|
27
|
+
## Attaching to any input (`target-id`)
|
|
28
|
+
|
|
29
|
+
`target-id` can point to **any** input — not only `<u-text-field>`. The typeahead reads `target.input?.value ?? target.value` and listens for the target's `input` event, so it works with:
|
|
30
|
+
|
|
31
|
+
- `<u-search>` — the M3 search bar; this is the **idiomatic pairing** (the popover anchors to its input). See the **search** skill.
|
|
32
|
+
- `<u-text-field>` / `<u-text-area>`.
|
|
33
|
+
- `<u-chip-field>` — multi-select chips.
|
|
34
|
+
- a plain native `<input>`, or any element from **another library** that exposes a `.value` and fires an `input` event.
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<u-search id="q" position="static"><span class="material-symbols-outlined" slot="leading-icon">search</span></u-search>
|
|
38
|
+
<u-typeahead target-id="q"></u-typeahead>
|
|
39
|
+
|
|
40
|
+
<!-- a native input (or a non-u-* component) works too -->
|
|
41
|
+
<input id="q2" />
|
|
42
|
+
<u-typeahead target-id="q2"></u-typeahead>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The popover anchors to the target's natural box: the search / text-field's inner input or container, or the bare element for a native input.
|
|
46
|
+
|
|
47
|
+
## Object results + label mapping
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<u-text-field id="user-input" label="User"></u-text-field>
|
|
51
|
+
<u-typeahead target-id="user-input"></u-typeahead>
|
|
52
|
+
|
|
53
|
+
<script>
|
|
54
|
+
const ta = document.querySelector('u-typeahead');
|
|
55
|
+
ta.source = async (term) => {
|
|
56
|
+
const r = await fetch(`/api/users?q=${encodeURIComponent(term)}`);
|
|
57
|
+
return await r.json(); // [{ id, name, email }]
|
|
58
|
+
};
|
|
59
|
+
// `formatter` maps an object value to the displayed string (input + default option label)
|
|
60
|
+
ta.formatter = (u) => u.name;
|
|
61
|
+
</script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Custom option rendering
|
|
65
|
+
|
|
66
|
+
`template` is a **function** returning a string / `HTMLElement` / Lit `TemplateResult` per option (not a `<template>` element):
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
import { html } from 'lit';
|
|
70
|
+
ta.template = (term, user) => html`
|
|
71
|
+
<div style="display:flex; align-items:center; gap:8px">
|
|
72
|
+
<span>${user.name}</span>
|
|
73
|
+
<span class="u-label-s u-text-low-emphasis">${user.email}</span>
|
|
74
|
+
</div>`;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`<u-highlight text="..." match="...">` wraps the matched substring of the query in a styled span — useful inside a template to show why a suggestion matched.
|
|
78
|
+
|
|
79
|
+
## Selection
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const ta = document.querySelector('u-typeahead')!;
|
|
83
|
+
ta.addEventListener('selected', (e: CustomEvent) => {
|
|
84
|
+
console.log('Selected:', e.detail); // the chosen value (string or object)
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The event is **`selected`** (cancelable; `e.detail` is the value). There is no `select` event.
|
|
89
|
+
|
|
90
|
+
## Useful properties / attributes
|
|
91
|
+
|
|
92
|
+
| Name | Default | Purpose |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `target-id` | — | **Required.** Id of the input/field the typeahead drives. |
|
|
95
|
+
| `source` (prop) | — | Array, or `(term) => Array \| Promise<Array>`. |
|
|
96
|
+
| `formatter` (prop) | `String(value)` | Maps an object value to its displayed label. |
|
|
97
|
+
| `template` (prop) | — | `(term, value) => string \| HTMLElement \| TemplateResult` per option. |
|
|
98
|
+
| `minlength` | `2` | Min chars before suggestions show. **Array sources show nothing until 2 chars** unless lowered. |
|
|
99
|
+
| `debounce` | `300` (ms) | Debounce before `source` is called. |
|
|
100
|
+
| `limit` | — | Max options shown. |
|
|
101
|
+
| `open-on-focus` | off | Open the popover on focus (before typing). |
|
|
102
|
+
| `editable` | — | Allow free text alongside suggestions. |
|
|
103
|
+
| `positioning="fixed"` | — | Let the popover escape an `overflow:hidden`/scroll wrapper. |
|
|
104
|
+
| `clear()` (method) | — | Clear the current value. |
|
|
105
|
+
|
|
106
|
+
For multi-select with chips, drive a `<u-chip-field>` from a typeahead instead.
|
|
107
|
+
|
|
108
|
+
## Caveats
|
|
109
|
+
|
|
110
|
+
- **No `optionsProvider` / `labelField` / `select`.** Those don't exist — use `source` / `formatter` / the `selected` event. A standalone `<u-typeahead label="…">` (no `target-id`) renders nothing.
|
|
111
|
+
- `source` is called on every keystroke (after `debounce`) — for remote data, abort in-flight requests (`AbortController`).
|
|
112
|
+
- The component does not de-duplicate — dedupe in your `source`.
|
|
113
|
+
- `positioning="fixed"` is needed inside a `<u-scaffold>`'s scrolling `<main>`.
|