@universal-material/web 3.8.0 → 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 +7 -6
- package/app-bar/top-app-bar.d.ts.map +1 -1
- package/app-bar/top-app-bar.js +71 -35
- 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 +2 -2
- package/badge/badge.d.ts.map +1 -1
- package/badge/badge.js +6 -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 +4469 -1277
- package/button/button-base.d.ts +2 -2
- package/button/button-base.d.ts.map +1 -1
- package/button/button-base.js +5 -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 +7 -7
- package/button/button.d.ts.map +1 -1
- package/button/button.js +14 -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 +7 -7
- package/button/icon-button.d.ts.map +1 -1
- package/button/icon-button.js +8 -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 +3 -3
- package/button-field/button-field.d.ts.map +1 -1
- package/button-field/button-field.js +9 -9
- package/button-field/button-field.js.map +1 -1
- package/calendar/calendar-base.d.ts +1 -1
- package/calendar/calendar-base.d.ts.map +1 -1
- package/calendar/calendar-base.js +10 -10
- package/calendar/calendar-base.js.map +1 -1
- package/calendar/calendar.d.ts +2 -2
- package/calendar/calendar.d.ts.map +1 -1
- package/calendar/calendar.js +8 -8
- package/calendar/calendar.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 +2 -2
- package/card/card-content.d.ts.map +1 -1
- package/card/card-content.js +5 -5
- package/card/card-content.js.map +1 -1
- package/card/card-media.d.ts +2 -2
- package/card/card-media.d.ts.map +1 -1
- package/card/card-media.js +5 -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 +3 -3
- package/checkbox/checkbox.d.ts.map +1 -1
- package/checkbox/checkbox.js +7 -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 +5 -5
- package/chip/chip.d.ts.map +1 -1
- package/chip/chip.js +20 -20
- package/chip/chip.js.map +1 -1
- package/chip-field/chip-field.d.ts +3 -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 +16615 -12152
- package/datepicker/datepicker.d.ts +6 -4
- package/datepicker/datepicker.d.ts.map +1 -1
- package/datepicker/datepicker.js +33 -19
- 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/range-datepicker.d.ts +6 -4
- package/datepicker/range-datepicker.d.ts.map +1 -1
- package/datepicker/range-datepicker.js +33 -19
- package/datepicker/range-datepicker.js.map +1 -1
- 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 +2 -2
- package/dialog/dialog.d.ts.map +1 -1
- package/dialog/dialog.js +14 -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 +3 -3
- package/field/field-base.d.ts.map +1 -1
- package/field/field-base.js +20 -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 +3 -3
- package/field/field.d.ts.map +1 -1
- package/field/field.js +6 -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 +24 -1
- package/index.d.ts.map +1 -1
- package/index.js +24 -1
- package/index.js.map +1 -1
- package/list/list-item.d.ts +16 -2
- package/list/list-item.d.ts.map +1 -1
- package/list/list-item.js +26 -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 +3 -3
- package/menu/menu-item.d.ts.map +1 -1
- package/menu/menu-item.js +10 -10
- package/menu/menu-item.js.map +1 -1
- package/menu/menu.d.ts +2 -2
- package/menu/menu.d.ts.map +1 -1
- package/menu/menu.js +13 -13
- package/menu/menu.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-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.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 +19 -3
- package/progress/circular-progress.d.ts +2 -2
- package/progress/circular-progress.d.ts.map +1 -1
- package/progress/circular-progress.js +6 -6
- package/progress/circular-progress.js.map +1 -1
- package/progress/progress-bar.d.ts +2 -2
- package/progress/progress-bar.d.ts.map +1 -1
- package/progress/progress-bar.js +6 -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 +3 -3
- package/radio/radio.d.ts.map +1 -1
- package/radio/radio.js +6 -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 +3 -3
- package/search/search.d.ts.map +1 -1
- package/search/search.js +7 -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 +3 -3
- package/select/option.d.ts.map +1 -1
- package/select/option.js +8 -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 +18 -12
- package/select/select.d.ts.map +1 -1
- package/select/select.js +77 -31
- package/select/select.js.map +1 -1
- package/shared/button-wrapper.d.ts +1 -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 +2 -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 +6 -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 +10 -1
- package/shared/selection-control/selection-control-list-item.js.map +1 -1
- package/shared/selection-control/selection-control.d.ts +1 -1
- package/shared/selection-control/selection-control.d.ts.map +1 -1
- package/shared/selection-control/selection-control.js +15 -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 +34 -2
- package/shared/text-field-base/text-field-base.d.ts.map +1 -1
- package/shared/text-field-base/text-field-base.js +63 -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 +4 -4
- package/snackbar/snackbar.d.ts.map +1 -1
- package/snackbar/snackbar.js +28 -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 +6 -6
- package/tab-bar/tab-bar.d.ts.map +1 -1
- package/tab-bar/tab-bar.js +40 -23
- package/tab-bar/tab-bar.js.map +1 -1
- package/tab-bar/tab.d.ts +5 -5
- package/tab-bar/tab.d.ts.map +1 -1
- package/tab-bar/tab.js +9 -9
- package/tab-bar/tab.js.map +1 -1
- package/text-area/text-area.d.ts +3 -3
- package/text-area/text-area.d.ts.map +1 -1
- package/text-area/text-area.js +9 -9
- package/text-area/text-area.js.map +1 -1
- package/text-field/text-field.d.ts +15 -3
- package/text-field/text-field.d.ts.map +1 -1
- package/text-field/text-field.js +46 -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.d.ts +7 -7
- package/typeahead/typeahead.d.ts.map +1 -1
- package/typeahead/typeahead.js +22 -18
- package/typeahead/typeahead.js.map +1 -1
- package/vscode.html-custom-data.json +870 -481
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-search — the Material 3 search bar (rounded input with leading/trailing icon slots), optionally driven by u-typeahead for suggestions.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Search
|
|
6
|
+
|
|
7
|
+
`<u-search>` is the Material 3 **search bar**: a rounded, single-line input with leading/trailing icon slots. It is form-associated (`value`, submits its `<form>` on Enter) and is the idiomatic input to pair with `<u-typeahead>` for autocomplete.
|
|
8
|
+
|
|
9
|
+
Use it for a search box; use `<u-text-field>` for a labeled form field.
|
|
10
|
+
|
|
11
|
+
## Basic
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<u-search placeholder="Search">
|
|
15
|
+
<span class="material-symbols-outlined" slot="leading-icon">search</span>
|
|
16
|
+
</u-search>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Slots: `leading-icon`, `trailing-icon` (e.g. a clear/voice button). Parts: `input`, `icon` / `leading` / `trailing`.
|
|
20
|
+
|
|
21
|
+
## Position
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<u-search position="static"></u-search> <!-- in-flow, inline (toolbar / pane header) -->
|
|
25
|
+
<u-search position="fixed"></u-search> <!-- floating bar (default) -->
|
|
26
|
+
<u-search position="absolute"></u-search>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`position` defaults to **`fixed`** (the floating M3 search bar). For a search input that sits inline in a header/toolbar, use `position="static"`.
|
|
30
|
+
|
|
31
|
+
## Reading the value
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const search = document.querySelector('u-search')!;
|
|
35
|
+
search.value; // current text (form-associated)
|
|
36
|
+
search.addEventListener('input', () => …); // fires as the user types
|
|
37
|
+
// Enter submits the associated <form> (form.requestSubmit()).
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Other props: `placeholder`, `autocomplete`, `maxlength`, `role`.
|
|
41
|
+
|
|
42
|
+
## With suggestions (`u-typeahead`)
|
|
43
|
+
|
|
44
|
+
`<u-search>` is the idiomatic target for `<u-typeahead>` — the suggestions popover anchors to the search input:
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<u-search id="q" position="static" placeholder="Search clients">
|
|
48
|
+
<span class="material-symbols-outlined" slot="leading-icon">search</span>
|
|
49
|
+
</u-search>
|
|
50
|
+
<u-typeahead target-id="q" positioning="fixed"></u-typeahead>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
const ta = document.querySelector('u-typeahead');
|
|
54
|
+
ta.source = (term) => clients.filter((c) => c.name.toLowerCase().includes(term.toLowerCase()));
|
|
55
|
+
ta.formatter = (c) => c.name;
|
|
56
|
+
ta.addEventListener('selected', (e) => openClient(e.detail));
|
|
57
|
+
</script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
See the **typeahead** skill for the full suggestions API.
|
|
61
|
+
|
|
62
|
+
## Caveats
|
|
63
|
+
|
|
64
|
+
- It's a search **bar**, not a labeled field — use `placeholder`; there is no floating label. For a labeled form input use `<u-text-field>`.
|
|
65
|
+
- Default `position` is `fixed` (floating). Set `position="static"` to keep it inline in a header/toolbar.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-select — a Material 3 dropdown built on the field chrome, with u-option children, supporting text and validation.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Select
|
|
6
|
+
|
|
7
|
+
`<u-select>` is a form-associated dropdown that opens a `<u-menu>` of `<u-option>` children. It shares the field chrome with `<u-text-field>` (label, supporting/error text, leading/trailing icons).
|
|
8
|
+
|
|
9
|
+
## Basic usage
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-select label="Country">
|
|
13
|
+
<u-option value="br">Brazil</u-option>
|
|
14
|
+
<u-option value="us">United States</u-option>
|
|
15
|
+
<u-option value="es">Spain</u-option>
|
|
16
|
+
<u-option value="jp">Japan</u-option>
|
|
17
|
+
</u-select>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Variants and helpers
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<u-select label="Country" variant="outlined" supporting-text="Pick where you live">
|
|
24
|
+
…
|
|
25
|
+
</u-select>
|
|
26
|
+
|
|
27
|
+
<u-select label="Country" error-text="Required" invalid>
|
|
28
|
+
…
|
|
29
|
+
</u-select>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Programmatic value
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const select = document.querySelector('u-select')!;
|
|
36
|
+
select.value = 'br'; // set
|
|
37
|
+
console.log(select.value); // get
|
|
38
|
+
|
|
39
|
+
select.addEventListener('change', () => console.log(select.value));
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Initial selection (in markup)
|
|
43
|
+
|
|
44
|
+
Like the native `<select>`, there is **no `value` attribute** — set the initial selection with `selected` on the option (or assign `.value` in JS after upgrade). With neither, the first enabled option is selected.
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<u-select label="Country">
|
|
48
|
+
<u-option value="br">Brazil</u-option>
|
|
49
|
+
<u-option value="us" selected>United States</u-option>
|
|
50
|
+
</u-select>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Icons in options
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<u-select label="Theme">
|
|
57
|
+
<u-option value="auto">
|
|
58
|
+
<span class="material-symbols-outlined" slot="icon">brightness_4</span>
|
|
59
|
+
System
|
|
60
|
+
</u-option>
|
|
61
|
+
<u-option value="light">
|
|
62
|
+
<span class="material-symbols-outlined" slot="icon">light_mode</span>
|
|
63
|
+
Light
|
|
64
|
+
</u-option>
|
|
65
|
+
<u-option value="dark">
|
|
66
|
+
<span class="material-symbols-outlined" slot="icon">dark_mode</span>
|
|
67
|
+
Dark
|
|
68
|
+
</u-option>
|
|
69
|
+
</u-select>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Positioning inside clipped containers
|
|
73
|
+
|
|
74
|
+
When the select sits inside a scrollable/clipped wrapper, set `menu-positioning="fixed"` so the dropdown escapes its bounds:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<u-select label="Country" menu-positioning="fixed">…</u-select>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Disabled / read-only
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<u-select label="Country" disabled>…</u-select>
|
|
84
|
+
<u-select label="Country" readOnly>…</u-select>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Required / validation
|
|
88
|
+
|
|
89
|
+
`required` participates in constraint validation and blocks native form submit. Because a select with options always has a selection, add an **empty-valued placeholder option** so "nothing chosen" is representable:
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<u-select label="Country" required error-text="Please choose a country">
|
|
93
|
+
<u-option value="">Choose…</u-option>
|
|
94
|
+
<u-option value="br">Brazil</u-option>
|
|
95
|
+
<u-option value="us">United States</u-option>
|
|
96
|
+
</u-select>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
select.checkValidity(); // boolean (fires `invalid` if not)
|
|
101
|
+
select.reportValidity(); // also shows the bubble + sets the visual `invalid` state
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## When NOT to use `<u-select>`
|
|
105
|
+
|
|
106
|
+
- Free-text input with suggestions → use `<u-typeahead>`.
|
|
107
|
+
- Multi-select chip input → use `<u-chip-field>`.
|
|
108
|
+
- A non-form action menu (Edit/Delete/Share) → use `<u-button>` + `<u-menu>` directly.
|
|
109
|
+
|
|
110
|
+
## SPA / framework binding
|
|
111
|
+
|
|
112
|
+
The select keeps its selection when the framework **re-renders the `<u-option>` list** (e.g. an `*ngFor`/`v-for`). It remembers the last value you set (via `.value`/`.selectedIndex`, a click, or `<u-option selected>`) and re-applies it once the matching option is present — so you don't need to re-assign `.value` after the options change. Setting `.value` **before** the options exist (async load) also works: it applies when that option appears. The first-option default is *not* sticky, matching the native `<select>`.
|
|
113
|
+
|
|
114
|
+
## Caveats
|
|
115
|
+
|
|
116
|
+
- The displayed value is the matching `<u-option>`'s text content. Keep option text concise. **An icon inside an option** (`<span slot="icon">`) shows in the dropdown but its ligature text leaks into the *closed* select's displayed value (e.g. "groups Todos") — omit option icons when the value is shown as text.
|
|
117
|
+
- **Single-select only** — there is no `multiple` attribute. For multiple values use `<u-chip-field>`.
|
|
118
|
+
- `required` only triggers when the current value is empty; without an empty-valued option the select always has a non-empty value and so is always valid.
|
|
119
|
+
- For long lists, the menu virtualizes after a threshold but very large lists (1000+) feel sluggish — consider a typeahead instead.
|
|
120
|
+
- Don't put non-`u-option` children inside `<u-select>` — they're ignored.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Use u-checkbox, u-radio, u-switch — and their u-*-list-item variants for selection lists.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Selection controls — checkbox, radio, switch
|
|
6
|
+
|
|
7
|
+
All three are form-associated and share API conventions: `checked`, `disabled`, `value`, `name`, plus a `change` event.
|
|
8
|
+
|
|
9
|
+
## Checkbox
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<u-checkbox></u-checkbox>
|
|
13
|
+
<u-checkbox checked></u-checkbox>
|
|
14
|
+
<u-checkbox indeterminate></u-checkbox>
|
|
15
|
+
<u-checkbox disabled></u-checkbox>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
With a label, either inline or via `<u-checkbox-list-item>`:
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<label class="flex items-center gap-2">
|
|
22
|
+
<u-checkbox></u-checkbox>
|
|
23
|
+
Subscribe to newsletter
|
|
24
|
+
</label>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Radio
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<u-radio name="color" value="red"></u-radio>
|
|
31
|
+
<u-radio name="color" value="green" checked></u-radio>
|
|
32
|
+
<u-radio name="color" value="blue"></u-radio>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`name` groups them — only one in a group can be checked. Listen on each, or use a wrapping `<form>` and read `FormData`.
|
|
36
|
+
|
|
37
|
+
## Switch
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<u-switch></u-switch>
|
|
41
|
+
<u-switch checked></u-switch>
|
|
42
|
+
<u-switch disabled></u-switch>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Same API as the checkbox.
|
|
46
|
+
|
|
47
|
+
## List-item variants
|
|
48
|
+
|
|
49
|
+
For settings screens with rows of controls, use the `u-*-list-item` components — they render a `<u-list-item>` with the control on the trailing side and a label/supporting-text on the leading side. Drop them inside a `<u-list>`:
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<u-list>
|
|
53
|
+
<u-switch-list-item checked>
|
|
54
|
+
Wi-Fi
|
|
55
|
+
<span slot="supporting-text">Connected to "Office"</span>
|
|
56
|
+
</u-switch-list-item>
|
|
57
|
+
|
|
58
|
+
<u-switch-list-item>
|
|
59
|
+
Bluetooth
|
|
60
|
+
<span slot="supporting-text">Off</span>
|
|
61
|
+
</u-switch-list-item>
|
|
62
|
+
|
|
63
|
+
<u-checkbox-list-item>
|
|
64
|
+
Show passwords
|
|
65
|
+
</u-checkbox-list-item>
|
|
66
|
+
|
|
67
|
+
<u-radio-list-item name="theme" value="light">Light</u-radio-list-item>
|
|
68
|
+
<u-radio-list-item name="theme" value="dark" checked>Dark</u-radio-list-item>
|
|
69
|
+
</u-list>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The list items handle the click on the whole row (toggling the control), the ripple, and the spacing.
|
|
73
|
+
|
|
74
|
+
## Programmatic
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const cb = document.querySelector('u-checkbox')!;
|
|
78
|
+
cb.checked = true;
|
|
79
|
+
cb.addEventListener('change', () => console.log(cb.checked));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Caveats
|
|
83
|
+
|
|
84
|
+
- `<u-checkbox>` and `<u-switch>` emit `change` on every toggle; `<u-radio>` emits `change` only on the newly-selected radio in a group (not on deselected siblings).
|
|
85
|
+
- `indeterminate` is visual only — `checked` still reads the underlying boolean. For **dynamically-built DOM** (innerHTML / generated rows) set it via the **property** after upgrade (`cb.indeterminate = true`), not the markup attribute. Setting `checked = true` clears `indeterminate`.
|
|
86
|
+
- `change` **bubbles**, so you can delegate it on an ancestor (e.g. a `<tbody>`) for bulk-selection — `wrapper.addEventListener('change', e => e.target.closest('u-checkbox') && …)` works.
|
|
87
|
+
- For groups of switches/checkboxes in settings, prefer the `*-list-item` variants — they're keyboard-accessible across the whole row and follow the M3 list spec.
|
|
88
|
+
- The `*-list-item` variants accept **`no-inset`** — pulls the row flush with surrounding content (a negative inline margin equal to the inline padding) so it lines up with the section heading/labels. See the **list** skill.
|
|
@@ -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.
|