@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,24 @@
|
|
|
1
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Command palette loading state component - shown when loading async results.
|
|
5
|
+
*
|
|
6
|
+
* @element ds-command-loading
|
|
7
|
+
* @slot - Loading state content (e.g., spinner)
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```html
|
|
11
|
+
* <ds-command-loading>
|
|
12
|
+
* <ds-spinner size="sm"></ds-spinner>
|
|
13
|
+
* Loading...
|
|
14
|
+
* </ds-command-loading>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export class DsCommandLoading extends DSElement {
|
|
18
|
+
connectedCallback(): void {
|
|
19
|
+
super.connectedCallback();
|
|
20
|
+
this.setAttribute("role", "status");
|
|
21
|
+
this.setAttribute("aria-live", "polite");
|
|
22
|
+
this.setAttribute("aria-label", "Loading");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Command palette separator component - visual divider between items/groups.
|
|
5
|
+
*
|
|
6
|
+
* @element ds-command-separator
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```html
|
|
10
|
+
* <ds-command-list>
|
|
11
|
+
* <ds-command-item value="copy">Copy</ds-command-item>
|
|
12
|
+
* <ds-command-separator></ds-command-separator>
|
|
13
|
+
* <ds-command-item value="delete">Delete</ds-command-item>
|
|
14
|
+
* </ds-command-list>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export class DsCommandSeparator extends DSElement {
|
|
18
|
+
connectedCallback(): void {
|
|
19
|
+
super.connectedCallback();
|
|
20
|
+
this.setAttribute("role", "separator");
|
|
21
|
+
this.setAttribute("aria-orientation", "horizontal");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { property, state } from "lit/decorators.js";
|
|
2
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
3
|
+
import { emitEvent } from "../../events/emit.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Command palette root component - provides search-based command/option selection.
|
|
7
|
+
*
|
|
8
|
+
* @element ds-command
|
|
9
|
+
* @slot - Command children (input, list, etc.)
|
|
10
|
+
*
|
|
11
|
+
* @fires ds:value-change - When the input value changes
|
|
12
|
+
* @fires ds:select - When an item is selected
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <ds-command>
|
|
17
|
+
* <ds-command-input placeholder="Search commands..."></ds-command-input>
|
|
18
|
+
* <ds-command-list>
|
|
19
|
+
* <ds-command-group heading="Actions">
|
|
20
|
+
* <ds-command-item value="copy">Copy</ds-command-item>
|
|
21
|
+
* <ds-command-item value="paste">Paste</ds-command-item>
|
|
22
|
+
* </ds-command-group>
|
|
23
|
+
* </ds-command-list>
|
|
24
|
+
* </ds-command>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class DsCommand extends DSElement {
|
|
28
|
+
/**
|
|
29
|
+
* Current search/filter value.
|
|
30
|
+
*/
|
|
31
|
+
@property({ type: String })
|
|
32
|
+
value = "";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Whether the command palette is in a loading state.
|
|
36
|
+
*/
|
|
37
|
+
@property({ type: Boolean, reflect: true })
|
|
38
|
+
loading = false;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Whether to use built-in fuzzy filtering.
|
|
42
|
+
* When false, filtering must be handled externally.
|
|
43
|
+
*/
|
|
44
|
+
@property({ type: Boolean, attribute: "filter" })
|
|
45
|
+
filter = true;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Label for accessibility.
|
|
49
|
+
*/
|
|
50
|
+
@property({ type: String })
|
|
51
|
+
label = "Command palette";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Tracks visible item count after filtering.
|
|
55
|
+
*/
|
|
56
|
+
@state()
|
|
57
|
+
private _visibleCount = 0;
|
|
58
|
+
|
|
59
|
+
connectedCallback(): void {
|
|
60
|
+
super.connectedCallback();
|
|
61
|
+
this.setAttribute("role", "search");
|
|
62
|
+
this.setAttribute("aria-label", this.label);
|
|
63
|
+
|
|
64
|
+
this.addEventListener("ds:command-input", this._handleInputChange);
|
|
65
|
+
this.addEventListener("ds:command-select", this._handleSelect);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
disconnectedCallback(): void {
|
|
69
|
+
super.disconnectedCallback();
|
|
70
|
+
this.removeEventListener("ds:command-input", this._handleInputChange);
|
|
71
|
+
this.removeEventListener("ds:command-select", this._handleSelect);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private _handleInputChange = (event: Event): void => {
|
|
75
|
+
const e = event as CustomEvent<{ value: string }>;
|
|
76
|
+
this.value = e.detail.value;
|
|
77
|
+
|
|
78
|
+
if (this.filter) {
|
|
79
|
+
this._filterItems(this.value);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
emitEvent(this, "value-change", { detail: { value: this.value } });
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
private _handleSelect = (event: Event): void => {
|
|
86
|
+
const e = event as CustomEvent<{ value: string }>;
|
|
87
|
+
emitEvent(this, "select", { detail: { value: e.detail.value } });
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
private _filterItems(query: string): void {
|
|
91
|
+
const normalizedQuery = query.toLowerCase().trim();
|
|
92
|
+
const items = this.querySelectorAll("ds-command-item");
|
|
93
|
+
let visibleCount = 0;
|
|
94
|
+
|
|
95
|
+
items.forEach((item) => {
|
|
96
|
+
const text = item.textContent?.toLowerCase() || "";
|
|
97
|
+
const value = item.getAttribute("value")?.toLowerCase() || "";
|
|
98
|
+
const keywords = item.getAttribute("keywords")?.toLowerCase() || "";
|
|
99
|
+
|
|
100
|
+
const matches =
|
|
101
|
+
normalizedQuery === "" ||
|
|
102
|
+
this._fuzzyMatch(normalizedQuery, text) ||
|
|
103
|
+
this._fuzzyMatch(normalizedQuery, value) ||
|
|
104
|
+
this._fuzzyMatch(normalizedQuery, keywords);
|
|
105
|
+
|
|
106
|
+
if (matches) {
|
|
107
|
+
item.removeAttribute("data-filtered");
|
|
108
|
+
visibleCount++;
|
|
109
|
+
} else {
|
|
110
|
+
item.setAttribute("data-filtered", "true");
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this._visibleCount = visibleCount;
|
|
115
|
+
this._updateGroupVisibility();
|
|
116
|
+
this._updateEmptyState();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private _fuzzyMatch(query: string, text: string): boolean {
|
|
120
|
+
if (!query) return true;
|
|
121
|
+
if (!text) return false;
|
|
122
|
+
|
|
123
|
+
// Simple fuzzy matching - characters must appear in order
|
|
124
|
+
let queryIndex = 0;
|
|
125
|
+
for (let i = 0; i < text.length && queryIndex < query.length; i++) {
|
|
126
|
+
if (text[i] === query[queryIndex]) {
|
|
127
|
+
queryIndex++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return queryIndex === query.length;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private _updateGroupVisibility(): void {
|
|
134
|
+
const groups = this.querySelectorAll("ds-command-group");
|
|
135
|
+
groups.forEach((group) => {
|
|
136
|
+
const visibleItems = group.querySelectorAll("ds-command-item:not([data-filtered])");
|
|
137
|
+
if (visibleItems.length === 0) {
|
|
138
|
+
group.setAttribute("data-empty", "true");
|
|
139
|
+
} else {
|
|
140
|
+
group.removeAttribute("data-empty");
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private _updateEmptyState(): void {
|
|
146
|
+
const emptyEl = this.querySelector("ds-command-empty");
|
|
147
|
+
if (emptyEl) {
|
|
148
|
+
if (this._visibleCount === 0 && this.value) {
|
|
149
|
+
emptyEl.removeAttribute("hidden");
|
|
150
|
+
} else {
|
|
151
|
+
emptyEl.setAttribute("hidden", "");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Programmatically set the search value.
|
|
158
|
+
*/
|
|
159
|
+
setValue(value: string): void {
|
|
160
|
+
this.value = value;
|
|
161
|
+
const input = this.querySelector("ds-command-input");
|
|
162
|
+
if (input) {
|
|
163
|
+
(input as HTMLElement & { value: string }).value = value;
|
|
164
|
+
}
|
|
165
|
+
if (this.filter) {
|
|
166
|
+
this._filterItems(value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Clear the search value.
|
|
172
|
+
*/
|
|
173
|
+
clear(): void {
|
|
174
|
+
this.setValue("");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMenu compound component exports.
|
|
3
|
+
*
|
|
4
|
+
* ContextMenu is used for right-click context menus with keyboard navigation.
|
|
5
|
+
* Opens at pointer position on right-click or long-press on touch devices.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { ContextMenu } from "@/components/ui";
|
|
10
|
+
*
|
|
11
|
+
* <ContextMenu.Root>
|
|
12
|
+
* <ContextMenu.Trigger>
|
|
13
|
+
* <div>Right-click me</div>
|
|
14
|
+
* </ContextMenu.Trigger>
|
|
15
|
+
* <ContextMenu.Content>
|
|
16
|
+
* <ContextMenu.Item value="copy">Copy</ContextMenu.Item>
|
|
17
|
+
* <ContextMenu.Item value="paste">Paste</ContextMenu.Item>
|
|
18
|
+
* <ContextMenu.Separator />
|
|
19
|
+
* <ContextMenu.Item value="delete" variant="destructive">Delete</ContextMenu.Item>
|
|
20
|
+
* </ContextMenu.Content>
|
|
21
|
+
* </ContextMenu.Root>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
type HTMLAttributes,
|
|
27
|
+
type ReactNode,
|
|
28
|
+
createElement,
|
|
29
|
+
forwardRef,
|
|
30
|
+
useCallback,
|
|
31
|
+
useEffect,
|
|
32
|
+
useRef,
|
|
33
|
+
useState,
|
|
34
|
+
} from "react";
|
|
35
|
+
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Types
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
export type ContextMenuItemVariant = "default" | "destructive";
|
|
41
|
+
|
|
42
|
+
export interface ContextMenuRootProps extends HTMLAttributes<HTMLElement> {
|
|
43
|
+
/** Content */
|
|
44
|
+
children?: ReactNode;
|
|
45
|
+
/** Controlled open state */
|
|
46
|
+
open?: boolean;
|
|
47
|
+
/** Called when open state changes */
|
|
48
|
+
onOpenChange?: (open: boolean) => void;
|
|
49
|
+
/** Whether to animate open/close transitions */
|
|
50
|
+
animated?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ContextMenuTriggerProps extends HTMLAttributes<HTMLElement> {
|
|
54
|
+
/** Trigger content (the area that responds to right-click) */
|
|
55
|
+
children?: ReactNode;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ContextMenuContentProps extends HTMLAttributes<HTMLElement> {
|
|
59
|
+
/** Content */
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ContextMenuItemProps extends Omit<HTMLAttributes<HTMLElement>, "onSelect"> {
|
|
64
|
+
/** Item content */
|
|
65
|
+
children?: ReactNode;
|
|
66
|
+
/** Value for selection events */
|
|
67
|
+
value?: string;
|
|
68
|
+
/** Visual variant */
|
|
69
|
+
variant?: ContextMenuItemVariant;
|
|
70
|
+
/** Disabled state */
|
|
71
|
+
disabled?: boolean;
|
|
72
|
+
/** Called when item is selected */
|
|
73
|
+
onSelect?: (value: string) => void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ContextMenuSeparatorProps extends HTMLAttributes<HTMLElement> {}
|
|
77
|
+
|
|
78
|
+
export interface ContextMenuLabelProps extends HTMLAttributes<HTMLElement> {
|
|
79
|
+
/** Label content */
|
|
80
|
+
children?: ReactNode;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Components
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* ContextMenu root component.
|
|
89
|
+
*/
|
|
90
|
+
const ContextMenuRoot = forwardRef<HTMLElement, ContextMenuRootProps>(function ContextMenuRoot(
|
|
91
|
+
{ children, className, open: controlledOpen, onOpenChange, animated = true, ...props },
|
|
92
|
+
ref
|
|
93
|
+
) {
|
|
94
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
95
|
+
const isControlled = controlledOpen !== undefined;
|
|
96
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
97
|
+
const elementRef = useRef<HTMLElement>(null);
|
|
98
|
+
|
|
99
|
+
// Combine refs
|
|
100
|
+
const combinedRef = (node: HTMLElement | null) => {
|
|
101
|
+
(elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
102
|
+
if (typeof ref === "function") {
|
|
103
|
+
ref(node);
|
|
104
|
+
} else if (ref) {
|
|
105
|
+
(ref as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const handleOpenChange = useCallback(
|
|
110
|
+
(event: Event) => {
|
|
111
|
+
const customEvent = event as CustomEvent;
|
|
112
|
+
const isOpen = customEvent.type === "ds:open";
|
|
113
|
+
|
|
114
|
+
if (!isControlled) {
|
|
115
|
+
setInternalOpen(isOpen);
|
|
116
|
+
}
|
|
117
|
+
onOpenChange?.(isOpen);
|
|
118
|
+
},
|
|
119
|
+
[isControlled, onOpenChange]
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Attach event listeners
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
const element = elementRef.current;
|
|
125
|
+
if (!element) return;
|
|
126
|
+
|
|
127
|
+
element.addEventListener("ds:open", handleOpenChange);
|
|
128
|
+
element.addEventListener("ds:close", handleOpenChange);
|
|
129
|
+
|
|
130
|
+
return () => {
|
|
131
|
+
element.removeEventListener("ds:open", handleOpenChange);
|
|
132
|
+
element.removeEventListener("ds:close", handleOpenChange);
|
|
133
|
+
};
|
|
134
|
+
}, [handleOpenChange]);
|
|
135
|
+
|
|
136
|
+
return createElement(
|
|
137
|
+
"ds-context-menu",
|
|
138
|
+
{
|
|
139
|
+
ref: combinedRef,
|
|
140
|
+
class: className,
|
|
141
|
+
open: open || undefined,
|
|
142
|
+
animated: animated || undefined,
|
|
143
|
+
...props,
|
|
144
|
+
},
|
|
145
|
+
children
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
ContextMenuRoot.displayName = "ContextMenu.Root";
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* ContextMenu trigger component.
|
|
152
|
+
*/
|
|
153
|
+
const ContextMenuTrigger = forwardRef<HTMLElement, ContextMenuTriggerProps>(
|
|
154
|
+
function ContextMenuTrigger({ children, className, ...props }, ref) {
|
|
155
|
+
return createElement("span", { ref, className, slot: "trigger", ...props }, children);
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
ContextMenuTrigger.displayName = "ContextMenu.Trigger";
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* ContextMenu content component.
|
|
162
|
+
*/
|
|
163
|
+
const ContextMenuContent = forwardRef<HTMLElement, ContextMenuContentProps>(
|
|
164
|
+
function ContextMenuContent({ children, className, ...props }, ref) {
|
|
165
|
+
return createElement("ds-context-menu-content", { ref, class: className, ...props }, children);
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
ContextMenuContent.displayName = "ContextMenu.Content";
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* ContextMenu item component.
|
|
172
|
+
*/
|
|
173
|
+
const ContextMenuItem = forwardRef<HTMLElement, ContextMenuItemProps>(function ContextMenuItem(
|
|
174
|
+
{ children, className, value, variant = "default", disabled = false, onSelect, ...props },
|
|
175
|
+
ref
|
|
176
|
+
) {
|
|
177
|
+
const elementRef = useRef<HTMLElement>(null);
|
|
178
|
+
|
|
179
|
+
// Combine refs
|
|
180
|
+
const combinedRef = (node: HTMLElement | null) => {
|
|
181
|
+
(elementRef as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
182
|
+
if (typeof ref === "function") {
|
|
183
|
+
ref(node);
|
|
184
|
+
} else if (ref) {
|
|
185
|
+
(ref as React.MutableRefObject<HTMLElement | null>).current = node;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Attach select handler
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
const element = elementRef.current;
|
|
192
|
+
if (!element || !onSelect) return;
|
|
193
|
+
|
|
194
|
+
const handleSelect = (event: Event) => {
|
|
195
|
+
const customEvent = event as CustomEvent<{ value: string }>;
|
|
196
|
+
onSelect(customEvent.detail.value);
|
|
197
|
+
};
|
|
198
|
+
element.addEventListener("ds:select", handleSelect);
|
|
199
|
+
|
|
200
|
+
return () => {
|
|
201
|
+
element.removeEventListener("ds:select", handleSelect);
|
|
202
|
+
};
|
|
203
|
+
}, [onSelect]);
|
|
204
|
+
|
|
205
|
+
return createElement(
|
|
206
|
+
"ds-context-menu-item",
|
|
207
|
+
{
|
|
208
|
+
ref: combinedRef,
|
|
209
|
+
class: className,
|
|
210
|
+
value,
|
|
211
|
+
variant,
|
|
212
|
+
disabled: disabled || undefined,
|
|
213
|
+
...props,
|
|
214
|
+
},
|
|
215
|
+
children
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
ContextMenuItem.displayName = "ContextMenu.Item";
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* ContextMenu separator component.
|
|
222
|
+
*/
|
|
223
|
+
const ContextMenuSeparator = forwardRef<HTMLElement, ContextMenuSeparatorProps>(
|
|
224
|
+
function ContextMenuSeparator({ className, ...props }, ref) {
|
|
225
|
+
return createElement("ds-context-menu-separator", { ref, class: className, ...props });
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
ContextMenuSeparator.displayName = "ContextMenu.Separator";
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* ContextMenu label component.
|
|
232
|
+
*/
|
|
233
|
+
const ContextMenuLabel = forwardRef<HTMLElement, ContextMenuLabelProps>(function ContextMenuLabel(
|
|
234
|
+
{ children, className, ...props },
|
|
235
|
+
ref
|
|
236
|
+
) {
|
|
237
|
+
return createElement("ds-context-menu-label", { ref, class: className, ...props }, children);
|
|
238
|
+
});
|
|
239
|
+
ContextMenuLabel.displayName = "ContextMenu.Label";
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Compound Component
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
export const ContextMenu = {
|
|
246
|
+
Root: ContextMenuRoot,
|
|
247
|
+
Trigger: ContextMenuTrigger,
|
|
248
|
+
Content: ContextMenuContent,
|
|
249
|
+
Item: ContextMenuItem,
|
|
250
|
+
Separator: ContextMenuSeparator,
|
|
251
|
+
Label: ContextMenuLabel,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Also export individual components
|
|
255
|
+
export {
|
|
256
|
+
ContextMenuRoot,
|
|
257
|
+
ContextMenuTrigger,
|
|
258
|
+
ContextMenuContent,
|
|
259
|
+
ContextMenuItem,
|
|
260
|
+
ContextMenuSeparator,
|
|
261
|
+
ContextMenuLabel,
|
|
262
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMenuContent component - container for context menu items.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-context-menu-content
|
|
5
|
+
*
|
|
6
|
+
* @slot - Menu items
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { property } from "lit/decorators.js";
|
|
11
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
12
|
+
import { define } from "../../registry/define.js";
|
|
13
|
+
|
|
14
|
+
export class DsContextMenuContent extends DSElement {
|
|
15
|
+
/** Data state for animations */
|
|
16
|
+
@property({ attribute: "data-state", reflect: true })
|
|
17
|
+
dataState: "open" | "closed" = "closed";
|
|
18
|
+
|
|
19
|
+
override connectedCallback(): void {
|
|
20
|
+
super.connectedCallback();
|
|
21
|
+
|
|
22
|
+
if (!this.id) {
|
|
23
|
+
this.id = `context-menu-content-${crypto.randomUUID().slice(0, 8)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.setAttribute("role", "menu");
|
|
27
|
+
this.setAttribute("hidden", "");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override render() {
|
|
31
|
+
return html`<slot></slot>`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
define("ds-context-menu-content", DsContextMenuContent);
|
|
36
|
+
|
|
37
|
+
declare global {
|
|
38
|
+
interface HTMLElementTagNameMap {
|
|
39
|
+
"ds-context-menu-content": DsContextMenuContent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMenuItem component - selectable context menu item.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-context-menu-item
|
|
5
|
+
*
|
|
6
|
+
* @slot - Item content
|
|
7
|
+
*
|
|
8
|
+
* @fires ds:select - Fired when item is selected
|
|
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 type ContextMenuItemVariant = "default" | "destructive";
|
|
18
|
+
|
|
19
|
+
export class DsContextMenuItem extends DSElement {
|
|
20
|
+
/** Value for selection events */
|
|
21
|
+
@property()
|
|
22
|
+
value = "";
|
|
23
|
+
|
|
24
|
+
/** Visual variant */
|
|
25
|
+
@property({ reflect: true })
|
|
26
|
+
variant: ContextMenuItemVariant = "default";
|
|
27
|
+
|
|
28
|
+
/** Disabled state */
|
|
29
|
+
@property({ type: Boolean, reflect: true })
|
|
30
|
+
disabled = false;
|
|
31
|
+
|
|
32
|
+
override connectedCallback(): void {
|
|
33
|
+
super.connectedCallback();
|
|
34
|
+
|
|
35
|
+
this.setAttribute("role", "menuitem");
|
|
36
|
+
this.setAttribute("tabindex", "-1");
|
|
37
|
+
|
|
38
|
+
this.addEventListener("click", this.handleSelect);
|
|
39
|
+
this.addEventListener("keydown", this.handleKeyDown);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override disconnectedCallback(): void {
|
|
43
|
+
super.disconnectedCallback();
|
|
44
|
+
this.removeEventListener("click", this.handleSelect);
|
|
45
|
+
this.removeEventListener("keydown", this.handleKeyDown);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private handleSelect = (): void => {
|
|
49
|
+
if (this.disabled) return;
|
|
50
|
+
|
|
51
|
+
emitEvent(this, "ds:select", {
|
|
52
|
+
detail: { value: this.value },
|
|
53
|
+
bubbles: true,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
private handleKeyDown = (event: KeyboardEvent): void => {
|
|
58
|
+
if (this.disabled) return;
|
|
59
|
+
|
|
60
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
this.handleSelect();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
67
|
+
if (changedProperties.has("disabled")) {
|
|
68
|
+
this.setAttribute("aria-disabled", String(this.disabled));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override render() {
|
|
73
|
+
return html`<slot></slot>`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
define("ds-context-menu-item", DsContextMenuItem);
|
|
78
|
+
|
|
79
|
+
declare global {
|
|
80
|
+
interface HTMLElementTagNameMap {
|
|
81
|
+
"ds-context-menu-item": DsContextMenuItem;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMenuLabel component - non-interactive label for menu sections.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-context-menu-label
|
|
5
|
+
*
|
|
6
|
+
* @slot - Label content
|
|
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 DsContextMenuLabel extends DSElement {
|
|
14
|
+
override connectedCallback(): void {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.setAttribute("aria-hidden", "true");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override render() {
|
|
20
|
+
return html`<slot></slot>`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
define("ds-context-menu-label", DsContextMenuLabel);
|
|
25
|
+
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
"ds-context-menu-label": DsContextMenuLabel;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextMenuSeparator component - visual divider between menu items.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-context-menu-separator
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { html } from "lit";
|
|
8
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
9
|
+
import { define } from "../../registry/define.js";
|
|
10
|
+
|
|
11
|
+
export class DsContextMenuSeparator extends DSElement {
|
|
12
|
+
override connectedCallback(): void {
|
|
13
|
+
super.connectedCallback();
|
|
14
|
+
this.setAttribute("role", "separator");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override render() {
|
|
18
|
+
return html``;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
define("ds-context-menu-separator", DsContextMenuSeparator);
|
|
23
|
+
|
|
24
|
+
declare global {
|
|
25
|
+
interface HTMLElementTagNameMap {
|
|
26
|
+
"ds-context-menu-separator": DsContextMenuSeparator;
|
|
27
|
+
}
|
|
28
|
+
}
|