@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,343 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AnchorPosition,
|
|
3
|
+
type DismissableLayer,
|
|
4
|
+
type Placement,
|
|
5
|
+
type Presence,
|
|
6
|
+
createAnchorPosition,
|
|
7
|
+
createDismissableLayer,
|
|
8
|
+
createPresence,
|
|
9
|
+
prefersReducedMotion,
|
|
10
|
+
} from "@hypoth-ui/primitives-dom";
|
|
11
|
+
import { html } from "lit";
|
|
12
|
+
import { property } from "lit/decorators.js";
|
|
13
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
14
|
+
import { StandardEvents, emitEvent } from "../../events/emit.js";
|
|
15
|
+
import { define } from "../../registry/define.js";
|
|
16
|
+
|
|
17
|
+
// Import child component to ensure it's registered
|
|
18
|
+
import type { DsPopoverContent } from "./popover-content.js";
|
|
19
|
+
import "./popover-content.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Non-modal popover component with anchor positioning.
|
|
23
|
+
*
|
|
24
|
+
* Unlike Dialog, Popover does not trap focus and allows Tab to exit.
|
|
25
|
+
* Positioned relative to its trigger using anchor positioning.
|
|
26
|
+
*
|
|
27
|
+
* @element ds-popover
|
|
28
|
+
*
|
|
29
|
+
* @slot trigger - Button or element that opens the popover
|
|
30
|
+
* @slot - Popover content (ds-popover-content)
|
|
31
|
+
*
|
|
32
|
+
* @fires ds:open - Fired when popover opens
|
|
33
|
+
* @fires ds:close - Fired when popover closes
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```html
|
|
37
|
+
* <ds-popover>
|
|
38
|
+
* <button slot="trigger">Open Menu</button>
|
|
39
|
+
* <ds-popover-content>
|
|
40
|
+
* <button>Option 1</button>
|
|
41
|
+
* <button>Option 2</button>
|
|
42
|
+
* </ds-popover-content>
|
|
43
|
+
* </ds-popover>
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class DsPopover extends DSElement {
|
|
47
|
+
/** Whether the popover is open */
|
|
48
|
+
@property({ type: Boolean, reflect: true })
|
|
49
|
+
open = false;
|
|
50
|
+
|
|
51
|
+
/** Placement relative to trigger */
|
|
52
|
+
@property({ type: String, reflect: true })
|
|
53
|
+
placement: Placement = "bottom";
|
|
54
|
+
|
|
55
|
+
/** Offset distance from trigger in pixels */
|
|
56
|
+
@property({ type: Number })
|
|
57
|
+
offset = 8;
|
|
58
|
+
|
|
59
|
+
/** Whether to flip placement when near viewport edge */
|
|
60
|
+
@property({ type: Boolean })
|
|
61
|
+
flip = true;
|
|
62
|
+
|
|
63
|
+
/** Whether Escape key closes the popover */
|
|
64
|
+
@property({
|
|
65
|
+
attribute: "close-on-escape",
|
|
66
|
+
converter: {
|
|
67
|
+
fromAttribute: (value: string | null) => value !== "false",
|
|
68
|
+
toAttribute: (value: boolean) => (value ? "" : "false"),
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
closeOnEscape = true;
|
|
72
|
+
|
|
73
|
+
/** Whether clicking outside closes the popover */
|
|
74
|
+
@property({
|
|
75
|
+
attribute: "close-on-outside-click",
|
|
76
|
+
converter: {
|
|
77
|
+
fromAttribute: (value: string | null) => value !== "false",
|
|
78
|
+
toAttribute: (value: boolean) => (value ? "" : "false"),
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
closeOnOutsideClick = true;
|
|
82
|
+
|
|
83
|
+
/** Whether to animate open/close transitions */
|
|
84
|
+
@property({ type: Boolean })
|
|
85
|
+
animated = true;
|
|
86
|
+
|
|
87
|
+
private anchorPosition: AnchorPosition | null = null;
|
|
88
|
+
private dismissLayer: DismissableLayer | null = null;
|
|
89
|
+
private presence: Presence | null = null;
|
|
90
|
+
private triggerElement: HTMLElement | null = null;
|
|
91
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
92
|
+
private scrollHandler: (() => void) | null = null;
|
|
93
|
+
|
|
94
|
+
override connectedCallback(): void {
|
|
95
|
+
super.connectedCallback();
|
|
96
|
+
|
|
97
|
+
// Listen for trigger clicks
|
|
98
|
+
this.addEventListener("click", this.handleTriggerClick);
|
|
99
|
+
|
|
100
|
+
// Setup after first render
|
|
101
|
+
this.updateComplete.then(() => {
|
|
102
|
+
this.setupTriggerAccessibility();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override disconnectedCallback(): void {
|
|
107
|
+
super.disconnectedCallback();
|
|
108
|
+
this.removeEventListener("click", this.handleTriggerClick);
|
|
109
|
+
this.cleanup();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Opens the popover.
|
|
114
|
+
*/
|
|
115
|
+
public show(): void {
|
|
116
|
+
if (this.open) return;
|
|
117
|
+
|
|
118
|
+
this.open = true;
|
|
119
|
+
emitEvent(this, StandardEvents.OPEN);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Closes the popover.
|
|
124
|
+
*/
|
|
125
|
+
public close(): void {
|
|
126
|
+
if (!this.open) return;
|
|
127
|
+
|
|
128
|
+
const content = this.querySelector("ds-popover-content") as DsPopoverContent | null;
|
|
129
|
+
|
|
130
|
+
// If animated, use presence for exit animation
|
|
131
|
+
if (this.animated && content && !prefersReducedMotion()) {
|
|
132
|
+
// Cleanup dismiss layer so clicks don't re-trigger close
|
|
133
|
+
this.dismissLayer?.deactivate();
|
|
134
|
+
this.dismissLayer = null;
|
|
135
|
+
|
|
136
|
+
// Create presence for exit animation
|
|
137
|
+
this.presence = createPresence({
|
|
138
|
+
onExitComplete: () => {
|
|
139
|
+
this.completeClose();
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
this.presence.hide(content);
|
|
143
|
+
} else {
|
|
144
|
+
// No animation - close immediately
|
|
145
|
+
this.cleanup();
|
|
146
|
+
this.open = false;
|
|
147
|
+
emitEvent(this, StandardEvents.CLOSE);
|
|
148
|
+
|
|
149
|
+
// Return focus to trigger
|
|
150
|
+
this.triggerElement?.focus();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Completes the close after exit animation.
|
|
156
|
+
*/
|
|
157
|
+
private completeClose(): void {
|
|
158
|
+
this.cleanup();
|
|
159
|
+
this.open = false;
|
|
160
|
+
emitEvent(this, StandardEvents.CLOSE);
|
|
161
|
+
|
|
162
|
+
// Return focus to trigger
|
|
163
|
+
this.triggerElement?.focus();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Toggles the popover open/closed state.
|
|
168
|
+
*/
|
|
169
|
+
public toggle(): void {
|
|
170
|
+
if (this.open) {
|
|
171
|
+
this.close();
|
|
172
|
+
} else {
|
|
173
|
+
this.show();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private handleTriggerClick = (event: Event): void => {
|
|
178
|
+
const target = event.target as HTMLElement;
|
|
179
|
+
const trigger = target.closest('[slot="trigger"]');
|
|
180
|
+
|
|
181
|
+
if (trigger && this.contains(trigger)) {
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
this.triggerElement = trigger as HTMLElement;
|
|
184
|
+
this.toggle();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
private handleDismiss = (reason: "escape" | "outside-click"): void => {
|
|
189
|
+
if (reason === "escape" && this.closeOnEscape) {
|
|
190
|
+
this.close();
|
|
191
|
+
} else if (reason === "outside-click" && this.closeOnOutsideClick) {
|
|
192
|
+
this.close();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
private setupTriggerAccessibility(): void {
|
|
197
|
+
const trigger = this.querySelector('[slot="trigger"]');
|
|
198
|
+
const content = this.querySelector("ds-popover-content");
|
|
199
|
+
|
|
200
|
+
if (trigger && content) {
|
|
201
|
+
// Store reference
|
|
202
|
+
this.triggerElement = trigger as HTMLElement;
|
|
203
|
+
|
|
204
|
+
// Set ARIA attributes on trigger
|
|
205
|
+
trigger.setAttribute("aria-haspopup", "true");
|
|
206
|
+
trigger.setAttribute("aria-expanded", String(this.open));
|
|
207
|
+
trigger.setAttribute("aria-controls", content.id);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private updateTriggerAria(): void {
|
|
212
|
+
const trigger = this.querySelector('[slot="trigger"]');
|
|
213
|
+
if (trigger) {
|
|
214
|
+
trigger.setAttribute("aria-expanded", String(this.open));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private setupPositioning(): void {
|
|
219
|
+
const trigger = this.querySelector('[slot="trigger"]') as HTMLElement | null;
|
|
220
|
+
const content = this.querySelector("ds-popover-content") as HTMLElement | null;
|
|
221
|
+
|
|
222
|
+
if (!trigger || !content) return;
|
|
223
|
+
|
|
224
|
+
// Setup anchor positioning
|
|
225
|
+
this.anchorPosition = createAnchorPosition({
|
|
226
|
+
anchor: trigger,
|
|
227
|
+
floating: content,
|
|
228
|
+
placement: this.placement,
|
|
229
|
+
offset: this.offset,
|
|
230
|
+
flip: this.flip,
|
|
231
|
+
onPositionChange: (pos) => {
|
|
232
|
+
content.setAttribute("data-placement", pos.placement);
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Setup resize observer for repositioning
|
|
237
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
238
|
+
this.anchorPosition?.update();
|
|
239
|
+
});
|
|
240
|
+
this.resizeObserver.observe(trigger);
|
|
241
|
+
this.resizeObserver.observe(content);
|
|
242
|
+
|
|
243
|
+
// Setup scroll handler for repositioning
|
|
244
|
+
this.scrollHandler = () => {
|
|
245
|
+
this.anchorPosition?.update();
|
|
246
|
+
};
|
|
247
|
+
window.addEventListener("scroll", this.scrollHandler, { passive: true });
|
|
248
|
+
window.addEventListener("resize", this.scrollHandler, { passive: true });
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private setupDismissLayer(): void {
|
|
252
|
+
const content = this.querySelector("ds-popover-content") as HTMLElement | null;
|
|
253
|
+
const trigger = this.querySelector('[slot="trigger"]') as HTMLElement | null;
|
|
254
|
+
|
|
255
|
+
if (!content) return;
|
|
256
|
+
|
|
257
|
+
this.dismissLayer = createDismissableLayer({
|
|
258
|
+
container: content,
|
|
259
|
+
excludeElements: trigger ? [trigger] : [],
|
|
260
|
+
onDismiss: this.handleDismiss,
|
|
261
|
+
closeOnEscape: this.closeOnEscape,
|
|
262
|
+
closeOnOutsideClick: this.closeOnOutsideClick,
|
|
263
|
+
});
|
|
264
|
+
this.dismissLayer.activate();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private cleanup(): void {
|
|
268
|
+
// Cleanup anchor positioning
|
|
269
|
+
this.anchorPosition?.destroy();
|
|
270
|
+
this.anchorPosition = null;
|
|
271
|
+
|
|
272
|
+
// Cleanup dismiss layer
|
|
273
|
+
this.dismissLayer?.deactivate();
|
|
274
|
+
this.dismissLayer = null;
|
|
275
|
+
|
|
276
|
+
// Cleanup presence
|
|
277
|
+
this.presence?.destroy();
|
|
278
|
+
this.presence = null;
|
|
279
|
+
|
|
280
|
+
// Cleanup resize observer
|
|
281
|
+
this.resizeObserver?.disconnect();
|
|
282
|
+
this.resizeObserver = null;
|
|
283
|
+
|
|
284
|
+
// Cleanup scroll handler
|
|
285
|
+
if (this.scrollHandler) {
|
|
286
|
+
window.removeEventListener("scroll", this.scrollHandler);
|
|
287
|
+
window.removeEventListener("resize", this.scrollHandler);
|
|
288
|
+
this.scrollHandler = null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
override async updated(changedProperties: Map<string, unknown>): Promise<void> {
|
|
293
|
+
super.updated(changedProperties);
|
|
294
|
+
|
|
295
|
+
if (changedProperties.has("open")) {
|
|
296
|
+
this.updateTriggerAria();
|
|
297
|
+
|
|
298
|
+
const content = this.querySelector("ds-popover-content") as DsPopoverContent | null;
|
|
299
|
+
|
|
300
|
+
if (this.open) {
|
|
301
|
+
// Show content
|
|
302
|
+
content?.removeAttribute("hidden");
|
|
303
|
+
|
|
304
|
+
// Set data-state to open for entry animation
|
|
305
|
+
if (content) {
|
|
306
|
+
content.dataState = "open";
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Wait for DOM update
|
|
310
|
+
await this.updateComplete;
|
|
311
|
+
|
|
312
|
+
// Setup positioning and dismiss
|
|
313
|
+
this.setupPositioning();
|
|
314
|
+
this.setupDismissLayer();
|
|
315
|
+
} else {
|
|
316
|
+
// Hide content
|
|
317
|
+
content?.setAttribute("hidden", "");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Update positioning if placement or offset changes while open
|
|
322
|
+
if (this.open && (changedProperties.has("placement") || changedProperties.has("offset"))) {
|
|
323
|
+
this.cleanup();
|
|
324
|
+
this.setupPositioning();
|
|
325
|
+
this.setupDismissLayer();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
override render() {
|
|
330
|
+
return html`
|
|
331
|
+
<slot name="trigger"></slot>
|
|
332
|
+
<slot></slot>
|
|
333
|
+
`;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
define("ds-popover", DsPopover);
|
|
338
|
+
|
|
339
|
+
declare global {
|
|
340
|
+
interface HTMLElementTagNameMap {
|
|
341
|
+
"ds-popover": DsPopover;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type HTMLAttributes, createElement, forwardRef } from "react";
|
|
4
|
+
import "@hypoth-ui/wc";
|
|
5
|
+
import {
|
|
6
|
+
type ResponsiveProp,
|
|
7
|
+
generateResponsiveDataAttr,
|
|
8
|
+
isResponsiveObject,
|
|
9
|
+
resolveResponsiveValue,
|
|
10
|
+
} from "../../primitives/responsive.js";
|
|
11
|
+
|
|
12
|
+
export type ProgressVariant = "linear" | "circular";
|
|
13
|
+
export type ProgressSize = "sm" | "md" | "lg";
|
|
14
|
+
|
|
15
|
+
export interface ProgressProps extends Omit<HTMLAttributes<HTMLElement>, "children"> {
|
|
16
|
+
/**
|
|
17
|
+
* Current progress value (0-100). Omit for indeterminate.
|
|
18
|
+
*/
|
|
19
|
+
value?: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Maximum value.
|
|
23
|
+
* @default 100
|
|
24
|
+
*/
|
|
25
|
+
max?: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Visual variant.
|
|
29
|
+
* @default "linear"
|
|
30
|
+
*/
|
|
31
|
+
variant?: ProgressVariant;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Size variant - supports responsive object syntax.
|
|
35
|
+
* @default "md"
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* // Single value
|
|
39
|
+
* <Progress value={75} size="md" />
|
|
40
|
+
*
|
|
41
|
+
* // Responsive
|
|
42
|
+
* <Progress value={75} size={{ base: "sm", md: "lg" }} />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
size?: ResponsiveProp<ProgressSize>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Accessible label.
|
|
49
|
+
*/
|
|
50
|
+
label?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Show value as percentage text (circular only).
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
showValue?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Progress indicator component for showing loading or completion status.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* // Determinate linear progress
|
|
65
|
+
* <Progress value={75} label="Uploading..." />
|
|
66
|
+
*
|
|
67
|
+
* // Indeterminate circular progress
|
|
68
|
+
* <Progress variant="circular" label="Loading" />
|
|
69
|
+
*
|
|
70
|
+
* // Circular with percentage display
|
|
71
|
+
* <Progress variant="circular" value={45} showValue />
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export const Progress = forwardRef<HTMLElement, ProgressProps>(function Progress(
|
|
75
|
+
{
|
|
76
|
+
value,
|
|
77
|
+
max = 100,
|
|
78
|
+
variant = "linear",
|
|
79
|
+
size = "md",
|
|
80
|
+
label,
|
|
81
|
+
showValue = false,
|
|
82
|
+
className,
|
|
83
|
+
...props
|
|
84
|
+
},
|
|
85
|
+
ref
|
|
86
|
+
) {
|
|
87
|
+
// Resolve responsive size - use base value for the WC attribute
|
|
88
|
+
const resolvedSize = resolveResponsiveValue(size, "md");
|
|
89
|
+
const isResponsive = isResponsiveObject(size);
|
|
90
|
+
const responsiveSizeAttr = isResponsive ? generateResponsiveDataAttr(size) : undefined;
|
|
91
|
+
|
|
92
|
+
return createElement("ds-progress", {
|
|
93
|
+
ref,
|
|
94
|
+
value,
|
|
95
|
+
max,
|
|
96
|
+
variant,
|
|
97
|
+
size: resolvedSize,
|
|
98
|
+
label,
|
|
99
|
+
"show-value": showValue || undefined,
|
|
100
|
+
class: className,
|
|
101
|
+
// Add responsive data attribute for CSS targeting
|
|
102
|
+
"data-size-responsive": responsiveSizeAttr,
|
|
103
|
+
...props,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// TypeScript declaration for JSX
|
|
108
|
+
declare global {
|
|
109
|
+
namespace JSX {
|
|
110
|
+
interface IntrinsicElements {
|
|
111
|
+
"ds-progress": ProgressProps & {
|
|
112
|
+
ref?: React.Ref<HTMLElement>;
|
|
113
|
+
"show-value"?: boolean;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { type TemplateResult, html, nothing } from "lit";
|
|
2
|
+
import { property } from "lit/decorators.js";
|
|
3
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
4
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
5
|
+
import { define } from "../../registry/define.js";
|
|
6
|
+
|
|
7
|
+
export type ProgressVariant = "linear" | "circular";
|
|
8
|
+
export type ProgressSize = "sm" | "md" | "lg";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Progress indicator component.
|
|
12
|
+
*
|
|
13
|
+
* @element ds-progress
|
|
14
|
+
*
|
|
15
|
+
* @csspart track - The progress track
|
|
16
|
+
* @csspart bar - The progress bar/fill
|
|
17
|
+
* @csspart label - The accessible label
|
|
18
|
+
*
|
|
19
|
+
* @cssprop --ds-progress-track - Track background color
|
|
20
|
+
* @cssprop --ds-progress-fill - Fill/indicator color
|
|
21
|
+
* @cssprop --ds-progress-height - Track height (linear)
|
|
22
|
+
*/
|
|
23
|
+
export class DsProgress extends DSElement {
|
|
24
|
+
static override styles = [];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Current progress value (0-100). Omit for indeterminate.
|
|
28
|
+
*/
|
|
29
|
+
@property({ type: Number })
|
|
30
|
+
value?: number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Maximum value.
|
|
34
|
+
*/
|
|
35
|
+
@property({ type: Number })
|
|
36
|
+
max = 100;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Visual variant.
|
|
40
|
+
*/
|
|
41
|
+
@property({ type: String, reflect: true })
|
|
42
|
+
variant: ProgressVariant = "linear";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Size variant.
|
|
46
|
+
*/
|
|
47
|
+
@property({ type: String, reflect: true })
|
|
48
|
+
size: ProgressSize = "md";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Accessible label.
|
|
52
|
+
*/
|
|
53
|
+
@property({ type: String })
|
|
54
|
+
label = "";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Show value as percentage text (circular only).
|
|
58
|
+
*/
|
|
59
|
+
@property({ type: Boolean, attribute: "show-value" })
|
|
60
|
+
showValue = false;
|
|
61
|
+
|
|
62
|
+
private get isIndeterminate(): boolean {
|
|
63
|
+
return this.value === undefined || this.value === null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private get percentage(): number {
|
|
67
|
+
if (this.isIndeterminate) return 0;
|
|
68
|
+
return Math.min(100, Math.max(0, ((this.value ?? 0) / this.max) * 100));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private get valueText(): string {
|
|
72
|
+
if (this.isIndeterminate) {
|
|
73
|
+
return this.label || "Loading...";
|
|
74
|
+
}
|
|
75
|
+
return `${Math.round(this.percentage)}% complete`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private renderLinear(): TemplateResult {
|
|
79
|
+
const classes = {
|
|
80
|
+
"ds-progress": true,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return html`
|
|
84
|
+
<div
|
|
85
|
+
part="track"
|
|
86
|
+
class=${classMap(classes)}
|
|
87
|
+
role="progressbar"
|
|
88
|
+
aria-valuenow=${this.isIndeterminate ? nothing : this.value}
|
|
89
|
+
aria-valuemin="0"
|
|
90
|
+
aria-valuemax=${this.max}
|
|
91
|
+
aria-valuetext=${this.valueText}
|
|
92
|
+
aria-label=${this.label || nothing}
|
|
93
|
+
?aria-busy=${this.isIndeterminate}
|
|
94
|
+
data-size=${this.size}
|
|
95
|
+
?data-indeterminate=${this.isIndeterminate}
|
|
96
|
+
>
|
|
97
|
+
<div
|
|
98
|
+
part="bar"
|
|
99
|
+
class="ds-progress__bar"
|
|
100
|
+
style=${this.isIndeterminate ? "" : `width: ${this.percentage}%`}
|
|
101
|
+
></div>
|
|
102
|
+
${
|
|
103
|
+
this.label
|
|
104
|
+
? html`<span part="label" class="ds-progress__label">${this.label}</span>`
|
|
105
|
+
: nothing
|
|
106
|
+
}
|
|
107
|
+
</div>
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private renderCircular(): TemplateResult {
|
|
112
|
+
// SVG circle calculations
|
|
113
|
+
const size = this.size === "sm" ? 24 : this.size === "lg" ? 64 : 40;
|
|
114
|
+
const strokeWidth = this.size === "sm" ? 3 : this.size === "lg" ? 6 : 4;
|
|
115
|
+
const radius = (size - strokeWidth) / 2;
|
|
116
|
+
const circumference = 2 * Math.PI * radius;
|
|
117
|
+
const offset = circumference - (this.percentage / 100) * circumference;
|
|
118
|
+
|
|
119
|
+
const classes = {
|
|
120
|
+
"ds-progress-circular": true,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return html`
|
|
124
|
+
<div
|
|
125
|
+
class=${classMap(classes)}
|
|
126
|
+
role="progressbar"
|
|
127
|
+
aria-valuenow=${this.isIndeterminate ? nothing : this.value}
|
|
128
|
+
aria-valuemin="0"
|
|
129
|
+
aria-valuemax=${this.max}
|
|
130
|
+
aria-valuetext=${this.valueText}
|
|
131
|
+
aria-label=${this.label || nothing}
|
|
132
|
+
?aria-busy=${this.isIndeterminate}
|
|
133
|
+
data-size=${this.size}
|
|
134
|
+
?data-indeterminate=${this.isIndeterminate}
|
|
135
|
+
>
|
|
136
|
+
<svg class="ds-progress-circular__svg" viewBox="0 0 ${size} ${size}">
|
|
137
|
+
<circle
|
|
138
|
+
class="ds-progress-circular__track"
|
|
139
|
+
cx=${size / 2}
|
|
140
|
+
cy=${size / 2}
|
|
141
|
+
r=${radius}
|
|
142
|
+
/>
|
|
143
|
+
<circle
|
|
144
|
+
class="ds-progress-circular__fill"
|
|
145
|
+
cx=${size / 2}
|
|
146
|
+
cy=${size / 2}
|
|
147
|
+
r=${radius}
|
|
148
|
+
stroke-dasharray=${circumference}
|
|
149
|
+
stroke-dashoffset=${this.isIndeterminate ? 0 : offset}
|
|
150
|
+
/>
|
|
151
|
+
</svg>
|
|
152
|
+
${
|
|
153
|
+
this.showValue && !this.isIndeterminate
|
|
154
|
+
? html`<span class="ds-progress-circular__label">${Math.round(this.percentage)}%</span>`
|
|
155
|
+
: nothing
|
|
156
|
+
}
|
|
157
|
+
</div>
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
override render(): TemplateResult {
|
|
162
|
+
return this.variant === "circular" ? this.renderCircular() : this.renderLinear();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Register the component
|
|
167
|
+
define("ds-progress", DsProgress);
|
|
168
|
+
|
|
169
|
+
// TypeScript declaration for HTML
|
|
170
|
+
declare global {
|
|
171
|
+
interface HTMLElementTagNameMap {
|
|
172
|
+
"ds-progress": DsProgress;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { type HTMLAttributes, createElement, forwardRef, useEffect, useRef } from "react";
|
|
3
|
+
|
|
4
|
+
export interface RadioProps extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
/** Radio value */
|
|
6
|
+
value: string;
|
|
7
|
+
/** Whether disabled */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Radio label content */
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* React wrapper for ds-radio Web Component.
|
|
15
|
+
* Individual radio option within a RadioGroup.
|
|
16
|
+
*/
|
|
17
|
+
export const Radio = forwardRef<HTMLElement, RadioProps>((props, forwardedRef) => {
|
|
18
|
+
const { value, disabled = false, children, className, ...rest } = props;
|
|
19
|
+
|
|
20
|
+
const internalRef = useRef<HTMLElement>(null);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (typeof forwardedRef === "function") {
|
|
24
|
+
forwardedRef(internalRef.current);
|
|
25
|
+
} else if (forwardedRef) {
|
|
26
|
+
(forwardedRef as React.MutableRefObject<HTMLElement | null>).current = internalRef.current;
|
|
27
|
+
}
|
|
28
|
+
}, [forwardedRef]);
|
|
29
|
+
|
|
30
|
+
return createElement(
|
|
31
|
+
"ds-radio",
|
|
32
|
+
{
|
|
33
|
+
ref: internalRef,
|
|
34
|
+
value,
|
|
35
|
+
disabled: disabled || undefined,
|
|
36
|
+
class: className,
|
|
37
|
+
...rest,
|
|
38
|
+
},
|
|
39
|
+
children
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Radio.displayName = "Radio";
|