@webjsdev/ui 0.3.16 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -10
- package/THIRD_PARTY_NOTICES.md +349 -0
- package/package.json +4 -2
- package/packages/registry/blocks/_shared/placeholder.svg +1 -0
- package/packages/registry/blocks/charts/chart-area-axes.ts +72 -0
- package/packages/registry/blocks/charts/chart-area-default.ts +64 -0
- package/packages/registry/blocks/charts/chart-area-gradient.ts +82 -0
- package/packages/registry/blocks/charts/chart-area-icons.ts +77 -0
- package/packages/registry/blocks/charts/chart-area-interactive.ts +204 -0
- package/packages/registry/blocks/charts/chart-area-legend.ts +72 -0
- package/packages/registry/blocks/charts/chart-area-linear.ts +64 -0
- package/packages/registry/blocks/charts/chart-area-stacked-expand.ts +77 -0
- package/packages/registry/blocks/charts/chart-area-stacked.ts +71 -0
- package/packages/registry/blocks/charts/chart-area-step.ts +68 -0
- package/packages/registry/blocks/charts/chart-bar-active.ts +93 -0
- package/packages/registry/blocks/charts/chart-bar-default.ts +60 -0
- package/packages/registry/blocks/charts/chart-bar-horizontal.ts +62 -0
- package/packages/registry/blocks/charts/chart-bar-interactive.ts +185 -0
- package/packages/registry/blocks/charts/chart-bar-label-custom.ts +78 -0
- package/packages/registry/blocks/charts/chart-bar-label.ts +66 -0
- package/packages/registry/blocks/charts/chart-bar-mixed.ts +87 -0
- package/packages/registry/blocks/charts/chart-bar-multiple.ts +67 -0
- package/packages/registry/blocks/charts/chart-bar-negative.ts +61 -0
- package/packages/registry/blocks/charts/chart-bar-stacked.ts +68 -0
- package/packages/registry/blocks/charts/chart-line-default.ts +61 -0
- package/packages/registry/blocks/charts/chart-line-dots-colors.ts +86 -0
- package/packages/registry/blocks/charts/chart-line-dots-custom.ts +75 -0
- package/packages/registry/blocks/charts/chart-line-dots.ts +65 -0
- package/packages/registry/blocks/charts/chart-line-interactive.ts +185 -0
- package/packages/registry/blocks/charts/chart-line-label-custom.ts +94 -0
- package/packages/registry/blocks/charts/chart-line-label.ts +73 -0
- package/packages/registry/blocks/charts/chart-line-linear.ts +61 -0
- package/packages/registry/blocks/charts/chart-line-multiple.ts +71 -0
- package/packages/registry/blocks/charts/chart-line-step.ts +61 -0
- package/packages/registry/blocks/charts/chart-pie-donut-active.ts +86 -0
- package/packages/registry/blocks/charts/chart-pie-donut-text.ts +89 -0
- package/packages/registry/blocks/charts/chart-pie-donut.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-interactive.ts +120 -0
- package/packages/registry/blocks/charts/chart-pie-label-custom.ts +82 -0
- package/packages/registry/blocks/charts/chart-pie-label-list.ts +86 -0
- package/packages/registry/blocks/charts/chart-pie-label.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-legend.ts +79 -0
- package/packages/registry/blocks/charts/chart-pie-separator-none.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-simple.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-stacked.ts +99 -0
- package/packages/registry/blocks/charts/chart-radar-default.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-dots.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle-fill.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle-no-lines.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-custom.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-fill.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-none.ts +60 -0
- package/packages/registry/blocks/charts/chart-radar-icons.ts +76 -0
- package/packages/registry/blocks/charts/chart-radar-label-custom.ts +77 -0
- package/packages/registry/blocks/charts/chart-radar-legend.ts +70 -0
- package/packages/registry/blocks/charts/chart-radar-lines-only.ts +68 -0
- package/packages/registry/blocks/charts/chart-radar-multiple.ts +68 -0
- package/packages/registry/blocks/charts/chart-radar-radius.ts +68 -0
- package/packages/registry/blocks/charts/chart-radial-grid.ts +80 -0
- package/packages/registry/blocks/charts/chart-radial-label.ts +85 -0
- package/packages/registry/blocks/charts/chart-radial-shape.ts +81 -0
- package/packages/registry/blocks/charts/chart-radial-simple.ts +79 -0
- package/packages/registry/blocks/charts/chart-radial-stacked.ts +69 -0
- package/packages/registry/blocks/charts/chart-radial-text.ts +82 -0
- package/packages/registry/blocks/charts/chart-tooltip-advanced.ts +84 -0
- package/packages/registry/blocks/charts/chart-tooltip-default.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-formatter.ts +75 -0
- package/packages/registry/blocks/charts/chart-tooltip-icons.ts +68 -0
- package/packages/registry/blocks/charts/chart-tooltip-indicator-line.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-indicator-none.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-custom.ts +65 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-formatter.ts +66 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-none.ts +62 -0
- package/packages/registry/blocks/dashboard-01/components/app-sidebar.ts +108 -0
- package/packages/registry/blocks/dashboard-01/components/chart-area-interactive.ts +276 -0
- package/packages/registry/blocks/dashboard-01/components/dashboard-data.ts +89 -0
- package/packages/registry/blocks/dashboard-01/components/data-table.ts +637 -0
- package/packages/registry/blocks/dashboard-01/components/nav-documents.ts +65 -0
- package/packages/registry/blocks/dashboard-01/components/nav-main.ts +61 -0
- package/packages/registry/blocks/dashboard-01/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/dashboard-01/components/nav-user.ts +66 -0
- package/packages/registry/blocks/dashboard-01/components/section-cards.ts +59 -0
- package/packages/registry/blocks/dashboard-01/components/site-header.ts +52 -0
- package/packages/registry/blocks/dashboard-01/page.ts +39 -0
- package/packages/registry/blocks/login-01/components/login-form.ts +70 -0
- package/packages/registry/blocks/login-01/page.ts +19 -0
- package/packages/registry/blocks/login-02/components/login-form.ts +68 -0
- package/packages/registry/blocks/login-02/page.ts +36 -0
- package/packages/registry/blocks/login-03/components/login-form.ts +89 -0
- package/packages/registry/blocks/login-03/page.ts +28 -0
- package/packages/registry/blocks/login-04/components/login-form.ts +91 -0
- package/packages/registry/blocks/login-04/page.ts +20 -0
- package/packages/registry/blocks/login-05/components/login-form.ts +75 -0
- package/packages/registry/blocks/login-05/page.ts +19 -0
- package/packages/registry/blocks/preview/cards/activate-agent-dialog.ts +77 -0
- package/packages/registry/blocks/preview/cards/analytics-card.ts +64 -0
- package/packages/registry/blocks/preview/cards/anomaly-alert.ts +35 -0
- package/packages/registry/blocks/preview/cards/bar-chart-card.ts +91 -0
- package/packages/registry/blocks/preview/cards/book-appointment.ts +51 -0
- package/packages/registry/blocks/preview/cards/codespaces-card.ts +172 -0
- package/packages/registry/blocks/preview/cards/contributions-activity.ts +63 -0
- package/packages/registry/blocks/preview/cards/contributors.ts +51 -0
- package/packages/registry/blocks/preview/cards/environment-variables.ts +47 -0
- package/packages/registry/blocks/preview/cards/feedback-form.ts +61 -0
- package/packages/registry/blocks/preview/cards/file-upload.ts +51 -0
- package/packages/registry/blocks/preview/cards/github-profile.ts +66 -0
- package/packages/registry/blocks/preview/cards/icon-preview-grid.ts +47 -0
- package/packages/registry/blocks/preview/cards/invite-team.ts +78 -0
- package/packages/registry/blocks/preview/cards/invoice.ts +91 -0
- package/packages/registry/blocks/preview/cards/live-waveform.ts +330 -0
- package/packages/registry/blocks/preview/cards/no-team-members.ts +61 -0
- package/packages/registry/blocks/preview/cards/not-found.ts +46 -0
- package/packages/registry/blocks/preview/cards/observability-card.ts +44 -0
- package/packages/registry/blocks/preview/cards/pie-chart-card.ts +84 -0
- package/packages/registry/blocks/preview/cards/report-bug.ts +71 -0
- package/packages/registry/blocks/preview/cards/shipping-address.ts +79 -0
- package/packages/registry/blocks/preview/cards/shortcuts.ts +57 -0
- package/packages/registry/blocks/preview/cards/skeleton-loading.ts +37 -0
- package/packages/registry/blocks/preview/cards/sleep-report.ts +85 -0
- package/packages/registry/blocks/preview/cards/style-overview.ts +64 -0
- package/packages/registry/blocks/preview/cards/typography-specimen.ts +107 -0
- package/packages/registry/blocks/preview/cards/ui-elements.ts +164 -0
- package/packages/registry/blocks/preview/cards/usage-card.ts +63 -0
- package/packages/registry/blocks/preview/cards/visitors.ts +71 -0
- package/packages/registry/blocks/preview/cards/weekly-fitness-summary.ts +54 -0
- package/packages/registry/blocks/preview/page.ts +103 -0
- package/packages/registry/blocks/preview-02/cards/account-access.ts +70 -0
- package/packages/registry/blocks/preview-02/cards/card-overview.ts +75 -0
- package/packages/registry/blocks/preview-02/cards/claimable-balance.ts +54 -0
- package/packages/registry/blocks/preview-02/cards/contribution-history.ts +80 -0
- package/packages/registry/blocks/preview-02/cards/cover-art.ts +41 -0
- package/packages/registry/blocks/preview-02/cards/dividend-income.ts +76 -0
- package/packages/registry/blocks/preview-02/cards/empty-connect-bank.ts +38 -0
- package/packages/registry/blocks/preview-02/cards/empty-distribute-track.ts +38 -0
- package/packages/registry/blocks/preview-02/cards/empty-explore-catalog.ts +39 -0
- package/packages/registry/blocks/preview-02/cards/faq.ts +79 -0
- package/packages/registry/blocks/preview-02/cards/front-door.ts +40 -0
- package/packages/registry/blocks/preview-02/cards/index-investing.ts +31 -0
- package/packages/registry/blocks/preview-02/cards/kitchen-island.ts +90 -0
- package/packages/registry/blocks/preview-02/cards/loading-card.ts +34 -0
- package/packages/registry/blocks/preview-02/cards/new-milestone.ts +53 -0
- package/packages/registry/blocks/preview-02/cards/notification-settings.ts +126 -0
- package/packages/registry/blocks/preview-02/cards/payments.ts +88 -0
- package/packages/registry/blocks/preview-02/cards/payout-threshold.ts +92 -0
- package/packages/registry/blocks/preview-02/cards/power-usage.ts +84 -0
- package/packages/registry/blocks/preview-02/cards/preferences.ts +89 -0
- package/packages/registry/blocks/preview-02/cards/qr-connect.ts +54 -0
- package/packages/registry/blocks/preview-02/cards/receiving-method.ts +89 -0
- package/packages/registry/blocks/preview-02/cards/recent-transactions.ts +101 -0
- package/packages/registry/blocks/preview-02/cards/release-catalog.ts +73 -0
- package/packages/registry/blocks/preview-02/cards/roller-shades.ts +110 -0
- package/packages/registry/blocks/preview-02/cards/savings-progress.ts +68 -0
- package/packages/registry/blocks/preview-02/cards/savings-targets.ts +132 -0
- package/packages/registry/blocks/preview-02/cards/sidebar-nav.ts +88 -0
- package/packages/registry/blocks/preview-02/cards/social-links.ts +57 -0
- package/packages/registry/blocks/preview-02/cards/stock-performance.ts +106 -0
- package/packages/registry/blocks/preview-02/cards/syncing-state.ts +37 -0
- package/packages/registry/blocks/preview-02/cards/transfer-funds.ts +111 -0
- package/packages/registry/blocks/preview-02/cards/upcoming-payments.ts +69 -0
- package/packages/registry/blocks/preview-02/page.ts +111 -0
- package/packages/registry/blocks/preview-03/cards/files-chat.ts +75 -0
- package/packages/registry/blocks/preview-03/cards/group-chat.ts +114 -0
- package/packages/registry/blocks/preview-03/cards/reasoning-chat.ts +88 -0
- package/packages/registry/blocks/preview-03/cards/simple-chat.ts +53 -0
- package/packages/registry/blocks/preview-03/components/chat-card.ts +126 -0
- package/packages/registry/blocks/preview-03/components/chat-player.ts +174 -0
- package/packages/registry/blocks/preview-03/components/part-file.ts +77 -0
- package/packages/registry/blocks/preview-03/components/part-reasoning.ts +25 -0
- package/packages/registry/blocks/preview-03/components/part-source.ts +48 -0
- package/packages/registry/blocks/preview-03/components/part-text.ts +69 -0
- package/packages/registry/blocks/preview-03/components/part-tool.ts +71 -0
- package/packages/registry/blocks/preview-03/components/prompt-input.ts +86 -0
- package/packages/registry/blocks/preview-03/page.ts +39 -0
- package/packages/registry/blocks/sidebar-01/components/app-sidebar.ts +113 -0
- package/packages/registry/blocks/sidebar-01/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-01/components/version-switcher.ts +50 -0
- package/packages/registry/blocks/sidebar-01/page.ts +58 -0
- package/packages/registry/blocks/sidebar-02/components/app-sidebar.ts +131 -0
- package/packages/registry/blocks/sidebar-02/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-02/components/version-switcher.ts +50 -0
- package/packages/registry/blocks/sidebar-02/page.ts +53 -0
- package/packages/registry/blocks/sidebar-03/components/app-sidebar.ts +134 -0
- package/packages/registry/blocks/sidebar-03/page.ts +60 -0
- package/packages/registry/blocks/sidebar-04/components/app-sidebar.ts +136 -0
- package/packages/registry/blocks/sidebar-04/page.ts +58 -0
- package/packages/registry/blocks/sidebar-05/components/app-sidebar.ts +147 -0
- package/packages/registry/blocks/sidebar-05/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-05/page.ts +58 -0
- package/packages/registry/blocks/sidebar-06/components/app-sidebar.ts +105 -0
- package/packages/registry/blocks/sidebar-06/components/nav-main.ts +56 -0
- package/packages/registry/blocks/sidebar-06/components/sidebar-opt-in-form.ts +44 -0
- package/packages/registry/blocks/sidebar-06/page.ts +57 -0
- package/packages/registry/blocks/sidebar-07/components/app-sidebar.ts +108 -0
- package/packages/registry/blocks/sidebar-07/components/nav-main.ts +61 -0
- package/packages/registry/blocks/sidebar-07/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-07/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-07/components/team-switcher.ts +66 -0
- package/packages/registry/blocks/sidebar-07/page.ts +59 -0
- package/packages/registry/blocks/sidebar-08/components/app-sidebar.ts +122 -0
- package/packages/registry/blocks/sidebar-08/components/nav-main.ts +68 -0
- package/packages/registry/blocks/sidebar-08/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-08/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/sidebar-08/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-08/page.ts +59 -0
- package/packages/registry/blocks/sidebar-09/components/app-sidebar.ts +213 -0
- package/packages/registry/blocks/sidebar-09/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-09/page.ts +52 -0
- package/packages/registry/blocks/sidebar-10/components/app-sidebar.ts +125 -0
- package/packages/registry/blocks/sidebar-10/components/nav-actions.ts +84 -0
- package/packages/registry/blocks/sidebar-10/components/nav-favorites.ts +66 -0
- package/packages/registry/blocks/sidebar-10/components/nav-main.ts +37 -0
- package/packages/registry/blocks/sidebar-10/components/nav-secondary.ts +43 -0
- package/packages/registry/blocks/sidebar-10/components/nav-workspaces.ts +78 -0
- package/packages/registry/blocks/sidebar-10/components/team-switcher.ts +63 -0
- package/packages/registry/blocks/sidebar-10/page.ts +46 -0
- package/packages/registry/blocks/sidebar-11/components/app-sidebar.ts +114 -0
- package/packages/registry/blocks/sidebar-11/page.ts +63 -0
- package/packages/registry/blocks/sidebar-12/components/app-sidebar.ts +63 -0
- package/packages/registry/blocks/sidebar-12/components/calendars.ts +53 -0
- package/packages/registry/blocks/sidebar-12/components/date-picker.ts +26 -0
- package/packages/registry/blocks/sidebar-12/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-12/page.ts +43 -0
- package/packages/registry/blocks/sidebar-13/components/settings-dialog.ts +114 -0
- package/packages/registry/blocks/sidebar-13/page.ts +21 -0
- package/packages/registry/blocks/sidebar-14/components/app-sidebar.ts +120 -0
- package/packages/registry/blocks/sidebar-14/page.ts +55 -0
- package/packages/registry/blocks/sidebar-15/components/calendars.ts +53 -0
- package/packages/registry/blocks/sidebar-15/components/date-picker.ts +26 -0
- package/packages/registry/blocks/sidebar-15/components/nav-favorites.ts +66 -0
- package/packages/registry/blocks/sidebar-15/components/nav-main.ts +35 -0
- package/packages/registry/blocks/sidebar-15/components/nav-secondary.ts +43 -0
- package/packages/registry/blocks/sidebar-15/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-15/components/nav-workspaces.ts +75 -0
- package/packages/registry/blocks/sidebar-15/components/sidebar-left.ts +126 -0
- package/packages/registry/blocks/sidebar-15/components/sidebar-right.ts +62 -0
- package/packages/registry/blocks/sidebar-15/components/team-switcher.ts +63 -0
- package/packages/registry/blocks/sidebar-15/page.ts +47 -0
- package/packages/registry/blocks/sidebar-16/components/app-sidebar.ts +124 -0
- package/packages/registry/blocks/sidebar-16/components/nav-main.ts +67 -0
- package/packages/registry/blocks/sidebar-16/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-16/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/sidebar-16/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-16/components/search-form.ts +27 -0
- package/packages/registry/blocks/sidebar-16/components/site-header.ts +42 -0
- package/packages/registry/blocks/sidebar-16/page.ts +38 -0
- package/packages/registry/blocks/signup-01/components/signup-form.ts +78 -0
- package/packages/registry/blocks/signup-01/page.ts +19 -0
- package/packages/registry/blocks/signup-02/components/signup-form.ts +78 -0
- package/packages/registry/blocks/signup-02/page.ts +36 -0
- package/packages/registry/blocks/signup-03/components/signup-form.ts +79 -0
- package/packages/registry/blocks/signup-03/page.ts +28 -0
- package/packages/registry/blocks/signup-04/components/signup-form.ts +100 -0
- package/packages/registry/blocks/signup-04/page.ts +20 -0
- package/packages/registry/blocks/signup-05/components/signup-form.ts +75 -0
- package/packages/registry/blocks/signup-05/page.ts +20 -0
- package/packages/registry/components/accordion.ts +20 -7
- package/packages/registry/components/alert-dialog.ts +58 -13
- package/packages/registry/components/alert.ts +11 -6
- package/packages/registry/components/attachment.ts +119 -0
- package/packages/registry/components/avatar.ts +17 -8
- package/packages/registry/components/badge.ts +16 -9
- package/packages/registry/components/breadcrumb.ts +6 -6
- package/packages/registry/components/bubble.ts +95 -0
- package/packages/registry/components/button-group.ts +73 -0
- package/packages/registry/components/button.ts +35 -25
- package/packages/registry/components/calendar.ts +566 -0
- package/packages/registry/components/card.ts +8 -8
- package/packages/registry/components/carousel.ts +352 -0
- package/packages/registry/components/chart-element.ts +547 -0
- package/packages/registry/components/chart-geometry.ts +457 -0
- package/packages/registry/components/chart.ts +932 -0
- package/packages/registry/components/checkbox.ts +22 -84
- package/packages/registry/components/code-block.ts +191 -0
- package/packages/registry/components/collapsible.ts +5 -2
- package/packages/registry/components/combobox.ts +802 -0
- package/packages/registry/components/command.ts +618 -0
- package/packages/registry/components/context-menu.ts +302 -0
- package/packages/registry/components/dialog.ts +156 -45
- package/packages/registry/components/direction.ts +43 -0
- package/packages/registry/components/drawer.ts +226 -0
- package/packages/registry/components/dropdown-menu.ts +262 -83
- package/packages/registry/components/empty.ts +88 -0
- package/packages/registry/components/field.ts +165 -0
- package/packages/registry/components/floating.ts +124 -0
- package/packages/registry/components/hover-card.ts +19 -8
- package/packages/registry/components/input-group.ts +118 -0
- package/packages/registry/components/input-otp.ts +365 -0
- package/packages/registry/components/input.ts +3 -3
- package/packages/registry/components/item.ts +134 -0
- package/packages/registry/components/kbd.ts +2 -2
- package/packages/registry/components/label.ts +1 -1
- package/packages/registry/components/marker.ts +63 -0
- package/packages/registry/components/menubar.ts +388 -0
- package/packages/registry/components/message-scroller.ts +470 -0
- package/packages/registry/components/message.ts +69 -0
- package/packages/registry/components/native-select.ts +5 -5
- package/packages/registry/components/navigation-menu.ts +564 -0
- package/packages/registry/components/pagination.ts +5 -5
- package/packages/registry/components/popover.ts +30 -84
- package/packages/registry/components/progress.ts +7 -3
- package/packages/registry/components/questionnaire.ts +840 -0
- package/packages/registry/components/radio-group.ts +18 -73
- package/packages/registry/components/resizable.ts +330 -0
- package/packages/registry/components/scroll-area.ts +46 -0
- package/packages/registry/components/select.ts +650 -0
- package/packages/registry/components/separator.ts +1 -1
- package/packages/registry/components/sheet.ts +128 -0
- package/packages/registry/components/sidebar.ts +457 -0
- package/packages/registry/components/skeleton.ts +1 -1
- package/packages/registry/components/slider.ts +333 -0
- package/packages/registry/components/sonner.ts +74 -7
- package/packages/registry/components/spinner.ts +66 -0
- package/packages/registry/components/switch.ts +117 -9
- package/packages/registry/components/table.ts +11 -9
- package/packages/registry/components/tabs.ts +76 -25
- package/packages/registry/components/textarea.ts +1 -1
- package/packages/registry/components/toggle-group.ts +30 -11
- package/packages/registry/components/toggle.ts +20 -13
- package/packages/registry/components/tooltip.ts +68 -7
- package/packages/registry/components/trace.ts +75 -0
- package/packages/registry/lib/icons-hugeicons.ts +955 -0
- package/packages/registry/lib/icons-phosphor.ts +955 -0
- package/packages/registry/lib/icons-remixicon.ts +955 -0
- package/packages/registry/lib/icons-tabler.ts +955 -0
- package/packages/registry/lib/icons.ts +768 -0
- package/packages/registry/lib/utils.ts +49 -4
- package/packages/registry/registry.json +4092 -60
- package/packages/registry/styles/shadcn-tailwind.css +654 -0
- package/packages/registry/styles/style-luma.css +1987 -0
- package/packages/registry/styles/style-lyra.css +1965 -0
- package/packages/registry/styles/style-maia.css +1987 -0
- package/packages/registry/styles/style-mira.css +1992 -0
- package/packages/registry/styles/style-new-york.css +1597 -0
- package/packages/registry/styles/style-nova.css +1990 -0
- package/packages/registry/styles/style-rhea.css +1987 -0
- package/packages/registry/styles/style-sera.css +1977 -0
- package/packages/registry/styles/style-vega.css +1990 -0
- package/packages/registry/styles/supplement.json +54 -0
- package/packages/registry/styles/tw-animate.css +6 -0
- package/packages/registry/themes/base-colors.js +8 -2
- package/packages/registry/themes/fonts.js +120 -0
- package/packages/registry/themes/index.css +2 -0
- package/packages/registry/themes/items.js +61 -0
- package/packages/registry/themes/preset.js +302 -0
- package/packages/registry/themes/themes.js +1193 -0
- package/src/commands/add.js +236 -12
- package/src/commands/diff.js +34 -20
- package/src/commands/info.js +7 -0
- package/src/commands/init.js +125 -8
- package/src/commands/list.js +43 -11
- package/src/commands/view.js +33 -5
- package/src/registry/extract.js +192 -2
- package/src/registry/icons.js +31 -0
- package/src/registry/local.js +15 -1
- package/src/registry/schema.js +13 -0
- package/src/registry/style-bake.js +506 -0
- package/src/utils/theme.js +110 -21
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combobox: a text input that filters a list of choices as you type, for one
|
|
3
|
+
* value or, in chips mode, several. Tier-2. It follows Base UI's Combobox,
|
|
4
|
+
* which shadcn builds on: typing filters the list, the arrow keys highlight
|
|
5
|
+
* while focus stays in the input, Enter picks, and the choice lives in a real
|
|
6
|
+
* form control, one `<input type="hidden" name>` per chosen value, so the
|
|
7
|
+
* form submits it with or without JavaScript.
|
|
8
|
+
*
|
|
9
|
+
* shadcn parity:
|
|
10
|
+
* Combobox (multiple, value, disabled)
|
|
11
|
+
* → <ui-combobox name multiple value disabled>
|
|
12
|
+
* ComboboxInput (showTrigger, showClear)
|
|
13
|
+
* → <ui-combobox-input placeholder input-id show-trigger="false" show-clear>
|
|
14
|
+
* ComboboxContent (side, align, sideOffset)
|
|
15
|
+
* → <ui-combobox-content side align side-offset>
|
|
16
|
+
* ComboboxList / ComboboxEmpty / ComboboxSeparator
|
|
17
|
+
* → <ui-combobox-list> / <ui-combobox-empty> / <ui-combobox-separator>
|
|
18
|
+
* ComboboxGroup + ComboboxLabel
|
|
19
|
+
* → <ui-combobox-group> + <ui-combobox-label>
|
|
20
|
+
* ComboboxItem value → <ui-combobox-item value>
|
|
21
|
+
* ComboboxChips + ComboboxChip + ComboboxChipsInput
|
|
22
|
+
* → <ui-combobox-chips> around <ui-combobox-chips-input>; the
|
|
23
|
+
* chips are drawn from the chosen values
|
|
24
|
+
* onValueChange → `ui-value-change` ({ detail: { value } }), a string, or a
|
|
25
|
+
* string array with `multiple`
|
|
26
|
+
* onOpenChange → `ui-open-change` ({ detail: { open } })
|
|
27
|
+
*
|
|
28
|
+
* `value` holds the initial choice: one value, or with `multiple` a comma
|
|
29
|
+
* separated list. An item's label is its text. The list filters on labels,
|
|
30
|
+
* case-insensitively, and the content carries `data-empty` when nothing
|
|
31
|
+
* matches, which is what shows `<ui-combobox-empty>`.
|
|
32
|
+
*
|
|
33
|
+
* Keyboard (as Base UI's): ArrowDown / ArrowUp open the list and move the
|
|
34
|
+
* highlight, Enter picks the highlighted item, Escape closes, Tab closes and
|
|
35
|
+
* moves on. With `multiple`, picking toggles and keeps the list open, and
|
|
36
|
+
* Backspace in an empty input removes the last chip. Leaving a single
|
|
37
|
+
* combobox puts the chosen item's label back in the input.
|
|
38
|
+
*
|
|
39
|
+
* A11y (handled by the element, plus your part): the input is a
|
|
40
|
+
* `role="combobox"` controlling a `role="listbox"` (multiselectable with
|
|
41
|
+
* `multiple`), pointing at the highlighted `role="option"` through
|
|
42
|
+
* `aria-activedescendant`; options carry `aria-selected`, a group is named by
|
|
43
|
+
* its label, and each chip's remove button names the value it removes. Your
|
|
44
|
+
* part: name the input, with `<label for>` matching `input-id`, or an
|
|
45
|
+
* `aria-label` on the input part.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```html
|
|
49
|
+
* <label for="framework" class=${labelClass()}>Framework</label>
|
|
50
|
+
* <ui-combobox name="framework">
|
|
51
|
+
* <ui-combobox-input input-id="framework" placeholder="Select a framework"></ui-combobox-input>
|
|
52
|
+
* <ui-combobox-content>
|
|
53
|
+
* <ui-combobox-empty>No items found.</ui-combobox-empty>
|
|
54
|
+
* <ui-combobox-list>
|
|
55
|
+
* <ui-combobox-item value="next">Next.js</ui-combobox-item>
|
|
56
|
+
* <ui-combobox-item value="sveltekit">SvelteKit</ui-combobox-item>
|
|
57
|
+
* <ui-combobox-item value="astro">Astro</ui-combobox-item>
|
|
58
|
+
* </ui-combobox-list>
|
|
59
|
+
* </ui-combobox-content>
|
|
60
|
+
* </ui-combobox>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
import { WebComponent, html, prop, signal, nothing } from '@webjsdev/core';
|
|
64
|
+
import { cn } from '../lib/utils.ts';
|
|
65
|
+
import { positionFloating } from './floating.ts';
|
|
66
|
+
import type { PopoverSide, PopoverAlign } from './popover.ts';
|
|
67
|
+
import { buttonClass } from './button.ts';
|
|
68
|
+
import { inputGroupClass, inputGroupInputClass, inputGroupAddonClass, inputGroupButtonClass } from './input-group.ts';
|
|
69
|
+
|
|
70
|
+
/** The input group around a single combobox's input (the element applies them). */
|
|
71
|
+
export const comboboxInputClass = (): string => 'cn-combobox-input w-auto';
|
|
72
|
+
/** The trigger button (the element applies them). */
|
|
73
|
+
export const comboboxTriggerClass = (): string => 'cn-combobox-trigger';
|
|
74
|
+
/** The trigger's chevron. */
|
|
75
|
+
export const comboboxTriggerIconClass = (): string => 'cn-combobox-trigger-icon pointer-events-none';
|
|
76
|
+
/** The clear button (the element applies them). */
|
|
77
|
+
export const comboboxClearClass = (): string => 'cn-combobox-clear';
|
|
78
|
+
/** The clear button's icon. */
|
|
79
|
+
export const comboboxClearIconClass = (): string => 'cn-combobox-clear-icon pointer-events-none';
|
|
80
|
+
/** The popup's classes (the element applies them). */
|
|
81
|
+
export const comboboxContentClass = (): string =>
|
|
82
|
+
'cn-combobox-content group/combobox-content z-50 max-h-(--available-height) origin-(--transform-origin) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] data-[chips=true]:min-w-(--anchor-width) not-open:hidden';
|
|
83
|
+
/** The list's classes (the element applies them). */
|
|
84
|
+
export const comboboxListClass = (): string => 'cn-combobox-list overflow-y-auto overscroll-contain';
|
|
85
|
+
/** An item's classes (the element applies them). */
|
|
86
|
+
export const comboboxItemClass = (): string =>
|
|
87
|
+
'cn-combobox-item relative flex w-full cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
88
|
+
/** A chosen item's check mark slot. */
|
|
89
|
+
export const comboboxItemIndicatorClass = (): string => 'cn-combobox-item-indicator';
|
|
90
|
+
/** A chosen item's check mark. */
|
|
91
|
+
export const comboboxItemIndicatorIconClass = (): string => 'cn-combobox-item-indicator-icon pointer-events-none';
|
|
92
|
+
/** A group's classes (the element applies them). */
|
|
93
|
+
export const comboboxGroupClass = (): string => 'cn-combobox-group';
|
|
94
|
+
/** A group label's classes (the element applies them). */
|
|
95
|
+
export const comboboxLabelClass = (): string => 'cn-combobox-label';
|
|
96
|
+
/** The empty state's classes (the element applies them). */
|
|
97
|
+
export const comboboxEmptyClass = (): string => 'cn-combobox-empty';
|
|
98
|
+
/** A separator's classes (the element applies them). */
|
|
99
|
+
export const comboboxSeparatorClass = (): string => 'cn-combobox-separator';
|
|
100
|
+
/** The chips box (the element applies them). */
|
|
101
|
+
export const comboboxChipsClass = (): string => 'cn-combobox-chips';
|
|
102
|
+
/** One chip (the element applies them). */
|
|
103
|
+
export const comboboxChipClass = (): string =>
|
|
104
|
+
'cn-combobox-chip has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50';
|
|
105
|
+
/** A chip's remove button (the element applies them). */
|
|
106
|
+
export const comboboxChipRemoveClass = (): string => 'cn-combobox-chip-remove';
|
|
107
|
+
/** A chip's remove icon. */
|
|
108
|
+
export const comboboxChipIndicatorIconClass = (): string => 'cn-combobox-chip-indicator-icon pointer-events-none';
|
|
109
|
+
/** The input inside the chips box (the element applies them). */
|
|
110
|
+
export const comboboxChipInputClass = (): string => 'cn-combobox-chip-input min-w-16 flex-1 outline-none';
|
|
111
|
+
|
|
112
|
+
const ROOT = 'ui-combobox';
|
|
113
|
+
let uid = 0;
|
|
114
|
+
|
|
115
|
+
function X_ICON(cls: string) {
|
|
116
|
+
return html`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class=${cls}><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class UiCombobox extends WebComponent({
|
|
120
|
+
name: String,
|
|
121
|
+
multiple: Boolean,
|
|
122
|
+
disabled: Boolean,
|
|
123
|
+
value: String,
|
|
124
|
+
open: prop(Boolean, { reflect: true }),
|
|
125
|
+
}) {
|
|
126
|
+
// The chosen values (the form's view of `value`).
|
|
127
|
+
readonly #values = signal<string[]>([]);
|
|
128
|
+
readonly #query = signal('');
|
|
129
|
+
readonly highlighted = signal('');
|
|
130
|
+
_id = '';
|
|
131
|
+
_parsed = false;
|
|
132
|
+
|
|
133
|
+
constructor() {
|
|
134
|
+
super();
|
|
135
|
+
this.name = '';
|
|
136
|
+
this.multiple = false;
|
|
137
|
+
this.disabled = false;
|
|
138
|
+
this.value = '';
|
|
139
|
+
this.open = false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
connectedCallback(): void {
|
|
143
|
+
super.connectedCallback?.();
|
|
144
|
+
this._id ||= `ui-combobox-${++uid}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Empty before connect (the server never connects an element), so the
|
|
148
|
+
// served markup carries no `-list` id that every combobox would share.
|
|
149
|
+
get listId(): string | null {
|
|
150
|
+
return this._id ? `${this._id}-list` : null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The initial choice, read from the attribute once.
|
|
154
|
+
_initial(): string[] {
|
|
155
|
+
const v = this.value ?? '';
|
|
156
|
+
if (!v) return [];
|
|
157
|
+
return this.multiple ? v.split(',').map((s) => s.trim()).filter(Boolean) : [v];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
willUpdate(changedProperties: Map<string, unknown>): void {
|
|
161
|
+
super.willUpdate?.(changedProperties);
|
|
162
|
+
if (!this._parsed) {
|
|
163
|
+
this._parsed = true;
|
|
164
|
+
this.#values.set(this._initial());
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
render() {
|
|
169
|
+
const name = this.name;
|
|
170
|
+
return html`<div data-slot="combobox" class="relative" @keydown=${this._onKeyDown} @focusout=${this._onFocusOut}><slot></slot>${name
|
|
171
|
+
? this.#values.get().map((v) => html`<input type="hidden" name=${name} value=${v}>`)
|
|
172
|
+
: ''}</div>`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_own<T extends Element>(selector: string): T[] {
|
|
176
|
+
if (typeof this.querySelectorAll !== 'function') return [];
|
|
177
|
+
return Array.from(this.querySelectorAll<T>(selector)).filter((el) => el.closest(ROOT) === this);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_items(): UiComboboxItem[] {
|
|
181
|
+
return this._own<UiComboboxItem>(`${ROOT}-item`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The text field: the single input, or the input inside the chips box. */
|
|
185
|
+
_input(): HTMLInputElement | null {
|
|
186
|
+
return this.querySelector<HTMLInputElement>('input[data-slot="input-group-control"], input[data-slot="combobox-chip-input"]');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* What the popup sits against: the chips box, else the text field itself, as
|
|
191
|
+
* Base UI's popup anchors to Combobox.Input. Its width is --anchor-width, so
|
|
192
|
+
* the styles' `min-w-[calc(var(--anchor-width)+--spacing(7))]` adds back the
|
|
193
|
+
* trigger button and the list spans the input group, as shadcn's does. (The
|
|
194
|
+
* group as the anchor made the list a button's width wider than the field.)
|
|
195
|
+
*/
|
|
196
|
+
_anchor(): HTMLElement | null {
|
|
197
|
+
return this.querySelector<HTMLElement>('[data-slot="combobox-chips"]')
|
|
198
|
+
?? this.querySelector<HTMLElement>('input[data-slot="input-group-control"]')
|
|
199
|
+
?? this.querySelector<HTMLElement>('[data-slot="input-group"]');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
_panel(): HTMLElement | null {
|
|
203
|
+
return this.querySelector<HTMLElement>('[data-slot="combobox-content"]');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** The label of the item with `value`, else the value itself. */
|
|
207
|
+
labelOf(value: string): string {
|
|
208
|
+
return this._items().find((i) => i.itemValue === value)?.label ?? value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** The items that match the typed text, in order. */
|
|
212
|
+
visibleItems(): UiComboboxItem[] {
|
|
213
|
+
const q = this.#query.get().trim().toLowerCase();
|
|
214
|
+
return this._items().filter((i) => !q || i.label.toLowerCase().includes(q));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_emit(type: string, detail: unknown): void {
|
|
218
|
+
this.dispatchEvent(new CustomEvent(type, { bubbles: true, detail }));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
show(): void {
|
|
222
|
+
if (this.disabled || this.open) return;
|
|
223
|
+
this.open = true;
|
|
224
|
+
this._emit('ui-open-change', { open: true });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
hide(): void {
|
|
228
|
+
if (!this.open) return;
|
|
229
|
+
this.open = false;
|
|
230
|
+
this._emit('ui-open-change', { open: false });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Choose (or, with `multiple`, toggle) the item with `value`. */
|
|
234
|
+
choose(value: string): void {
|
|
235
|
+
const item = this._items().find((i) => i.itemValue === value);
|
|
236
|
+
if (!item || item.disabled) return;
|
|
237
|
+
const input = this._input();
|
|
238
|
+
if (this.multiple) {
|
|
239
|
+
const values = this.#values.get();
|
|
240
|
+
this.#values.set(values.includes(value) ? values.filter((v) => v !== value) : [...values, value]);
|
|
241
|
+
this.#query.set('');
|
|
242
|
+
if (input) input.value = '';
|
|
243
|
+
} else {
|
|
244
|
+
this.#values.set([value]);
|
|
245
|
+
this.#query.set('');
|
|
246
|
+
if (input) input.value = item.label;
|
|
247
|
+
this.hide();
|
|
248
|
+
}
|
|
249
|
+
this._emit('ui-value-change', { value: this.multiple ? [...this.#values.get()] : value });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Remove one chosen value. Not named `remove`: that would override the
|
|
254
|
+
* native Element.remove(), so taking the element out of the page would
|
|
255
|
+
* silently do nothing instead.
|
|
256
|
+
*/
|
|
257
|
+
removeValue(value: string): void {
|
|
258
|
+
const values = this.#values.get();
|
|
259
|
+
if (!values.includes(value)) return;
|
|
260
|
+
const next = values.filter((v) => v !== value);
|
|
261
|
+
this.#values.set(next);
|
|
262
|
+
this._emit('ui-value-change', { value: this.multiple ? [...next] : '' });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Clear every chosen value and the typed text. */
|
|
266
|
+
clear(): void {
|
|
267
|
+
const input = this._input();
|
|
268
|
+
if (input) input.value = '';
|
|
269
|
+
this.#query.set('');
|
|
270
|
+
this.#values.set([]);
|
|
271
|
+
this._emit('ui-value-change', { value: this.multiple ? [] : '' });
|
|
272
|
+
input?.focus();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
_setQuery(text: string): void {
|
|
276
|
+
this.#query.set(text);
|
|
277
|
+
this.show();
|
|
278
|
+
// A new filter highlights its first match.
|
|
279
|
+
const first = this.visibleItems().find((i) => !i.disabled);
|
|
280
|
+
this.highlighted.set(first?.itemValue ?? '');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
updated(changedProperties: Map<string, unknown>): void {
|
|
284
|
+
super.updated?.(changedProperties);
|
|
285
|
+
this._syncParts();
|
|
286
|
+
if (changedProperties.has('open') && changedProperties.get('open') !== undefined) {
|
|
287
|
+
queueMicrotask(() => (this.open ? this._afterOpen() : this._afterClose()));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Push the state into every part.
|
|
292
|
+
_syncParts(): void {
|
|
293
|
+
const visible = new Set(this.visibleItems());
|
|
294
|
+
for (const item of this._items()) {
|
|
295
|
+
item.state?.set({
|
|
296
|
+
visible: visible.has(item),
|
|
297
|
+
selected: this.#values.get().includes(item.itemValue),
|
|
298
|
+
highlighted: this.open && item.itemValue === this.highlighted.get() && visible.has(item),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
for (const g of this._own<UiComboboxGroup>(`${ROOT}-group`)) {
|
|
302
|
+
g.shown?.set(this._items().some((i) => i.closest(`${ROOT}-group`) === g && visible.has(i)));
|
|
303
|
+
}
|
|
304
|
+
const empty = visible.size === 0;
|
|
305
|
+
for (const part of this._own<UiComboboxContent | UiComboboxList>(`${ROOT}-content, ${ROOT}-list`)) part.empty?.set(empty);
|
|
306
|
+
for (const content of this._own<UiComboboxContent>(`${ROOT}-content`)) content.open?.set(this.open);
|
|
307
|
+
for (const field of this._own<UiComboboxInput | UiComboboxChipsInput>(`${ROOT}-input, ${ROOT}-chips-input`)) {
|
|
308
|
+
const h = this._items().find((i) => i.itemValue === this.highlighted.get() && visible.has(i));
|
|
309
|
+
field.state?.set({ open: this.open, activeId: this.open && h ? h.optionId : '', hasValue: this.#values.get().length > 0 });
|
|
310
|
+
}
|
|
311
|
+
for (const chips of this._own<UiComboboxChips>(`${ROOT}-chips`)) chips.chips?.set(this.#values.get().map((v) => ({ value: v, label: this.labelOf(v) })));
|
|
312
|
+
// A single combobox shows its choice in the input until the user types.
|
|
313
|
+
const input = this._input();
|
|
314
|
+
if (input && !this.multiple && !this.open && !this.#query.get()) {
|
|
315
|
+
const first = this.#values.get()[0];
|
|
316
|
+
const label = first ? this.labelOf(first) : '';
|
|
317
|
+
if (input.value !== label && document.activeElement !== input) input.value = label;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
_afterOpen(): void {
|
|
322
|
+
const panel = this._panel() as (HTMLElement & { showPopover?: () => void }) | null;
|
|
323
|
+
const anchor = this._anchor();
|
|
324
|
+
if (!panel || !anchor) return;
|
|
325
|
+
if (typeof panel.showPopover === 'function' && !panel.matches(':popover-open')) panel.showPopover();
|
|
326
|
+
this._reposition();
|
|
327
|
+
document.addEventListener('pointerdown', this._onDocPointerDown, true);
|
|
328
|
+
window.addEventListener('resize', this._reposition);
|
|
329
|
+
if (!this.highlighted.get()) {
|
|
330
|
+
const start = this._items().find((i) => this.#values.get().includes(i.itemValue) && !i.disabled)
|
|
331
|
+
?? this.visibleItems().find((i) => !i.disabled);
|
|
332
|
+
this.highlighted.set(start?.itemValue ?? '');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
_afterClose(): void {
|
|
337
|
+
const panel = this._panel() as (HTMLElement & { hidePopover?: () => void }) | null;
|
|
338
|
+
if (panel && typeof panel.hidePopover === 'function' && panel.matches(':popover-open')) panel.hidePopover();
|
|
339
|
+
document.removeEventListener('pointerdown', this._onDocPointerDown, true);
|
|
340
|
+
window.removeEventListener('resize', this._reposition);
|
|
341
|
+
this.highlighted.set('');
|
|
342
|
+
if (!this.multiple) this.#query.set('');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
_reposition = (): void => {
|
|
346
|
+
const panel = this._panel();
|
|
347
|
+
const anchor = this._anchor();
|
|
348
|
+
const host = this.querySelector(`${ROOT}-content`);
|
|
349
|
+
if (!panel || !anchor || !host) return;
|
|
350
|
+
const a = anchor.getBoundingClientRect();
|
|
351
|
+
panel.style.setProperty('--anchor-width', `${a.width}px`);
|
|
352
|
+
panel.style.setProperty('--available-width', `${window.innerWidth - 16}px`);
|
|
353
|
+
panel.style.setProperty('--available-height', `${Math.max(window.innerHeight - a.bottom, a.top) - 12}px`);
|
|
354
|
+
positionFloating(anchor, panel, {
|
|
355
|
+
side: (host.getAttribute('side') ?? 'bottom') as PopoverSide,
|
|
356
|
+
align: (host.getAttribute('align') ?? 'start') as PopoverAlign,
|
|
357
|
+
sideOffset: Number(host.getAttribute('side-offset') ?? 6),
|
|
358
|
+
alignOffset: Number(host.getAttribute('align-offset') ?? 0),
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
_move(by: number): void {
|
|
363
|
+
const enabled = this.visibleItems().filter((i) => !i.disabled);
|
|
364
|
+
if (!enabled.length) return;
|
|
365
|
+
const at = enabled.findIndex((i) => i.itemValue === this.highlighted.get());
|
|
366
|
+
const next = at < 0 ? (by > 0 ? 0 : enabled.length - 1) : Math.max(0, Math.min(enabled.length - 1, at + by));
|
|
367
|
+
this.highlighted.set(enabled[next].itemValue);
|
|
368
|
+
enabled[next].scrollIntoViewIfShown();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
_onKeyDown = (e: KeyboardEvent): void => {
|
|
372
|
+
const input = this._input();
|
|
373
|
+
if (!input || e.target !== input || e.isComposing) return;
|
|
374
|
+
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
375
|
+
e.preventDefault();
|
|
376
|
+
if (!this.open) { this.show(); return; }
|
|
377
|
+
this._move(e.key === 'ArrowDown' ? 1 : -1);
|
|
378
|
+
} else if (e.key === 'Enter') {
|
|
379
|
+
if (!this.open || !this.highlighted.get()) return;
|
|
380
|
+
e.preventDefault();
|
|
381
|
+
this.choose(this.highlighted.get());
|
|
382
|
+
} else if (e.key === 'Escape') {
|
|
383
|
+
if (!this.open) return;
|
|
384
|
+
e.preventDefault();
|
|
385
|
+
this.hide();
|
|
386
|
+
} else if (e.key === 'Tab') {
|
|
387
|
+
this.hide();
|
|
388
|
+
} else if (e.key === 'Backspace' && this.multiple && !input.value && this.#values.get().length) {
|
|
389
|
+
const values = this.#values.get();
|
|
390
|
+
this.removeValue(values[values.length - 1]);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
_onInput(text: string): void {
|
|
395
|
+
this._setQuery(text);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
_onFocusOut = (e: FocusEvent): void => {
|
|
399
|
+
const next = e.relatedTarget as Node | null;
|
|
400
|
+
if (next && this.contains(next)) return;
|
|
401
|
+
this.hide();
|
|
402
|
+
// Leaving a single combobox puts its choice back in the input.
|
|
403
|
+
if (!this.multiple) {
|
|
404
|
+
this.#query.set('');
|
|
405
|
+
const input = this._input();
|
|
406
|
+
const first = this.#values.get()[0];
|
|
407
|
+
if (input) input.value = first ? this.labelOf(first) : '';
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
_onDocPointerDown = (e: Event): void => {
|
|
412
|
+
if (e.composedPath().includes(this)) return;
|
|
413
|
+
this.hide();
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
UiCombobox.register('ui-combobox');
|
|
417
|
+
|
|
418
|
+
type FieldState = { open: boolean; activeId: string; hasValue: boolean };
|
|
419
|
+
|
|
420
|
+
function rootOf(el: Element): UiCombobox | null {
|
|
421
|
+
return (typeof el.closest === 'function' ? el.closest(ROOT) : null) as UiCombobox | null;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// A part connected after the root's first update (a client render appends
|
|
425
|
+
// children in order) asks the root to push its state again.
|
|
426
|
+
function announce(el: Element): void {
|
|
427
|
+
const root = rootOf(el);
|
|
428
|
+
if (root) queueMicrotask(() => root.requestUpdate?.());
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// --------------------------------------------------------------------------
|
|
432
|
+
// <ui-combobox-input>
|
|
433
|
+
// --------------------------------------------------------------------------
|
|
434
|
+
|
|
435
|
+
export class UiComboboxInput extends WebComponent({
|
|
436
|
+
placeholder: String,
|
|
437
|
+
inputId: prop(String, { attribute: 'input-id' }),
|
|
438
|
+
showTrigger: prop(String, { attribute: 'show-trigger' }),
|
|
439
|
+
showClear: prop(Boolean, { attribute: 'show-clear' }),
|
|
440
|
+
// The field state an author writes on the host belongs on the input, the
|
|
441
|
+
// focusable control, as shadcn passes ComboboxInput's props to its input:
|
|
442
|
+
// `aria-invalid` for the error look and the announcement, and
|
|
443
|
+
// `aria-describedby` for the error text. Observed, so a re-validation that
|
|
444
|
+
// changes them reaches the input.
|
|
445
|
+
invalid: prop(String, { attribute: 'aria-invalid' }),
|
|
446
|
+
describedBy: prop(String, { attribute: 'aria-describedby' }),
|
|
447
|
+
}) {
|
|
448
|
+
readonly state = signal<FieldState>({ open: false, activeId: '', hasValue: false });
|
|
449
|
+
connectedCallback(): void {
|
|
450
|
+
super.connectedCallback?.();
|
|
451
|
+
announce(this);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
constructor() {
|
|
455
|
+
super();
|
|
456
|
+
this.placeholder = '';
|
|
457
|
+
this.inputId = '';
|
|
458
|
+
this.invalid = '';
|
|
459
|
+
this.describedBy = '';
|
|
460
|
+
this.showTrigger = 'true';
|
|
461
|
+
this.showClear = false;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
render() {
|
|
465
|
+
const root = rootOf(this);
|
|
466
|
+
const s = this.state.get();
|
|
467
|
+
const disabled = !!root?.disabled;
|
|
468
|
+
return html`<div data-slot="input-group" class=${cn(inputGroupClass(), comboboxInputClass())}><input
|
|
469
|
+
data-slot="input-group-control"
|
|
470
|
+
id=${this.inputId || nothing}
|
|
471
|
+
type="text"
|
|
472
|
+
role="combobox"
|
|
473
|
+
autocomplete="off"
|
|
474
|
+
aria-autocomplete="list"
|
|
475
|
+
aria-expanded=${s.open ? 'true' : 'false'}
|
|
476
|
+
aria-controls=${root?.listId || nothing}
|
|
477
|
+
aria-activedescendant=${s.activeId || nothing}
|
|
478
|
+
aria-label=${this.getAttribute?.('aria-label') || nothing}
|
|
479
|
+
aria-invalid=${this.invalid === 'true' ? 'true' : nothing}
|
|
480
|
+
aria-describedby=${this.describedBy || nothing}
|
|
481
|
+
placeholder=${this.placeholder || nothing}
|
|
482
|
+
?disabled=${disabled}
|
|
483
|
+
class=${inputGroupInputClass()}
|
|
484
|
+
@input=${(e: Event) => rootOf(this)?._onInput((e.target as HTMLInputElement).value)}
|
|
485
|
+
@click=${() => rootOf(this)?.show()}
|
|
486
|
+
><div data-slot="input-group-addon" data-align="inline-end" class=${inputGroupAddonClass({ align: 'inline-end' })}>${this.showTrigger !== 'false'
|
|
487
|
+
? html`<button
|
|
488
|
+
type="button"
|
|
489
|
+
data-slot="input-group-button"
|
|
490
|
+
tabindex="-1"
|
|
491
|
+
aria-label="Open"
|
|
492
|
+
?disabled=${disabled}
|
|
493
|
+
class=${cn(buttonClass({ variant: 'ghost' }), inputGroupButtonClass({ size: 'icon-xs' }), 'group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent', comboboxTriggerClass())}
|
|
494
|
+
@click=${this._onTrigger}
|
|
495
|
+
><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class=${comboboxTriggerIconClass()}><path d="m6 9 6 6 6-6"></path></svg></button>`
|
|
496
|
+
: ''}${this.showClear && s.hasValue
|
|
497
|
+
? html`<button
|
|
498
|
+
type="button"
|
|
499
|
+
data-slot="combobox-clear"
|
|
500
|
+
aria-label="Clear"
|
|
501
|
+
?disabled=${disabled}
|
|
502
|
+
class=${cn(buttonClass({ variant: 'ghost' }), inputGroupButtonClass({ size: 'icon-xs' }), comboboxClearClass())}
|
|
503
|
+
@click=${() => rootOf(this)?.clear()}
|
|
504
|
+
>${X_ICON(comboboxClearIconClass())}</button>`
|
|
505
|
+
: ''}</div></div>`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
_onTrigger = (): void => {
|
|
509
|
+
const root = rootOf(this);
|
|
510
|
+
if (!root) return;
|
|
511
|
+
root._input()?.focus();
|
|
512
|
+
if (root.open) root.hide();
|
|
513
|
+
else root.show();
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
UiComboboxInput.register('ui-combobox-input');
|
|
517
|
+
|
|
518
|
+
// --------------------------------------------------------------------------
|
|
519
|
+
// <ui-combobox-content> and <ui-combobox-list>
|
|
520
|
+
// --------------------------------------------------------------------------
|
|
521
|
+
|
|
522
|
+
export class UiComboboxContent extends WebComponent {
|
|
523
|
+
readonly open = signal(false);
|
|
524
|
+
readonly empty = signal(false);
|
|
525
|
+
connectedCallback(): void {
|
|
526
|
+
super.connectedCallback?.();
|
|
527
|
+
announce(this);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
constructor() {
|
|
531
|
+
super();
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
render() {
|
|
535
|
+
const chips = !!rootOf(this)?.querySelector?.('[data-slot="combobox-chips"]');
|
|
536
|
+
return html`<div
|
|
537
|
+
data-slot="combobox-content"
|
|
538
|
+
popover="manual"
|
|
539
|
+
data-state=${this.open.get() ? 'open' : 'closed'}
|
|
540
|
+
?data-empty=${this.empty.get()}
|
|
541
|
+
data-chips=${chips ? 'true' : 'false'}
|
|
542
|
+
class=${comboboxContentClass()}
|
|
543
|
+
@pointerdown=${(e: PointerEvent) => { if (!(e.target as Element).closest('input')) e.preventDefault(); }}
|
|
544
|
+
><slot></slot></div>`;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
UiComboboxContent.register('ui-combobox-content');
|
|
548
|
+
|
|
549
|
+
export class UiComboboxList extends WebComponent {
|
|
550
|
+
readonly empty = signal(false);
|
|
551
|
+
connectedCallback(): void {
|
|
552
|
+
super.connectedCallback?.();
|
|
553
|
+
announce(this);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
constructor() {
|
|
557
|
+
super();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
render() {
|
|
561
|
+
const root = rootOf(this);
|
|
562
|
+
return html`<div
|
|
563
|
+
data-slot="combobox-list"
|
|
564
|
+
role="listbox"
|
|
565
|
+
id=${root?.listId || nothing}
|
|
566
|
+
aria-multiselectable=${root?.multiple ? 'true' : nothing}
|
|
567
|
+
?data-empty=${this.empty.get()}
|
|
568
|
+
class=${comboboxListClass()}
|
|
569
|
+
><slot></slot></div>`;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
UiComboboxList.register('ui-combobox-list');
|
|
573
|
+
|
|
574
|
+
// --------------------------------------------------------------------------
|
|
575
|
+
// <ui-combobox-item>
|
|
576
|
+
// --------------------------------------------------------------------------
|
|
577
|
+
|
|
578
|
+
type ItemState = { visible: boolean; selected: boolean; highlighted: boolean };
|
|
579
|
+
|
|
580
|
+
export class UiComboboxItem extends WebComponent({
|
|
581
|
+
value: String,
|
|
582
|
+
disabled: Boolean,
|
|
583
|
+
}) {
|
|
584
|
+
readonly state = signal<ItemState>({ visible: true, selected: false, highlighted: false });
|
|
585
|
+
_id = '';
|
|
586
|
+
|
|
587
|
+
constructor() {
|
|
588
|
+
super();
|
|
589
|
+
this.value = '';
|
|
590
|
+
this.disabled = false;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
connectedCallback(): void {
|
|
594
|
+
super.connectedCallback?.();
|
|
595
|
+
this._id ||= `ui-combobox-item-${++uid}`;
|
|
596
|
+
announce(this);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
get optionId(): string {
|
|
600
|
+
return `${this._id}-option`;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** The item's label: its text. */
|
|
604
|
+
get label(): string {
|
|
605
|
+
const text = this.querySelector?.('[data-slot="combobox-item-text"]')?.textContent ?? this.textContent ?? '';
|
|
606
|
+
return text.trim();
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/** The item's value: its `value` attribute, else its label. */
|
|
610
|
+
get itemValue(): string {
|
|
611
|
+
return this.value || this.label;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
scrollIntoViewIfShown(): void {
|
|
615
|
+
const option = this.querySelector?.<HTMLElement>('[role="option"]');
|
|
616
|
+
if (option && typeof option.scrollIntoView === 'function') option.scrollIntoView({ block: 'nearest' });
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
updated(changedProperties: Map<string, unknown>): void {
|
|
620
|
+
super.updated?.(changedProperties);
|
|
621
|
+
this.hidden = !this.state.get().visible;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
render() {
|
|
625
|
+
const s = this.state.get();
|
|
626
|
+
return html`<div
|
|
627
|
+
data-slot="combobox-item"
|
|
628
|
+
role="option"
|
|
629
|
+
id=${this._id ? this.optionId : nothing}
|
|
630
|
+
aria-selected=${s.selected ? 'true' : 'false'}
|
|
631
|
+
?data-selected=${s.selected}
|
|
632
|
+
?data-highlighted=${s.highlighted}
|
|
633
|
+
aria-disabled=${this.disabled ? 'true' : nothing}
|
|
634
|
+
?data-disabled=${this.disabled}
|
|
635
|
+
class=${comboboxItemClass()}
|
|
636
|
+
@pointermove=${this._onPointerMove}
|
|
637
|
+
@click=${this._onClick}
|
|
638
|
+
><span data-slot="combobox-item-text" class="cn-combobox-item-text"><slot></slot></span><span class=${comboboxItemIndicatorClass()}>${s.selected
|
|
639
|
+
? html`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class=${comboboxItemIndicatorIconClass()}><path d="M20 6 9 17l-5-5"></path></svg>`
|
|
640
|
+
: ''}</span></div>`;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
_onPointerMove = (): void => {
|
|
644
|
+
const root = rootOf(this);
|
|
645
|
+
if (!root || this.disabled || this.state.get().highlighted) return;
|
|
646
|
+
root.highlighted?.set(this.itemValue);
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
_onClick = (): void => {
|
|
650
|
+
rootOf(this)?.choose(this.itemValue);
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
UiComboboxItem.register('ui-combobox-item');
|
|
654
|
+
|
|
655
|
+
// --------------------------------------------------------------------------
|
|
656
|
+
// <ui-combobox-group>, <ui-combobox-label>, <ui-combobox-empty>, <ui-combobox-separator>
|
|
657
|
+
// --------------------------------------------------------------------------
|
|
658
|
+
|
|
659
|
+
export class UiComboboxGroup extends WebComponent {
|
|
660
|
+
readonly shown = signal(true);
|
|
661
|
+
constructor() {
|
|
662
|
+
super();
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
updated(changedProperties: Map<string, unknown>): void {
|
|
666
|
+
super.updated?.(changedProperties);
|
|
667
|
+
this.hidden = !this.shown.get();
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** The group's label, or null on the server, where there is no DOM to query. */
|
|
671
|
+
_label(): Element | null {
|
|
672
|
+
return typeof this.querySelector === 'function' ? this.querySelector('ui-combobox-label [data-slot="combobox-label"]') : null;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
render() {
|
|
676
|
+
const label = this._label();
|
|
677
|
+
return html`<div data-slot="combobox-group" role="group" aria-labelledby=${label?.id || nothing} class=${comboboxGroupClass()}><slot></slot></div>`;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
connectedCallback(): void {
|
|
681
|
+
super.connectedCallback?.();
|
|
682
|
+
// The label renders after the group, so name the group once it has.
|
|
683
|
+
queueMicrotask(() => this.requestUpdate?.());
|
|
684
|
+
announce(this);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
UiComboboxGroup.register('ui-combobox-group');
|
|
688
|
+
|
|
689
|
+
export class UiComboboxLabel extends WebComponent {
|
|
690
|
+
_id = '';
|
|
691
|
+
|
|
692
|
+
connectedCallback(): void {
|
|
693
|
+
this._id ||= `ui-combobox-label-${++uid}`;
|
|
694
|
+
super.connectedCallback?.();
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
render() {
|
|
698
|
+
return html`<div data-slot="combobox-label" id=${this._id || nothing} class=${comboboxLabelClass()}><slot></slot></div>`;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
UiComboboxLabel.register('ui-combobox-label');
|
|
702
|
+
|
|
703
|
+
export class UiComboboxEmpty extends WebComponent {
|
|
704
|
+
connectedCallback(): void {
|
|
705
|
+
super.connectedCallback?.();
|
|
706
|
+
announce(this);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
render() {
|
|
710
|
+
return html`<div data-slot="combobox-empty" class=${comboboxEmptyClass()}><slot></slot></div>`;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
UiComboboxEmpty.register('ui-combobox-empty');
|
|
714
|
+
|
|
715
|
+
export class UiComboboxSeparator extends WebComponent {
|
|
716
|
+
connectedCallback(): void {
|
|
717
|
+
super.connectedCallback?.();
|
|
718
|
+
announce(this);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
render() {
|
|
722
|
+
return html`<div data-slot="combobox-separator" role="separator" class=${comboboxSeparatorClass()}></div>`;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
UiComboboxSeparator.register('ui-combobox-separator');
|
|
726
|
+
|
|
727
|
+
// --------------------------------------------------------------------------
|
|
728
|
+
// <ui-combobox-chips> and <ui-combobox-chips-input>
|
|
729
|
+
// --------------------------------------------------------------------------
|
|
730
|
+
|
|
731
|
+
export class UiComboboxChips extends WebComponent {
|
|
732
|
+
readonly chips = signal<{ value: string; label: string }[]>([]);
|
|
733
|
+
connectedCallback(): void {
|
|
734
|
+
super.connectedCallback?.();
|
|
735
|
+
announce(this);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
constructor() {
|
|
739
|
+
super();
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
render() {
|
|
743
|
+
const root = rootOf(this);
|
|
744
|
+
const disabled = !!root?.disabled;
|
|
745
|
+
return html`<div data-slot="combobox-chips" class=${comboboxChipsClass()} @click=${this._focusInput}>${this.chips.get().map((c) => html`<div
|
|
746
|
+
data-slot="combobox-chip" class=${comboboxChipClass()}
|
|
747
|
+
>${c.label}<button
|
|
748
|
+
type="button"
|
|
749
|
+
data-slot="combobox-chip-remove"
|
|
750
|
+
aria-label=${`Remove ${c.label}`}
|
|
751
|
+
?disabled=${disabled}
|
|
752
|
+
class=${cn(buttonClass({ variant: 'ghost', size: 'icon-xs' }), comboboxChipRemoveClass())}
|
|
753
|
+
@click=${(e: Event) => { e.stopPropagation(); rootOf(this)?.removeValue(c.value); rootOf(this)?._input()?.focus(); }}
|
|
754
|
+
>${X_ICON(comboboxChipIndicatorIconClass())}</button></div>`)}<slot></slot></div>`;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
_focusInput = (e: Event): void => {
|
|
758
|
+
if ((e.target as Element).closest('button')) return;
|
|
759
|
+
rootOf(this)?._input()?.focus();
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
UiComboboxChips.register('ui-combobox-chips');
|
|
763
|
+
|
|
764
|
+
export class UiComboboxChipsInput extends WebComponent({
|
|
765
|
+
placeholder: String,
|
|
766
|
+
inputId: prop(String, { attribute: 'input-id' }),
|
|
767
|
+
}) {
|
|
768
|
+
readonly state = signal<FieldState>({ open: false, activeId: '', hasValue: false });
|
|
769
|
+
connectedCallback(): void {
|
|
770
|
+
super.connectedCallback?.();
|
|
771
|
+
announce(this);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
constructor() {
|
|
775
|
+
super();
|
|
776
|
+
this.placeholder = '';
|
|
777
|
+
this.inputId = '';
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
render() {
|
|
781
|
+
const root = rootOf(this);
|
|
782
|
+
const s = this.state.get();
|
|
783
|
+
return html`<input
|
|
784
|
+
data-slot="combobox-chip-input"
|
|
785
|
+
id=${this.inputId || nothing}
|
|
786
|
+
type="text"
|
|
787
|
+
role="combobox"
|
|
788
|
+
autocomplete="off"
|
|
789
|
+
aria-autocomplete="list"
|
|
790
|
+
aria-expanded=${s.open ? 'true' : 'false'}
|
|
791
|
+
aria-controls=${root?.listId || nothing}
|
|
792
|
+
aria-activedescendant=${s.activeId || nothing}
|
|
793
|
+
aria-label=${this.getAttribute?.('aria-label') || nothing}
|
|
794
|
+
placeholder=${this.placeholder || nothing}
|
|
795
|
+
?disabled=${!!root?.disabled}
|
|
796
|
+
class=${comboboxChipInputClass()}
|
|
797
|
+
@input=${(e: Event) => rootOf(this)?._onInput((e.target as HTMLInputElement).value)}
|
|
798
|
+
@click=${() => rootOf(this)?.show()}
|
|
799
|
+
>`;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
UiComboboxChipsInput.register('ui-combobox-chips-input');
|