@hypoth-ui/cli 0.0.1 → 0.1.1
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/LICENSE +21 -0
- package/README.md +19 -115
- package/dist/{add-PDBC4JTE.js → add-V5PW73GC.js} +29 -17
- package/dist/{chunk-5LTQ2XVL.js → chunk-27CLUUVC.js} +0 -2
- package/dist/{chunk-YPKFYE45.js → chunk-NWIRSZUQ.js} +6 -13
- package/dist/{chunk-GJ6JOQ3Q.js → chunk-PBK72SJJ.js} +1 -1
- package/dist/{diff-BQEXG7HU.js → diff-776UATCA.js} +2 -2
- package/dist/index.js +5 -5
- package/dist/{init-7AZXYAPJ.js → init-GDU2PW7K.js} +10 -13
- package/dist/{list-X6ZLM2NQ.js → list-XDP5I537.js} +3 -3
- package/package.json +16 -12
- package/registry/components.json +1820 -206
- package/templates/accordion/index.tsx +266 -0
- package/templates/accordion/wc/accordion-content.ts +113 -0
- package/templates/accordion/wc/accordion-item.ts +111 -0
- package/templates/accordion/wc/accordion-trigger.ts +105 -0
- package/templates/accordion/wc/accordion.ts +213 -0
- package/templates/accordion/wc/index.ts +12 -0
- package/templates/alert/index.tsx +177 -0
- package/templates/alert/wc/alert.ts +167 -0
- package/templates/alert/wc/index.ts +1 -0
- package/templates/alert-dialog/index.tsx +360 -0
- package/templates/alert-dialog/wc/alert-dialog-action.ts +43 -0
- package/templates/alert-dialog/wc/alert-dialog-cancel.ts +43 -0
- package/templates/alert-dialog/wc/alert-dialog-content.ts +42 -0
- package/templates/alert-dialog/wc/alert-dialog-description.ts +34 -0
- package/templates/alert-dialog/wc/alert-dialog-footer.ts +25 -0
- package/templates/alert-dialog/wc/alert-dialog-header.ts +25 -0
- package/templates/alert-dialog/wc/alert-dialog-title.ts +34 -0
- package/templates/alert-dialog/wc/alert-dialog-trigger.ts +46 -0
- package/templates/alert-dialog/wc/alert-dialog.ts +302 -0
- package/templates/alert-dialog/wc/index.ts +13 -0
- package/templates/aspect-ratio/index.tsx +50 -0
- package/templates/aspect-ratio/wc/aspect-ratio.ts +78 -0
- package/templates/aspect-ratio/wc/index.ts +5 -0
- package/templates/avatar/avatar-group.tsx +88 -0
- package/templates/avatar/avatar.tsx +124 -0
- package/templates/avatar/index.tsx +33 -0
- package/templates/avatar/wc/avatar-group.ts +112 -0
- package/templates/avatar/wc/avatar.ts +184 -0
- package/templates/avatar/wc/index.ts +5 -0
- package/templates/badge/index.tsx +140 -0
- package/templates/badge/wc/badge.ts +119 -0
- package/templates/badge/wc/index.ts +9 -0
- package/templates/breadcrumb/index.tsx +157 -0
- package/templates/breadcrumb/wc/breadcrumb-item.ts +30 -0
- package/templates/breadcrumb/wc/breadcrumb-link.ts +70 -0
- package/templates/breadcrumb/wc/breadcrumb-list.ts +30 -0
- package/templates/breadcrumb/wc/breadcrumb-page.ts +32 -0
- package/templates/breadcrumb/wc/breadcrumb-separator.ts +31 -0
- package/templates/breadcrumb/wc/breadcrumb.ts +55 -0
- package/templates/breadcrumb/wc/index.ts +10 -0
- package/templates/button/button.tsx +119 -0
- package/templates/button/index.ts +1 -0
- package/templates/button/wc/button.ts +169 -0
- package/templates/calendar/index.tsx +149 -0
- package/templates/calendar/wc/calendar.ts +316 -0
- package/templates/calendar/wc/index.ts +4 -0
- package/templates/card/index.tsx +108 -0
- package/templates/card/wc/card-content.ts +25 -0
- package/templates/card/wc/card-footer.ts +25 -0
- package/templates/card/wc/card-header.ts +25 -0
- package/templates/card/wc/card.ts +43 -0
- package/templates/card/wc/index.ts +8 -0
- package/templates/checkbox/checkbox.tsx +85 -0
- package/templates/checkbox/wc/checkbox.ts +247 -0
- package/templates/collapsible/index.tsx +172 -0
- package/templates/collapsible/wc/collapsible-content.ts +97 -0
- package/templates/collapsible/wc/collapsible-trigger.ts +39 -0
- package/templates/collapsible/wc/collapsible.ts +143 -0
- package/templates/collapsible/wc/index.ts +7 -0
- package/templates/combobox/combobox-content.tsx +141 -0
- package/templates/combobox/combobox-context.ts +36 -0
- package/templates/combobox/combobox-empty.tsx +38 -0
- package/templates/combobox/combobox-input.tsx +159 -0
- package/templates/combobox/combobox-loading.tsx +38 -0
- package/templates/combobox/combobox-option.tsx +99 -0
- package/templates/combobox/combobox-root.tsx +207 -0
- package/templates/combobox/combobox-tag.tsx +62 -0
- package/templates/combobox/index.ts +62 -0
- package/templates/combobox/wc/combobox-content.ts +97 -0
- package/templates/combobox/wc/combobox-input.ts +134 -0
- package/templates/combobox/wc/combobox-option.ts +111 -0
- package/templates/combobox/wc/combobox-tag.ts +103 -0
- package/templates/combobox/wc/combobox.ts +981 -0
- package/templates/combobox/wc/index.ts +5 -0
- package/templates/command/index.tsx +279 -0
- package/templates/command/wc/command-empty.ts +24 -0
- package/templates/command/wc/command-group.ts +60 -0
- package/templates/command/wc/command-input.ts +136 -0
- package/templates/command/wc/command-item.ts +78 -0
- package/templates/command/wc/command-list.ts +103 -0
- package/templates/command/wc/command-loading.ts +24 -0
- package/templates/command/wc/command-separator.ts +23 -0
- package/templates/command/wc/command.ts +176 -0
- package/templates/context-menu/index.tsx +262 -0
- package/templates/context-menu/wc/context-menu-content.ts +41 -0
- package/templates/context-menu/wc/context-menu-item.ts +83 -0
- package/templates/context-menu/wc/context-menu-label.ts +30 -0
- package/templates/context-menu/wc/context-menu-separator.ts +28 -0
- package/templates/context-menu/wc/context-menu.ts +324 -0
- package/templates/context-menu/wc/index.ts +9 -0
- package/templates/data-table/index.tsx +263 -0
- package/templates/data-table/wc/data-table.ts +405 -0
- package/templates/data-table/wc/index.ts +10 -0
- package/templates/date-picker/date-picker-calendar.tsx +352 -0
- package/templates/date-picker/date-picker-content.tsx +121 -0
- package/templates/date-picker/date-picker-context.ts +46 -0
- package/templates/date-picker/date-picker-root.tsx +201 -0
- package/templates/date-picker/date-picker-trigger.tsx +95 -0
- package/templates/date-picker/index.ts +44 -0
- package/templates/date-picker/wc/date-picker-calendar.ts +457 -0
- package/templates/date-picker/wc/date-picker.ts +592 -0
- package/templates/date-picker/wc/date-utils.ts +467 -0
- package/templates/date-picker/wc/index.ts +3 -0
- package/templates/dialog/dialog-close.tsx +57 -0
- package/templates/dialog/dialog-content.tsx +106 -0
- package/templates/dialog/dialog-context.ts +24 -0
- package/templates/dialog/dialog-description.tsx +51 -0
- package/templates/dialog/dialog-root.tsx +104 -0
- package/templates/dialog/dialog-title.tsx +38 -0
- package/templates/dialog/dialog-trigger.tsx +94 -0
- package/templates/dialog/index.ts +52 -0
- package/templates/dialog/wc/dialog-content.ts +59 -0
- package/templates/dialog/wc/dialog-description.ts +58 -0
- package/templates/dialog/wc/dialog-title.ts +56 -0
- package/templates/dialog/wc/dialog.ts +411 -0
- package/templates/drawer/index.tsx +263 -0
- package/templates/drawer/wc/drawer-content.ts +150 -0
- package/templates/drawer/wc/drawer-description.ts +34 -0
- package/templates/drawer/wc/drawer-footer.ts +25 -0
- package/templates/drawer/wc/drawer-header.ts +25 -0
- package/templates/drawer/wc/drawer-title.ts +34 -0
- package/templates/drawer/wc/drawer.ts +348 -0
- package/templates/drawer/wc/index.ts +10 -0
- package/templates/dropdown-menu/index.tsx +454 -0
- package/templates/dropdown-menu/wc/dropdown-menu-checkbox-item.ts +93 -0
- package/templates/dropdown-menu/wc/dropdown-menu-content.ts +43 -0
- package/templates/dropdown-menu/wc/dropdown-menu-item.ts +85 -0
- package/templates/dropdown-menu/wc/dropdown-menu-label.ts +31 -0
- package/templates/dropdown-menu/wc/dropdown-menu-radio-group.ts +80 -0
- package/templates/dropdown-menu/wc/dropdown-menu-radio-item.ts +101 -0
- package/templates/dropdown-menu/wc/dropdown-menu-separator.ts +28 -0
- package/templates/dropdown-menu/wc/dropdown-menu.ts +358 -0
- package/templates/dropdown-menu/wc/index.ts +12 -0
- package/templates/field/field-description.tsx +39 -0
- package/templates/field/field-error.tsx +37 -0
- package/templates/field/field.tsx +46 -0
- package/templates/field/index.ts +4 -0
- package/templates/field/label.tsx +40 -0
- package/templates/field/wc/field-description.ts +42 -0
- package/templates/field/wc/field-error.ts +46 -0
- package/templates/field/wc/field.ts +210 -0
- package/templates/field/wc/label.ts +54 -0
- package/templates/file-upload/file-upload-context.ts +26 -0
- package/templates/file-upload/file-upload-dropzone.tsx +111 -0
- package/templates/file-upload/file-upload-input.tsx +86 -0
- package/templates/file-upload/file-upload-item.tsx +105 -0
- package/templates/file-upload/file-upload-root.tsx +115 -0
- package/templates/file-upload/index.ts +50 -0
- package/templates/file-upload/wc/file-upload.ts +380 -0
- package/templates/file-upload/wc/index.ts +1 -0
- package/templates/hover-card/index.tsx +203 -0
- package/templates/hover-card/wc/hover-card-content.ts +50 -0
- package/templates/hover-card/wc/hover-card.ts +382 -0
- package/templates/hover-card/wc/index.ts +6 -0
- package/templates/icon/icon.tsx +76 -0
- package/templates/icon/wc/icon-adapter.ts +108 -0
- package/templates/icon/wc/icon.ts +161 -0
- package/templates/input/input.tsx +130 -0
- package/templates/input/wc/input.ts +216 -0
- package/templates/layout/app-shell.tsx +177 -0
- package/templates/layout/box.tsx +53 -0
- package/templates/layout/center.tsx +42 -0
- package/templates/layout/container.tsx +43 -0
- package/templates/layout/flow.tsx +83 -0
- package/templates/layout/grid.tsx +79 -0
- package/templates/layout/index.ts +33 -0
- package/templates/layout/inline.tsx +16 -0
- package/templates/layout/page.tsx +43 -0
- package/templates/layout/section.tsx +39 -0
- package/templates/layout/spacer.tsx +30 -0
- package/templates/layout/split.tsx +47 -0
- package/templates/layout/stack.tsx +16 -0
- package/templates/layout/wc/app-shell.ts +58 -0
- package/templates/layout/wc/box.ts +117 -0
- package/templates/layout/wc/center.ts +78 -0
- package/templates/layout/wc/container.ts +77 -0
- package/templates/layout/wc/flow.ts +149 -0
- package/templates/layout/wc/footer.ts +57 -0
- package/templates/layout/wc/grid.ts +142 -0
- package/templates/layout/wc/header.ts +57 -0
- package/templates/layout/wc/index.ts +41 -0
- package/templates/layout/wc/main.ts +46 -0
- package/templates/layout/wc/page.ts +81 -0
- package/templates/layout/wc/section.ts +65 -0
- package/templates/layout/wc/spacer.ts +77 -0
- package/templates/layout/wc/split.ts +94 -0
- package/templates/layout/wc/wrap.ts +93 -0
- package/templates/layout/wrap.tsx +46 -0
- package/templates/link/link.tsx +109 -0
- package/templates/link/wc/link.ts +124 -0
- package/templates/list/index.tsx +55 -0
- package/templates/list/list-item.tsx +117 -0
- package/templates/list/list.tsx +115 -0
- package/templates/list/wc/index.ts +5 -0
- package/templates/list/wc/list-item.ts +127 -0
- package/templates/list/wc/list.ts +114 -0
- package/templates/menu/index.ts +49 -0
- package/templates/menu/menu-content.tsx +109 -0
- package/templates/menu/menu-context.ts +17 -0
- package/templates/menu/menu-item.tsx +108 -0
- package/templates/menu/menu-label.tsx +32 -0
- package/templates/menu/menu-root.tsx +108 -0
- package/templates/menu/menu-separator.tsx +24 -0
- package/templates/menu/menu-trigger.tsx +104 -0
- package/templates/menu/wc/menu-content.ts +67 -0
- package/templates/menu/wc/menu-item.ts +109 -0
- package/templates/menu/wc/menu.ts +449 -0
- package/templates/navigation-menu/index.tsx +328 -0
- package/templates/navigation-menu/wc/index.ts +12 -0
- package/templates/navigation-menu/wc/navigation-menu-content.ts +30 -0
- package/templates/navigation-menu/wc/navigation-menu-indicator.ts +30 -0
- package/templates/navigation-menu/wc/navigation-menu-item.ts +60 -0
- package/templates/navigation-menu/wc/navigation-menu-link.ts +97 -0
- package/templates/navigation-menu/wc/navigation-menu-list.ts +30 -0
- package/templates/navigation-menu/wc/navigation-menu-trigger.ts +110 -0
- package/templates/navigation-menu/wc/navigation-menu-viewport.ts +85 -0
- package/templates/navigation-menu/wc/navigation-menu.ts +272 -0
- package/templates/number-input/index.ts +46 -0
- package/templates/number-input/number-input-context.ts +38 -0
- package/templates/number-input/number-input-decrement.tsx +53 -0
- package/templates/number-input/number-input-field.tsx +93 -0
- package/templates/number-input/number-input-increment.tsx +53 -0
- package/templates/number-input/number-input-root.tsx +137 -0
- package/templates/number-input/wc/index.ts +1 -0
- package/templates/number-input/wc/number-input.ts +283 -0
- package/templates/pagination/index.tsx +198 -0
- package/templates/pagination/wc/index.ts +11 -0
- package/templates/pagination/wc/pagination-content.ts +30 -0
- package/templates/pagination/wc/pagination-ellipsis.ts +28 -0
- package/templates/pagination/wc/pagination-item.ts +30 -0
- package/templates/pagination/wc/pagination-link.ts +76 -0
- package/templates/pagination/wc/pagination-next.ts +69 -0
- package/templates/pagination/wc/pagination-previous.ts +69 -0
- package/templates/pagination/wc/pagination.ts +156 -0
- package/templates/pin-input/index.ts +39 -0
- package/templates/pin-input/pin-input-context.ts +30 -0
- package/templates/pin-input/pin-input-field.tsx +186 -0
- package/templates/pin-input/pin-input-root.tsx +120 -0
- package/templates/pin-input/wc/index.ts +1 -0
- package/templates/pin-input/wc/pin-input.ts +259 -0
- package/templates/popover/popover.tsx +121 -0
- package/templates/popover/wc/popover-content.ts +66 -0
- package/templates/popover/wc/popover.ts +343 -0
- package/templates/progress/index.tsx +117 -0
- package/templates/progress/wc/index.ts +4 -0
- package/templates/progress/wc/progress.ts +174 -0
- package/templates/radio/radio.tsx +43 -0
- package/templates/radio/wc/radio-group.ts +261 -0
- package/templates/radio/wc/radio.ts +145 -0
- package/templates/scroll-area/index.tsx +144 -0
- package/templates/scroll-area/wc/index.ts +8 -0
- package/templates/scroll-area/wc/scroll-area-scrollbar.ts +143 -0
- package/templates/scroll-area/wc/scroll-area-thumb.ts +225 -0
- package/templates/scroll-area/wc/scroll-area-viewport.ts +120 -0
- package/templates/scroll-area/wc/scroll-area.ts +63 -0
- package/templates/select/index.ts +57 -0
- package/templates/select/select-content.tsx +243 -0
- package/templates/select/select-context.ts +30 -0
- package/templates/select/select-group.tsx +53 -0
- package/templates/select/select-label.tsx +34 -0
- package/templates/select/select-option.tsx +97 -0
- package/templates/select/select-root.tsx +153 -0
- package/templates/select/select-separator.tsx +27 -0
- package/templates/select/select-trigger.tsx +112 -0
- package/templates/select/select-value.tsx +48 -0
- package/templates/select/wc/index.ts +6 -0
- package/templates/select/wc/select-content.ts +89 -0
- package/templates/select/wc/select-group.ts +82 -0
- package/templates/select/wc/select-label.ts +49 -0
- package/templates/select/wc/select-option.ts +111 -0
- package/templates/select/wc/select-trigger.ts +101 -0
- package/templates/select/wc/select.ts +840 -0
- package/templates/separator/index.tsx +49 -0
- package/templates/separator/wc/index.ts +5 -0
- package/templates/separator/wc/separator.ts +60 -0
- package/templates/sheet/index.tsx +291 -0
- package/templates/sheet/wc/index.ts +12 -0
- package/templates/sheet/wc/sheet-close.ts +43 -0
- package/templates/sheet/wc/sheet-content.ts +47 -0
- package/templates/sheet/wc/sheet-description.ts +34 -0
- package/templates/sheet/wc/sheet-footer.ts +25 -0
- package/templates/sheet/wc/sheet-header.ts +25 -0
- package/templates/sheet/wc/sheet-overlay.ts +23 -0
- package/templates/sheet/wc/sheet-title.ts +34 -0
- package/templates/sheet/wc/sheet.ts +336 -0
- package/templates/skeleton/index.tsx +131 -0
- package/templates/skeleton/wc/index.ts +10 -0
- package/templates/skeleton/wc/skeleton.ts +107 -0
- package/templates/slider/index.ts +41 -0
- package/templates/slider/slider-context.ts +36 -0
- package/templates/slider/slider-range.tsx +59 -0
- package/templates/slider/slider-root.tsx +166 -0
- package/templates/slider/slider-thumb.tsx +213 -0
- package/templates/slider/slider-track.tsx +113 -0
- package/templates/slider/wc/index.ts +1 -0
- package/templates/slider/wc/slider.ts +465 -0
- package/templates/spinner/spinner.tsx +64 -0
- package/templates/spinner/wc/spinner.ts +70 -0
- package/templates/stepper/index.tsx +230 -0
- package/templates/stepper/wc/index.ts +12 -0
- package/templates/stepper/wc/stepper-content.ts +30 -0
- package/templates/stepper/wc/stepper-description.ts +25 -0
- package/templates/stepper/wc/stepper-indicator.ts +30 -0
- package/templates/stepper/wc/stepper-item.ts +55 -0
- package/templates/stepper/wc/stepper-separator.ts +29 -0
- package/templates/stepper/wc/stepper-title.ts +25 -0
- package/templates/stepper/wc/stepper-trigger.ts +67 -0
- package/templates/stepper/wc/stepper.ts +164 -0
- package/templates/switch/switch.tsx +90 -0
- package/templates/switch/wc/switch.ts +228 -0
- package/templates/table/body.tsx +21 -0
- package/templates/table/cell.tsx +44 -0
- package/templates/table/head.tsx +112 -0
- package/templates/table/header.tsx +21 -0
- package/templates/table/index.tsx +93 -0
- package/templates/table/root.tsx +82 -0
- package/templates/table/row.tsx +36 -0
- package/templates/table/wc/index.ts +9 -0
- package/templates/table/wc/table-body.ts +32 -0
- package/templates/table/wc/table-cell.ts +58 -0
- package/templates/table/wc/table-head.ts +129 -0
- package/templates/table/wc/table-header.ts +32 -0
- package/templates/table/wc/table-row.ts +50 -0
- package/templates/table/wc/table.ts +93 -0
- package/templates/tabs/index.tsx +222 -0
- package/templates/tabs/wc/index.ts +8 -0
- package/templates/tabs/wc/tabs-content.ts +82 -0
- package/templates/tabs/wc/tabs-list.ts +56 -0
- package/templates/tabs/wc/tabs-trigger.ts +136 -0
- package/templates/tabs/wc/tabs.ts +202 -0
- package/templates/tag/index.tsx +186 -0
- package/templates/tag/wc/index.ts +4 -0
- package/templates/tag/wc/tag.ts +166 -0
- package/templates/text/text.tsx +100 -0
- package/templates/text/wc/text.ts +94 -0
- package/templates/textarea/textarea.tsx +134 -0
- package/templates/textarea/wc/textarea.ts +280 -0
- package/templates/time-picker/index.ts +42 -0
- package/templates/time-picker/time-picker-context.ts +28 -0
- package/templates/time-picker/time-picker-root.tsx +113 -0
- package/templates/time-picker/time-picker-segment.tsx +91 -0
- package/templates/time-picker/wc/index.ts +1 -0
- package/templates/time-picker/wc/time-picker.ts +221 -0
- package/templates/toast/index.tsx +71 -0
- package/templates/toast/provider.tsx +228 -0
- package/templates/toast/toast.tsx +142 -0
- package/templates/toast/use-toast.ts +89 -0
- package/templates/toast/wc/index.ts +15 -0
- package/templates/toast/wc/toast-controller.ts +282 -0
- package/templates/toast/wc/toast-provider.ts +161 -0
- package/templates/toast/wc/toast.ts +165 -0
- package/templates/tooltip/tooltip.tsx +62 -0
- package/templates/tooltip/wc/tooltip-content.ts +64 -0
- package/templates/tooltip/wc/tooltip.ts +289 -0
- package/templates/tree/index.tsx +60 -0
- package/templates/tree/tree-item.tsx +131 -0
- package/templates/tree/tree.tsx +138 -0
- package/templates/tree/wc/index.ts +11 -0
- package/templates/tree/wc/tree-item.ts +273 -0
- package/templates/tree/wc/tree-utils.ts +143 -0
- package/templates/tree/wc/tree.ts +139 -0
- package/templates/visually-hidden/visually-hidden.tsx +45 -0
- package/templates/visually-hidden/wc/visually-hidden.ts +64 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenu compound component exports.
|
|
3
|
+
*
|
|
4
|
+
* NavigationMenu provides mega-menu style navigation with smooth transitions.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { NavigationMenu } from "@/components/ui";
|
|
9
|
+
*
|
|
10
|
+
* <NavigationMenu.Root>
|
|
11
|
+
* <NavigationMenu.List>
|
|
12
|
+
* <NavigationMenu.Item value="products">
|
|
13
|
+
* <NavigationMenu.Trigger>Products</NavigationMenu.Trigger>
|
|
14
|
+
* <NavigationMenu.Content>
|
|
15
|
+
* <NavigationMenu.Link href="/products/a">Product A</NavigationMenu.Link>
|
|
16
|
+
* </NavigationMenu.Content>
|
|
17
|
+
* </NavigationMenu.Item>
|
|
18
|
+
* </NavigationMenu.List>
|
|
19
|
+
* <NavigationMenu.Viewport />
|
|
20
|
+
* </NavigationMenu.Root>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
type HTMLAttributes,
|
|
26
|
+
type ReactNode,
|
|
27
|
+
createElement,
|
|
28
|
+
forwardRef,
|
|
29
|
+
useCallback,
|
|
30
|
+
useEffect,
|
|
31
|
+
useRef,
|
|
32
|
+
useState,
|
|
33
|
+
} from "react";
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Types
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
export type NavigationMenuOrientation = "horizontal" | "vertical";
|
|
40
|
+
|
|
41
|
+
export interface NavigationMenuRootProps extends HTMLAttributes<HTMLElement> {
|
|
42
|
+
/** Content */
|
|
43
|
+
children?: ReactNode;
|
|
44
|
+
/** Controlled active value */
|
|
45
|
+
value?: string;
|
|
46
|
+
/** Default active value (uncontrolled) */
|
|
47
|
+
defaultValue?: string;
|
|
48
|
+
/** Called when active value changes */
|
|
49
|
+
onValueChange?: (value: string) => void;
|
|
50
|
+
/** Delay in ms before opening on hover */
|
|
51
|
+
delayDuration?: number;
|
|
52
|
+
/** Delay in ms before closing when pointer leaves */
|
|
53
|
+
skipDelayDuration?: number;
|
|
54
|
+
/** Orientation (horizontal or vertical) */
|
|
55
|
+
orientation?: NavigationMenuOrientation;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface NavigationMenuListProps extends HTMLAttributes<HTMLElement> {
|
|
59
|
+
/** List items */
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface NavigationMenuItemProps extends HTMLAttributes<HTMLElement> {
|
|
64
|
+
/** Item content */
|
|
65
|
+
children?: ReactNode;
|
|
66
|
+
/** Unique value for this item */
|
|
67
|
+
value: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface NavigationMenuTriggerProps extends HTMLAttributes<HTMLElement> {
|
|
71
|
+
/** Trigger content */
|
|
72
|
+
children?: ReactNode;
|
|
73
|
+
/** Disabled state */
|
|
74
|
+
disabled?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface NavigationMenuContentProps extends HTMLAttributes<HTMLElement> {
|
|
78
|
+
/** Content */
|
|
79
|
+
children?: ReactNode;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface NavigationMenuLinkProps extends HTMLAttributes<HTMLElement> {
|
|
83
|
+
/** Link content */
|
|
84
|
+
children?: ReactNode;
|
|
85
|
+
/** URL to navigate to */
|
|
86
|
+
href?: string;
|
|
87
|
+
/** Whether this link is currently active */
|
|
88
|
+
active?: boolean;
|
|
89
|
+
/** Disabled state */
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
/** Called when link is clicked */
|
|
92
|
+
onNavigate?: (href: string) => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface NavigationMenuIndicatorProps extends HTMLAttributes<HTMLElement> {}
|
|
96
|
+
|
|
97
|
+
export interface NavigationMenuViewportProps extends HTMLAttributes<HTMLElement> {}
|
|
98
|
+
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Components
|
|
101
|
+
// ============================================================================
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* NavigationMenu root component.
|
|
105
|
+
*/
|
|
106
|
+
const NavigationMenuRoot = forwardRef<HTMLElement, NavigationMenuRootProps>(
|
|
107
|
+
function NavigationMenuRoot(
|
|
108
|
+
{
|
|
109
|
+
children,
|
|
110
|
+
className,
|
|
111
|
+
value: controlledValue,
|
|
112
|
+
defaultValue = "",
|
|
113
|
+
onValueChange,
|
|
114
|
+
delayDuration = 200,
|
|
115
|
+
skipDelayDuration = 300,
|
|
116
|
+
orientation = "horizontal",
|
|
117
|
+
...props
|
|
118
|
+
},
|
|
119
|
+
ref
|
|
120
|
+
) {
|
|
121
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
122
|
+
const isControlled = controlledValue !== undefined;
|
|
123
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
124
|
+
const elementRef = useRef<HTMLElement>(null);
|
|
125
|
+
|
|
126
|
+
// Combine refs
|
|
127
|
+
const combinedRef = (node: HTMLElement | null) => {
|
|
128
|
+
(elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
129
|
+
if (typeof ref === "function") {
|
|
130
|
+
ref(node);
|
|
131
|
+
} else if (ref) {
|
|
132
|
+
(ref as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleValueChange = useCallback(
|
|
137
|
+
(event: Event) => {
|
|
138
|
+
const customEvent = event as CustomEvent<{ value: string }>;
|
|
139
|
+
const newValue = customEvent.detail.value;
|
|
140
|
+
|
|
141
|
+
if (!isControlled) {
|
|
142
|
+
setInternalValue(newValue);
|
|
143
|
+
}
|
|
144
|
+
onValueChange?.(newValue);
|
|
145
|
+
},
|
|
146
|
+
[isControlled, onValueChange]
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// Attach event listeners
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
const element = elementRef.current;
|
|
152
|
+
if (!element) return;
|
|
153
|
+
|
|
154
|
+
element.addEventListener("ds:value-change", handleValueChange);
|
|
155
|
+
|
|
156
|
+
return () => {
|
|
157
|
+
element.removeEventListener("ds:value-change", handleValueChange);
|
|
158
|
+
};
|
|
159
|
+
}, [handleValueChange]);
|
|
160
|
+
|
|
161
|
+
return createElement(
|
|
162
|
+
"ds-navigation-menu",
|
|
163
|
+
{
|
|
164
|
+
ref: combinedRef,
|
|
165
|
+
class: className,
|
|
166
|
+
value,
|
|
167
|
+
"delay-duration": delayDuration,
|
|
168
|
+
"skip-delay-duration": skipDelayDuration,
|
|
169
|
+
orientation,
|
|
170
|
+
...props,
|
|
171
|
+
},
|
|
172
|
+
children
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
NavigationMenuRoot.displayName = "NavigationMenu.Root";
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* NavigationMenu list component.
|
|
180
|
+
*/
|
|
181
|
+
const NavigationMenuList = forwardRef<HTMLElement, NavigationMenuListProps>(
|
|
182
|
+
function NavigationMenuList({ children, className, ...props }, ref) {
|
|
183
|
+
return createElement("ds-navigation-menu-list", { ref, class: className, ...props }, children);
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
NavigationMenuList.displayName = "NavigationMenu.List";
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* NavigationMenu item component.
|
|
190
|
+
*/
|
|
191
|
+
const NavigationMenuItem = forwardRef<HTMLElement, NavigationMenuItemProps>(
|
|
192
|
+
function NavigationMenuItem({ children, className, value, ...props }, ref) {
|
|
193
|
+
return createElement(
|
|
194
|
+
"ds-navigation-menu-item",
|
|
195
|
+
{ ref, class: className, value, ...props },
|
|
196
|
+
children
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
NavigationMenuItem.displayName = "NavigationMenu.Item";
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* NavigationMenu trigger component.
|
|
204
|
+
*/
|
|
205
|
+
const NavigationMenuTrigger = forwardRef<HTMLElement, NavigationMenuTriggerProps>(
|
|
206
|
+
function NavigationMenuTrigger({ children, className, disabled = false, ...props }, ref) {
|
|
207
|
+
return createElement(
|
|
208
|
+
"ds-navigation-menu-trigger",
|
|
209
|
+
{ ref, class: className, disabled: disabled || undefined, ...props },
|
|
210
|
+
children
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
NavigationMenuTrigger.displayName = "NavigationMenu.Trigger";
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* NavigationMenu content component.
|
|
218
|
+
*/
|
|
219
|
+
const NavigationMenuContent = forwardRef<HTMLElement, NavigationMenuContentProps>(
|
|
220
|
+
function NavigationMenuContent({ children, className, ...props }, ref) {
|
|
221
|
+
return createElement(
|
|
222
|
+
"ds-navigation-menu-content",
|
|
223
|
+
{ ref, class: className, ...props },
|
|
224
|
+
children
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
NavigationMenuContent.displayName = "NavigationMenu.Content";
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* NavigationMenu link component.
|
|
232
|
+
*/
|
|
233
|
+
const NavigationMenuLink = forwardRef<HTMLElement, NavigationMenuLinkProps>(
|
|
234
|
+
function NavigationMenuLink(
|
|
235
|
+
{ children, className, href, active = false, disabled = false, onNavigate, ...props },
|
|
236
|
+
ref
|
|
237
|
+
) {
|
|
238
|
+
const elementRef = useRef<HTMLElement>(null);
|
|
239
|
+
|
|
240
|
+
// Combine refs
|
|
241
|
+
const combinedRef = (node: HTMLElement | null) => {
|
|
242
|
+
(elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
243
|
+
if (typeof ref === "function") {
|
|
244
|
+
ref(node);
|
|
245
|
+
} else if (ref) {
|
|
246
|
+
(ref as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// Attach navigate handler
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
const element = elementRef.current;
|
|
253
|
+
if (!element || !onNavigate) return;
|
|
254
|
+
|
|
255
|
+
const handleNavigate = (event: Event) => {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
const customEvent = event as CustomEvent<{ href: string }>;
|
|
258
|
+
onNavigate(customEvent.detail.href);
|
|
259
|
+
};
|
|
260
|
+
element.addEventListener("ds:navigate", handleNavigate);
|
|
261
|
+
|
|
262
|
+
return () => {
|
|
263
|
+
element.removeEventListener("ds:navigate", handleNavigate);
|
|
264
|
+
};
|
|
265
|
+
}, [onNavigate]);
|
|
266
|
+
|
|
267
|
+
return createElement(
|
|
268
|
+
"ds-navigation-menu-link",
|
|
269
|
+
{
|
|
270
|
+
ref: combinedRef,
|
|
271
|
+
class: className,
|
|
272
|
+
href,
|
|
273
|
+
active: active || undefined,
|
|
274
|
+
disabled: disabled || undefined,
|
|
275
|
+
...props,
|
|
276
|
+
},
|
|
277
|
+
children
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
NavigationMenuLink.displayName = "NavigationMenu.Link";
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* NavigationMenu indicator component.
|
|
285
|
+
*/
|
|
286
|
+
const NavigationMenuIndicator = forwardRef<HTMLElement, NavigationMenuIndicatorProps>(
|
|
287
|
+
function NavigationMenuIndicator({ className, ...props }, ref) {
|
|
288
|
+
return createElement("ds-navigation-menu-indicator", { ref, class: className, ...props });
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
NavigationMenuIndicator.displayName = "NavigationMenu.Indicator";
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* NavigationMenu viewport component.
|
|
295
|
+
*/
|
|
296
|
+
const NavigationMenuViewport = forwardRef<HTMLElement, NavigationMenuViewportProps>(
|
|
297
|
+
function NavigationMenuViewport({ className, ...props }, ref) {
|
|
298
|
+
return createElement("ds-navigation-menu-viewport", { ref, class: className, ...props });
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
NavigationMenuViewport.displayName = "NavigationMenu.Viewport";
|
|
302
|
+
|
|
303
|
+
// ============================================================================
|
|
304
|
+
// Compound Component
|
|
305
|
+
// ============================================================================
|
|
306
|
+
|
|
307
|
+
export const NavigationMenu = {
|
|
308
|
+
Root: NavigationMenuRoot,
|
|
309
|
+
List: NavigationMenuList,
|
|
310
|
+
Item: NavigationMenuItem,
|
|
311
|
+
Trigger: NavigationMenuTrigger,
|
|
312
|
+
Content: NavigationMenuContent,
|
|
313
|
+
Link: NavigationMenuLink,
|
|
314
|
+
Indicator: NavigationMenuIndicator,
|
|
315
|
+
Viewport: NavigationMenuViewport,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// Also export individual components
|
|
319
|
+
export {
|
|
320
|
+
NavigationMenuRoot,
|
|
321
|
+
NavigationMenuList,
|
|
322
|
+
NavigationMenuItem,
|
|
323
|
+
NavigationMenuTrigger,
|
|
324
|
+
NavigationMenuContent,
|
|
325
|
+
NavigationMenuLink,
|
|
326
|
+
NavigationMenuIndicator,
|
|
327
|
+
NavigationMenuViewport,
|
|
328
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenu component exports.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { DsNavigationMenu } from "./navigation-menu.js";
|
|
6
|
+
export { DsNavigationMenuList } from "./navigation-menu-list.js";
|
|
7
|
+
export { DsNavigationMenuItem } from "./navigation-menu-item.js";
|
|
8
|
+
export { DsNavigationMenuTrigger } from "./navigation-menu-trigger.js";
|
|
9
|
+
export { DsNavigationMenuContent } from "./navigation-menu-content.js";
|
|
10
|
+
export { DsNavigationMenuLink } from "./navigation-menu-link.js";
|
|
11
|
+
export { DsNavigationMenuIndicator } from "./navigation-menu-indicator.js";
|
|
12
|
+
export { DsNavigationMenuViewport } from "./navigation-menu-viewport.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuContent component - dropdown content panel.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-navigation-menu-content
|
|
5
|
+
*
|
|
6
|
+
* @slot - Content (links, cards, etc.)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
11
|
+
import { define } from "../../registry/define.js";
|
|
12
|
+
|
|
13
|
+
export class DsNavigationMenuContent extends DSElement {
|
|
14
|
+
override connectedCallback(): void {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.setAttribute("role", "menu");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override render() {
|
|
20
|
+
return html`<slot></slot>`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
define("ds-navigation-menu-content", DsNavigationMenuContent);
|
|
25
|
+
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"ds-navigation-menu-content": DsNavigationMenuContent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuIndicator component - visual indicator for active item.
|
|
3
|
+
*
|
|
4
|
+
* Shows which navigation item is currently active/hovered.
|
|
5
|
+
*
|
|
6
|
+
* @element ds-navigation-menu-indicator
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
11
|
+
import { define } from "../../registry/define.js";
|
|
12
|
+
|
|
13
|
+
export class DsNavigationMenuIndicator extends DSElement {
|
|
14
|
+
override connectedCallback(): void {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.setAttribute("aria-hidden", "true");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override render() {
|
|
20
|
+
return html`<div class="ds-navigation-menu-indicator__arrow"></div>`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
define("ds-navigation-menu-indicator", DsNavigationMenuIndicator);
|
|
25
|
+
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"ds-navigation-menu-indicator": DsNavigationMenuIndicator;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuItem component - wrapper for trigger and content.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-navigation-menu-item
|
|
5
|
+
*
|
|
6
|
+
* @slot - Trigger and content
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { property } from "lit/decorators.js";
|
|
11
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
12
|
+
import { emitEvent } from "../../events/emit.js";
|
|
13
|
+
import { define } from "../../registry/define.js";
|
|
14
|
+
|
|
15
|
+
export class DsNavigationMenuItem extends DSElement {
|
|
16
|
+
/** Unique value for this item */
|
|
17
|
+
@property({ type: String, reflect: true })
|
|
18
|
+
value = "";
|
|
19
|
+
|
|
20
|
+
override connectedCallback(): void {
|
|
21
|
+
super.connectedCallback();
|
|
22
|
+
this.setAttribute("role", "none");
|
|
23
|
+
this.setAttribute("data-state", "closed");
|
|
24
|
+
|
|
25
|
+
this.addEventListener("mouseenter", this.handleMouseEnter);
|
|
26
|
+
this.addEventListener("mouseleave", this.handleMouseLeave);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override disconnectedCallback(): void {
|
|
30
|
+
super.disconnectedCallback();
|
|
31
|
+
this.removeEventListener("mouseenter", this.handleMouseEnter);
|
|
32
|
+
this.removeEventListener("mouseleave", this.handleMouseLeave);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private handleMouseEnter = (): void => {
|
|
36
|
+
emitEvent(this, "ds:navigation-item-enter", {
|
|
37
|
+
detail: { value: this.value },
|
|
38
|
+
bubbles: true,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
private handleMouseLeave = (): void => {
|
|
43
|
+
emitEvent(this, "ds:navigation-item-leave", {
|
|
44
|
+
detail: { value: this.value },
|
|
45
|
+
bubbles: true,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
override render() {
|
|
50
|
+
return html`<slot></slot>`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
define("ds-navigation-menu-item", DsNavigationMenuItem);
|
|
55
|
+
|
|
56
|
+
declare global {
|
|
57
|
+
interface HTMLElementTagNameMap {
|
|
58
|
+
"ds-navigation-menu-item": DsNavigationMenuItem;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuLink component - navigation link.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-navigation-menu-link
|
|
5
|
+
*
|
|
6
|
+
* @slot - Link content
|
|
7
|
+
*
|
|
8
|
+
* @fires ds:navigate - Fired when link is clicked (for SPA navigation)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { html } from "lit";
|
|
12
|
+
import { property } from "lit/decorators.js";
|
|
13
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
14
|
+
import { emitEvent } from "../../events/emit.js";
|
|
15
|
+
import { define } from "../../registry/define.js";
|
|
16
|
+
|
|
17
|
+
export class DsNavigationMenuLink extends DSElement {
|
|
18
|
+
/** URL to navigate to */
|
|
19
|
+
@property({ type: String, reflect: true })
|
|
20
|
+
href = "";
|
|
21
|
+
|
|
22
|
+
/** Whether this link is currently active */
|
|
23
|
+
@property({ type: Boolean, reflect: true })
|
|
24
|
+
active = false;
|
|
25
|
+
|
|
26
|
+
/** Disabled state */
|
|
27
|
+
@property({ type: Boolean, reflect: true })
|
|
28
|
+
disabled = false;
|
|
29
|
+
|
|
30
|
+
override connectedCallback(): void {
|
|
31
|
+
super.connectedCallback();
|
|
32
|
+
|
|
33
|
+
this.setAttribute("role", "menuitem");
|
|
34
|
+
this.setAttribute("tabindex", "0");
|
|
35
|
+
|
|
36
|
+
this.addEventListener("click", this.handleClick);
|
|
37
|
+
this.addEventListener("keydown", this.handleKeyDown);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override disconnectedCallback(): void {
|
|
41
|
+
super.disconnectedCallback();
|
|
42
|
+
this.removeEventListener("click", this.handleClick);
|
|
43
|
+
this.removeEventListener("keydown", this.handleKeyDown);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private handleClick = (event: MouseEvent): void => {
|
|
47
|
+
if (this.disabled) return;
|
|
48
|
+
|
|
49
|
+
// Emit navigate event for SPA handling
|
|
50
|
+
const navigateEvent = emitEvent(this, "ds:navigate", {
|
|
51
|
+
detail: { href: this.href },
|
|
52
|
+
bubbles: true,
|
|
53
|
+
cancelable: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// If not canceled and has href, do native navigation
|
|
57
|
+
if (!navigateEvent.defaultPrevented && this.href) {
|
|
58
|
+
// Allow Ctrl/Cmd+click for new tab
|
|
59
|
+
if (event.ctrlKey || event.metaKey) {
|
|
60
|
+
window.open(this.href, "_blank");
|
|
61
|
+
} else {
|
|
62
|
+
window.location.href = this.href;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
private handleKeyDown = (event: KeyboardEvent): void => {
|
|
68
|
+
if (this.disabled) return;
|
|
69
|
+
|
|
70
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
this.handleClick(new MouseEvent("click"));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
77
|
+
if (changedProperties.has("active")) {
|
|
78
|
+
this.setAttribute("aria-current", this.active ? "page" : "false");
|
|
79
|
+
}
|
|
80
|
+
if (changedProperties.has("disabled")) {
|
|
81
|
+
this.setAttribute("aria-disabled", String(this.disabled));
|
|
82
|
+
this.setAttribute("tabindex", this.disabled ? "-1" : "0");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override render() {
|
|
87
|
+
return html`<slot></slot>`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
define("ds-navigation-menu-link", DsNavigationMenuLink);
|
|
92
|
+
|
|
93
|
+
declare global {
|
|
94
|
+
interface HTMLElementTagNameMap {
|
|
95
|
+
"ds-navigation-menu-link": DsNavigationMenuLink;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuList component - container for navigation items.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-navigation-menu-list
|
|
5
|
+
*
|
|
6
|
+
* @slot - Navigation menu items
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
11
|
+
import { define } from "../../registry/define.js";
|
|
12
|
+
|
|
13
|
+
export class DsNavigationMenuList extends DSElement {
|
|
14
|
+
override connectedCallback(): void {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.setAttribute("role", "menubar");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override render() {
|
|
20
|
+
return html`<slot></slot>`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
define("ds-navigation-menu-list", DsNavigationMenuList);
|
|
25
|
+
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"ds-navigation-menu-list": DsNavigationMenuList;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NavigationMenuTrigger component - button that opens content panel.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-navigation-menu-trigger
|
|
5
|
+
*
|
|
6
|
+
* @slot - Trigger content
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { property } from "lit/decorators.js";
|
|
11
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
12
|
+
import { emitEvent } from "../../events/emit.js";
|
|
13
|
+
import { define } from "../../registry/define.js";
|
|
14
|
+
|
|
15
|
+
export class DsNavigationMenuTrigger extends DSElement {
|
|
16
|
+
/** Disabled state */
|
|
17
|
+
@property({ type: Boolean, reflect: true })
|
|
18
|
+
disabled = false;
|
|
19
|
+
|
|
20
|
+
private observer: MutationObserver | null = null;
|
|
21
|
+
|
|
22
|
+
override connectedCallback(): void {
|
|
23
|
+
super.connectedCallback();
|
|
24
|
+
|
|
25
|
+
this.setAttribute("role", "menuitem");
|
|
26
|
+
this.setAttribute("tabindex", "0");
|
|
27
|
+
this.setAttribute("aria-haspopup", "menu");
|
|
28
|
+
this.updateAriaExpanded();
|
|
29
|
+
|
|
30
|
+
// Observe parent item's data-state changes to update aria-expanded
|
|
31
|
+
const item = this.closest("ds-navigation-menu-item");
|
|
32
|
+
if (item) {
|
|
33
|
+
this.observer = new MutationObserver(() => {
|
|
34
|
+
this.updateAriaExpanded();
|
|
35
|
+
});
|
|
36
|
+
this.observer.observe(item, { attributes: true, attributeFilter: ["data-state"] });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.addEventListener("click", this.handleClick);
|
|
40
|
+
this.addEventListener("keydown", this.handleKeyDown);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override disconnectedCallback(): void {
|
|
44
|
+
super.disconnectedCallback();
|
|
45
|
+
this.removeEventListener("click", this.handleClick);
|
|
46
|
+
this.removeEventListener("keydown", this.handleKeyDown);
|
|
47
|
+
this.observer?.disconnect();
|
|
48
|
+
this.observer = null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Update aria-expanded based on parent item's state.
|
|
53
|
+
* Per APG, menuitem with submenu should have aria-expanded.
|
|
54
|
+
*/
|
|
55
|
+
private updateAriaExpanded(): void {
|
|
56
|
+
const item = this.closest("ds-navigation-menu-item");
|
|
57
|
+
const isOpen = item?.getAttribute("data-state") === "open";
|
|
58
|
+
this.setAttribute("aria-expanded", String(isOpen));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private getItemValue(): string {
|
|
62
|
+
const item = this.closest("ds-navigation-menu-item");
|
|
63
|
+
return item?.getAttribute("value") || "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private handleClick = (): void => {
|
|
67
|
+
if (this.disabled) return;
|
|
68
|
+
|
|
69
|
+
const value = this.getItemValue();
|
|
70
|
+
emitEvent(this, "ds:navigation-trigger", {
|
|
71
|
+
detail: { value, type: "click" },
|
|
72
|
+
bubbles: true,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
private handleKeyDown = (event: KeyboardEvent): void => {
|
|
77
|
+
if (this.disabled) return;
|
|
78
|
+
|
|
79
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
this.handleClick();
|
|
82
|
+
} else if (event.key === "ArrowDown") {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
const value = this.getItemValue();
|
|
85
|
+
emitEvent(this, "ds:navigation-trigger", {
|
|
86
|
+
detail: { value, type: "focus" },
|
|
87
|
+
bubbles: true,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
93
|
+
if (changedProperties.has("disabled")) {
|
|
94
|
+
this.setAttribute("aria-disabled", String(this.disabled));
|
|
95
|
+
this.setAttribute("tabindex", this.disabled ? "-1" : "0");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override render() {
|
|
100
|
+
return html`<slot></slot>`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
define("ds-navigation-menu-trigger", DsNavigationMenuTrigger);
|
|
105
|
+
|
|
106
|
+
declare global {
|
|
107
|
+
interface HTMLElementTagNameMap {
|
|
108
|
+
"ds-navigation-menu-trigger": DsNavigationMenuTrigger;
|
|
109
|
+
}
|
|
110
|
+
}
|