@webjsdev/ui 0.3.17 → 0.5.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 +67 -8
- 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 +644 -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 +8 -8
- package/packages/registry/components/field.ts +20 -18
- 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 +7 -4
- 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/dom.ts +3 -4
- 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 +52 -8
- package/packages/registry/registry.json +4056 -72
- 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 +266 -14
- package/src/commands/diff.js +34 -20
- package/src/commands/info.js +7 -0
- package/src/commands/init.js +127 -10
- package/src/commands/list.js +43 -11
- package/src/commands/view.js +33 -5
- package/src/lint/rules/no-restyle.js +1 -1
- package/src/registry/extract.js +194 -5
- 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
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* APG pattern: https://www.w3.org/WAI/ARIA/apg/patterns/menu/
|
|
6
6
|
*
|
|
7
7
|
* shadcn parity:
|
|
8
|
-
* DropdownMenu → <ui-dropdown-menu open>
|
|
9
|
-
* DropdownMenuTrigger → <ui-dropdown-menu-trigger
|
|
8
|
+
* DropdownMenu → <ui-dropdown-menu open trigger>
|
|
9
|
+
* DropdownMenuTrigger → <ui-dropdown-menu-trigger>, or, for a trigger
|
|
10
|
+
* that must be a direct child of something
|
|
11
|
+
* else (a button group's corner rules select
|
|
12
|
+
* direct children), the button itself named by
|
|
13
|
+
* the menu's `trigger="<id>"`
|
|
10
14
|
* DropdownMenuContent → <ui-dropdown-menu-content side align side-offset align-offset>
|
|
11
15
|
* DropdownMenuItem → <ui-dropdown-menu-item variant inset>
|
|
12
16
|
* DropdownMenuCheckboxItem → <ui-dropdown-menu-item type="checkbox" checked>
|
|
@@ -135,42 +139,107 @@
|
|
|
135
139
|
* ```
|
|
136
140
|
*/
|
|
137
141
|
import { WebComponent, html, unsafeHTML, signal, prop } from '@webjsdev/core';
|
|
138
|
-
import { ensureId } from '../lib/utils.ts';
|
|
142
|
+
import { cn, ensureId, takeAuthoredClass } from '../lib/utils.ts';
|
|
139
143
|
import { onBeforeCache } from '../lib/dom.ts';
|
|
140
|
-
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The tag family an element belongs to: `ui-dropdown-menu` here, and the
|
|
147
|
+
* family a subclass names when it reuses these elements under its own tags
|
|
148
|
+
* (context-menu, menubar). Every tag this file looks up is built from it, so
|
|
149
|
+
* a subclass's elements find each other and never a dropdown's.
|
|
150
|
+
*/
|
|
151
|
+
function fam(el: Element): string {
|
|
152
|
+
return (el.constructor as { family?: string }).family ?? 'ui-dropdown-menu';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The data-slot for one part of an element's family: `dropdown-menu-item`, `context-menu-item`. */
|
|
156
|
+
function slot(el: Element, part: string): string {
|
|
157
|
+
return fam(el).replace(/^ui-/, '') + part;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The tag of the element that owns one menu: the family tag itself for a
|
|
162
|
+
* dropdown or a context menu, and `ui-menubar-menu` for a menubar, whose
|
|
163
|
+
* family tag is the bar that holds several menus.
|
|
164
|
+
*/
|
|
165
|
+
function rootTag(el: Element): string {
|
|
166
|
+
return (el.constructor as { rootTag?: string }).rootTag ?? fam(el);
|
|
167
|
+
}
|
|
168
|
+
import { positionFloating } from './floating.ts';
|
|
169
|
+
import type { PopoverSide, PopoverAlign } from './popover.ts';
|
|
141
170
|
|
|
142
171
|
// --------------------------------------------------------------------------
|
|
143
172
|
// Class helpers
|
|
144
173
|
// --------------------------------------------------------------------------
|
|
145
174
|
|
|
146
175
|
export const dropdownMenuContentClass = (): string =>
|
|
147
|
-
'
|
|
176
|
+
'cn-dropdown-menu-content z-50 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden not-open:hidden';
|
|
148
177
|
|
|
149
178
|
export const dropdownMenuItemClass = (): string =>
|
|
150
|
-
|
|
179
|
+
'cn-dropdown-menu-item group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
151
180
|
|
|
152
181
|
export const dropdownMenuCheckboxItemClass = (): string =>
|
|
153
|
-
|
|
182
|
+
'cn-dropdown-menu-checkbox-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
154
183
|
|
|
155
184
|
export const dropdownMenuRadioItemClass = (): string =>
|
|
156
|
-
|
|
185
|
+
'cn-dropdown-menu-radio-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
157
186
|
|
|
158
187
|
export const dropdownMenuLabelClass = (): string =>
|
|
159
|
-
'
|
|
188
|
+
'cn-dropdown-menu-label';
|
|
160
189
|
|
|
161
|
-
export const dropdownMenuSeparatorClass = (): string => '-
|
|
190
|
+
export const dropdownMenuSeparatorClass = (): string => 'cn-dropdown-menu-separator';
|
|
162
191
|
|
|
163
192
|
export const dropdownMenuShortcutClass = (): string =>
|
|
164
|
-
'
|
|
193
|
+
'cn-dropdown-menu-shortcut';
|
|
165
194
|
|
|
166
195
|
export const dropdownMenuSubTriggerClass = (): string =>
|
|
167
|
-
|
|
196
|
+
'cn-dropdown-menu-sub-trigger flex cursor-default items-center select-none outline-hidden [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
168
197
|
|
|
169
198
|
export const dropdownMenuSubContentClass = (): string =>
|
|
170
|
-
'
|
|
199
|
+
'cn-dropdown-menu-sub-content z-50 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden not-open:hidden';
|
|
200
|
+
|
|
201
|
+
const dropdownMenuItemIndicatorClass = (): string =>
|
|
202
|
+
'cn-dropdown-menu-item-indicator pointer-events-none';
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* The classes one menu family paints its parts with. Every element reads its
|
|
206
|
+
* classes through its family's table, so context-menu and menubar render the
|
|
207
|
+
* same elements under their own `cn-context-menu-*` / `cn-menubar-*` names,
|
|
208
|
+
* which is what each style keys on.
|
|
209
|
+
*/
|
|
210
|
+
export interface MenuClasses {
|
|
211
|
+
content(): string;
|
|
212
|
+
item(): string;
|
|
213
|
+
checkboxItem(): string;
|
|
214
|
+
radioItem(): string;
|
|
215
|
+
/** A checkable item's indicator; menubar styles the checkbox and radio ones apart. */
|
|
216
|
+
itemIndicator(type?: 'checkbox' | 'radio'): string;
|
|
217
|
+
label(): string;
|
|
218
|
+
separator(): string;
|
|
219
|
+
shortcut(): string;
|
|
220
|
+
subTrigger(): string;
|
|
221
|
+
subContent(): string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const DROPDOWN_MENU_CLASSES: MenuClasses = {
|
|
225
|
+
content: dropdownMenuContentClass,
|
|
226
|
+
item: dropdownMenuItemClass,
|
|
227
|
+
checkboxItem: dropdownMenuCheckboxItemClass,
|
|
228
|
+
radioItem: dropdownMenuRadioItemClass,
|
|
229
|
+
itemIndicator: dropdownMenuItemIndicatorClass,
|
|
230
|
+
label: dropdownMenuLabelClass,
|
|
231
|
+
separator: dropdownMenuSeparatorClass,
|
|
232
|
+
shortcut: dropdownMenuShortcutClass,
|
|
233
|
+
subTrigger: dropdownMenuSubTriggerClass,
|
|
234
|
+
subContent: dropdownMenuSubContentClass,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
function cls(el: Element): MenuClasses {
|
|
238
|
+
return (el.constructor as { classes?: MenuClasses }).classes ?? DROPDOWN_MENU_CLASSES;
|
|
239
|
+
}
|
|
171
240
|
|
|
172
241
|
const CHEVRON_RIGHT_SVG =
|
|
173
|
-
'<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" class="
|
|
242
|
+
'<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" class="cn-rtl-flip ms-auto size-4 rtl:rotate-180" aria-hidden="true"><polyline points="9 18 15 12 9 6"></polyline></svg>';
|
|
174
243
|
|
|
175
244
|
// Checked-state indicators for a checkbox / radio item. Decorative: the state
|
|
176
245
|
// they draw is announced from aria-checked, so both are aria-hidden.
|
|
@@ -195,11 +264,15 @@ const ENABLED_MENU_ITEM = `${MENU_ITEM}:not([data-disabled])`;
|
|
|
195
264
|
export class UiDropdownMenu extends WebComponent({
|
|
196
265
|
open: prop(Boolean, { reflect: true }),
|
|
197
266
|
}) {
|
|
267
|
+
static family = 'ui-dropdown-menu';
|
|
268
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
198
269
|
_typeBuffer = '';
|
|
199
270
|
_typeBufferTimer: number | undefined;
|
|
200
271
|
|
|
201
272
|
_docClickHandler = (e: MouseEvent): void => this._onDocClick(e);
|
|
202
273
|
_docPointerDownHandler = (e: Event): void => this._onDocPointerDown(e);
|
|
274
|
+
_externalClick = (e: MouseEvent): void => this.toggle(e);
|
|
275
|
+
_wiredExternal: HTMLElement | null = null;
|
|
203
276
|
_keyHandler = (e: KeyboardEvent): void => this._onKeyDown(e);
|
|
204
277
|
_resizeHandler = (): void => this._reposition();
|
|
205
278
|
|
|
@@ -213,10 +286,60 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
213
286
|
disconnectedCallback(): void {
|
|
214
287
|
if (this.open) this._teardown();
|
|
215
288
|
this._disposeBeforeCache?.();
|
|
289
|
+
this._wiredExternal?.removeEventListener('click', this._externalClick);
|
|
290
|
+
this._wiredExternal = null;
|
|
216
291
|
super.disconnectedCallback?.();
|
|
217
292
|
}
|
|
218
293
|
|
|
219
|
-
|
|
294
|
+
/**
|
|
295
|
+
* The control a `trigger="<id>"` attribute names, when the menu has no
|
|
296
|
+
* <ui-dropdown-menu-trigger> child. shadcn's trigger is `asChild`, so the
|
|
297
|
+
* button is wherever the author put it, typically the direct child of a
|
|
298
|
+
* button group, whose corner rules select direct children. A wrapper there
|
|
299
|
+
* would be the child instead of the button, so the menu can name a button
|
|
300
|
+
* that lives outside it.
|
|
301
|
+
*/
|
|
302
|
+
_external(): HTMLElement | null {
|
|
303
|
+
const id = typeof this.getAttribute === 'function' ? this.getAttribute('trigger') : null;
|
|
304
|
+
if (!id || typeof document === 'undefined') return null;
|
|
305
|
+
if (this.querySelector(`${fam(this)}-trigger`)) return null;
|
|
306
|
+
return document.getElementById(id);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* The element the panel is positioned against: the control itself, as
|
|
311
|
+
* Radix's asChild trigger is, never the `-trigger` wrapper, which is a block
|
|
312
|
+
* and would lend the panel a whole row's width and start edge.
|
|
313
|
+
*/
|
|
314
|
+
_anchor(): HTMLElement | null {
|
|
315
|
+
return this._triggerControl();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Inside the menu for an outside-click check: the menu itself, or its named trigger. */
|
|
319
|
+
_owns(n: EventTarget): boolean {
|
|
320
|
+
return n === this || (!!this._wiredExternal && n === this._wiredExternal);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
_wireExternal(): void {
|
|
324
|
+
const control = this._external();
|
|
325
|
+
if (control === this._wiredExternal) return;
|
|
326
|
+
this._wiredExternal?.removeEventListener('click', this._externalClick);
|
|
327
|
+
control?.addEventListener('click', this._externalClick);
|
|
328
|
+
this._wiredExternal = control;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Whether the menu was last opened by a pointer. A click a keyboard
|
|
333
|
+
* produced (Enter or Space on the trigger) has `detail` 0; a real press
|
|
334
|
+
* counts its clicks. As in shadcn, a pointer open focuses the panel and
|
|
335
|
+
* highlights nothing, and a keyboard open moves to the first item.
|
|
336
|
+
*/
|
|
337
|
+
_pointerOpen = false;
|
|
338
|
+
|
|
339
|
+
toggle(e?: MouseEvent): void {
|
|
340
|
+
this._pointerOpen = !!e && e.detail > 0;
|
|
341
|
+
this.open = !this.open;
|
|
342
|
+
}
|
|
220
343
|
show(): void { this.open = true; }
|
|
221
344
|
hide(): void { this.open = false; }
|
|
222
345
|
|
|
@@ -245,7 +368,7 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
245
368
|
}
|
|
246
369
|
|
|
247
370
|
render() {
|
|
248
|
-
return html`<div data-slot
|
|
371
|
+
return html`<div data-slot=${rootTag(this).replace(/^ui-/, '')} data-state=${this.open ? 'open' : 'closed'}>
|
|
249
372
|
<slot></slot>
|
|
250
373
|
</div>`;
|
|
251
374
|
}
|
|
@@ -263,7 +386,10 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
263
386
|
// render, so the trigger button and the menu are not in place at
|
|
264
387
|
// connect. Defer to the next frame, when the projection has run.
|
|
265
388
|
if (typeof requestAnimationFrame === 'function') {
|
|
266
|
-
requestAnimationFrame(() =>
|
|
389
|
+
requestAnimationFrame(() => {
|
|
390
|
+
this._wireExternal();
|
|
391
|
+
this._wireAria();
|
|
392
|
+
});
|
|
267
393
|
}
|
|
268
394
|
// Close (and tear down) before a back/forward snapshot so the menu does not
|
|
269
395
|
// restore open (#766). Closing the root also hides any open submenu.
|
|
@@ -286,8 +412,8 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
286
412
|
// the menu, and the menu is labelled back by the trigger. Done at runtime
|
|
287
413
|
// because the menu is JS-driven (never shown without script).
|
|
288
414
|
_triggerControl(): HTMLElement | null {
|
|
289
|
-
const trigger = this.querySelector(
|
|
290
|
-
if (!trigger) return
|
|
415
|
+
const trigger = this.querySelector(`${fam(this)}-trigger`);
|
|
416
|
+
if (!trigger) return this._external();
|
|
291
417
|
return (
|
|
292
418
|
trigger.querySelector<HTMLElement>('button, [role="button"], a[href], [tabindex]') ??
|
|
293
419
|
(trigger as HTMLElement)
|
|
@@ -295,7 +421,7 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
295
421
|
}
|
|
296
422
|
|
|
297
423
|
_menuEl(): HTMLElement | null {
|
|
298
|
-
return this.querySelector(
|
|
424
|
+
return this.querySelector(`${fam(this)}-content [role="menu"]`);
|
|
299
425
|
}
|
|
300
426
|
|
|
301
427
|
_wireAria(): void {
|
|
@@ -317,19 +443,19 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
317
443
|
// menuitem that opens it, with that menuitem pointing back via aria-controls.
|
|
318
444
|
// Only the root panel was wired, so every submenu shipped as an unnamed menu.
|
|
319
445
|
_wireSubmenuAria(): void {
|
|
320
|
-
this.querySelectorAll<HTMLElement>(
|
|
446
|
+
this.querySelectorAll<HTMLElement>(`${fam(this)}-sub`).forEach((sub) => {
|
|
321
447
|
// NOT `:scope >`: the sub renders its own wrapper div with a <slot>, so the
|
|
322
448
|
// trigger and content are grandchildren, not direct children. Match on the
|
|
323
449
|
// nearest enclosing sub instead, which also keeps a NESTED submenu's nodes
|
|
324
450
|
// from being wired to its outer sub.
|
|
325
451
|
const owns = (el: Element | null): boolean =>
|
|
326
|
-
!!el && el.closest(
|
|
452
|
+
!!el && el.closest(`${fam(this)}-sub`) === sub;
|
|
327
453
|
const trigger = Array.from(
|
|
328
|
-
sub.querySelectorAll<HTMLElement>(
|
|
329
|
-
).find((el) => owns(el.closest(
|
|
454
|
+
sub.querySelectorAll<HTMLElement>(`${fam(this)}-sub-trigger ${MENU_ITEM}`),
|
|
455
|
+
).find((el) => owns(el.closest(`${fam(this)}-sub-trigger`)));
|
|
330
456
|
const panel = Array.from(
|
|
331
|
-
sub.querySelectorAll<HTMLElement>(
|
|
332
|
-
).find((el) => owns(el.closest(
|
|
457
|
+
sub.querySelectorAll<HTMLElement>(`${fam(this)}-sub-content [role="menu"]`),
|
|
458
|
+
).find((el) => owns(el.closest(`${fam(this)}-sub-content`)));
|
|
333
459
|
if (!trigger || !panel) return;
|
|
334
460
|
trigger.setAttribute('aria-controls', ensureId(panel, 'ui-submenu'));
|
|
335
461
|
if (!panel.hasAttribute('aria-label') && !panel.hasAttribute('aria-labelledby')) {
|
|
@@ -339,7 +465,7 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
339
465
|
}
|
|
340
466
|
|
|
341
467
|
_content(): HTMLElement | null {
|
|
342
|
-
return this.querySelector(
|
|
468
|
+
return this.querySelector(`${fam(this)}-content [popover]`);
|
|
343
469
|
}
|
|
344
470
|
|
|
345
471
|
_syncContentPopover(content: HTMLElement): void {
|
|
@@ -353,16 +479,24 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
353
479
|
else if (!this.open && p.matches(':popover-open')) p.hidePopover();
|
|
354
480
|
}
|
|
355
481
|
|
|
482
|
+
/**
|
|
483
|
+
* The panel's offsets when its content element names none: shadcn's
|
|
484
|
+
* dropdown sits 4px off its trigger, a menubar menu 8px off and 4px back.
|
|
485
|
+
*/
|
|
486
|
+
static placement = { sideOffset: 4, alignOffset: 0 };
|
|
487
|
+
|
|
356
488
|
_reposition(): void {
|
|
357
|
-
const
|
|
489
|
+
const placement = (this.constructor as typeof UiDropdownMenu).placement;
|
|
490
|
+
const trigger = this._anchor();
|
|
358
491
|
const content = this._content();
|
|
359
|
-
const host = this.querySelector<HTMLElement>(
|
|
492
|
+
const host = this.querySelector<HTMLElement>(`${fam(this)}-content`);
|
|
360
493
|
if (!trigger || !content || !host) return;
|
|
361
494
|
positionFloating(trigger, content, {
|
|
362
495
|
side: (host.getAttribute('side') ?? 'bottom') as PopoverSide,
|
|
363
496
|
align: (host.getAttribute('align') ?? 'start') as PopoverAlign,
|
|
364
|
-
sideOffset: Number(host.getAttribute('side-offset') ??
|
|
365
|
-
alignOffset: Number(host.getAttribute('align-offset') ??
|
|
497
|
+
sideOffset: Number(host.getAttribute('side-offset') ?? placement.sideOffset),
|
|
498
|
+
alignOffset: Number(host.getAttribute('align-offset') ?? placement.alignOffset),
|
|
499
|
+
radix: fam(this).slice(3),
|
|
366
500
|
});
|
|
367
501
|
}
|
|
368
502
|
|
|
@@ -374,8 +508,12 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
374
508
|
window.addEventListener('resize', this._resizeHandler);
|
|
375
509
|
window.addEventListener('scroll', this._resizeHandler, true);
|
|
376
510
|
queueMicrotask(() => {
|
|
511
|
+
if (this._pointerOpen) {
|
|
512
|
+
this._menuEl()?.focus();
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
377
515
|
const first = this.querySelector<HTMLElement>(
|
|
378
|
-
|
|
516
|
+
`${fam(this)}-item:not([data-disabled]) ${MENU_ITEM}`,
|
|
379
517
|
);
|
|
380
518
|
first?.focus();
|
|
381
519
|
});
|
|
@@ -388,7 +526,7 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
388
526
|
this._focusWasInsideAtPointerDown = false;
|
|
389
527
|
window.removeEventListener('resize', this._resizeHandler);
|
|
390
528
|
window.removeEventListener('scroll', this._resizeHandler, true);
|
|
391
|
-
this.querySelectorAll<UiDropdownMenuSub>(
|
|
529
|
+
this.querySelectorAll<UiDropdownMenuSub>(`${fam(this)}-sub[open]`).forEach(
|
|
392
530
|
(sub) => sub.hide(),
|
|
393
531
|
);
|
|
394
532
|
}
|
|
@@ -402,13 +540,13 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
402
540
|
|
|
403
541
|
_onDocPointerDown(e: Event): void {
|
|
404
542
|
if (!this.open) return;
|
|
405
|
-
if (e.composedPath().some((n) => n
|
|
543
|
+
if (e.composedPath().some((n) => this._owns(n))) return;
|
|
406
544
|
this._focusWasInsideAtPointerDown = this._focusIsInside();
|
|
407
545
|
}
|
|
408
546
|
|
|
409
547
|
_onDocClick(e: MouseEvent): void {
|
|
410
548
|
if (!this.open) return;
|
|
411
|
-
if (e.composedPath().some((n) => n
|
|
549
|
+
if (e.composedPath().some((n) => this._owns(n))) return;
|
|
412
550
|
// An outside click dismisses the menu, and it is still a close of a
|
|
413
551
|
// popover="manual" panel, so it owes the same focus care as Escape: leaving
|
|
414
552
|
// focus on an item that is about to become display:none drops it to <body>.
|
|
@@ -440,10 +578,10 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
440
578
|
// submenu first"). Focus on the sub-trigger itself is focus in the ROOT
|
|
441
579
|
// panel, so that case closes the whole menu, which is why this reads the
|
|
442
580
|
// panel rather than walking up to any open <ui-dropdown-menu-sub>.
|
|
443
|
-
const subContent = context?.closest(
|
|
444
|
-
const sub = subContent?.closest(
|
|
581
|
+
const subContent = context?.closest(`${fam(this)}-sub-content`);
|
|
582
|
+
const sub = subContent?.closest(`${fam(this)}-sub`) as UiDropdownMenuSub | null;
|
|
445
583
|
if (sub) {
|
|
446
|
-
sub.querySelector<HTMLElement>(
|
|
584
|
+
sub.querySelector<HTMLElement>(`${fam(this)}-sub-trigger ${MENU_ITEM}`)?.focus();
|
|
447
585
|
sub.hide();
|
|
448
586
|
return;
|
|
449
587
|
}
|
|
@@ -476,7 +614,8 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
476
614
|
items[(idx + 1) % items.length].focus();
|
|
477
615
|
} else if (e.key === 'ArrowUp') {
|
|
478
616
|
e.preventDefault();
|
|
479
|
-
|
|
617
|
+
// From the panel itself (a pointer open), ArrowUp goes to the last item.
|
|
618
|
+
items[idx < 0 ? items.length - 1 : (idx - 1 + items.length) % items.length].focus();
|
|
480
619
|
} else if (e.key === 'Home') {
|
|
481
620
|
e.preventDefault();
|
|
482
621
|
items[0].focus();
|
|
@@ -485,10 +624,10 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
485
624
|
items[items.length - 1].focus();
|
|
486
625
|
} else if (e.key === 'ArrowRight') {
|
|
487
626
|
// Open submenu owned by the focused sub-trigger and move focus into it.
|
|
488
|
-
const subTrigger = active?.closest(
|
|
627
|
+
const subTrigger = active?.closest(`${fam(this)}-sub-trigger`);
|
|
489
628
|
if (subTrigger) {
|
|
490
629
|
e.preventDefault();
|
|
491
|
-
const sub = subTrigger.closest(
|
|
630
|
+
const sub = subTrigger.closest(`${fam(this)}-sub`) as UiDropdownMenuSub | null;
|
|
492
631
|
// The sub owns the open-then-focus sequencing: its panel is
|
|
493
632
|
// popover="manual" and only becomes visible a microtask later, so
|
|
494
633
|
// focusing from here races the reveal and loses (see the method).
|
|
@@ -496,11 +635,11 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
496
635
|
}
|
|
497
636
|
} else if (e.key === 'ArrowLeft') {
|
|
498
637
|
// Inside a sub-content: close the submenu and refocus its trigger.
|
|
499
|
-
if (context.closest(
|
|
638
|
+
if (context.closest(`${fam(this)}-sub-content`)) {
|
|
500
639
|
e.preventDefault();
|
|
501
|
-
const sub = context.closest(
|
|
640
|
+
const sub = context.closest(`${fam(this)}-sub`) as UiDropdownMenuSub | null;
|
|
502
641
|
const trigger = sub?.querySelector<HTMLElement>(
|
|
503
|
-
|
|
642
|
+
`${fam(this)}-sub-trigger ${MENU_ITEM}`,
|
|
504
643
|
);
|
|
505
644
|
trigger?.focus();
|
|
506
645
|
sub?.hide();
|
|
@@ -516,8 +655,8 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
516
655
|
// too, so preventing Space unconditionally would swallow it there with
|
|
517
656
|
// nothing to handle it, and the user could not type a space into their own
|
|
518
657
|
// input. Bail before touching the event when the focus is not an item.
|
|
519
|
-
const subTrigger = active?.closest(
|
|
520
|
-
const activeItem = active?.closest(
|
|
658
|
+
const subTrigger = active?.closest(`${fam(this)}-sub-trigger`);
|
|
659
|
+
const activeItem = active?.closest(`${fam(this)}-item`) as UiDropdownMenuItem | null;
|
|
521
660
|
if (!subTrigger && !activeItem) return;
|
|
522
661
|
// Space while a typeahead search is in flight belongs to the SEARCH, or a
|
|
523
662
|
// multi-word item is unreachable past its first word ("Status bar" could
|
|
@@ -533,7 +672,7 @@ export class UiDropdownMenu extends WebComponent({
|
|
|
533
672
|
if (subTrigger) {
|
|
534
673
|
// Same as ArrowRight on a sub-trigger: open it and move focus in.
|
|
535
674
|
if (!subTrigger.hasAttribute('data-disabled')) {
|
|
536
|
-
const sub = subTrigger.closest(
|
|
675
|
+
const sub = subTrigger.closest(`${fam(this)}-sub`) as UiDropdownMenuSub | null;
|
|
537
676
|
sub?.openAndFocusFirstItem();
|
|
538
677
|
}
|
|
539
678
|
return;
|
|
@@ -566,14 +705,16 @@ UiDropdownMenu.register('ui-dropdown-menu');
|
|
|
566
705
|
// --------------------------------------------------------------------------
|
|
567
706
|
|
|
568
707
|
export class UiDropdownMenuTrigger extends WebComponent {
|
|
708
|
+
static family = 'ui-dropdown-menu';
|
|
709
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
569
710
|
render() {
|
|
570
711
|
return html`<div
|
|
571
|
-
data-slot
|
|
712
|
+
data-slot=${slot(this, '-trigger')}
|
|
572
713
|
@click=${this._onClick}
|
|
573
714
|
><slot></slot></div>`;
|
|
574
715
|
}
|
|
575
716
|
|
|
576
|
-
_onClick = (): void => (this.closest(
|
|
717
|
+
_onClick = (e: MouseEvent): void => (this.closest(rootTag(this)) as UiDropdownMenu | null)?.toggle(e);
|
|
577
718
|
}
|
|
578
719
|
UiDropdownMenuTrigger.register('ui-dropdown-menu-trigger');
|
|
579
720
|
|
|
@@ -582,13 +723,25 @@ UiDropdownMenuTrigger.register('ui-dropdown-menu-trigger');
|
|
|
582
723
|
// --------------------------------------------------------------------------
|
|
583
724
|
|
|
584
725
|
export class UiDropdownMenuContent extends WebComponent {
|
|
726
|
+
static family = 'ui-dropdown-menu';
|
|
727
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
728
|
+
_authored: string | null = null;
|
|
729
|
+
|
|
730
|
+
// The class an author writes on the content is shadcn's `className` on
|
|
731
|
+
// DropdownMenuContent, which lands on the menu panel (a `w-40`, say), so it
|
|
732
|
+
// moves from this host onto the panel. `text-start` undoes the legacy HTML
|
|
733
|
+
// `align` attribute: `align="end"` here means "align the panel's end with
|
|
734
|
+
// the trigger's", but browsers also map it to `text-align: end`, which every
|
|
735
|
+
// label and item in the menu would inherit.
|
|
585
736
|
render() {
|
|
737
|
+
this._authored = takeAuthoredClass(this, null);
|
|
586
738
|
return html`<div
|
|
587
|
-
data-slot
|
|
739
|
+
data-slot=${slot(this, '-content')}
|
|
588
740
|
role="menu"
|
|
589
741
|
aria-orientation="vertical"
|
|
590
742
|
popover="manual"
|
|
591
|
-
|
|
743
|
+
tabindex="-1"
|
|
744
|
+
class=${cn(cls(this).content(), 'text-start', this._authored)}
|
|
592
745
|
><slot></slot></div>`;
|
|
593
746
|
}
|
|
594
747
|
}
|
|
@@ -609,11 +762,13 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
609
762
|
checked: prop(Boolean, { reflect: true }),
|
|
610
763
|
value: prop(String, { reflect: true }),
|
|
611
764
|
}) {
|
|
765
|
+
static family = 'ui-dropdown-menu';
|
|
766
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
612
767
|
// Keyboard / pointer highlight state for the own-rendered menuitem. A
|
|
613
768
|
// local signal bound with ?data-highlighted keeps the highlight in the
|
|
614
769
|
// declarative template instead of an imperative setAttribute on
|
|
615
770
|
// e.currentTarget (the lit-idiomatic form).
|
|
616
|
-
#highlighted = signal(false);
|
|
771
|
+
readonly #highlighted = signal(false);
|
|
617
772
|
|
|
618
773
|
constructor() {
|
|
619
774
|
super();
|
|
@@ -645,7 +800,7 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
645
800
|
// shapes differ by the indicator anyway.
|
|
646
801
|
if (checkbox || radio) {
|
|
647
802
|
return html`<div
|
|
648
|
-
data-slot=${
|
|
803
|
+
data-slot=${slot(this, `-${this.type}-item`)}
|
|
649
804
|
role=${checkbox ? 'menuitemcheckbox' : 'menuitemradio'}
|
|
650
805
|
tabindex="-1"
|
|
651
806
|
data-variant=${this.variant}
|
|
@@ -655,17 +810,17 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
655
810
|
aria-checked=${String(this.checked)}
|
|
656
811
|
data-state=${this.checked ? 'checked' : 'unchecked'}
|
|
657
812
|
?data-highlighted=${this.#highlighted.get()}
|
|
658
|
-
class=${checkbox ?
|
|
813
|
+
class=${checkbox ? cls(this).checkboxItem() : cls(this).radioItem()}
|
|
659
814
|
@click=${this._onClick}
|
|
660
815
|
@pointerenter=${this._onPointerEnter}
|
|
661
816
|
@focus=${this._onFocus}
|
|
662
817
|
@blur=${this._onBlur}
|
|
663
818
|
><span
|
|
664
|
-
class
|
|
819
|
+
class=${cls(this).itemIndicator(checkbox ? 'checkbox' : 'radio')}
|
|
665
820
|
>${this.checked ? unsafeHTML(radio ? RADIO_DOT_SVG : CHECK_SVG) : ''}</span><slot></slot></div>`;
|
|
666
821
|
}
|
|
667
822
|
return html`<div
|
|
668
|
-
data-slot
|
|
823
|
+
data-slot=${slot(this, '-item')}
|
|
669
824
|
role="menuitem"
|
|
670
825
|
tabindex="-1"
|
|
671
826
|
data-variant=${this.variant}
|
|
@@ -673,7 +828,7 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
673
828
|
?data-disabled=${disabled}
|
|
674
829
|
aria-disabled=${disabled ? 'true' : 'false'}
|
|
675
830
|
?data-highlighted=${this.#highlighted.get()}
|
|
676
|
-
class=${
|
|
831
|
+
class=${cls(this).item()}
|
|
677
832
|
@click=${this._onClick}
|
|
678
833
|
@pointerenter=${this._onPointerEnter}
|
|
679
834
|
@focus=${this._onFocus}
|
|
@@ -702,7 +857,7 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
702
857
|
}),
|
|
703
858
|
);
|
|
704
859
|
if (!proceed) return;
|
|
705
|
-
(this.closest(
|
|
860
|
+
(this.closest(rootTag(this)) as UiDropdownMenu | null)?._closeAndRestoreFocus();
|
|
706
861
|
}
|
|
707
862
|
|
|
708
863
|
// The radio set is the nearest <ui-dropdown-menu-group>, which is the APG
|
|
@@ -711,9 +866,9 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
711
866
|
_radioScope(): Element | null {
|
|
712
867
|
if (typeof this.closest !== 'function') return null;
|
|
713
868
|
return (
|
|
714
|
-
this.closest(
|
|
715
|
-
this.closest(
|
|
716
|
-
this.closest(
|
|
869
|
+
this.closest(`${fam(this)}-group`) ??
|
|
870
|
+
this.closest(`${fam(this)}-sub-content`) ??
|
|
871
|
+
this.closest(`${fam(this)}-content`)
|
|
717
872
|
);
|
|
718
873
|
}
|
|
719
874
|
|
|
@@ -727,7 +882,7 @@ export class UiDropdownMenuItem extends WebComponent({
|
|
|
727
882
|
// is unreflected, so an item configured through the property alone would
|
|
728
883
|
// be invisible to an attribute query and survive as a second checked item.
|
|
729
884
|
// The scope re-check keeps a nested group's items out of this set.
|
|
730
|
-
Array.from(scope.querySelectorAll<UiDropdownMenuItem>(
|
|
885
|
+
Array.from(scope.querySelectorAll<UiDropdownMenuItem>(`${fam(this)}-item`))
|
|
731
886
|
.filter((it) => it.type === 'radio' && it._radioScope() === scope)
|
|
732
887
|
.forEach((it) => {
|
|
733
888
|
it.checked = it === this;
|
|
@@ -755,6 +910,8 @@ UiDropdownMenuItem.register('ui-dropdown-menu-item');
|
|
|
755
910
|
// --------------------------------------------------------------------------
|
|
756
911
|
|
|
757
912
|
export class UiDropdownMenuLabel extends WebComponent({ inset: Boolean }) {
|
|
913
|
+
static family = 'ui-dropdown-menu';
|
|
914
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
758
915
|
constructor() {
|
|
759
916
|
super();
|
|
760
917
|
this.inset = false;
|
|
@@ -762,9 +919,9 @@ export class UiDropdownMenuLabel extends WebComponent({ inset: Boolean }) {
|
|
|
762
919
|
|
|
763
920
|
render() {
|
|
764
921
|
return html`<div
|
|
765
|
-
data-slot
|
|
922
|
+
data-slot=${slot(this, '-label')}
|
|
766
923
|
?data-inset=${this.inset}
|
|
767
|
-
class=${
|
|
924
|
+
class=${cls(this).label()}
|
|
768
925
|
><slot></slot></div>`;
|
|
769
926
|
}
|
|
770
927
|
}
|
|
@@ -775,11 +932,13 @@ UiDropdownMenuLabel.register('ui-dropdown-menu-label');
|
|
|
775
932
|
// --------------------------------------------------------------------------
|
|
776
933
|
|
|
777
934
|
export class UiDropdownMenuSeparator extends WebComponent {
|
|
935
|
+
static family = 'ui-dropdown-menu';
|
|
936
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
778
937
|
render() {
|
|
779
938
|
return html`<div
|
|
780
|
-
data-slot
|
|
939
|
+
data-slot=${slot(this, '-separator')}
|
|
781
940
|
role="separator"
|
|
782
|
-
class=${
|
|
941
|
+
class=${cls(this).separator()}
|
|
783
942
|
></div>`;
|
|
784
943
|
}
|
|
785
944
|
}
|
|
@@ -790,10 +949,16 @@ UiDropdownMenuSeparator.register('ui-dropdown-menu-separator');
|
|
|
790
949
|
// --------------------------------------------------------------------------
|
|
791
950
|
|
|
792
951
|
export class UiDropdownMenuShortcut extends WebComponent {
|
|
952
|
+
static family = 'ui-dropdown-menu';
|
|
953
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
954
|
+
// The span is the item's flex item, as shadcn's shortcut is, so the styles'
|
|
955
|
+
// `ms-auto` pushes it to the end of the row. The host's box is turned off
|
|
956
|
+
// through its style, which the server serves.
|
|
793
957
|
render() {
|
|
958
|
+
if (typeof this.getAttribute === 'function' && !this.getAttribute('style')) this.setAttribute('style', 'display: contents');
|
|
794
959
|
return html`<span
|
|
795
|
-
data-slot
|
|
796
|
-
class=${
|
|
960
|
+
data-slot=${slot(this, '-shortcut')}
|
|
961
|
+
class=${cls(this).shortcut()}
|
|
797
962
|
><slot></slot></span>`;
|
|
798
963
|
}
|
|
799
964
|
}
|
|
@@ -804,6 +969,8 @@ UiDropdownMenuShortcut.register('ui-dropdown-menu-shortcut');
|
|
|
804
969
|
// --------------------------------------------------------------------------
|
|
805
970
|
|
|
806
971
|
export class UiDropdownMenuGroup extends WebComponent {
|
|
972
|
+
static family = 'ui-dropdown-menu';
|
|
973
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
807
974
|
// role="group", NOT role="radiogroup". radiogroup is the grouping role for
|
|
808
975
|
// role="radio"; the grouping role ARIA specifies for menuitemradio is plain
|
|
809
976
|
// group, so a radio set inside this element is already correctly grouped.
|
|
@@ -822,20 +989,20 @@ export class UiDropdownMenuGroup extends WebComponent {
|
|
|
822
989
|
const label = attr('aria-label');
|
|
823
990
|
if (labelledBy) {
|
|
824
991
|
return html`<div
|
|
825
|
-
data-slot
|
|
992
|
+
data-slot=${slot(this, '-group')}
|
|
826
993
|
role="group"
|
|
827
994
|
aria-labelledby=${labelledBy}
|
|
828
995
|
><slot></slot></div>`;
|
|
829
996
|
}
|
|
830
997
|
if (label) {
|
|
831
998
|
return html`<div
|
|
832
|
-
data-slot
|
|
999
|
+
data-slot=${slot(this, '-group')}
|
|
833
1000
|
role="group"
|
|
834
1001
|
aria-label=${label}
|
|
835
1002
|
><slot></slot></div>`;
|
|
836
1003
|
}
|
|
837
1004
|
return html`<div
|
|
838
|
-
data-slot
|
|
1005
|
+
data-slot=${slot(this, '-group')}
|
|
839
1006
|
role="group"
|
|
840
1007
|
><slot></slot></div>`;
|
|
841
1008
|
}
|
|
@@ -849,6 +1016,8 @@ UiDropdownMenuGroup.register('ui-dropdown-menu-group');
|
|
|
849
1016
|
export class UiDropdownMenuSub extends WebComponent({
|
|
850
1017
|
open: prop(Boolean, { reflect: true }),
|
|
851
1018
|
}) {
|
|
1019
|
+
static family = 'ui-dropdown-menu';
|
|
1020
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
852
1021
|
_closeTimer: number | undefined;
|
|
853
1022
|
|
|
854
1023
|
constructor() {
|
|
@@ -883,7 +1052,7 @@ export class UiDropdownMenuSub extends WebComponent({
|
|
|
883
1052
|
|
|
884
1053
|
_panelIsOpen(): boolean {
|
|
885
1054
|
const panel = this.querySelector<HTMLElement & { showPopover?: () => void }>(
|
|
886
|
-
|
|
1055
|
+
`${fam(this)}-sub-content [popover]`,
|
|
887
1056
|
);
|
|
888
1057
|
// Gate on showPopover, not just on matches, like the two sibling call sites.
|
|
889
1058
|
// `:popover-open` is an unknown pseudo-class where the Popover API is
|
|
@@ -898,13 +1067,13 @@ export class UiDropdownMenuSub extends WebComponent({
|
|
|
898
1067
|
if (!this._focusFirstOnOpen) return;
|
|
899
1068
|
this._focusFirstOnOpen = false;
|
|
900
1069
|
this.querySelector<HTMLElement>(
|
|
901
|
-
|
|
1070
|
+
`${fam(this)}-sub-content ${ENABLED_MENU_ITEM}`,
|
|
902
1071
|
)?.focus();
|
|
903
1072
|
}
|
|
904
1073
|
|
|
905
1074
|
render() {
|
|
906
1075
|
return html`<div
|
|
907
|
-
data-slot
|
|
1076
|
+
data-slot=${slot(this, '-sub')}
|
|
908
1077
|
data-state=${this.open ? 'open' : 'closed'}
|
|
909
1078
|
@pointerenter=${this._cancelCloseHandler}
|
|
910
1079
|
@pointerleave=${this._scheduleCloseHandler}
|
|
@@ -918,7 +1087,7 @@ export class UiDropdownMenuSub extends WebComponent({
|
|
|
918
1087
|
}
|
|
919
1088
|
|
|
920
1089
|
_afterRender(): void {
|
|
921
|
-
const subContent = this.querySelector<HTMLElement>(
|
|
1090
|
+
const subContent = this.querySelector<HTMLElement>(`${fam(this)}-sub-content [popover]`);
|
|
922
1091
|
if (subContent) {
|
|
923
1092
|
const p = subContent as HTMLElement & {
|
|
924
1093
|
showPopover?: () => void;
|
|
@@ -963,24 +1132,27 @@ export class UiDropdownMenuSub extends WebComponent({
|
|
|
963
1132
|
|
|
964
1133
|
_position(): void {
|
|
965
1134
|
const trigger = this.querySelector<HTMLElement>(
|
|
966
|
-
|
|
1135
|
+
`${fam(this)}-sub-trigger [role="menuitem"]`,
|
|
967
1136
|
);
|
|
968
1137
|
const content = this.querySelector<HTMLElement>(
|
|
969
|
-
|
|
1138
|
+
`${fam(this)}-sub-content [popover]`,
|
|
970
1139
|
);
|
|
971
|
-
const contentHost = this.querySelector<HTMLElement>(
|
|
1140
|
+
const contentHost = this.querySelector<HTMLElement>(`${fam(this)}-sub-content`);
|
|
972
1141
|
if (!trigger || !content || !contentHost) return;
|
|
973
1142
|
positionFloating(trigger, content, {
|
|
974
1143
|
side: (contentHost.getAttribute('side') ?? 'right') as PopoverSide,
|
|
975
1144
|
align: (contentHost.getAttribute('align') ?? 'start') as PopoverAlign,
|
|
976
1145
|
sideOffset: Number(contentHost.getAttribute('side-offset') ?? -4),
|
|
977
1146
|
alignOffset: Number(contentHost.getAttribute('align-offset') ?? 0),
|
|
1147
|
+
radix: fam(this).slice(3),
|
|
978
1148
|
});
|
|
979
1149
|
}
|
|
980
1150
|
}
|
|
981
1151
|
UiDropdownMenuSub.register('ui-dropdown-menu-sub');
|
|
982
1152
|
|
|
983
1153
|
export class UiDropdownMenuSubTrigger extends WebComponent({ inset: Boolean }) {
|
|
1154
|
+
static family = 'ui-dropdown-menu';
|
|
1155
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
984
1156
|
constructor() {
|
|
985
1157
|
super();
|
|
986
1158
|
this.inset = false;
|
|
@@ -989,14 +1161,14 @@ export class UiDropdownMenuSubTrigger extends WebComponent({ inset: Boolean }) {
|
|
|
989
1161
|
// SSR-safe: linkedom doesn't implement closest() on custom elements.
|
|
990
1162
|
_sub(): UiDropdownMenuSub | null {
|
|
991
1163
|
if (typeof this.closest !== 'function') return null;
|
|
992
|
-
return this.closest(
|
|
1164
|
+
return this.closest(`${fam(this)}-sub`) as UiDropdownMenuSub | null;
|
|
993
1165
|
}
|
|
994
1166
|
|
|
995
1167
|
render() {
|
|
996
1168
|
const open = !!this._sub()?.open;
|
|
997
1169
|
const disabled = typeof this.hasAttribute === 'function' && this.hasAttribute('data-disabled');
|
|
998
1170
|
return html`<div
|
|
999
|
-
data-slot
|
|
1171
|
+
data-slot=${slot(this, '-sub-trigger')}
|
|
1000
1172
|
role="menuitem"
|
|
1001
1173
|
tabindex="-1"
|
|
1002
1174
|
aria-haspopup="menu"
|
|
@@ -1005,7 +1177,7 @@ export class UiDropdownMenuSubTrigger extends WebComponent({ inset: Boolean }) {
|
|
|
1005
1177
|
data-state=${open ? 'open' : 'closed'}
|
|
1006
1178
|
?data-inset=${this.inset}
|
|
1007
1179
|
?data-disabled=${disabled}
|
|
1008
|
-
class=${
|
|
1180
|
+
class=${cls(this).subTrigger()}
|
|
1009
1181
|
@click=${this._onClick}
|
|
1010
1182
|
@pointerenter=${this._onPointerEnter}
|
|
1011
1183
|
><slot></slot>${unsafeHTML(CHEVRON_RIGHT_SVG)}</div>`;
|
|
@@ -1031,13 +1203,20 @@ export class UiDropdownMenuSubTrigger extends WebComponent({ inset: Boolean }) {
|
|
|
1031
1203
|
UiDropdownMenuSubTrigger.register('ui-dropdown-menu-sub-trigger');
|
|
1032
1204
|
|
|
1033
1205
|
export class UiDropdownMenuSubContent extends WebComponent {
|
|
1206
|
+
static family = 'ui-dropdown-menu';
|
|
1207
|
+
static classes: MenuClasses = DROPDOWN_MENU_CLASSES;
|
|
1208
|
+
_authored: string | null = null;
|
|
1209
|
+
|
|
1210
|
+
// As on the content: shadcn's className on the sub-content lands on the
|
|
1211
|
+
// submenu panel, so the class written on this host moves there.
|
|
1034
1212
|
render() {
|
|
1213
|
+
this._authored = takeAuthoredClass(this, null);
|
|
1035
1214
|
return html`<div
|
|
1036
|
-
data-slot
|
|
1215
|
+
data-slot=${slot(this, '-sub-content')}
|
|
1037
1216
|
role="menu"
|
|
1038
1217
|
aria-orientation="vertical"
|
|
1039
1218
|
popover="manual"
|
|
1040
|
-
class=${
|
|
1219
|
+
class=${cn(cls(this).subContent(), this._authored)}
|
|
1041
1220
|
><slot></slot></div>`;
|
|
1042
1221
|
}
|
|
1043
1222
|
}
|