@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,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog Root component - provides context to all Dialog compound components.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { type DialogRole, createDialogBehavior } from "@hypoth-ui/primitives-dom";
|
|
6
|
+
import { type ReactNode, useCallback, useMemo, useState } from "react";
|
|
7
|
+
import { useStableId } from "../../hooks/use-stable-id.js";
|
|
8
|
+
import { DialogProvider } from "./dialog-context.js";
|
|
9
|
+
|
|
10
|
+
export interface DialogRootProps {
|
|
11
|
+
/** Dialog content */
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
/** Custom ID for the dialog (SSR-safe auto-generated if not provided) */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Controlled open state */
|
|
16
|
+
open?: boolean;
|
|
17
|
+
/** Default open state (uncontrolled) */
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
/** Called when open state changes */
|
|
20
|
+
onOpenChange?: (open: boolean) => void;
|
|
21
|
+
/** Dialog role */
|
|
22
|
+
role?: DialogRole;
|
|
23
|
+
/** Whether dialog is modal (traps focus) */
|
|
24
|
+
modal?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Root component for Dialog compound pattern.
|
|
29
|
+
* Provides context to Trigger, Content, Title, Description, and Close.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <Dialog.Root>
|
|
34
|
+
* <Dialog.Trigger>Open</Dialog.Trigger>
|
|
35
|
+
* <Dialog.Content>
|
|
36
|
+
* <Dialog.Title>Dialog Title</Dialog.Title>
|
|
37
|
+
* <Dialog.Description>Dialog description</Dialog.Description>
|
|
38
|
+
* <Dialog.Close>Close</Dialog.Close>
|
|
39
|
+
* </Dialog.Content>
|
|
40
|
+
* </Dialog.Root>
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function DialogRoot({
|
|
44
|
+
children,
|
|
45
|
+
id,
|
|
46
|
+
open: controlledOpen,
|
|
47
|
+
defaultOpen = false,
|
|
48
|
+
onOpenChange,
|
|
49
|
+
role = "dialog",
|
|
50
|
+
modal = true,
|
|
51
|
+
}: DialogRootProps) {
|
|
52
|
+
// Generate SSR-safe stable ID using React 18's useId under the hood
|
|
53
|
+
const stableId = useStableId({ id, prefix: "dialog" });
|
|
54
|
+
|
|
55
|
+
// Support both controlled and uncontrolled modes
|
|
56
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
57
|
+
const isControlled = controlledOpen !== undefined;
|
|
58
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
59
|
+
|
|
60
|
+
// Track description presence for aria-describedby
|
|
61
|
+
const [descriptionId, setDescriptionId] = useState<string | null>(null);
|
|
62
|
+
|
|
63
|
+
const setOpen = useCallback(
|
|
64
|
+
(nextOpen: boolean) => {
|
|
65
|
+
if (!isControlled) {
|
|
66
|
+
setInternalOpen(nextOpen);
|
|
67
|
+
}
|
|
68
|
+
onOpenChange?.(nextOpen);
|
|
69
|
+
},
|
|
70
|
+
[isControlled, onOpenChange]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Create behavior instance - intentionally created once with initial values
|
|
74
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: behavior is created once, open state synced via setOpen callback
|
|
75
|
+
const behavior = useMemo(
|
|
76
|
+
() =>
|
|
77
|
+
createDialogBehavior({
|
|
78
|
+
defaultOpen: open,
|
|
79
|
+
role,
|
|
80
|
+
closeOnEscape: true,
|
|
81
|
+
closeOnOutsideClick: true,
|
|
82
|
+
onOpenChange: setOpen,
|
|
83
|
+
// Use SSR-safe stable ID generator
|
|
84
|
+
generateId: () => stableId,
|
|
85
|
+
}),
|
|
86
|
+
[stableId]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const contextValue = useMemo(
|
|
90
|
+
() => ({
|
|
91
|
+
behavior,
|
|
92
|
+
open,
|
|
93
|
+
setOpen,
|
|
94
|
+
modal,
|
|
95
|
+
descriptionId,
|
|
96
|
+
setDescriptionId,
|
|
97
|
+
}),
|
|
98
|
+
[behavior, open, setOpen, modal, descriptionId]
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return <DialogProvider value={contextValue}>{children}</DialogProvider>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
DialogRoot.displayName = "Dialog.Root";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog Title component - accessible title for the dialog.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { type HTMLAttributes, type ReactNode, forwardRef } from "react";
|
|
6
|
+
import { useDialogContext } from "./dialog-context.js";
|
|
7
|
+
|
|
8
|
+
export interface DialogTitleProps extends HTMLAttributes<HTMLHeadingElement> {
|
|
9
|
+
/** Title content */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Accessible title for the dialog.
|
|
15
|
+
* Automatically linked to dialog via aria-labelledby.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <Dialog.Content>
|
|
20
|
+
* <Dialog.Title>Confirm Action</Dialog.Title>
|
|
21
|
+
* ...
|
|
22
|
+
* </Dialog.Content>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const DialogTitle = forwardRef<HTMLHeadingElement, DialogTitleProps>(
|
|
26
|
+
({ children, ...restProps }, ref) => {
|
|
27
|
+
const { behavior } = useDialogContext("Dialog.Title");
|
|
28
|
+
const titleProps = behavior.getTitleProps();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<h2 ref={ref} id={titleProps.id} {...restProps}>
|
|
32
|
+
{children}
|
|
33
|
+
</h2>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
DialogTitle.displayName = "Dialog.Title";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog Trigger component - opens the dialog when activated.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type ButtonHTMLAttributes,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
forwardRef,
|
|
9
|
+
useCallback,
|
|
10
|
+
useEffect,
|
|
11
|
+
useRef,
|
|
12
|
+
} from "react";
|
|
13
|
+
import { Slot } from "../../primitives/slot.js";
|
|
14
|
+
import { useDialogContext } from "./dialog-context.js";
|
|
15
|
+
|
|
16
|
+
export interface DialogTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
17
|
+
/** Trigger content */
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
/** Render as child element (polymorphic) */
|
|
20
|
+
asChild?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Trigger button that opens the dialog.
|
|
25
|
+
* Supports asChild for custom trigger elements.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
30
|
+
*
|
|
31
|
+
* <Dialog.Trigger asChild>
|
|
32
|
+
* <button className="custom-button">Custom Trigger</button>
|
|
33
|
+
* </Dialog.Trigger>
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export const DialogTrigger = forwardRef<HTMLButtonElement, DialogTriggerProps>(
|
|
37
|
+
({ children, asChild = false, onClick, ...restProps }, ref) => {
|
|
38
|
+
const { behavior, open, setOpen } = useDialogContext("Dialog.Trigger");
|
|
39
|
+
const internalRef = useRef<HTMLButtonElement>(null);
|
|
40
|
+
|
|
41
|
+
// Register trigger element with behavior
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const element = internalRef.current;
|
|
44
|
+
behavior.setTriggerElement(element);
|
|
45
|
+
return () => {
|
|
46
|
+
behavior.setTriggerElement(null);
|
|
47
|
+
};
|
|
48
|
+
}, [behavior]);
|
|
49
|
+
|
|
50
|
+
// Handle click to open dialog
|
|
51
|
+
const handleClick = useCallback(
|
|
52
|
+
(event: React.MouseEvent<HTMLButtonElement>) => {
|
|
53
|
+
setOpen(true);
|
|
54
|
+
onClick?.(event);
|
|
55
|
+
},
|
|
56
|
+
[setOpen, onClick]
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Get trigger props from behavior
|
|
60
|
+
const triggerProps = behavior.getTriggerProps();
|
|
61
|
+
|
|
62
|
+
const Component = asChild ? Slot : "button";
|
|
63
|
+
|
|
64
|
+
// Merge refs
|
|
65
|
+
const mergedRef = useCallback(
|
|
66
|
+
(element: HTMLButtonElement | null) => {
|
|
67
|
+
(internalRef as React.MutableRefObject<HTMLButtonElement | null>).current = element;
|
|
68
|
+
if (typeof ref === "function") {
|
|
69
|
+
ref(element);
|
|
70
|
+
} else if (ref) {
|
|
71
|
+
(ref as React.MutableRefObject<HTMLButtonElement | null>).current = element;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
[ref]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Component
|
|
79
|
+
ref={mergedRef}
|
|
80
|
+
type={asChild ? undefined : "button"}
|
|
81
|
+
id={triggerProps.id}
|
|
82
|
+
aria-haspopup={triggerProps["aria-haspopup"]}
|
|
83
|
+
aria-expanded={open ? "true" : "false"}
|
|
84
|
+
aria-controls={triggerProps["aria-controls"]}
|
|
85
|
+
onClick={handleClick}
|
|
86
|
+
{...restProps}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
</Component>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
DialogTrigger.displayName = "Dialog.Trigger";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog compound component exports.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { Dialog } from "@/components/ui";
|
|
7
|
+
*
|
|
8
|
+
* <Dialog.Root>
|
|
9
|
+
* <Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
10
|
+
* <Dialog.Content>
|
|
11
|
+
* <Dialog.Title>Dialog Title</Dialog.Title>
|
|
12
|
+
* <Dialog.Description>Dialog description</Dialog.Description>
|
|
13
|
+
* <Dialog.Close>Close</Dialog.Close>
|
|
14
|
+
* </Dialog.Content>
|
|
15
|
+
* </Dialog.Root>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { DialogClose, type DialogCloseProps } from "./dialog-close.js";
|
|
20
|
+
import {
|
|
21
|
+
DialogContent,
|
|
22
|
+
type DialogContentProps,
|
|
23
|
+
type DialogContentSize,
|
|
24
|
+
} from "./dialog-content.js";
|
|
25
|
+
import { DialogDescription, type DialogDescriptionProps } from "./dialog-description.js";
|
|
26
|
+
import { DialogRoot, type DialogRootProps } from "./dialog-root.js";
|
|
27
|
+
import { DialogTitle, type DialogTitleProps } from "./dialog-title.js";
|
|
28
|
+
import { DialogTrigger, type DialogTriggerProps } from "./dialog-trigger.js";
|
|
29
|
+
|
|
30
|
+
// Compound component
|
|
31
|
+
export const Dialog = {
|
|
32
|
+
Root: DialogRoot,
|
|
33
|
+
Trigger: DialogTrigger,
|
|
34
|
+
Content: DialogContent,
|
|
35
|
+
Title: DialogTitle,
|
|
36
|
+
Description: DialogDescription,
|
|
37
|
+
Close: DialogClose,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Type exports
|
|
41
|
+
export type {
|
|
42
|
+
DialogCloseProps,
|
|
43
|
+
DialogContentProps,
|
|
44
|
+
DialogContentSize,
|
|
45
|
+
DialogDescriptionProps,
|
|
46
|
+
DialogRootProps,
|
|
47
|
+
DialogTitleProps,
|
|
48
|
+
DialogTriggerProps,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Re-export DialogRole from primitives-dom
|
|
52
|
+
export type { DialogRole } from "@hypoth-ui/primitives-dom";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import { property } from "lit/decorators.js";
|
|
3
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
4
|
+
import { define } from "../../registry/define.js";
|
|
5
|
+
|
|
6
|
+
export type DialogContentSize = "sm" | "md" | "lg" | "xl" | "full";
|
|
7
|
+
export type DialogContentState = "open" | "closed";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Dialog content container component.
|
|
11
|
+
*
|
|
12
|
+
* Contains the dialog's content including title, description, and actions.
|
|
13
|
+
* Receives accessibility attributes from parent ds-dialog.
|
|
14
|
+
*
|
|
15
|
+
* @element ds-dialog-content
|
|
16
|
+
*
|
|
17
|
+
* @slot - Dialog content (title, description, body, actions)
|
|
18
|
+
*
|
|
19
|
+
* @csspart container - The content container element
|
|
20
|
+
*
|
|
21
|
+
* @attr {string} data-state - Animation state ("open" or "closed")
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```html
|
|
25
|
+
* <ds-dialog-content size="lg">
|
|
26
|
+
* <ds-dialog-title>Large Dialog</ds-dialog-title>
|
|
27
|
+
* <p>Dialog body content here.</p>
|
|
28
|
+
* <div class="ds-dialog__footer">
|
|
29
|
+
* <button>Cancel</button>
|
|
30
|
+
* <button>Confirm</button>
|
|
31
|
+
* </div>
|
|
32
|
+
* </ds-dialog-content>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class DsDialogContent extends DSElement {
|
|
36
|
+
/** Size variant of the dialog */
|
|
37
|
+
@property({ type: String, reflect: true })
|
|
38
|
+
size: DialogContentSize = "md";
|
|
39
|
+
|
|
40
|
+
/** Animation state (open or closed) - set by parent ds-dialog */
|
|
41
|
+
@property({ type: String, reflect: true, attribute: "data-state" })
|
|
42
|
+
dataState: DialogContentState = "open";
|
|
43
|
+
|
|
44
|
+
override render() {
|
|
45
|
+
return html`
|
|
46
|
+
<div class="ds-dialog-content" part="container" data-size=${this.size}>
|
|
47
|
+
<slot></slot>
|
|
48
|
+
</div>
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
define("ds-dialog-content", DsDialogContent);
|
|
54
|
+
|
|
55
|
+
declare global {
|
|
56
|
+
interface HTMLElementTagNameMap {
|
|
57
|
+
"ds-dialog-content": DsDialogContent;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { html, nothing } from "lit";
|
|
2
|
+
import { state } from "lit/decorators.js";
|
|
3
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
4
|
+
import { define } from "../../registry/define.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Dialog description component.
|
|
8
|
+
*
|
|
9
|
+
* Renders the dialog's accessible description. The parent ds-dialog
|
|
10
|
+
* automatically connects this to the dialog content via aria-describedby.
|
|
11
|
+
*
|
|
12
|
+
* @element ds-dialog-description
|
|
13
|
+
*
|
|
14
|
+
* @csspart description - The description element
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <ds-dialog-description>
|
|
19
|
+
* This action cannot be undone.
|
|
20
|
+
* </ds-dialog-description>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class DsDialogDescription extends DSElement {
|
|
24
|
+
/** Preserved text content from initial children */
|
|
25
|
+
@state()
|
|
26
|
+
private descriptionText = "";
|
|
27
|
+
|
|
28
|
+
override connectedCallback(): void {
|
|
29
|
+
// Capture original text content before Lit renders
|
|
30
|
+
this.descriptionText = this.textContent?.trim() ?? "";
|
|
31
|
+
|
|
32
|
+
super.connectedCallback();
|
|
33
|
+
|
|
34
|
+
// Generate ID if not provided
|
|
35
|
+
if (!this.id) {
|
|
36
|
+
this.id = `dialog-desc-${crypto.randomUUID().slice(0, 8)}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override render() {
|
|
41
|
+
// Only render p if there's content
|
|
42
|
+
if (!this.descriptionText) {
|
|
43
|
+
return nothing;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return html`
|
|
47
|
+
<p class="ds-dialog-description" part="description">${this.descriptionText}</p>
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
define("ds-dialog-description", DsDialogDescription);
|
|
53
|
+
|
|
54
|
+
declare global {
|
|
55
|
+
interface HTMLElementTagNameMap {
|
|
56
|
+
"ds-dialog-description": DsDialogDescription;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { html, nothing } from "lit";
|
|
2
|
+
import { state } from "lit/decorators.js";
|
|
3
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
4
|
+
import { define } from "../../registry/define.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Dialog title component.
|
|
8
|
+
*
|
|
9
|
+
* Renders the dialog's accessible title. The parent ds-dialog
|
|
10
|
+
* automatically connects this to the dialog content via aria-labelledby.
|
|
11
|
+
*
|
|
12
|
+
* @element ds-dialog-title
|
|
13
|
+
*
|
|
14
|
+
* @csspart title - The title element
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <ds-dialog-title>Confirm Deletion</ds-dialog-title>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export class DsDialogTitle extends DSElement {
|
|
22
|
+
/** Preserved text content from initial children */
|
|
23
|
+
@state()
|
|
24
|
+
private titleText = "";
|
|
25
|
+
|
|
26
|
+
override connectedCallback(): void {
|
|
27
|
+
// Capture original text content before Lit renders
|
|
28
|
+
this.titleText = this.textContent?.trim() ?? "";
|
|
29
|
+
|
|
30
|
+
super.connectedCallback();
|
|
31
|
+
|
|
32
|
+
// Generate ID if not provided
|
|
33
|
+
if (!this.id) {
|
|
34
|
+
this.id = `dialog-title-${crypto.randomUUID().slice(0, 8)}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override render() {
|
|
39
|
+
// Only render h2 if there's content (avoid empty heading a11y violation)
|
|
40
|
+
if (!this.titleText) {
|
|
41
|
+
return nothing;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return html`
|
|
45
|
+
<h2 class="ds-dialog-title" part="title">${this.titleText}</h2>
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
define("ds-dialog-title", DsDialogTitle);
|
|
51
|
+
|
|
52
|
+
declare global {
|
|
53
|
+
interface HTMLElementTagNameMap {
|
|
54
|
+
"ds-dialog-title": DsDialogTitle;
|
|
55
|
+
}
|
|
56
|
+
}
|