@hypoth-ui/cli 0.0.1 → 0.1.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/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,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs Content component - panel content for a tab.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-tabs-content
|
|
5
|
+
*
|
|
6
|
+
* @slot - Tab panel content
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { property, state } from "lit/decorators.js";
|
|
11
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
12
|
+
import { define } from "../../registry/define.js";
|
|
13
|
+
import type { DsTabs } from "./tabs.js";
|
|
14
|
+
|
|
15
|
+
export class DsTabsContent extends DSElement {
|
|
16
|
+
/** Value of associated tab */
|
|
17
|
+
@property({ reflect: true })
|
|
18
|
+
value = "";
|
|
19
|
+
|
|
20
|
+
/** Keep mounted when inactive (for animations) */
|
|
21
|
+
@property({ type: Boolean, attribute: "force-mount" })
|
|
22
|
+
forceMount = false;
|
|
23
|
+
|
|
24
|
+
/** Internal active state */
|
|
25
|
+
@state()
|
|
26
|
+
private active = false;
|
|
27
|
+
|
|
28
|
+
override connectedCallback(): void {
|
|
29
|
+
super.connectedCallback();
|
|
30
|
+
|
|
31
|
+
// Apply panel props after DOM is ready
|
|
32
|
+
requestAnimationFrame(() => {
|
|
33
|
+
this.applyBehaviorProps();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private applyBehaviorProps(): void {
|
|
38
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
39
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
40
|
+
|
|
41
|
+
if (!tabsBehavior) {
|
|
42
|
+
// Fallback for standalone usage
|
|
43
|
+
this.setAttribute("role", "tabpanel");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const panelProps = tabsBehavior.getPanelProps(this.value);
|
|
48
|
+
this.id = panelProps.id;
|
|
49
|
+
this.setAttribute("role", panelProps.role);
|
|
50
|
+
this.setAttribute("aria-labelledby", panelProps["aria-labelledby"]);
|
|
51
|
+
this.setAttribute("tabindex", String(panelProps.tabIndex));
|
|
52
|
+
|
|
53
|
+
// Handle visibility (respecting forceMount)
|
|
54
|
+
if (this.forceMount) {
|
|
55
|
+
this.hidden = false;
|
|
56
|
+
} else {
|
|
57
|
+
this.hidden = panelProps.hidden;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.setAttribute("data-state", panelProps.hidden ? "inactive" : "active");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Update from behavior (called by parent).
|
|
65
|
+
*/
|
|
66
|
+
public updateFromBehavior(active: boolean): void {
|
|
67
|
+
this.active = active;
|
|
68
|
+
this.applyBehaviorProps();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override render() {
|
|
72
|
+
return html`<slot></slot>`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
define("ds-tabs-content", DsTabsContent);
|
|
77
|
+
|
|
78
|
+
declare global {
|
|
79
|
+
interface HTMLElementTagNameMap {
|
|
80
|
+
"ds-tabs-content": DsTabsContent;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs List component - container for tab triggers.
|
|
3
|
+
*
|
|
4
|
+
* Implements keyboard navigation with arrow keys via behavior primitive.
|
|
5
|
+
*
|
|
6
|
+
* @element ds-tabs-list
|
|
7
|
+
*
|
|
8
|
+
* @slot - Tab triggers (ds-tabs-trigger)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { html } from "lit";
|
|
12
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
13
|
+
import { define } from "../../registry/define.js";
|
|
14
|
+
import type { DsTabs } from "./tabs.js";
|
|
15
|
+
|
|
16
|
+
export class DsTabsList extends DSElement {
|
|
17
|
+
override connectedCallback(): void {
|
|
18
|
+
super.connectedCallback();
|
|
19
|
+
|
|
20
|
+
// Initialize after DOM is ready
|
|
21
|
+
requestAnimationFrame(() => {
|
|
22
|
+
this.setupBehavior();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Setup behavior connection (called by parent when options change).
|
|
28
|
+
*/
|
|
29
|
+
public setupBehavior(): void {
|
|
30
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
31
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
32
|
+
|
|
33
|
+
if (!tabsBehavior) return;
|
|
34
|
+
|
|
35
|
+
// Apply tablist props from behavior
|
|
36
|
+
const tablistProps = tabsBehavior.getTabListProps();
|
|
37
|
+
this.setAttribute("id", tablistProps.id);
|
|
38
|
+
this.setAttribute("role", tablistProps.role);
|
|
39
|
+
this.setAttribute("aria-orientation", tablistProps["aria-orientation"]);
|
|
40
|
+
|
|
41
|
+
// Set tablist element to activate roving focus
|
|
42
|
+
tabsBehavior.setTablistElement(this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override render() {
|
|
46
|
+
return html`<slot></slot>`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
define("ds-tabs-list", DsTabsList);
|
|
51
|
+
|
|
52
|
+
declare global {
|
|
53
|
+
interface HTMLElementTagNameMap {
|
|
54
|
+
"ds-tabs-list": DsTabsList;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs Trigger component - button that activates a tab panel.
|
|
3
|
+
*
|
|
4
|
+
* @element ds-tabs-trigger
|
|
5
|
+
*
|
|
6
|
+
* @slot - Trigger label content
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { html } from "lit";
|
|
10
|
+
import { property, state } from "lit/decorators.js";
|
|
11
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
12
|
+
import { define } from "../../registry/define.js";
|
|
13
|
+
import type { DsTabs } from "./tabs.js";
|
|
14
|
+
|
|
15
|
+
export class DsTabsTrigger extends DSElement {
|
|
16
|
+
/** Unique value identifying this tab */
|
|
17
|
+
@property({ reflect: true })
|
|
18
|
+
value = "";
|
|
19
|
+
|
|
20
|
+
/** Disable this tab */
|
|
21
|
+
@property({ type: Boolean, reflect: true })
|
|
22
|
+
disabled = false;
|
|
23
|
+
|
|
24
|
+
/** Internal selected state */
|
|
25
|
+
@state()
|
|
26
|
+
private selected = false;
|
|
27
|
+
|
|
28
|
+
override connectedCallback(): void {
|
|
29
|
+
super.connectedCallback();
|
|
30
|
+
|
|
31
|
+
// Handle interactions
|
|
32
|
+
this.addEventListener("click", this.handleClick);
|
|
33
|
+
this.addEventListener("keydown", this.handleKeyDown);
|
|
34
|
+
this.addEventListener("focus", this.handleFocus);
|
|
35
|
+
|
|
36
|
+
// Register with behavior after DOM is ready
|
|
37
|
+
requestAnimationFrame(() => {
|
|
38
|
+
this.registerWithBehavior();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override disconnectedCallback(): void {
|
|
43
|
+
super.disconnectedCallback();
|
|
44
|
+
this.removeEventListener("click", this.handleClick);
|
|
45
|
+
this.removeEventListener("keydown", this.handleKeyDown);
|
|
46
|
+
this.removeEventListener("focus", this.handleFocus);
|
|
47
|
+
|
|
48
|
+
// Unregister from behavior
|
|
49
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
50
|
+
tabsRoot?.getTabsBehavior()?.unregisterTab(this.value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private registerWithBehavior(): void {
|
|
54
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
55
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
56
|
+
|
|
57
|
+
if (!tabsBehavior) return;
|
|
58
|
+
|
|
59
|
+
// Register this tab
|
|
60
|
+
tabsBehavior.registerTab(this.value, { disabled: this.disabled });
|
|
61
|
+
|
|
62
|
+
// Apply trigger props from behavior
|
|
63
|
+
this.applyBehaviorProps();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private applyBehaviorProps(): void {
|
|
67
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
68
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
69
|
+
|
|
70
|
+
if (!tabsBehavior) return;
|
|
71
|
+
|
|
72
|
+
const triggerProps = tabsBehavior.getTriggerProps(this.value, { disabled: this.disabled });
|
|
73
|
+
this.id = triggerProps.id;
|
|
74
|
+
this.setAttribute("role", triggerProps.role);
|
|
75
|
+
this.setAttribute("tabindex", String(triggerProps.tabIndex));
|
|
76
|
+
this.setAttribute("aria-selected", triggerProps["aria-selected"]);
|
|
77
|
+
this.setAttribute("aria-controls", triggerProps["aria-controls"]);
|
|
78
|
+
|
|
79
|
+
if (triggerProps["aria-disabled"]) {
|
|
80
|
+
this.setAttribute("aria-disabled", triggerProps["aria-disabled"]);
|
|
81
|
+
} else {
|
|
82
|
+
this.removeAttribute("aria-disabled");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Update from behavior (called by parent).
|
|
88
|
+
*/
|
|
89
|
+
public updateFromBehavior(selected: boolean): void {
|
|
90
|
+
this.selected = selected;
|
|
91
|
+
this.applyBehaviorProps();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private handleClick = (): void => {
|
|
95
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
96
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
97
|
+
tabsBehavior?.handleTriggerClick(this.value);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
private handleKeyDown = (event: KeyboardEvent): void => {
|
|
101
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
102
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
103
|
+
tabsBehavior?.handleTriggerKeyDown(event, this.value);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
private handleFocus = (): void => {
|
|
107
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
108
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
109
|
+
tabsBehavior?.handleTriggerFocus(this.value);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
113
|
+
// Re-register if disabled state changes
|
|
114
|
+
if (changedProperties.has("disabled")) {
|
|
115
|
+
const tabsRoot = this.closest("ds-tabs") as DsTabs | null;
|
|
116
|
+
const tabsBehavior = tabsRoot?.getTabsBehavior();
|
|
117
|
+
if (tabsBehavior) {
|
|
118
|
+
tabsBehavior.unregisterTab(this.value);
|
|
119
|
+
tabsBehavior.registerTab(this.value, { disabled: this.disabled });
|
|
120
|
+
this.applyBehaviorProps();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override render() {
|
|
126
|
+
return html`<slot></slot>`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
define("ds-tabs-trigger", DsTabsTrigger);
|
|
131
|
+
|
|
132
|
+
declare global {
|
|
133
|
+
interface HTMLElementTagNameMap {
|
|
134
|
+
"ds-tabs-trigger": DsTabsTrigger;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tabs component - tabbed interface for organizing content.
|
|
3
|
+
*
|
|
4
|
+
* Implements WAI-ARIA Tabs pattern with keyboard navigation.
|
|
5
|
+
*
|
|
6
|
+
* @element ds-tabs
|
|
7
|
+
*
|
|
8
|
+
* @slot - Tabs content (ds-tabs-list, ds-tabs-content)
|
|
9
|
+
*
|
|
10
|
+
* @fires ds:change - Fired when selected tab changes
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```html
|
|
14
|
+
* <ds-tabs default-value="tab1">
|
|
15
|
+
* <ds-tabs-list>
|
|
16
|
+
* <ds-tabs-trigger value="tab1">Tab 1</ds-tabs-trigger>
|
|
17
|
+
* <ds-tabs-trigger value="tab2">Tab 2</ds-tabs-trigger>
|
|
18
|
+
* </ds-tabs-list>
|
|
19
|
+
* <ds-tabs-content value="tab1">Content 1</ds-tabs-content>
|
|
20
|
+
* <ds-tabs-content value="tab2">Content 2</ds-tabs-content>
|
|
21
|
+
* </ds-tabs>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
type TabsBehavior,
|
|
27
|
+
type TabsOrientation as BehaviorTabsOrientation,
|
|
28
|
+
type TabsActivationMode as BehaviorTabsActivationMode,
|
|
29
|
+
createTabsBehavior,
|
|
30
|
+
} from "@hypoth-ui/primitives-dom";
|
|
31
|
+
import { html } from "lit";
|
|
32
|
+
import { property, state } from "lit/decorators.js";
|
|
33
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
34
|
+
import { emitEvent } from "../../events/emit.js";
|
|
35
|
+
import { define } from "../../registry/define.js";
|
|
36
|
+
|
|
37
|
+
// Import child components
|
|
38
|
+
import type { DsTabsContent } from "./tabs-content.js";
|
|
39
|
+
import type { DsTabsList } from "./tabs-list.js";
|
|
40
|
+
import type { DsTabsTrigger } from "./tabs-trigger.js";
|
|
41
|
+
import "./tabs-list.js";
|
|
42
|
+
import "./tabs-trigger.js";
|
|
43
|
+
import "./tabs-content.js";
|
|
44
|
+
|
|
45
|
+
export type TabsOrientation = BehaviorTabsOrientation;
|
|
46
|
+
export type TabsActivationMode = BehaviorTabsActivationMode;
|
|
47
|
+
|
|
48
|
+
export class DsTabs extends DSElement {
|
|
49
|
+
/** Controlled value */
|
|
50
|
+
@property()
|
|
51
|
+
value: string | undefined;
|
|
52
|
+
|
|
53
|
+
/** Default value (uncontrolled) */
|
|
54
|
+
@property({ attribute: "default-value" })
|
|
55
|
+
defaultValue: string | undefined;
|
|
56
|
+
|
|
57
|
+
/** Keyboard navigation orientation */
|
|
58
|
+
@property({ reflect: true })
|
|
59
|
+
orientation: TabsOrientation = "horizontal";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Activation mode:
|
|
63
|
+
* - automatic: selection follows focus
|
|
64
|
+
* - manual: selection requires Enter/Space
|
|
65
|
+
*/
|
|
66
|
+
@property({ attribute: "activation-mode" })
|
|
67
|
+
activationMode: TabsActivationMode = "automatic";
|
|
68
|
+
|
|
69
|
+
/** Loop keyboard navigation at ends */
|
|
70
|
+
@property({ type: Boolean })
|
|
71
|
+
loop = true;
|
|
72
|
+
|
|
73
|
+
/** Internal tracked value */
|
|
74
|
+
@state()
|
|
75
|
+
private internalValue: string | undefined;
|
|
76
|
+
|
|
77
|
+
/** Behavior primitive instance */
|
|
78
|
+
private tabsBehavior: TabsBehavior | null = null;
|
|
79
|
+
|
|
80
|
+
/** Whether we're in controlled mode */
|
|
81
|
+
private get isControlled(): boolean {
|
|
82
|
+
return this.value !== undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Current active value */
|
|
86
|
+
get activeValue(): string | undefined {
|
|
87
|
+
return this.isControlled ? this.value : this.internalValue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Get the tabs behavior (for child components) */
|
|
91
|
+
getTabsBehavior(): TabsBehavior | null {
|
|
92
|
+
return this.tabsBehavior;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override connectedCallback(): void {
|
|
96
|
+
super.connectedCallback();
|
|
97
|
+
|
|
98
|
+
// Initialize internal value from default
|
|
99
|
+
if (!this.isControlled && this.defaultValue) {
|
|
100
|
+
this.internalValue = this.defaultValue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Initialize behavior
|
|
104
|
+
this.initTabsBehavior();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
override disconnectedCallback(): void {
|
|
108
|
+
super.disconnectedCallback();
|
|
109
|
+
this.tabsBehavior?.destroy();
|
|
110
|
+
this.tabsBehavior = null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private initTabsBehavior(): void {
|
|
114
|
+
this.tabsBehavior = createTabsBehavior({
|
|
115
|
+
defaultValue: this.activeValue ?? this.defaultValue ?? "",
|
|
116
|
+
orientation: this.orientation,
|
|
117
|
+
activationMode: this.activationMode,
|
|
118
|
+
loop: this.loop,
|
|
119
|
+
onValueChange: (newValue) => {
|
|
120
|
+
if (!this.isControlled) {
|
|
121
|
+
this.internalValue = newValue;
|
|
122
|
+
}
|
|
123
|
+
emitEvent(this, "ds:change", { detail: { value: newValue } });
|
|
124
|
+
this.updateTabsState();
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Select a tab by value.
|
|
131
|
+
*/
|
|
132
|
+
public selectTab(value: string): void {
|
|
133
|
+
if (this.activeValue === value) return;
|
|
134
|
+
this.tabsBehavior?.select(value);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
138
|
+
// Handle controlled value changes
|
|
139
|
+
if (changedProperties.has("value") && this.isControlled && this.value) {
|
|
140
|
+
this.tabsBehavior?.select(this.value);
|
|
141
|
+
this.updateTabsState();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Handle internal value changes
|
|
145
|
+
if (changedProperties.has("internalValue")) {
|
|
146
|
+
this.updateTabsState();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Initial update when defaultValue is set
|
|
150
|
+
if (changedProperties.has("defaultValue") && !this.isControlled && !this.internalValue) {
|
|
151
|
+
this.internalValue = this.defaultValue;
|
|
152
|
+
this.tabsBehavior?.select(this.defaultValue ?? "");
|
|
153
|
+
this.updateTabsState();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Re-create behavior if orientation/activationMode/loop change
|
|
157
|
+
if (
|
|
158
|
+
changedProperties.has("orientation") ||
|
|
159
|
+
changedProperties.has("activationMode") ||
|
|
160
|
+
changedProperties.has("loop")
|
|
161
|
+
) {
|
|
162
|
+
const currentValue = this.activeValue;
|
|
163
|
+
this.tabsBehavior?.destroy();
|
|
164
|
+
this.initTabsBehavior();
|
|
165
|
+
if (currentValue) {
|
|
166
|
+
this.tabsBehavior?.select(currentValue);
|
|
167
|
+
}
|
|
168
|
+
// Re-setup tablist element
|
|
169
|
+
const tabsList = this.querySelector("ds-tabs-list") as DsTabsList | null;
|
|
170
|
+
tabsList?.setupBehavior();
|
|
171
|
+
this.updateTabsState();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private updateTabsState(): void {
|
|
176
|
+
const activeValue = this.activeValue;
|
|
177
|
+
|
|
178
|
+
// Update triggers
|
|
179
|
+
const triggers = this.querySelectorAll("ds-tabs-trigger") as NodeListOf<DsTabsTrigger>;
|
|
180
|
+
for (const trigger of triggers) {
|
|
181
|
+
trigger.updateFromBehavior(trigger.value === activeValue);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Update content panels
|
|
185
|
+
const contents = this.querySelectorAll("ds-tabs-content") as NodeListOf<DsTabsContent>;
|
|
186
|
+
for (const content of contents) {
|
|
187
|
+
content.updateFromBehavior(content.value === activeValue);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override render() {
|
|
192
|
+
return html`<slot></slot>`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
define("ds-tabs", DsTabs);
|
|
197
|
+
|
|
198
|
+
declare global {
|
|
199
|
+
interface HTMLElementTagNameMap {
|
|
200
|
+
"ds-tabs": DsTabs;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type HTMLAttributes,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
createElement,
|
|
7
|
+
forwardRef,
|
|
8
|
+
useEffect,
|
|
9
|
+
useRef,
|
|
10
|
+
} from "react";
|
|
11
|
+
import "@hypoth-ui/wc";
|
|
12
|
+
import {
|
|
13
|
+
type ResponsiveProp,
|
|
14
|
+
generateResponsiveDataAttr,
|
|
15
|
+
isResponsiveObject,
|
|
16
|
+
resolveResponsiveValue,
|
|
17
|
+
} from "../../primitives/responsive.js";
|
|
18
|
+
|
|
19
|
+
export type TagVariant =
|
|
20
|
+
| "neutral"
|
|
21
|
+
| "primary"
|
|
22
|
+
| "secondary"
|
|
23
|
+
| "success"
|
|
24
|
+
| "warning"
|
|
25
|
+
| "error"
|
|
26
|
+
| "info";
|
|
27
|
+
export type TagSize = "sm" | "md" | "lg";
|
|
28
|
+
|
|
29
|
+
export interface TagProps extends HTMLAttributes<HTMLElement> {
|
|
30
|
+
/**
|
|
31
|
+
* Color variant.
|
|
32
|
+
* @default "neutral"
|
|
33
|
+
*/
|
|
34
|
+
variant?: TagVariant;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Size variant - supports responsive object syntax.
|
|
38
|
+
* @default "md"
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* // Single value
|
|
42
|
+
* <Tag size="md">React</Tag>
|
|
43
|
+
*
|
|
44
|
+
* // Responsive
|
|
45
|
+
* <Tag size={{ base: "sm", md: "md" }}>React</Tag>
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
size?: ResponsiveProp<TagSize>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Use solid (filled) style instead of subtle.
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
solid?: boolean;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Show remove button.
|
|
58
|
+
* @default false
|
|
59
|
+
*/
|
|
60
|
+
removable?: boolean;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Make tag clickable/interactive.
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
clickable?: boolean;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Disable the tag.
|
|
70
|
+
* @default false
|
|
71
|
+
*/
|
|
72
|
+
disabled?: boolean;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Value for identification in events.
|
|
76
|
+
*/
|
|
77
|
+
value?: string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Callback when remove button is clicked.
|
|
81
|
+
*/
|
|
82
|
+
onRemove?: (value: string) => void;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Tag content.
|
|
86
|
+
*/
|
|
87
|
+
children?: ReactNode;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Tag component for categorization with optional remove action.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```tsx
|
|
95
|
+
* // Basic tag
|
|
96
|
+
* <Tag variant="primary">React</Tag>
|
|
97
|
+
*
|
|
98
|
+
* // Removable tag
|
|
99
|
+
* <Tag removable onRemove={(value) => console.log('Removed:', value)} value="react">
|
|
100
|
+
* React
|
|
101
|
+
* </Tag>
|
|
102
|
+
*
|
|
103
|
+
* // Clickable tag
|
|
104
|
+
* <Tag clickable onClick={() => console.log('Clicked')}>
|
|
105
|
+
* Click me
|
|
106
|
+
* </Tag>
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export const Tag = forwardRef<HTMLElement, TagProps>(function Tag(
|
|
110
|
+
{
|
|
111
|
+
variant = "neutral",
|
|
112
|
+
size = "md",
|
|
113
|
+
solid = false,
|
|
114
|
+
removable = false,
|
|
115
|
+
clickable = false,
|
|
116
|
+
disabled = false,
|
|
117
|
+
value,
|
|
118
|
+
onRemove,
|
|
119
|
+
children,
|
|
120
|
+
className,
|
|
121
|
+
...props
|
|
122
|
+
},
|
|
123
|
+
forwardedRef
|
|
124
|
+
) {
|
|
125
|
+
const internalRef = useRef<HTMLElement>(null);
|
|
126
|
+
|
|
127
|
+
// Sync forwarded ref
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (typeof forwardedRef === "function") {
|
|
130
|
+
forwardedRef(internalRef.current);
|
|
131
|
+
} else if (forwardedRef) {
|
|
132
|
+
(forwardedRef as React.MutableRefObject<HTMLElement | null>).current = internalRef.current;
|
|
133
|
+
}
|
|
134
|
+
}, [forwardedRef]);
|
|
135
|
+
|
|
136
|
+
// Set up event listeners
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
const element = internalRef.current;
|
|
139
|
+
if (!element) return;
|
|
140
|
+
|
|
141
|
+
const handleRemove = (e: Event) => {
|
|
142
|
+
const event = e as CustomEvent<{ value: string }>;
|
|
143
|
+
onRemove?.(event.detail.value);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
element.addEventListener("ds:remove", handleRemove);
|
|
147
|
+
return () => element.removeEventListener("ds:remove", handleRemove);
|
|
148
|
+
}, [onRemove]);
|
|
149
|
+
|
|
150
|
+
// Resolve responsive size - use base value for the WC attribute
|
|
151
|
+
const resolvedSize = resolveResponsiveValue(size, "md");
|
|
152
|
+
const isResponsive = isResponsiveObject(size);
|
|
153
|
+
const responsiveSizeAttr = isResponsive ? generateResponsiveDataAttr(size) : undefined;
|
|
154
|
+
|
|
155
|
+
return createElement(
|
|
156
|
+
"ds-tag",
|
|
157
|
+
{
|
|
158
|
+
ref: internalRef,
|
|
159
|
+
variant,
|
|
160
|
+
size: resolvedSize,
|
|
161
|
+
solid: solid || undefined,
|
|
162
|
+
removable: removable || undefined,
|
|
163
|
+
clickable: clickable || undefined,
|
|
164
|
+
disabled: disabled || undefined,
|
|
165
|
+
value,
|
|
166
|
+
class: className,
|
|
167
|
+
// Add responsive data attribute for CSS targeting
|
|
168
|
+
"data-size-responsive": responsiveSizeAttr,
|
|
169
|
+
...props,
|
|
170
|
+
},
|
|
171
|
+
children
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// TypeScript declaration for JSX
|
|
176
|
+
declare global {
|
|
177
|
+
namespace JSX {
|
|
178
|
+
interface IntrinsicElements {
|
|
179
|
+
"ds-tag": TagProps & {
|
|
180
|
+
ref?: React.Ref<HTMLElement>;
|
|
181
|
+
"onDs-remove"?: (event: CustomEvent) => void;
|
|
182
|
+
"onDs-click"?: (event: CustomEvent) => void;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|