@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,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useToast Hook
|
|
5
|
+
*
|
|
6
|
+
* React hook for showing and managing toasts.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useCallback, useContext } from "react";
|
|
10
|
+
import { ToastContext } from "./provider.js";
|
|
11
|
+
|
|
12
|
+
export interface ToastOptions {
|
|
13
|
+
/** Toast title (required) */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Optional description */
|
|
16
|
+
description?: string;
|
|
17
|
+
/** Visual variant */
|
|
18
|
+
variant?: "info" | "success" | "warning" | "error";
|
|
19
|
+
/** Auto-dismiss duration in ms (0 = no auto-dismiss) */
|
|
20
|
+
duration?: number;
|
|
21
|
+
/** Optional action button */
|
|
22
|
+
action?: {
|
|
23
|
+
label: string;
|
|
24
|
+
onClick: () => void;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UseToastReturn {
|
|
29
|
+
/** Show a toast notification */
|
|
30
|
+
toast: (options: ToastOptions) => string;
|
|
31
|
+
/** Dismiss a specific toast */
|
|
32
|
+
dismiss: (id: string) => void;
|
|
33
|
+
/** Dismiss all toasts */
|
|
34
|
+
dismissAll: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Hook for showing toast notifications.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* function MyComponent() {
|
|
43
|
+
* const { toast, dismiss } = useToast();
|
|
44
|
+
*
|
|
45
|
+
* const handleSave = async () => {
|
|
46
|
+
* try {
|
|
47
|
+
* await saveData();
|
|
48
|
+
* toast({ title: "Saved!", variant: "success" });
|
|
49
|
+
* } catch {
|
|
50
|
+
* toast({
|
|
51
|
+
* title: "Error",
|
|
52
|
+
* description: "Failed to save",
|
|
53
|
+
* variant: "error",
|
|
54
|
+
* action: { label: "Retry", onClick: handleSave },
|
|
55
|
+
* });
|
|
56
|
+
* }
|
|
57
|
+
* };
|
|
58
|
+
*
|
|
59
|
+
* return <button onClick={handleSave}>Save</button>;
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function useToast(): UseToastReturn {
|
|
64
|
+
const context = useContext(ToastContext);
|
|
65
|
+
|
|
66
|
+
if (!context) {
|
|
67
|
+
throw new Error("useToast must be used within a Toast.Provider");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const toast = useCallback(
|
|
71
|
+
(options: ToastOptions): string => {
|
|
72
|
+
return context.show(options);
|
|
73
|
+
},
|
|
74
|
+
[context]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const dismiss = useCallback(
|
|
78
|
+
(id: string): void => {
|
|
79
|
+
context.dismiss(id);
|
|
80
|
+
},
|
|
81
|
+
[context]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const dismissAll = useCallback((): void => {
|
|
85
|
+
context.dismissAll();
|
|
86
|
+
}, [context]);
|
|
87
|
+
|
|
88
|
+
return { toast, dismiss, dismissAll };
|
|
89
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { DsToast } from "./toast.js";
|
|
2
|
+
export { DsToastProvider } from "./toast-provider.js";
|
|
3
|
+
export {
|
|
4
|
+
ToastController,
|
|
5
|
+
dsToast,
|
|
6
|
+
getGlobalToastController,
|
|
7
|
+
setGlobalToastController,
|
|
8
|
+
type ToastOptions,
|
|
9
|
+
type ToastData,
|
|
10
|
+
type ToastVariant,
|
|
11
|
+
type ToastPosition,
|
|
12
|
+
type ToastState,
|
|
13
|
+
type ToastAction,
|
|
14
|
+
type ToastControllerOptions,
|
|
15
|
+
} from "./toast-controller.js";
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast Controller
|
|
3
|
+
*
|
|
4
|
+
* Manages toast queue, lifecycle, and provides imperative API
|
|
5
|
+
* for showing and dismissing toasts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type ToastVariant = "info" | "success" | "warning" | "error";
|
|
9
|
+
export type ToastPosition =
|
|
10
|
+
| "top-left"
|
|
11
|
+
| "top-center"
|
|
12
|
+
| "top-right"
|
|
13
|
+
| "bottom-left"
|
|
14
|
+
| "bottom-center"
|
|
15
|
+
| "bottom-right";
|
|
16
|
+
|
|
17
|
+
export type ToastState = "entering" | "visible" | "exiting" | "dismissed";
|
|
18
|
+
|
|
19
|
+
export interface ToastAction {
|
|
20
|
+
label: string;
|
|
21
|
+
onClick: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ToastOptions {
|
|
25
|
+
/** Toast title (required) */
|
|
26
|
+
title: string;
|
|
27
|
+
/** Optional description */
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Visual variant */
|
|
30
|
+
variant?: ToastVariant;
|
|
31
|
+
/** Auto-dismiss duration in ms (0 = no auto-dismiss) */
|
|
32
|
+
duration?: number;
|
|
33
|
+
/** Optional action button */
|
|
34
|
+
action?: ToastAction;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ToastData extends ToastOptions {
|
|
38
|
+
/** Unique toast ID */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Current lifecycle state */
|
|
41
|
+
state: ToastState;
|
|
42
|
+
/** Timestamp when created */
|
|
43
|
+
createdAt: number;
|
|
44
|
+
/** Timer ID for auto-dismiss */
|
|
45
|
+
timerId?: ReturnType<typeof setTimeout>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ToastControllerOptions {
|
|
49
|
+
/** Maximum simultaneous toasts */
|
|
50
|
+
maxToasts?: number;
|
|
51
|
+
/** Default duration in ms */
|
|
52
|
+
defaultDuration?: number;
|
|
53
|
+
/** Toast position */
|
|
54
|
+
position?: ToastPosition;
|
|
55
|
+
/** Callback when toast list changes */
|
|
56
|
+
onUpdate?: (toasts: ToastData[]) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let toastIdCounter = 0;
|
|
60
|
+
|
|
61
|
+
function generateId(): string {
|
|
62
|
+
return `toast-${++toastIdCounter}-${Date.now()}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* ToastController manages the toast queue and lifecycle.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const controller = new ToastController({
|
|
71
|
+
* maxToasts: 5,
|
|
72
|
+
* defaultDuration: 5000,
|
|
73
|
+
* onUpdate: (toasts) => renderToasts(toasts),
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* // Show a toast
|
|
77
|
+
* const id = controller.show({ title: "Saved!", variant: "success" });
|
|
78
|
+
*
|
|
79
|
+
* // Dismiss a specific toast
|
|
80
|
+
* controller.dismiss(id);
|
|
81
|
+
*
|
|
82
|
+
* // Dismiss all toasts
|
|
83
|
+
* controller.dismissAll();
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export class ToastController {
|
|
87
|
+
private toasts: ToastData[] = [];
|
|
88
|
+
private options: Required<ToastControllerOptions>;
|
|
89
|
+
|
|
90
|
+
constructor(options: ToastControllerOptions = {}) {
|
|
91
|
+
this.options = {
|
|
92
|
+
maxToasts: options.maxToasts ?? 5,
|
|
93
|
+
defaultDuration: options.defaultDuration ?? 5000,
|
|
94
|
+
position: options.position ?? "top-right",
|
|
95
|
+
onUpdate: options.onUpdate ?? (() => {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Show a new toast
|
|
101
|
+
*/
|
|
102
|
+
show(options: ToastOptions): string {
|
|
103
|
+
const id = generateId();
|
|
104
|
+
const duration = options.duration ?? this.options.defaultDuration;
|
|
105
|
+
|
|
106
|
+
const toast: ToastData = {
|
|
107
|
+
id,
|
|
108
|
+
title: options.title,
|
|
109
|
+
description: options.description,
|
|
110
|
+
variant: options.variant ?? "info",
|
|
111
|
+
duration,
|
|
112
|
+
action: options.action,
|
|
113
|
+
state: "entering",
|
|
114
|
+
createdAt: Date.now(),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Add to queue
|
|
118
|
+
this.toasts = [toast, ...this.toasts];
|
|
119
|
+
|
|
120
|
+
// Trim to max
|
|
121
|
+
if (this.toasts.length > this.options.maxToasts) {
|
|
122
|
+
const toRemove = this.toasts.slice(this.options.maxToasts);
|
|
123
|
+
for (const t of toRemove) {
|
|
124
|
+
this.dismiss(t.id);
|
|
125
|
+
}
|
|
126
|
+
this.toasts = this.toasts.slice(0, this.options.maxToasts);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Transition to visible after animation
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
this.updateState(id, "visible");
|
|
132
|
+
}, 200);
|
|
133
|
+
|
|
134
|
+
// Set up auto-dismiss
|
|
135
|
+
if (duration > 0) {
|
|
136
|
+
toast.timerId = setTimeout(() => {
|
|
137
|
+
this.dismiss(id);
|
|
138
|
+
}, duration);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.notify();
|
|
142
|
+
return id;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Dismiss a toast by ID
|
|
147
|
+
*/
|
|
148
|
+
dismiss(id: string): void {
|
|
149
|
+
const toast = this.toasts.find((t) => t.id === id);
|
|
150
|
+
if (!toast || toast.state === "exiting" || toast.state === "dismissed") {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Clear auto-dismiss timer
|
|
155
|
+
if (toast.timerId) {
|
|
156
|
+
clearTimeout(toast.timerId);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Start exit animation
|
|
160
|
+
this.updateState(id, "exiting");
|
|
161
|
+
|
|
162
|
+
// Remove after animation
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
this.toasts = this.toasts.filter((t) => t.id !== id);
|
|
165
|
+
this.notify();
|
|
166
|
+
}, 150);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Dismiss all toasts
|
|
171
|
+
*/
|
|
172
|
+
dismissAll(): void {
|
|
173
|
+
const ids = this.toasts.map((t) => t.id);
|
|
174
|
+
for (const id of ids) {
|
|
175
|
+
this.dismiss(id);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Pause auto-dismiss for a toast (e.g., on hover)
|
|
181
|
+
*/
|
|
182
|
+
pause(id: string): void {
|
|
183
|
+
const toast = this.toasts.find((t) => t.id === id);
|
|
184
|
+
if (toast?.timerId) {
|
|
185
|
+
clearTimeout(toast.timerId);
|
|
186
|
+
toast.timerId = undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Resume auto-dismiss for a toast
|
|
192
|
+
*/
|
|
193
|
+
resume(id: string): void {
|
|
194
|
+
const toast = this.toasts.find((t) => t.id === id);
|
|
195
|
+
if (toast?.duration && toast.duration > 0 && toast.state === "visible") {
|
|
196
|
+
// Calculate remaining time based on elapsed time
|
|
197
|
+
const elapsed = Date.now() - toast.createdAt;
|
|
198
|
+
const remaining = Math.max(toast.duration - elapsed, 1000);
|
|
199
|
+
|
|
200
|
+
toast.timerId = setTimeout(() => {
|
|
201
|
+
this.dismiss(id);
|
|
202
|
+
}, remaining);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get current toasts
|
|
208
|
+
*/
|
|
209
|
+
getToasts(): ToastData[] {
|
|
210
|
+
return [...this.toasts];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get controller options
|
|
215
|
+
*/
|
|
216
|
+
getOptions(): Required<ToastControllerOptions> {
|
|
217
|
+
return { ...this.options };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Update controller options
|
|
222
|
+
*/
|
|
223
|
+
setOptions(options: Partial<ToastControllerOptions>): void {
|
|
224
|
+
this.options = { ...this.options, ...options };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private updateState(id: string, state: ToastState): void {
|
|
228
|
+
const toast = this.toasts.find((t) => t.id === id);
|
|
229
|
+
if (toast) {
|
|
230
|
+
toast.state = state;
|
|
231
|
+
this.notify();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private notify(): void {
|
|
236
|
+
this.options.onUpdate(this.getToasts());
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Global singleton controller
|
|
241
|
+
let globalController: ToastController | null = null;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get or create the global toast controller
|
|
245
|
+
*/
|
|
246
|
+
export function getGlobalToastController(): ToastController {
|
|
247
|
+
if (!globalController) {
|
|
248
|
+
globalController = new ToastController();
|
|
249
|
+
}
|
|
250
|
+
return globalController;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Set the global toast controller (used by ToastProvider)
|
|
255
|
+
*/
|
|
256
|
+
export function setGlobalToastController(controller: ToastController): void {
|
|
257
|
+
globalController = controller;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Global toast function for showing toasts
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* dsToast({ title: "Saved!", variant: "success" });
|
|
266
|
+
*
|
|
267
|
+
* dsToast({
|
|
268
|
+
* title: "Error",
|
|
269
|
+
* description: "Something went wrong",
|
|
270
|
+
* variant: "error",
|
|
271
|
+
* action: { label: "Retry", onClick: () => retry() },
|
|
272
|
+
* });
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
export function dsToast(options: ToastOptions): string {
|
|
276
|
+
return getGlobalToastController().show(options);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Make dsToast available globally
|
|
280
|
+
if (typeof window !== "undefined") {
|
|
281
|
+
(window as unknown as { dsToast: typeof dsToast }).dsToast = dsToast;
|
|
282
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { type TemplateResult, html } from "lit";
|
|
2
|
+
import { property, state } from "lit/decorators.js";
|
|
3
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
4
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
5
|
+
import { define } from "../../registry/define.js";
|
|
6
|
+
import {
|
|
7
|
+
ToastController,
|
|
8
|
+
type ToastData,
|
|
9
|
+
type ToastPosition,
|
|
10
|
+
setGlobalToastController,
|
|
11
|
+
} from "./toast-controller.js";
|
|
12
|
+
import "./toast.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Toast provider component that manages toast queue and rendering.
|
|
16
|
+
*
|
|
17
|
+
* @element ds-toast-provider
|
|
18
|
+
* @slot - Default slot for app content
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```html
|
|
22
|
+
* <ds-toast-provider position="top-right" max="5">
|
|
23
|
+
* <!-- Your app content -->
|
|
24
|
+
* </ds-toast-provider>
|
|
25
|
+
*
|
|
26
|
+
* <script>
|
|
27
|
+
* dsToast({ title: "Hello!", variant: "success" });
|
|
28
|
+
* </script>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export class DsToastProvider extends DSElement {
|
|
32
|
+
static override styles = [];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Toast position
|
|
36
|
+
*/
|
|
37
|
+
@property({ type: String, reflect: true })
|
|
38
|
+
position: ToastPosition = "top-right";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Maximum simultaneous toasts
|
|
42
|
+
*/
|
|
43
|
+
@property({ type: Number })
|
|
44
|
+
max = 5;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Default duration in ms
|
|
48
|
+
*/
|
|
49
|
+
@property({ type: Number })
|
|
50
|
+
duration = 5000;
|
|
51
|
+
|
|
52
|
+
@state()
|
|
53
|
+
private toasts: ToastData[] = [];
|
|
54
|
+
|
|
55
|
+
private controller!: ToastController;
|
|
56
|
+
|
|
57
|
+
override connectedCallback(): void {
|
|
58
|
+
super.connectedCallback();
|
|
59
|
+
|
|
60
|
+
this.controller = new ToastController({
|
|
61
|
+
maxToasts: this.max,
|
|
62
|
+
defaultDuration: this.duration,
|
|
63
|
+
position: this.position,
|
|
64
|
+
onUpdate: (toasts) => {
|
|
65
|
+
this.toasts = toasts;
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Set as global controller
|
|
70
|
+
setGlobalToastController(this.controller);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
override updated(changedProperties: Map<string, unknown>): void {
|
|
74
|
+
super.updated(changedProperties);
|
|
75
|
+
|
|
76
|
+
if (
|
|
77
|
+
changedProperties.has("max") ||
|
|
78
|
+
changedProperties.has("duration") ||
|
|
79
|
+
changedProperties.has("position")
|
|
80
|
+
) {
|
|
81
|
+
this.controller.setOptions({
|
|
82
|
+
maxToasts: this.max,
|
|
83
|
+
defaultDuration: this.duration,
|
|
84
|
+
position: this.position,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private handleDismiss(event: CustomEvent<{ id: string }>): void {
|
|
90
|
+
this.controller.dismiss(event.detail.id);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private handlePause(event: CustomEvent<{ id: string }>): void {
|
|
94
|
+
this.controller.pause(event.detail.id);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private handleResume(event: CustomEvent<{ id: string }>): void {
|
|
98
|
+
this.controller.resume(event.detail.id);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private handleActionClick(toast: ToastData): void {
|
|
102
|
+
toast.action?.onClick();
|
|
103
|
+
this.controller.dismiss(toast.id);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override render(): TemplateResult {
|
|
107
|
+
return html`
|
|
108
|
+
<slot></slot>
|
|
109
|
+
|
|
110
|
+
<div
|
|
111
|
+
class="ds-toast-viewport"
|
|
112
|
+
data-position=${this.position}
|
|
113
|
+
role="region"
|
|
114
|
+
aria-label="Notifications"
|
|
115
|
+
aria-live="polite"
|
|
116
|
+
>
|
|
117
|
+
${repeat(
|
|
118
|
+
this.toasts,
|
|
119
|
+
(toast) => toast.id,
|
|
120
|
+
(toast) => html`
|
|
121
|
+
<ds-toast
|
|
122
|
+
.toastId=${toast.id}
|
|
123
|
+
.toastTitle=${toast.title}
|
|
124
|
+
.description=${toast.description ?? ""}
|
|
125
|
+
.variant=${toast.variant ?? "info"}
|
|
126
|
+
.toastState=${toast.state}
|
|
127
|
+
.duration=${toast.duration ?? 0}
|
|
128
|
+
@ds:dismiss=${this.handleDismiss}
|
|
129
|
+
@ds:pause=${this.handlePause}
|
|
130
|
+
@ds:resume=${this.handleResume}
|
|
131
|
+
>
|
|
132
|
+
${
|
|
133
|
+
toast.action
|
|
134
|
+
? html`
|
|
135
|
+
<button
|
|
136
|
+
slot="action"
|
|
137
|
+
class="ds-button ds-button--sm ds-button--ghost"
|
|
138
|
+
@click=${() => this.handleActionClick(toast)}
|
|
139
|
+
>
|
|
140
|
+
${toast.action.label}
|
|
141
|
+
</button>
|
|
142
|
+
`
|
|
143
|
+
: null
|
|
144
|
+
}
|
|
145
|
+
</ds-toast>
|
|
146
|
+
`
|
|
147
|
+
)}
|
|
148
|
+
</div>
|
|
149
|
+
`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Register the component
|
|
154
|
+
define("ds-toast-provider", DsToastProvider);
|
|
155
|
+
|
|
156
|
+
// TypeScript declaration for HTML
|
|
157
|
+
declare global {
|
|
158
|
+
interface HTMLElementTagNameMap {
|
|
159
|
+
"ds-toast-provider": DsToastProvider;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { type TemplateResult, html, nothing } from "lit";
|
|
2
|
+
import { property, state } from "lit/decorators.js";
|
|
3
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
4
|
+
import { DSElement } from "../../base/ds-element.js";
|
|
5
|
+
import { emitEvent } from "../../events/emit.js";
|
|
6
|
+
import { define } from "../../registry/define.js";
|
|
7
|
+
import type { ToastState, ToastVariant } from "./toast-controller.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SVG icons for different toast variants
|
|
11
|
+
*/
|
|
12
|
+
const VARIANT_ICONS: Record<ToastVariant, TemplateResult> = {
|
|
13
|
+
info: html`<svg class="ds-toast__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
14
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
|
|
15
|
+
</svg>`,
|
|
16
|
+
success: html`<svg class="ds-toast__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
17
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
|
|
18
|
+
</svg>`,
|
|
19
|
+
warning: html`<svg class="ds-toast__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
20
|
+
<path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
|
|
21
|
+
</svg>`,
|
|
22
|
+
error: html`<svg class="ds-toast__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
23
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
|
|
24
|
+
</svg>`,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const CLOSE_ICON = html`<svg class="ds-toast__close-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
28
|
+
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
|
|
29
|
+
</svg>`;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Individual toast notification element.
|
|
33
|
+
*
|
|
34
|
+
* @element ds-toast
|
|
35
|
+
* @slot action - Action button slot
|
|
36
|
+
*
|
|
37
|
+
* @fires ds:dismiss - Fired when toast is dismissed
|
|
38
|
+
* @fires ds:pause - Fired when mouse enters (for pause)
|
|
39
|
+
* @fires ds:resume - Fired when mouse leaves (for resume)
|
|
40
|
+
*/
|
|
41
|
+
export class DsToast extends DSElement {
|
|
42
|
+
static override styles = [];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Unique toast ID
|
|
46
|
+
*/
|
|
47
|
+
@property({ type: String, reflect: true })
|
|
48
|
+
toastId = "";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Toast title
|
|
52
|
+
*/
|
|
53
|
+
@property({ type: String })
|
|
54
|
+
toastTitle = "";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Toast description
|
|
58
|
+
*/
|
|
59
|
+
@property({ type: String })
|
|
60
|
+
description = "";
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Visual variant
|
|
64
|
+
*/
|
|
65
|
+
@property({ type: String, reflect: true })
|
|
66
|
+
variant: ToastVariant = "info";
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Current state
|
|
70
|
+
*/
|
|
71
|
+
@property({ type: String, reflect: true })
|
|
72
|
+
toastState: ToastState = "entering";
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Duration for progress bar (0 = no progress)
|
|
76
|
+
*/
|
|
77
|
+
@property({ type: Number })
|
|
78
|
+
duration = 5000;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Hide the icon
|
|
82
|
+
*/
|
|
83
|
+
@property({ type: Boolean, attribute: "hide-icon" })
|
|
84
|
+
hideIcon = false;
|
|
85
|
+
|
|
86
|
+
@state()
|
|
87
|
+
private isPaused = false;
|
|
88
|
+
|
|
89
|
+
private handleDismiss(): void {
|
|
90
|
+
emitEvent(this, "dismiss", { detail: { id: this.toastId } });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private handleMouseEnter(): void {
|
|
94
|
+
this.isPaused = true;
|
|
95
|
+
emitEvent(this, "pause", { detail: { id: this.toastId } });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private handleMouseLeave(): void {
|
|
99
|
+
this.isPaused = false;
|
|
100
|
+
emitEvent(this, "resume", { detail: { id: this.toastId } });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override render(): TemplateResult {
|
|
104
|
+
const classes = {
|
|
105
|
+
"ds-toast": true,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return html`
|
|
109
|
+
<div
|
|
110
|
+
class=${classMap(classes)}
|
|
111
|
+
role="status"
|
|
112
|
+
aria-live="polite"
|
|
113
|
+
aria-atomic="true"
|
|
114
|
+
data-variant=${this.variant}
|
|
115
|
+
data-state=${this.toastState}
|
|
116
|
+
@mouseenter=${this.handleMouseEnter}
|
|
117
|
+
@mouseleave=${this.handleMouseLeave}
|
|
118
|
+
>
|
|
119
|
+
${!this.hideIcon ? VARIANT_ICONS[this.variant] : nothing}
|
|
120
|
+
|
|
121
|
+
<div class="ds-toast__content">
|
|
122
|
+
<p class="ds-toast__title">${this.toastTitle}</p>
|
|
123
|
+
${
|
|
124
|
+
this.description
|
|
125
|
+
? html`<p class="ds-toast__description">${this.description}</p>`
|
|
126
|
+
: nothing
|
|
127
|
+
}
|
|
128
|
+
<slot name="action" class="ds-toast__action"></slot>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<button
|
|
132
|
+
class="ds-toast__close"
|
|
133
|
+
type="button"
|
|
134
|
+
aria-label="Dismiss notification"
|
|
135
|
+
@click=${this.handleDismiss}
|
|
136
|
+
>
|
|
137
|
+
${CLOSE_ICON}
|
|
138
|
+
</button>
|
|
139
|
+
|
|
140
|
+
${
|
|
141
|
+
this.duration > 0
|
|
142
|
+
? html`
|
|
143
|
+
<div class="ds-toast__progress">
|
|
144
|
+
<div
|
|
145
|
+
class="ds-toast__progress-bar"
|
|
146
|
+
style="animation: ds-toast-progress ${this.duration}ms linear forwards; animation-play-state: ${this.isPaused ? "paused" : "running"}"
|
|
147
|
+
></div>
|
|
148
|
+
</div>
|
|
149
|
+
`
|
|
150
|
+
: nothing
|
|
151
|
+
}
|
|
152
|
+
</div>
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Register the component
|
|
158
|
+
define("ds-toast", DsToast);
|
|
159
|
+
|
|
160
|
+
// TypeScript declaration for HTML
|
|
161
|
+
declare global {
|
|
162
|
+
interface HTMLElementTagNameMap {
|
|
163
|
+
"ds-toast": DsToast;
|
|
164
|
+
}
|
|
165
|
+
}
|