luxen-ui 0.7.0 → 0.9.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/bin/cli.mjs +189 -18
- package/cdn/chunks/decorate.js +1 -1
- package/cdn/chunks/floating-ui.dom.js +1 -1
- package/cdn/chunks/floating-ui.dom.js.map +1 -1
- package/cdn/chunks/lit-html.js +3 -0
- package/cdn/chunks/lit-html.js.map +1 -0
- package/cdn/chunks/lit.js +1 -2
- package/cdn/chunks/lit.js.map +1 -1
- package/cdn/chunks/static-html.js +2 -0
- package/cdn/chunks/static-html.js.map +1 -0
- package/cdn/custom-elements.json +3174 -16266
- package/cdn/elements/avatar/avatar.d.ts +13 -0
- package/cdn/elements/avatar/avatar.d.ts.map +1 -1
- package/cdn/elements/avatar/avatar.js +8 -8
- package/cdn/elements/avatar/avatar.js.map +1 -1
- package/cdn/elements/button/button.meta.d.ts +33 -0
- package/cdn/elements/button/button.meta.d.ts.map +1 -0
- package/cdn/elements/button/button.meta.js +0 -0
- package/cdn/elements/button-group/button-group.d.ts +33 -0
- package/cdn/elements/button-group/button-group.d.ts.map +1 -0
- package/cdn/elements/button-group/button-group.js +2 -0
- package/cdn/elements/button-group/button-group.js.map +1 -0
- package/cdn/elements/button-group/index.d.ts +2 -0
- package/cdn/elements/button-group/index.d.ts.map +1 -0
- package/cdn/elements/button-group/index.js +2 -0
- package/cdn/elements/button-group/index.js.map +1 -0
- package/cdn/elements/carousel/carousel.d.ts +6 -0
- package/cdn/elements/carousel/carousel.d.ts.map +1 -1
- package/cdn/elements/carousel/carousel.js +5 -5
- package/cdn/elements/carousel/carousel.js.map +1 -1
- package/cdn/elements/carousel-item/carousel-item.d.ts +2 -0
- package/cdn/elements/carousel-item/carousel-item.d.ts.map +1 -1
- package/cdn/elements/carousel-item/carousel-item.js +1 -1
- package/cdn/elements/carousel-item/carousel-item.js.map +1 -1
- package/cdn/elements/checkbox/checkbox.meta.d.ts +31 -0
- package/cdn/elements/checkbox/checkbox.meta.d.ts.map +1 -0
- package/cdn/elements/checkbox/checkbox.meta.js +0 -0
- package/cdn/elements/close-button/close-button.meta.d.ts +24 -0
- package/cdn/elements/close-button/close-button.meta.d.ts.map +1 -0
- package/cdn/elements/close-button/close-button.meta.js +0 -0
- package/cdn/elements/dialog/dialog.d.ts +12 -6
- package/cdn/elements/dialog/dialog.d.ts.map +1 -1
- package/cdn/elements/dialog/dialog.js +8 -5
- package/cdn/elements/dialog/dialog.js.map +1 -1
- package/cdn/elements/dialog/dialog.styles.js +1 -1
- package/cdn/elements/dialog/dialog.styles.js.map +1 -1
- package/cdn/elements/disclosure/disclosure.meta.d.ts +28 -0
- package/cdn/elements/disclosure/disclosure.meta.d.ts.map +1 -0
- package/cdn/elements/disclosure/disclosure.meta.js +0 -0
- package/cdn/elements/divider/divider.d.ts +1 -1
- package/cdn/elements/divider/divider.js.map +1 -1
- package/cdn/elements/drawer/drawer.d.ts +5 -0
- package/cdn/elements/drawer/drawer.d.ts.map +1 -1
- package/cdn/elements/drawer/drawer.js +1 -1
- package/cdn/elements/drawer/drawer.js.map +1 -1
- package/cdn/elements/dropdown/dropdown.d.ts +11 -1
- package/cdn/elements/dropdown/dropdown.d.ts.map +1 -1
- package/cdn/elements/dropdown/dropdown.js +2 -2
- package/cdn/elements/dropdown/dropdown.js.map +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.d.ts +2 -0
- package/cdn/elements/dropdown-item/dropdown-item.d.ts.map +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js +5 -5
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
- package/cdn/elements/dropdown-label/dropdown-label.d.ts +17 -0
- package/cdn/elements/dropdown-label/dropdown-label.d.ts.map +1 -0
- package/cdn/elements/dropdown-label/dropdown-label.js +4 -0
- package/cdn/elements/dropdown-label/dropdown-label.js.map +1 -0
- package/cdn/elements/dropdown-label/index.d.ts +2 -0
- package/cdn/elements/dropdown-label/index.d.ts.map +1 -0
- package/cdn/elements/dropdown-label/index.js +2 -0
- package/cdn/elements/dropdown-label/index.js.map +1 -0
- package/cdn/elements/form-field/form-field.d.ts +62 -0
- package/cdn/elements/form-field/form-field.d.ts.map +1 -0
- package/cdn/elements/form-field/form-field.js +2 -0
- package/cdn/elements/form-field/form-field.js.map +1 -0
- package/cdn/elements/form-field/index.d.ts +2 -0
- package/cdn/elements/form-field/index.d.ts.map +1 -0
- package/cdn/elements/form-field/index.js +2 -0
- package/cdn/elements/form-field/index.js.map +1 -0
- package/cdn/elements/icon/icon.js +1 -1
- package/cdn/elements/icon/icon.js.map +1 -1
- package/cdn/elements/input-otp/input-otp.d.ts +2 -0
- package/cdn/elements/input-otp/input-otp.d.ts.map +1 -1
- package/cdn/elements/input-otp/input-otp.js.map +1 -1
- package/cdn/elements/input-stepper/input-stepper.d.ts +2 -0
- package/cdn/elements/input-stepper/input-stepper.d.ts.map +1 -1
- package/cdn/elements/input-stepper/input-stepper.js +1 -1
- package/cdn/elements/input-stepper/input-stepper.js.map +1 -1
- package/cdn/elements/kbd/kbd.meta.d.ts +14 -0
- package/cdn/elements/kbd/kbd.meta.d.ts.map +1 -0
- package/cdn/elements/kbd/kbd.meta.js +0 -0
- package/cdn/elements/popover/popover.js +2 -2
- package/cdn/elements/popover/popover.js.map +1 -1
- package/cdn/elements/progress/progress.meta.d.ts +22 -0
- package/cdn/elements/progress/progress.meta.d.ts.map +1 -0
- package/cdn/elements/progress/progress.meta.js +0 -0
- package/cdn/elements/prose-editor/prose-editor.d.ts +12 -1
- package/cdn/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.js +42 -42
- package/cdn/elements/prose-editor/prose-editor.js.map +1 -1
- package/cdn/elements/rating/rating.d.ts +2 -0
- package/cdn/elements/rating/rating.d.ts.map +1 -1
- package/cdn/elements/rating/rating.js +5 -5
- package/cdn/elements/rating/rating.js.map +1 -1
- package/cdn/elements/select/select.meta.d.ts +28 -0
- package/cdn/elements/select/select.meta.d.ts.map +1 -0
- package/cdn/elements/select/select.meta.js +0 -0
- package/cdn/elements/skeleton/skeleton.d.ts +3 -0
- package/cdn/elements/skeleton/skeleton.d.ts.map +1 -1
- package/cdn/elements/skeleton/skeleton.js.map +1 -1
- package/cdn/elements/spinner/spinner.js +1 -1
- package/cdn/elements/spinner/spinner.js.map +1 -1
- package/cdn/elements/sticky-bar/sticky-bar.js +1 -1
- package/cdn/elements/sticky-bar/sticky-bar.js.map +1 -1
- package/cdn/elements/stories-viewer/stories-viewer.d.ts +1 -1
- package/cdn/elements/stories-viewer/stories-viewer.d.ts.map +1 -1
- package/cdn/elements/stories-viewer/stories-viewer.js +27 -27
- package/cdn/elements/stories-viewer/stories-viewer.js.map +1 -1
- package/cdn/elements/story/story.d.ts +10 -1
- package/cdn/elements/story/story.d.ts.map +1 -1
- package/cdn/elements/story/story.js +20 -20
- package/cdn/elements/story/story.js.map +1 -1
- package/cdn/elements/toast/toast.d.ts +5 -0
- package/cdn/elements/toast/toast.d.ts.map +1 -1
- package/cdn/elements/toast/toast.js.map +1 -1
- package/cdn/elements/tooltip/tooltip.js +2 -2
- package/cdn/elements/tooltip/tooltip.js.map +1 -1
- package/cdn/elements/tree/tree.d.ts +2 -0
- package/cdn/elements/tree/tree.d.ts.map +1 -1
- package/cdn/elements/tree/tree.js +1 -1
- package/cdn/elements/tree/tree.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.d.ts +2 -0
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +6 -6
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/registry.d.ts +1 -1
- package/cdn/registry.d.ts.map +1 -1
- package/cdn/registry.js.map +1 -1
- package/cdn/shared/controllers/has-slot-controller.d.ts +37 -0
- package/cdn/shared/controllers/has-slot-controller.d.ts.map +1 -0
- package/cdn/shared/controllers/has-slot-controller.js +2 -0
- package/cdn/shared/controllers/has-slot-controller.js.map +1 -0
- package/cdn/shared/controllers/popover.d.ts +2 -0
- package/cdn/shared/controllers/popover.d.ts.map +1 -1
- package/cdn/shared/controllers/popover.js +1 -1
- package/cdn/shared/controllers/popover.js.map +1 -1
- package/cdn/shared/styles/checkbox-appearance.styles.d.ts +9 -0
- package/cdn/shared/styles/checkbox-appearance.styles.d.ts.map +1 -0
- package/cdn/shared/styles/checkbox-appearance.styles.js +2 -0
- package/cdn/shared/styles/checkbox-appearance.styles.js.map +1 -0
- package/cdn/shared/styles/host.styles.js +1 -1
- package/cdn/standalone.css +337 -9
- package/cdn/standalone.js +513 -46
- package/cdn/standalone.js.map +1 -1
- package/cdn/static-tag.d.ts +17 -0
- package/cdn/static-tag.d.ts.map +1 -0
- package/cdn/static-tag.js +2 -0
- package/cdn/static-tag.js.map +1 -0
- package/cdn/styles/elements/button-group.css +88 -0
- package/cdn/styles/elements/button.css +7 -2
- package/cdn/styles/elements/checkbox.css +101 -0
- package/cdn/styles/elements/form-field.css +67 -0
- package/cdn/styles/elements/input-stepper/default.css +10 -4
- package/cdn/styles/elements/input-stepper/rounded.css +9 -3
- package/cdn/styles/preset.css +49 -0
- package/cdn/styles/tokens/forms.css +52 -0
- package/cdn/styles/tokens.css +49 -0
- package/dist/css/elements/button-group.css +88 -0
- package/dist/css/elements/button.css +7 -2
- package/dist/css/elements/checkbox.css +101 -0
- package/dist/css/elements/form-field.css +67 -0
- package/dist/css/elements/input-stepper/default.css +10 -4
- package/dist/css/elements/input-stepper/rounded.css +9 -3
- package/dist/css/preset.css +49 -0
- package/dist/css/tokens/forms.css +52 -0
- package/dist/css/tokens.css +49 -0
- package/dist/custom-elements.json +3174 -16266
- package/dist/elements/avatar/avatar.css +37 -10
- package/dist/elements/avatar/avatar.d.ts +13 -0
- package/dist/elements/avatar/avatar.d.ts.map +1 -1
- package/dist/elements/avatar/avatar.js +14 -1
- package/dist/elements/button/button.meta.d.ts +33 -0
- package/dist/elements/button/button.meta.d.ts.map +1 -0
- package/dist/elements/button/button.meta.js +44 -0
- package/dist/elements/button-group/button-group.d.ts +33 -0
- package/dist/elements/button-group/button-group.d.ts.map +1 -0
- package/dist/elements/button-group/button-group.js +57 -0
- package/dist/elements/button-group/index.d.ts +2 -0
- package/dist/elements/button-group/index.d.ts.map +1 -0
- package/dist/elements/button-group/index.js +4 -0
- package/dist/elements/carousel/carousel.d.ts +6 -0
- package/dist/elements/carousel/carousel.d.ts.map +1 -1
- package/dist/elements/carousel/carousel.js +6 -0
- package/dist/elements/carousel-item/carousel-item.d.ts +2 -0
- package/dist/elements/carousel-item/carousel-item.d.ts.map +1 -1
- package/dist/elements/carousel-item/carousel-item.js +2 -0
- package/dist/elements/checkbox/checkbox.meta.d.ts +31 -0
- package/dist/elements/checkbox/checkbox.meta.d.ts.map +1 -0
- package/dist/elements/checkbox/checkbox.meta.js +41 -0
- package/dist/elements/close-button/close-button.meta.d.ts +24 -0
- package/dist/elements/close-button/close-button.meta.d.ts.map +1 -0
- package/dist/elements/close-button/close-button.meta.js +30 -0
- package/dist/elements/dialog/dialog.css +15 -0
- package/dist/elements/dialog/dialog.d.ts +12 -6
- package/dist/elements/dialog/dialog.d.ts.map +1 -1
- package/dist/elements/dialog/dialog.js +21 -7
- package/dist/elements/disclosure/disclosure.meta.d.ts +28 -0
- package/dist/elements/disclosure/disclosure.meta.d.ts.map +1 -0
- package/dist/elements/disclosure/disclosure.meta.js +34 -0
- package/dist/elements/divider/divider.d.ts +1 -1
- package/dist/elements/divider/divider.js +1 -1
- package/dist/elements/drawer/drawer.d.ts +5 -0
- package/dist/elements/drawer/drawer.d.ts.map +1 -1
- package/dist/elements/drawer/drawer.js +5 -0
- package/dist/elements/dropdown/dropdown.css +0 -1
- package/dist/elements/dropdown/dropdown.d.ts +11 -1
- package/dist/elements/dropdown/dropdown.d.ts.map +1 -1
- package/dist/elements/dropdown/dropdown.js +23 -4
- package/dist/elements/dropdown-item/dropdown-item.d.ts +2 -0
- package/dist/elements/dropdown-item/dropdown-item.d.ts.map +1 -1
- package/dist/elements/dropdown-item/dropdown-item.js +2 -0
- package/dist/elements/dropdown-label/dropdown-label.css +18 -0
- package/dist/elements/dropdown-label/dropdown-label.d.ts +17 -0
- package/dist/elements/dropdown-label/dropdown-label.d.ts.map +1 -0
- package/dist/elements/dropdown-label/dropdown-label.js +31 -0
- package/dist/elements/dropdown-label/index.d.ts +2 -0
- package/dist/elements/dropdown-label/index.d.ts.map +1 -0
- package/dist/elements/dropdown-label/index.js +4 -0
- package/dist/elements/form-field/form-field.d.ts +62 -0
- package/dist/elements/form-field/form-field.d.ts.map +1 -0
- package/dist/elements/form-field/form-field.js +191 -0
- package/dist/elements/form-field/index.d.ts +2 -0
- package/dist/elements/form-field/index.d.ts.map +1 -0
- package/dist/elements/form-field/index.js +4 -0
- package/dist/elements/input-otp/input-otp.d.ts +2 -0
- package/dist/elements/input-otp/input-otp.d.ts.map +1 -1
- package/dist/elements/input-otp/input-otp.js +2 -0
- package/dist/elements/input-stepper/input-stepper.d.ts +2 -0
- package/dist/elements/input-stepper/input-stepper.d.ts.map +1 -1
- package/dist/elements/input-stepper/input-stepper.js +5 -1
- package/dist/elements/kbd/kbd.meta.d.ts +14 -0
- package/dist/elements/kbd/kbd.meta.d.ts.map +1 -0
- package/dist/elements/kbd/kbd.meta.js +20 -0
- package/dist/elements/progress/progress.meta.d.ts +22 -0
- package/dist/elements/progress/progress.meta.d.ts.map +1 -0
- package/dist/elements/progress/progress.meta.js +28 -0
- package/dist/elements/prose-editor/prose-editor.d.ts +12 -1
- package/dist/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/dist/elements/prose-editor/prose-editor.js +58 -13
- package/dist/elements/rating/rating.d.ts +2 -0
- package/dist/elements/rating/rating.d.ts.map +1 -1
- package/dist/elements/rating/rating.js +2 -0
- package/dist/elements/select/select.meta.d.ts +28 -0
- package/dist/elements/select/select.meta.d.ts.map +1 -0
- package/dist/elements/select/select.meta.js +34 -0
- package/dist/elements/skeleton/skeleton.d.ts +3 -0
- package/dist/elements/skeleton/skeleton.d.ts.map +1 -1
- package/dist/elements/skeleton/skeleton.js +3 -0
- package/dist/elements/stories-viewer/stories-viewer.d.ts +1 -1
- package/dist/elements/stories-viewer/stories-viewer.d.ts.map +1 -1
- package/dist/elements/stories-viewer/stories-viewer.js +23 -19
- package/dist/elements/story/story.d.ts +10 -1
- package/dist/elements/story/story.d.ts.map +1 -1
- package/dist/elements/story/story.js +29 -17
- package/dist/elements/toast/toast.d.ts +5 -0
- package/dist/elements/toast/toast.d.ts.map +1 -1
- package/dist/elements/toast/toast.js +5 -0
- package/dist/elements/tree/tree.d.ts +2 -0
- package/dist/elements/tree/tree.d.ts.map +1 -1
- package/dist/elements/tree/tree.js +13 -1
- package/dist/elements/tree-item/tree-item.css +6 -12
- package/dist/elements/tree-item/tree-item.d.ts +2 -0
- package/dist/elements/tree-item/tree-item.d.ts.map +1 -1
- package/dist/elements/tree-item/tree-item.js +5 -2
- package/dist/metadata/avatar.json +93 -0
- package/dist/metadata/badge.json +59 -0
- package/dist/metadata/button-group.json +49 -0
- package/dist/metadata/button.json +138 -0
- package/dist/metadata/carousel-item.json +32 -0
- package/dist/metadata/carousel.json +388 -0
- package/dist/metadata/checkbox.json +89 -0
- package/dist/metadata/close-button.json +90 -0
- package/dist/metadata/dialog.json +163 -0
- package/dist/metadata/disclosure.json +88 -0
- package/dist/metadata/divider.json +65 -0
- package/dist/metadata/drawer.json +176 -0
- package/dist/metadata/dropdown-item.json +85 -0
- package/dist/metadata/dropdown-label.json +37 -0
- package/dist/metadata/dropdown.json +165 -0
- package/dist/metadata/form-field.json +87 -0
- package/dist/metadata/icon.json +49 -0
- package/dist/metadata/index.json +4342 -0
- package/dist/metadata/input-otp.json +86 -0
- package/dist/metadata/input-stepper.json +122 -0
- package/dist/metadata/kbd.json +37 -0
- package/dist/metadata/popover.json +157 -0
- package/dist/metadata/progress.json +71 -0
- package/dist/metadata/prose-editor.json +365 -0
- package/dist/metadata/rating.json +126 -0
- package/dist/metadata/select.json +82 -0
- package/dist/metadata/skeleton.json +56 -0
- package/dist/metadata/spinner.json +47 -0
- package/dist/metadata/sticky-bar.json +93 -0
- package/dist/metadata/stories-viewer.json +316 -0
- package/dist/metadata/stories.json +109 -0
- package/dist/metadata/story.json +148 -0
- package/dist/metadata/tabs.json +74 -0
- package/dist/metadata/toast.json +122 -0
- package/dist/metadata/tooltip.json +144 -0
- package/dist/metadata/tree-item.json +199 -0
- package/dist/metadata/tree.json +130 -0
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/shared/controllers/has-slot-controller.d.ts +37 -0
- package/dist/shared/controllers/has-slot-controller.d.ts.map +1 -0
- package/dist/shared/controllers/has-slot-controller.js +66 -0
- package/dist/shared/controllers/popover.d.ts +2 -0
- package/dist/shared/controllers/popover.d.ts.map +1 -1
- package/dist/shared/controllers/popover.js +14 -1
- package/dist/shared/styles/checkbox-appearance.css +92 -0
- package/dist/shared/styles/checkbox-appearance.styles.d.ts +9 -0
- package/dist/shared/styles/checkbox-appearance.styles.d.ts.map +1 -0
- package/dist/shared/styles/checkbox-appearance.styles.js +9 -0
- package/dist/static-tag.d.ts +17 -0
- package/dist/static-tag.d.ts.map +1 -0
- package/dist/static-tag.js +22 -0
- package/dist/templates/elements/avatar.md +30 -31
- package/dist/templates/elements/badge.md +9 -15
- package/dist/templates/elements/button-group.md +164 -0
- package/dist/templates/elements/button.md +39 -51
- package/dist/templates/elements/checkbox.md +200 -0
- package/dist/templates/elements/close-button.md +24 -36
- package/dist/templates/elements/dialog.md +73 -54
- package/dist/templates/elements/drawer.md +39 -52
- package/dist/templates/elements/form-field.md +115 -0
- package/dist/templates/elements/progress.md +13 -23
- package/dist/templates/elements/prose-editor.md +71 -76
- package/dist/templates/elements/select.md +20 -31
- package/dist/templates/elements/sticky-bar.md +16 -60
- package/dist/templates/elements/toast.md +33 -53
- package/dist/templates/elements/tree.md +46 -74
- package/elements.json +73 -1
- package/package.json +10 -3
- package/templates/SKILL.md.tpl +20 -2
- package/templates/integration.md.tpl +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @summary A circular/square icon button that renders an X via CSS mask, for dismissing dialogs and panels.
|
|
3
|
+
*
|
|
4
|
+
* @nativeElement button
|
|
5
|
+
* @selector .l-close
|
|
6
|
+
*
|
|
7
|
+
* @attribute data-appearance - ring | square | circle — Visual appearance (matches the imported appearance CSS).
|
|
8
|
+
* @attribute command - Invoker command (typically `close`).
|
|
9
|
+
* @attribute commandfor - ID of the target element to close.
|
|
10
|
+
*
|
|
11
|
+
* @cssClass .l-close - Base close button with X icon via CSS mask.
|
|
12
|
+
*
|
|
13
|
+
* @cssproperty [--size=36px] - Button size.
|
|
14
|
+
* @cssproperty --icon-color - Icon color.
|
|
15
|
+
* @cssproperty [--icon-size=24px] - Icon size.
|
|
16
|
+
* @cssproperty --ring-color - Hover ring color (`ring` appearance only).
|
|
17
|
+
* @cssproperty --ring-tickness - Hover ring thickness (`ring` appearance only).
|
|
18
|
+
*
|
|
19
|
+
* @example Ring appearance
|
|
20
|
+
* <button class="l-close" data-appearance="ring" aria-label="Close"></button>
|
|
21
|
+
*/
|
|
22
|
+
export declare class CloseButtonMeta {
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=close-button.meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"close-button.meta.d.ts","sourceRoot":"","sources":["../../../src/html/elements/close-button/close-button.meta.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,qBAAa,eAAe;CAAG"}
|
|
File without changes
|
|
@@ -17,18 +17,23 @@ import { LuxenElement } from '../../shared/luxen-element.js';
|
|
|
17
17
|
* @csspart body - The body wrapper around the default slot.
|
|
18
18
|
* @csspart footer - The footer wrapper around the footer slot.
|
|
19
19
|
*
|
|
20
|
-
* @cssproperty --width - Dialog width.
|
|
21
|
-
* @cssproperty --border-radius - Dialog border radius.
|
|
22
|
-
* @cssproperty --padding - Padding applied to the header, footer, and inline-padding of the body.
|
|
23
|
-
* @cssproperty --show-duration - Open transition duration.
|
|
24
|
-
* @cssproperty --hide-duration - Close transition duration.
|
|
20
|
+
* @cssproperty [--width=31rem] - Dialog width.
|
|
21
|
+
* @cssproperty [--border-radius=6px] - Dialog border radius.
|
|
22
|
+
* @cssproperty [--padding=1.5rem] - Padding applied to the header, footer, and inline-padding of the body. Set to `0` to remove all internal spacing (e.g. for edge-to-edge media).
|
|
23
|
+
* @cssproperty [--show-duration=200ms] - Open transition duration.
|
|
24
|
+
* @cssproperty [--hide-duration=200ms] - Close transition duration.
|
|
25
25
|
* @cssproperty --backdrop - Backdrop color.
|
|
26
|
-
* @cssproperty --backdrop-blur - Backdrop blur amount (any CSS length).
|
|
26
|
+
* @cssproperty [--backdrop-blur=0] - Backdrop blur amount (any CSS length). `0` means no blur; set e.g. `4px` for a subtle frost.
|
|
27
27
|
*
|
|
28
28
|
* @event show - Fired when the dialog opens. Not cancelable.
|
|
29
29
|
* @event after-show - Fired after the open animation completes.
|
|
30
30
|
* @event hide - Fired when the dialog is about to close. Cancelable — call `event.preventDefault()` to keep it open.
|
|
31
31
|
* @event after-hide - Fired after the close animation completes.
|
|
32
|
+
*
|
|
33
|
+
* @command --show - Sets `open = true`.
|
|
34
|
+
* @command --hide - Sets `open = false`.
|
|
35
|
+
*
|
|
36
|
+
* @customElement l-dialog
|
|
32
37
|
*/
|
|
33
38
|
export declare class Dialog extends LuxenElement {
|
|
34
39
|
static styles: import('lit').CSSResult[];
|
|
@@ -40,6 +45,7 @@ export declare class Dialog extends LuxenElement {
|
|
|
40
45
|
lightDismiss: boolean;
|
|
41
46
|
/** Hide the header entirely (title and close slot). */
|
|
42
47
|
withoutHeader: boolean;
|
|
48
|
+
private _slots;
|
|
43
49
|
dialog: HTMLDialogElement;
|
|
44
50
|
protected _modalKind: 'centered' | 'edge';
|
|
45
51
|
private _mouseDownTarget;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,MAAO,SAAQ,YAAY;IACtC,MAAM,CAAC,MAAM,4BAAwB;IAErC,2CAA2C;IAE3C,KAAK,SAAM;IAEX,kCAAkC;IAElC,IAAI,UAAS;IAEb,0CAA0C;IAE1C,YAAY,UAAS;IAErB,uDAAuD;IAEvD,aAAa,UAAS;IAMtB,OAAO,CAAC,MAAM,CAAyC;IAGvD,MAAM,EAAG,iBAAiB,CAAC;IAI3B,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAc;IAEvD,OAAO,CAAC,gBAAgB,CAA4B;IAEpD,OAAO,CAAC,gBAAgB,CAEtB;IAIF,iBAAiB;IAKjB,oBAAoB;IAKpB,YAAY;IASZ,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IA0BrC,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,eAAe,CAAC,CAAY;IAEpC,OAAO,CAAC,aAAa;YAcP,UAAU;IAUxB,OAAO,CAAC,qBAAqB;IAK7B,MAAM;CA6BP"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{a as e,
|
|
1
|
+
import"../../chunks/lit.js";import{a as e,t}from"../../chunks/lit-html.js";import{LuxenElement as n}from"../../shared/luxen-element.js";import{i as r,n as i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";import s from"./dialog.styles.js";import{HasSlotController as c}from"../../shared/controllers/has-slot-controller.js";var l=typeof HTMLDialogElement<`u`&&`closedBy`in HTMLDialogElement.prototype,u=Symbol.for(`luxen-dialog-scroll-lock`);if(typeof document<`u`&&!(u in document)){let e=new CSSStyleSheet;e.replaceSync(`
|
|
2
2
|
html:has([data-modal]) { overflow: hidden; }
|
|
3
3
|
html:has([data-modal="centered"]) { scrollbar-gutter: stable; }
|
|
4
|
-
`),document.adoptedStyleSheets.push(e),Object.defineProperty(document,
|
|
4
|
+
`),document.adoptedStyleSheets.push(e),Object.defineProperty(document,u,{value:e})}var d=class extends n{constructor(...e){super(...e),this.title=``,this.open=!1,this.lightDismiss=!1,this.withoutHeader=!1,this._slots=new c(this,`footer`),this._modalKind=`centered`,this._mouseDownTarget=null,this._commandListener={handleEvent:e=>this._onCommand(e)}}static{this.styles=[o,s]}connectedCallback(){super.connectedCallback(),this.addEventListener(`command`,this._commandListener)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(`command`,this._commandListener)}firstUpdated(){this.dialog.addEventListener(`cancel`,e=>this._onCancel(e)),this.dialog.addEventListener(`close`,()=>this._onNativeClose()),this.dialog.addEventListener(`mousedown`,e=>{this._mouseDownTarget=e.target}),this.dialog.addEventListener(`click`,e=>this._onDialogClick(e))}updated(e){if(e.has(`open`)){if(this.open&&!this.dialog.open)this.emit(`show`),this.setAttribute(`data-modal`,this._modalKind),this.dialog.showModal(),this._focusAutofocusTarget(),this._emitAfter(`after-show`);else if(!this.open&&this.dialog.open){if(!this.emit(`hide`,{cancelable:!0})){this.open=!0;return}this.dialog.close()}}}_onCommand(e){switch(e.command){case`--hide`:this.open=!1;break;case`--show`:this.open=!0;break}}_onCancel(e){this.emit(`hide`,{cancelable:!0})||e.preventDefault()}_onNativeClose(){this.open=!1,this.removeAttribute(`data-modal`),this._emitAfter(`after-hide`)}_onDialogClick(e){let t=e.target===this.dialog&&this._mouseDownTarget===this.dialog;if(this._mouseDownTarget=null,t){if(this.lightDismiss){l||(this.open=!1);return}this._nudgeDismiss()}}_nudgeDismiss(){matchMedia(`(prefers-reduced-motion: reduce)`).matches||(this._nudgeAnimation?.cancel(),this._nudgeAnimation=this.dialog.animate([{transform:`scale(1)`},{transform:`scale(1.02)`},{transform:`scale(1)`}],{duration:250,easing:`ease-in-out`}))}async _emitAfter(e){await new Promise(e=>requestAnimationFrame(()=>e(null)));let t=this.dialog.getAnimations({subtree:!1});await Promise.all(t.map(e=>e.finished.catch(()=>{}))),e===`after-show`===this.open&&this.emit(e)}_focusAutofocusTarget(){this.querySelector(`[autofocus]`)?.focus({preventScroll:!0})}render(){return e`
|
|
5
5
|
<dialog
|
|
6
6
|
part="dialog"
|
|
7
|
-
closedby=${this.lightDismiss&&
|
|
7
|
+
closedby=${this.lightDismiss&&l?`any`:t}
|
|
8
8
|
>
|
|
9
9
|
${this.withoutHeader?t:e`
|
|
10
10
|
<header part="header">
|
|
@@ -17,9 +17,12 @@ import{a as e,n as t}from"../../chunks/lit.js";import{LuxenElement as n}from"../
|
|
|
17
17
|
<div part="body">
|
|
18
18
|
<slot></slot>
|
|
19
19
|
</div>
|
|
20
|
-
<footer
|
|
20
|
+
<footer
|
|
21
|
+
part="footer"
|
|
22
|
+
?data-empty=${!this._slots.test(`footer`)}
|
|
23
|
+
>
|
|
21
24
|
<slot name="footer"></slot>
|
|
22
25
|
</footer>
|
|
23
26
|
</dialog>
|
|
24
|
-
`}};a([r()],
|
|
27
|
+
`}};a([r()],d.prototype,`title`,void 0),a([r({type:Boolean,reflect:!0})],d.prototype,`open`,void 0),a([r({type:Boolean,reflect:!0,attribute:`light-dismiss`})],d.prototype,`lightDismiss`,void 0),a([r({type:Boolean,reflect:!0,attribute:`without-header`})],d.prototype,`withoutHeader`,void 0),a([i(`dialog`)],d.prototype,`dialog`,void 0);export{d as Dialog};
|
|
25
28
|
//# sourceMappingURL=dialog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","names":[],"sources":["../../../src/html/elements/dialog/dialog.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport styles from './dialog.styles.js';\n\ninterface CommandEventLike extends Event {\n command: string;\n source: Element | null;\n}\n\nconst supportsClosedBy =\n typeof HTMLDialogElement !== 'undefined' && 'closedBy' in HTMLDialogElement.prototype;\n\n// Native <dialog> doesn't lock body scroll. Inject a global rule that uses\n// `:has()` to freeze the root scroll container whenever any modal l-dialog\n// is open. Purely declarative — no manual lock/unlock bookkeeping.\n// Symbol guard makes the injection idempotent across HMR reloads.\n//\n// `scrollbar-gutter: stable` only applies to centered modals — it prevents\n// the page behind from shifting horizontally when the scrollbar disappears.\n// Edge-attached modals (drawers) opt out via `data-modal=\"edge\"`: a reserved\n// gutter would push the drawer off the actual viewport edge.\nconst SCROLL_LOCK_SHEET = Symbol.for('luxen-dialog-scroll-lock');\nif (typeof document !== 'undefined' && !(SCROLL_LOCK_SHEET in document)) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n html:has([data-modal]) { overflow: hidden; }\n html:has([data-modal=\"centered\"]) { scrollbar-gutter: stable; }\n `);\n document.adoptedStyleSheets.push(sheet);\n Object.defineProperty(document, SCROLL_LOCK_SHEET, { value: sheet });\n}\n\n/**\n * A modal dialog rendered in the top layer via the native `<dialog>` element.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). There are no public `show()` / `close()` methods.\n *\n * @slot - Body content.\n * @slot title - Custom heading element. Overrides the default `<h2>` rendered from the `title` property.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The dialog title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty --width - Dialog width. Default `31rem`.\n * @cssproperty --border-radius - Dialog border radius. Default `6px`.\n * @cssproperty --padding - Padding applied to the header, footer, and inline-padding of the body. Default `1.5rem`. Set to `0` to remove all internal spacing (e.g. for edge-to-edge media).\n * @cssproperty --show-duration - Open transition duration. Default `200ms`.\n * @cssproperty --hide-duration - Close transition duration. Default `200ms`.\n * @cssproperty --backdrop - Backdrop color.\n * @cssproperty --backdrop-blur - Backdrop blur amount (any CSS length). Default `0` (no blur). Set to e.g. `4px` for a subtle frost.\n *\n * @event show - Fired when the dialog opens. Not cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired when the dialog is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes.\n */\nexport class Dialog extends LuxenElement {\n static styles = [hostStyles, styles];\n\n /** Dialog title rendered in the header. */\n @property()\n title = '';\n\n /** Whether the dialog is open. */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /** Close when the backdrop is clicked. */\n @property({ type: Boolean, reflect: true, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /** Hide the header entirely (title and close slot). */\n @property({ type: Boolean, reflect: true, attribute: 'without-header' })\n withoutHeader = false;\n\n @query('dialog')\n dialog!: HTMLDialogElement;\n\n // Drives the scroll-lock stylesheet: `centered` reserves the scrollbar\n // gutter (no page shift); `edge` skips it (drawers sit flush to the edge).\n protected _modalKind: 'centered' | 'edge' = 'centered';\n\n private _mouseDownTarget: EventTarget | null = null;\n\n private _commandListener: EventListenerObject = {\n handleEvent: (e: Event) => this._onCommand(e as CommandEventLike),\n };\n\n // --- Lifecycle ---\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('command', this._commandListener);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('command', this._commandListener);\n }\n\n firstUpdated() {\n this.dialog.addEventListener('cancel', (e) => this._onCancel(e));\n this.dialog.addEventListener('close', () => this._onNativeClose());\n this.dialog.addEventListener('mousedown', (e) => {\n this._mouseDownTarget = e.target;\n });\n this.dialog.addEventListener('click', (e) => this._onDialogClick(e));\n }\n\n updated(changed: PropertyValues<this>) {\n if (!changed.has('open')) return;\n\n if (this.open && !this.dialog.open) {\n // Opening — not cancelable.\n this.emit('show');\n this.setAttribute('data-modal', this._modalKind);\n this.dialog.showModal();\n this._focusAutofocusTarget();\n void this._emitAfter('after-show');\n } else if (!this.open && this.dialog.open) {\n // Closing — cancelable. Revert the property if consumer prevents.\n if (!this.emit('hide', { cancelable: true })) {\n this.open = true;\n return;\n }\n this.dialog.close();\n // `after-hide` is emitted from `_onNativeClose` (runs for every close path).\n }\n }\n\n // --- Event handlers ---\n\n // Custom commands on a custom element must start with `--`.\n // Built-in commands like \"close\" are reserved for native elements\n // and won't fire here.\n private _onCommand(e: CommandEventLike) {\n switch (e.command) {\n case '--hide':\n this.open = false;\n break;\n case '--show':\n this.open = true;\n break;\n }\n }\n\n // Fires on Escape and on `closedby=\"any\"` close requests.\n // Does NOT fire when script calls `.close()`, so `updated()`'s cancelable\n // `hide` emit doesn't collide with this one.\n private _onCancel(e: Event) {\n if (!this.emit('hide', { cancelable: true })) {\n e.preventDefault();\n }\n }\n\n private _onNativeClose() {\n this.open = false;\n this.removeAttribute('data-modal');\n void this._emitAfter('after-hide');\n }\n\n private _onDialogClick(e: MouseEvent) {\n // With `dialog { padding: 0 }`, `e.target === this.dialog` only fires\n // for backdrop clicks. The mousedown guard prevents drag-out dismissal.\n const clickedBackdrop = e.target === this.dialog && this._mouseDownTarget === this.dialog;\n this._mouseDownTarget = null;\n if (!clickedBackdrop) return;\n\n if (this.lightDismiss) {\n // When `supportsClosedBy`, the native `closedby=\"any\"` already closed.\n if (!supportsClosedBy) this.open = false;\n return;\n }\n this._nudgeDismiss();\n }\n\n private _nudgeAnimation?: Animation;\n\n private _nudgeDismiss() {\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n this._nudgeAnimation?.cancel();\n this._nudgeAnimation = this.dialog.animate(\n [{ transform: 'scale(1)' }, { transform: 'scale(1.02)' }, { transform: 'scale(1)' }],\n { duration: 250, easing: 'ease-in-out' },\n );\n }\n\n // Awaits every active animation on the dialog (transitions + @keyframes)\n // and then emits. Resolves immediately when no animations are running,\n // which covers `prefers-reduced-motion` and consumers that zero the\n // duration custom properties — cases where `transitionend` never fires.\n // Waits one frame first so @starting-style transitions have registered.\n private async _emitAfter(name: 'after-show' | 'after-hide') {\n await new Promise((r) => requestAnimationFrame(() => r(null)));\n const anims = this.dialog.getAnimations({ subtree: false });\n await Promise.all(anims.map((a) => a.finished.catch(() => {})));\n if ((name === 'after-show') !== this.open) return;\n this.emit(name);\n }\n\n // Firefox/Safari don't reliably resolve `[autofocus]` when `<dialog>`\n // is in shadow DOM and the target is in light DOM. Resolve it manually.\n private _focusAutofocusTarget() {\n const target = this.querySelector<HTMLElement>('[autofocus]');\n target?.focus({ preventScroll: true });\n }\n\n render() {\n const closedby = this.lightDismiss && supportsClosedBy ? 'any' : nothing;\n return html`\n <dialog\n part=\"dialog\"\n closedby=${closedby}\n >\n ${this.withoutHeader\n ? nothing\n : html`\n <header part=\"header\">\n <slot name=\"title\">\n ${this.title ? html`<h2 part=\"title\">${this.title}</h2>` : nothing}\n </slot>\n <slot name=\"close\"></slot>\n </header>\n `}\n <div part=\"body\">\n <slot></slot>\n </div>\n <footer part=\"footer\">\n <slot name=\"footer\"></slot>\n </footer>\n </dialog>\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dialog.js","names":[],"sources":["../../../src/html/elements/dialog/dialog.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { HasSlotController } from '../../shared/controllers/has-slot-controller.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport styles from './dialog.styles.js';\n\ninterface CommandEventLike extends Event {\n command: string;\n source: Element | null;\n}\n\nconst supportsClosedBy =\n typeof HTMLDialogElement !== 'undefined' && 'closedBy' in HTMLDialogElement.prototype;\n\n// Native <dialog> doesn't lock body scroll. Inject a global rule that uses\n// `:has()` to freeze the root scroll container whenever any modal l-dialog\n// is open. Purely declarative — no manual lock/unlock bookkeeping.\n// Symbol guard makes the injection idempotent across HMR reloads.\n//\n// `scrollbar-gutter: stable` only applies to centered modals — it prevents\n// the page behind from shifting horizontally when the scrollbar disappears.\n// Edge-attached modals (drawers) opt out via `data-modal=\"edge\"`: a reserved\n// gutter would push the drawer off the actual viewport edge.\nconst SCROLL_LOCK_SHEET = Symbol.for('luxen-dialog-scroll-lock');\nif (typeof document !== 'undefined' && !(SCROLL_LOCK_SHEET in document)) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n html:has([data-modal]) { overflow: hidden; }\n html:has([data-modal=\"centered\"]) { scrollbar-gutter: stable; }\n `);\n document.adoptedStyleSheets.push(sheet);\n Object.defineProperty(document, SCROLL_LOCK_SHEET, { value: sheet });\n}\n\n/**\n * A modal dialog rendered in the top layer via the native `<dialog>` element.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). There are no public `show()` / `close()` methods.\n *\n * @slot - Body content.\n * @slot title - Custom heading element. Overrides the default `<h2>` rendered from the `title` property.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The dialog title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty [--width=31rem] - Dialog width.\n * @cssproperty [--border-radius=6px] - Dialog border radius.\n * @cssproperty [--padding=1.5rem] - Padding applied to the header, footer, and inline-padding of the body. Set to `0` to remove all internal spacing (e.g. for edge-to-edge media).\n * @cssproperty [--show-duration=200ms] - Open transition duration.\n * @cssproperty [--hide-duration=200ms] - Close transition duration.\n * @cssproperty --backdrop - Backdrop color.\n * @cssproperty [--backdrop-blur=0] - Backdrop blur amount (any CSS length). `0` means no blur; set e.g. `4px` for a subtle frost.\n *\n * @event show - Fired when the dialog opens. Not cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired when the dialog is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes.\n *\n * @command --show - Sets `open = true`.\n * @command --hide - Sets `open = false`.\n *\n * @customElement l-dialog\n */\nexport class Dialog extends LuxenElement {\n static styles = [hostStyles, styles];\n\n /** Dialog title rendered in the header. */\n @property()\n title = '';\n\n /** Whether the dialog is open. */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /** Close when the backdrop is clicked. */\n @property({ type: Boolean, reflect: true, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /** Hide the header entirely (title and close slot). */\n @property({ type: Boolean, reflect: true, attribute: 'without-header' })\n withoutHeader = false;\n\n // Tracks whether the footer slot has content, so the footer row can collapse\n // when empty (toggles `data-empty` below). A controller drives this because\n // `:host(:has(> [slot='footer']))` is invalid — `:has()` can't be nested in\n // `:host()`, so browsers drop the whole rule.\n private _slots = new HasSlotController(this, 'footer');\n\n @query('dialog')\n dialog!: HTMLDialogElement;\n\n // Drives the scroll-lock stylesheet: `centered` reserves the scrollbar\n // gutter (no page shift); `edge` skips it (drawers sit flush to the edge).\n protected _modalKind: 'centered' | 'edge' = 'centered';\n\n private _mouseDownTarget: EventTarget | null = null;\n\n private _commandListener: EventListenerObject = {\n handleEvent: (e: Event) => this._onCommand(e as CommandEventLike),\n };\n\n // --- Lifecycle ---\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('command', this._commandListener);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('command', this._commandListener);\n }\n\n firstUpdated() {\n this.dialog.addEventListener('cancel', (e) => this._onCancel(e));\n this.dialog.addEventListener('close', () => this._onNativeClose());\n this.dialog.addEventListener('mousedown', (e) => {\n this._mouseDownTarget = e.target;\n });\n this.dialog.addEventListener('click', (e) => this._onDialogClick(e));\n }\n\n updated(changed: PropertyValues<this>) {\n if (!changed.has('open')) return;\n\n if (this.open && !this.dialog.open) {\n // Opening — not cancelable.\n this.emit('show');\n this.setAttribute('data-modal', this._modalKind);\n this.dialog.showModal();\n this._focusAutofocusTarget();\n void this._emitAfter('after-show');\n } else if (!this.open && this.dialog.open) {\n // Closing — cancelable. Revert the property if consumer prevents.\n if (!this.emit('hide', { cancelable: true })) {\n this.open = true;\n return;\n }\n this.dialog.close();\n // `after-hide` is emitted from `_onNativeClose` (runs for every close path).\n }\n }\n\n // --- Event handlers ---\n\n // Custom commands on a custom element must start with `--`.\n // Built-in commands like \"close\" are reserved for native elements\n // and won't fire here.\n private _onCommand(e: CommandEventLike) {\n switch (e.command) {\n case '--hide':\n this.open = false;\n break;\n case '--show':\n this.open = true;\n break;\n }\n }\n\n // Fires on Escape and on `closedby=\"any\"` close requests.\n // Does NOT fire when script calls `.close()`, so `updated()`'s cancelable\n // `hide` emit doesn't collide with this one.\n private _onCancel(e: Event) {\n if (!this.emit('hide', { cancelable: true })) {\n e.preventDefault();\n }\n }\n\n private _onNativeClose() {\n this.open = false;\n this.removeAttribute('data-modal');\n void this._emitAfter('after-hide');\n }\n\n private _onDialogClick(e: MouseEvent) {\n // With `dialog { padding: 0 }`, `e.target === this.dialog` only fires\n // for backdrop clicks. The mousedown guard prevents drag-out dismissal.\n const clickedBackdrop = e.target === this.dialog && this._mouseDownTarget === this.dialog;\n this._mouseDownTarget = null;\n if (!clickedBackdrop) return;\n\n if (this.lightDismiss) {\n // When `supportsClosedBy`, the native `closedby=\"any\"` already closed.\n if (!supportsClosedBy) this.open = false;\n return;\n }\n this._nudgeDismiss();\n }\n\n private _nudgeAnimation?: Animation;\n\n private _nudgeDismiss() {\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n this._nudgeAnimation?.cancel();\n this._nudgeAnimation = this.dialog.animate(\n [{ transform: 'scale(1)' }, { transform: 'scale(1.02)' }, { transform: 'scale(1)' }],\n { duration: 250, easing: 'ease-in-out' },\n );\n }\n\n // Awaits every active animation on the dialog (transitions + @keyframes)\n // and then emits. Resolves immediately when no animations are running,\n // which covers `prefers-reduced-motion` and consumers that zero the\n // duration custom properties — cases where `transitionend` never fires.\n // Waits one frame first so @starting-style transitions have registered.\n private async _emitAfter(name: 'after-show' | 'after-hide') {\n await new Promise((r) => requestAnimationFrame(() => r(null)));\n const anims = this.dialog.getAnimations({ subtree: false });\n await Promise.all(anims.map((a) => a.finished.catch(() => {})));\n if ((name === 'after-show') !== this.open) return;\n this.emit(name);\n }\n\n // Firefox/Safari don't reliably resolve `[autofocus]` when `<dialog>`\n // is in shadow DOM and the target is in light DOM. Resolve it manually.\n private _focusAutofocusTarget() {\n const target = this.querySelector<HTMLElement>('[autofocus]');\n target?.focus({ preventScroll: true });\n }\n\n render() {\n const closedby = this.lightDismiss && supportsClosedBy ? 'any' : nothing;\n return html`\n <dialog\n part=\"dialog\"\n closedby=${closedby}\n >\n ${this.withoutHeader\n ? nothing\n : html`\n <header part=\"header\">\n <slot name=\"title\">\n ${this.title ? html`<h2 part=\"title\">${this.title}</h2>` : nothing}\n </slot>\n <slot name=\"close\"></slot>\n </header>\n `}\n <div part=\"body\">\n <slot></slot>\n </div>\n <footer\n part=\"footer\"\n ?data-empty=${!this._slots.test('footer')}\n >\n <slot name=\"footer\"></slot>\n </footer>\n </dialog>\n `;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";var t=e(`:host{--width:31rem;--border-radius:6px;--padding:1.5rem;--header-padding:var(--padding);--footer-padding:var(--padding);--show-duration:.2s;--hide-duration:.2s;--backdrop:var(--l-backdrop);--backdrop-blur:0;display:contents}dialog{box-sizing:border-box;width:var(--width);max-inline-size:min(90vw, var(--width));border-radius:var(--border-radius);background-color:var(--l-color-surface-overlay);max-block-size:min(80dvb,100%);color:var(--l-color-text-primary);opacity:0;transition-property:opacity,display,overlay;transition-duration:var(--hide-duration);transition-behavior:allow-discrete;border:0;margin:auto;padding:0;position:fixed;inset:0}dialog::backdrop{background:var(--backdrop);-webkit-backdrop-filter:blur(var(--backdrop-blur));backdrop-filter:blur(var(--backdrop-blur))}dialog[open]{opacity:1;transition-duration:var(--show-duration);grid-template-rows:auto minmax(0,1fr) auto;display:grid}@starting-style{dialog[open]{opacity:0}}[part=header]{padding:var(--header-padding);justify-content:space-between;align-items:center;gap:1rem;display:flex}[part=title]{margin:0;font-size:1.125rem;font-weight:600;line-height:1.4}[part=body]{padding-inline:var(--padding);grid-row:2;overflow-y:auto}[part=footer]{padding:var(--footer-padding);grid-row:3;place-content:end;gap:.5rem;display:flex}[part=footer][data-empty]{display:none}[part=body]:has(~[part=footer][data-empty]){padding-block-end:var(--padding)}:host([without-header]) [part=body]{padding-block-start:var(--padding)}::slotted(menu[slot=footer]){display:contents}@media (prefers-reduced-motion:reduce){:host{--show-duration:0s;--hide-duration:0s}}`);export{t as default};
|
|
2
2
|
//# sourceMappingURL=dialog.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.styles.js","names":[],"sources":["../../../src/html/elements/dialog/dialog.css?inline","../../../src/html/elements/dialog/dialog.styles.ts"],"sourcesContent":[":host {\n --width: 31rem;\n --border-radius: 6px;\n --padding: 1.5rem;\n --header-padding: var(--padding);\n --footer-padding: var(--padding);\n --show-duration: 200ms;\n --hide-duration: 200ms;\n --backdrop: var(--l-backdrop);\n --backdrop-blur: 0;\n\n display: contents;\n}\n\ndialog {\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n width: var(--width);\n max-inline-size: min(90vw, var(--width));\n max-block-size: min(80dvb, 100%);\n margin: auto;\n padding: 0;\n border: 0;\n border-radius: var(--border-radius);\n background-color: var(--l-color-surface-overlay);\n color: var(--l-color-text-primary);\n\n /* EXIT STATE */\n opacity: 0;\n\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-behavior: allow-discrete;\n\n &::backdrop {\n background: var(--backdrop);\n backdrop-filter: blur(var(--backdrop-blur));\n }\n\n /* OPEN STATE */\n /* grid layout pins header/footer; the middle row (body) scrolls via\n overflow on [part='body'] and minmax(0, 1fr) allowing it to shrink. */\n &[open] {\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n /* BEFORE-OPEN STATE */\n @starting-style {\n &[open] {\n opacity: 0;\n }\n }\n}\n\n[part='header'] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 1rem;\n padding: var(--header-padding);\n}\n\n[part='title'] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n line-height: 1.4;\n}\n\n/* Pin body and footer so the layout stays correct when [without-header]\n removes the header and only two children auto-place into the grid. */\n[part='body'] {\n grid-row: 2;\n padding-inline: var(--padding);\n overflow-y: auto;\n}\n\n[part='footer'] {\n grid-row: 3;\n display: flex;\n place-content: end;\n gap: 0.5rem;\n padding: var(--footer-padding);\n}\n\n/* Without a header, the body has to provide its own block-start padding\n (normally inherited visually from the header padding above it). */\n:host([without-header]) [part='body'] {\n padding-block-start: var(--padding);\n}\n\n::slotted(menu[slot='footer']) {\n display: contents;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport raw from './dialog.css?inline';\n\n/**\n * Wrapper module: imported by both `dialog.ts` and `drawer.ts`.\n * `unsafeCSS()` is called once here so both importers share the same\n * `CSSResult` instance (one constructed `CSSStyleSheet`, not two).\n */\nexport default unsafeCSS(raw);\n"],"mappings":"wCCQA,IAAA,EAAe,EAAU,
|
|
1
|
+
{"version":3,"file":"dialog.styles.js","names":[],"sources":["../../../src/html/elements/dialog/dialog.css?inline","../../../src/html/elements/dialog/dialog.styles.ts"],"sourcesContent":[":host {\n --width: 31rem;\n --border-radius: 6px;\n --padding: 1.5rem;\n --header-padding: var(--padding);\n --footer-padding: var(--padding);\n --show-duration: 200ms;\n --hide-duration: 200ms;\n --backdrop: var(--l-backdrop);\n --backdrop-blur: 0;\n\n display: contents;\n}\n\ndialog {\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n width: var(--width);\n max-inline-size: min(90vw, var(--width));\n max-block-size: min(80dvb, 100%);\n margin: auto;\n padding: 0;\n border: 0;\n border-radius: var(--border-radius);\n background-color: var(--l-color-surface-overlay);\n color: var(--l-color-text-primary);\n\n /* EXIT STATE */\n opacity: 0;\n\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-behavior: allow-discrete;\n\n &::backdrop {\n background: var(--backdrop);\n backdrop-filter: blur(var(--backdrop-blur));\n }\n\n /* OPEN STATE */\n /* grid layout pins header/footer; the middle row (body) scrolls via\n overflow on [part='body'] and minmax(0, 1fr) allowing it to shrink. */\n &[open] {\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n /* BEFORE-OPEN STATE */\n @starting-style {\n &[open] {\n opacity: 0;\n }\n }\n}\n\n[part='header'] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 1rem;\n padding: var(--header-padding);\n}\n\n[part='title'] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n line-height: 1.4;\n}\n\n/* Pin body and footer so the layout stays correct when [without-header]\n removes the header and only two children auto-place into the grid. */\n[part='body'] {\n grid-row: 2;\n padding-inline: var(--padding);\n overflow-y: auto;\n}\n\n[part='footer'] {\n grid-row: 3;\n display: flex;\n place-content: end;\n gap: 0.5rem;\n padding: var(--footer-padding);\n}\n\n/* Collapse the footer row when nothing is slotted into it, so an empty\n dialog/drawer reserves no space at the bottom. `data-empty` is toggled by the\n HasSlotController in dialog.ts: `:host(:has(...))` can't be used because\n `:has()` is invalid inside `:host()` and the whole rule is dropped by the\n browser. */\n[part='footer'][data-empty] {\n display: none;\n}\n\n/* With the footer collapsed, the body has to provide its own block-end padding\n (normally inherited visually from the footer padding below it). */\n[part='body']:has(~ [part='footer'][data-empty]) {\n padding-block-end: var(--padding);\n}\n\n/* Without a header, the body has to provide its own block-start padding\n (normally inherited visually from the header padding above it). */\n:host([without-header]) [part='body'] {\n padding-block-start: var(--padding);\n}\n\n::slotted(menu[slot='footer']) {\n display: contents;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport raw from './dialog.css?inline';\n\n/**\n * Wrapper module: imported by both `dialog.ts` and `drawer.ts`.\n * `unsafeCSS()` is called once here so both importers share the same\n * `CSSResult` instance (one constructed `CSSStyleSheet`, not two).\n */\nexport default unsafeCSS(raw);\n"],"mappings":"wCCQA,IAAA,EAAe,EAAU,glDAAI"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @summary A headless, animated disclosure built on native `<details>`/`<summary>`.
|
|
3
|
+
*
|
|
4
|
+
* @nativeElement details
|
|
5
|
+
* @selector .l-disclosure
|
|
6
|
+
*
|
|
7
|
+
* @attribute open - Native attribute — starts the disclosure expanded.
|
|
8
|
+
* @attribute name - Native attribute — groups disclosures into an exclusive accordion.
|
|
9
|
+
* @attribute data-marker - arrow | plus — Marker icon: `arrow` rotates 180° when open; `plus` rotates 45° into a cross.
|
|
10
|
+
* @attribute data-variant - bordered — Adds border, background, and border-radius.
|
|
11
|
+
* @attribute disabled - Disables interaction (set on `<details>` or `<summary>`).
|
|
12
|
+
*
|
|
13
|
+
* @event toggle - Fires when the disclosure opens or closes (`e.newState` is `"open"` or `"closed"`).
|
|
14
|
+
*
|
|
15
|
+
* @cssClass .l-disclosure - Headless base — layout, animation, and marker behavior only.
|
|
16
|
+
*
|
|
17
|
+
* @cssproperty [--marker-size=20px] - Marker icon size.
|
|
18
|
+
* @cssproperty --marker-color - Marker icon color (default `var(--l-color-text-tertiary)`).
|
|
19
|
+
*
|
|
20
|
+
* @example Bordered with arrow marker
|
|
21
|
+
* <details class="l-disclosure" data-variant="bordered" data-marker="arrow">
|
|
22
|
+
* <summary>Details</summary>
|
|
23
|
+
* <div>Content</div>
|
|
24
|
+
* </details>
|
|
25
|
+
*/
|
|
26
|
+
export declare class DisclosureMeta {
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=disclosure.meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.meta.d.ts","sourceRoot":"","sources":["../../../src/html/elements/disclosure/disclosure.meta.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,qBAAa,cAAc;CAAG"}
|
|
File without changes
|
|
@@ -6,7 +6,7 @@ export type DividerOrientation = 'horizontal' | 'vertical';
|
|
|
6
6
|
* @example <l-divider></l-divider>
|
|
7
7
|
*
|
|
8
8
|
* @cssproperty --color - The color of the divider line.
|
|
9
|
-
* @cssproperty --
|
|
9
|
+
* @cssproperty --thickness - The thickness of the divider line.
|
|
10
10
|
* @cssproperty --spacing - The spacing between the divider and its neighboring elements.
|
|
11
11
|
*
|
|
12
12
|
* @customElement l-divider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"divider.js","names":[],"sources":["../../../src/html/elements/divider/divider.ts"],"sourcesContent":["import { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\n\nexport type DividerOrientation = 'horizontal' | 'vertical';\n\n/**\n * @summary Dividers visually separate or group elements.\n *\n * @example <l-divider></l-divider>\n *\n * @cssproperty --color - The color of the divider line.\n * @cssproperty --
|
|
1
|
+
{"version":3,"file":"divider.js","names":[],"sources":["../../../src/html/elements/divider/divider.ts"],"sourcesContent":["import { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\n\nexport type DividerOrientation = 'horizontal' | 'vertical';\n\n/**\n * @summary Dividers visually separate or group elements.\n *\n * @example <l-divider></l-divider>\n *\n * @cssproperty --color - The color of the divider line.\n * @cssproperty --thickness - The thickness of the divider line.\n * @cssproperty --spacing - The spacing between the divider and its neighboring elements.\n *\n * @customElement l-divider\n */\nexport class Divider extends LuxenElement {\n override createRenderRoot() {\n return this;\n }\n\n /** The divider's orientation. */\n @property({ reflect: true })\n orientation: DividerOrientation = 'horizontal';\n\n /** Optional text label displayed over the divider line. */\n @property({ reflect: true })\n label?: string;\n\n override connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'separator');\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('orientation')) {\n if (this.orientation === 'vertical') {\n this.setAttribute('aria-orientation', 'vertical');\n } else {\n this.removeAttribute('aria-orientation');\n }\n }\n }\n}\n"],"mappings":"iHAgBA,IAAa,EAAb,cAA6B,CAAa,gDAON,aANlC,kBAA4B,CAC1B,OAAO,KAWT,mBAA6B,CAC3B,MAAM,mBAAmB,CACzB,KAAK,aAAa,OAAQ,YAAY,CAGxC,QAAiB,EAA+B,CAC1C,EAAQ,IAAI,cAAc,GACxB,KAAK,cAAgB,WACvB,KAAK,aAAa,mBAAoB,WAAW,CAEjD,KAAK,gBAAgB,mBAAmB,OAjB7C,EAAS,CAAE,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,cAAA,IAAA,GAAA,IAI3B,EAAS,CAAE,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,QAAA,IAAA,GAAA"}
|
|
@@ -25,6 +25,11 @@ import { Dialog } from '../dialog/dialog.js';
|
|
|
25
25
|
* @event after-show - Fired after the open animation completes.
|
|
26
26
|
* @event hide - Fired when the drawer is about to close. Cancelable — call `event.preventDefault()` to keep it open.
|
|
27
27
|
* @event after-hide - Fired after the close animation completes.
|
|
28
|
+
*
|
|
29
|
+
* @command --show - Sets `open = true`.
|
|
30
|
+
* @command --hide - Sets `open = false`.
|
|
31
|
+
*
|
|
32
|
+
* @customElement l-drawer
|
|
28
33
|
*/
|
|
29
34
|
export declare class Drawer extends Dialog {
|
|
30
35
|
static styles: import('lit').CSSResult[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../src/html/elements/drawer/drawer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAM7C
|
|
1
|
+
{"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../src/html/elements/drawer/drawer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAM7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,MAAO,SAAQ,MAAM;IAChC,OAAgB,MAAM,4BAA4C;IAIlE,UAAmB,UAAU,EAAG,MAAM,CAAU;IAEhD,iFAAiF;IAEjF,SAAS,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;CACxC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{i as t,t as n}from"../../chunks/decorate.js";import r from"../../shared/styles/host.styles.js";import i from"../dialog/dialog.styles.js";import{Dialog as a}from"../dialog/dialog.js";var o=e(`:host{--size:320px;--border-radius:.375rem}dialog{width:min(var(--size), 100dvw);max-inline-size:100dvw;height:100dvh;border-radius:0 var(--border-radius) var(--border-radius) 0;opacity:1;max-block-size:100dvh;margin:0;transition-property:translate,display,overlay;inset:0;translate:-100%}dialog[open]{translate:0}@starting-style{dialog[open]{translate:-100%}}:host([placement=end]) dialog{border-radius:var(--border-radius) 0 0 var(--border-radius);margin-inline-start:auto;translate:100%}:host([placement=end]) dialog[open]{translate:0}@starting-style{:host([placement=end]) dialog[open]{translate:100%}}:host([placement=bottom]) dialog{width:100dvw;max-inline-size:100dvw;height:min(var(--size), 100dvh);border-radius:var(--border-radius) var(--border-radius) 0 0;max-block-size:100dvh;margin-block-start:auto;translate:0 100%}:host([placement=bottom]) dialog[open]{translate:0}@starting-style{:host([placement=bottom]) dialog[open]{translate:0 100%}}`),s=class extends a{constructor(...e){super(...e),this._modalKind=`edge`}static{this.styles=[r,i,o]}};n([t({reflect:!0})],s.prototype,`placement`,void 0);export{s as Drawer};
|
|
2
2
|
//# sourceMappingURL=drawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.js","names":[],"sources":["../../../src/html/elements/drawer/drawer.css?inline","../../../src/html/elements/drawer/drawer.ts"],"sourcesContent":[":host {\n --size: 320px;\n --border-radius: 0.375rem;\n}\n\n/* Override dialog's opacity fade with a slide from the inline-start edge. */\ndialog {\n inset: 0;\n margin: 0;\n width: min(var(--size), 100dvw);\n max-inline-size: 100dvw;\n height: 100dvh;\n max-block-size: 100dvh;\n border-radius: 0 var(--border-radius) var(--border-radius) 0;\n opacity: 1;\n translate: -100% 0;\n transition-property: translate, display, overlay;\n}\n\ndialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n dialog[open] {\n translate: -100% 0;\n }\n}\n\n/* Inline-end edge */\n:host([placement='end']) dialog {\n border-radius: var(--border-radius) 0 0 var(--border-radius);\n margin-inline-start: auto;\n translate: 100% 0;\n}\n\n:host([placement='end']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='end']) dialog[open] {\n translate: 100% 0;\n }\n}\n\n/* Block-end (bottom) edge */\n:host([placement='bottom']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n margin-block-start: auto;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n translate: 0 100%;\n}\n\n:host([placement='bottom']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='bottom']) dialog[open] {\n translate: 0 100%;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport { Dialog } from '../dialog/dialog.js';\nimport dialogStyles from '../dialog/dialog.styles.js';\nimport rawDrawerStyles from './drawer.css?inline';\n\nconst drawerStyles = unsafeCSS(rawDrawerStyles);\n\n/**\n * A drawer that slides in from a screen edge. Extends `<l-dialog>`.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). Always opens as modal.\n *\n * @slot - Body content.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The drawer title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty --size - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `bottom`). Default `320px`.\n * @cssproperty --border-radius - Drawer border radius on the inner edges. Default `0.375rem`.\n * @cssproperty --show-duration - Open transition duration. Default `200ms`.\n * @cssproperty --hide-duration - Close transition duration. Default `200ms`.\n * @cssproperty --backdrop - Backdrop color.\n *\n * @event show - Fired when the drawer opens. Not cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired when the drawer is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes.\n */\nexport class Drawer extends Dialog {\n static override styles = [hostStyles, dialogStyles, drawerStyles];\n\n // Edge-attached: opt out of the centered modal's stable scrollbar gutter,\n // which would otherwise push the drawer off the actual viewport edge.\n protected override _modalKind = 'edge' as const;\n\n /** Edge the drawer slides in from. Defaults to the start (inline-start) edge. */\n @property({ reflect: true })\n placement?: 'start' | 'end' | 'bottom';\n}\n"],"mappings":"qOCOA,IAAM,EAAe,EAAU,67BAAgB,
|
|
1
|
+
{"version":3,"file":"drawer.js","names":[],"sources":["../../../src/html/elements/drawer/drawer.css?inline","../../../src/html/elements/drawer/drawer.ts"],"sourcesContent":[":host {\n --size: 320px;\n --border-radius: 0.375rem;\n}\n\n/* Override dialog's opacity fade with a slide from the inline-start edge. */\ndialog {\n inset: 0;\n margin: 0;\n width: min(var(--size), 100dvw);\n max-inline-size: 100dvw;\n height: 100dvh;\n max-block-size: 100dvh;\n border-radius: 0 var(--border-radius) var(--border-radius) 0;\n opacity: 1;\n translate: -100% 0;\n transition-property: translate, display, overlay;\n}\n\ndialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n dialog[open] {\n translate: -100% 0;\n }\n}\n\n/* Inline-end edge */\n:host([placement='end']) dialog {\n border-radius: var(--border-radius) 0 0 var(--border-radius);\n margin-inline-start: auto;\n translate: 100% 0;\n}\n\n:host([placement='end']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='end']) dialog[open] {\n translate: 100% 0;\n }\n}\n\n/* Block-end (bottom) edge */\n:host([placement='bottom']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n margin-block-start: auto;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n translate: 0 100%;\n}\n\n:host([placement='bottom']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='bottom']) dialog[open] {\n translate: 0 100%;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport { Dialog } from '../dialog/dialog.js';\nimport dialogStyles from '../dialog/dialog.styles.js';\nimport rawDrawerStyles from './drawer.css?inline';\n\nconst drawerStyles = unsafeCSS(rawDrawerStyles);\n\n/**\n * A drawer that slides in from a screen edge. Extends `<l-dialog>`.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). Always opens as modal.\n *\n * @slot - Body content.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The drawer title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty --size - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `bottom`). Default `320px`.\n * @cssproperty --border-radius - Drawer border radius on the inner edges. Default `0.375rem`.\n * @cssproperty --show-duration - Open transition duration. Default `200ms`.\n * @cssproperty --hide-duration - Close transition duration. Default `200ms`.\n * @cssproperty --backdrop - Backdrop color.\n *\n * @event show - Fired when the drawer opens. Not cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired when the drawer is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes.\n *\n * @command --show - Sets `open = true`.\n * @command --hide - Sets `open = false`.\n *\n * @customElement l-drawer\n */\nexport class Drawer extends Dialog {\n static override styles = [hostStyles, dialogStyles, drawerStyles];\n\n // Edge-attached: opt out of the centered modal's stable scrollbar gutter,\n // which would otherwise push the drawer off the actual viewport edge.\n protected override _modalKind = 'edge' as const;\n\n /** Edge the drawer slides in from. Defaults to the start (inline-start) edge. */\n @property({ reflect: true })\n placement?: 'start' | 'end' | 'bottom';\n}\n"],"mappings":"qOCOA,IAAM,EAAe,EAAU,67BAAgB,CAkClC,EAAb,cAA4B,CAAO,+CAKD,0BAJP,CAAC,EAAY,EAAc,EAAa,MAOhE,EAAS,CAAE,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,YAAA,IAAA,GAAA"}
|
|
@@ -6,7 +6,7 @@ import { Placement } from '@floating-ui/dom';
|
|
|
6
6
|
*
|
|
7
7
|
* @slot trigger - The element that triggers the dropdown.
|
|
8
8
|
* @slot header - Optional content rendered above the menu items (e.g. a user profile row). Use an `<l-divider>` (or `<hr>`) after it to separate from items.
|
|
9
|
-
* @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator.
|
|
9
|
+
* @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator, or an `<l-dropdown-label>` to caption a group of items.
|
|
10
10
|
* @slot footer - Optional content rendered below the menu items (e.g. a version label or shortcut row). Use an `<l-divider>` (or `<hr>`) before it to separate from items.
|
|
11
11
|
*
|
|
12
12
|
* @csspart panel - The floating menu container.
|
|
@@ -23,6 +23,8 @@ import { Placement } from '@floating-ui/dom';
|
|
|
23
23
|
* @event hide - Fired before the dropdown closes. Cancelable.
|
|
24
24
|
* @event after-hide - Fired after the close animation completes.
|
|
25
25
|
* @event select - Fired when an item is selected. Detail: `{ item: DropdownItem }`.
|
|
26
|
+
*
|
|
27
|
+
* @customElement l-dropdown
|
|
26
28
|
*/
|
|
27
29
|
export declare class Dropdown extends LuxenElement {
|
|
28
30
|
static styles: import('lit').CSSResult[];
|
|
@@ -37,6 +39,14 @@ export declare class Dropdown extends LuxenElement {
|
|
|
37
39
|
accessor distance: number;
|
|
38
40
|
/** Disables the dropdown trigger. */
|
|
39
41
|
accessor disabled: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Floor the panel's width at the trigger's width. Set to `trigger` so the
|
|
44
|
+
* panel is never narrower than the trigger; it still grows with its content.
|
|
45
|
+
* Useful for select-like triggers (a date-range or filter button) where the
|
|
46
|
+
* panel should line up with the control. Re-applies if the trigger resizes
|
|
47
|
+
* while open.
|
|
48
|
+
*/
|
|
49
|
+
accessor minWidth: 'trigger' | undefined;
|
|
40
50
|
private get _triggerEl();
|
|
41
51
|
private get _panelEl();
|
|
42
52
|
private _getItems;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown/dropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AASlD
|
|
1
|
+
{"version":3,"file":"dropdown.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown/dropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AASlD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,QAAS,SAAQ,YAAY;IACxC,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,SAAS,CAId;IAEH,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAE9B,oCAAoC;IAEpC,QAAQ,CAAC,IAAI,UAAS;IAEtB,wCAAwC;IAExC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAkB;IAE/C,2CAA2C;IAE3C,QAAQ,CAAC,QAAQ,SAAK;IAEtB,qCAAqC;IAErC,QAAQ,CAAC,QAAQ,UAAS;IAE1B;;;;;;OAMG;IAEH,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS,CAAC;IAEzC,OAAO,KAAK,UAAU,GAGrB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,YAAY;IAOpB,IAAI;IAKJ,IAAI;IAKJ,MAAM;IAOG,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;YAQhC,iBAAiB;IA6B/B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,eAAe,CAQrB;IAEF,OAAO,CAAC,iBAAiB,CAYvB;IAEF,OAAO,CAAC,eAAe,CAiCrB;IAEF,OAAO,CAAC,YAAY,CAKlB;IAEF,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,WAAW;IAWnB,2DAA2D;IAC3D,OAAO,CAAC,SAAS,CAMf;IAEO,MAAM;CAwBhB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{tagName as e}from"../../registry.js";import{
|
|
1
|
+
import{tagName as e}from"../../registry.js";import{i as t}from"../../chunks/lit.js";import{a as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";import{PopoverController as s}from"../../shared/controllers/popover.js";var c=t(`:host{--padding:.25rem;--background:var(--l-color-bg-surface,Canvas);--border-radius:6px;--shadow:0 4px 6px -1px #00000014, 0 2px 4px -2px #0000000f;--show-duration:150;--hide-duration:150;display:inline-block;position:relative}.trigger{display:contents}[popover]{inset:unset;box-sizing:border-box;width:max-content;padding:var(--padding);border:1px solid var(--l-color-border-overlay,var(--lightningcss-light,#e5e7eb)var(--lightningcss-dark,#374151));border-radius:var(--border-radius);background:var(--background);color:var(--l-color-text-primary,CanvasText);box-shadow:var(--shadow);margin:0;font-size:.875rem;line-height:1.5;overflow:visible}::slotted(hr){height:1px;margin-block:var(--padding);margin-inline:calc(var(--padding) * -1);background:var(--l-color-divider);border:0}`),l=class extends r{constructor(...t){super(...t),this._floating=new s(this,{getTriggerElement:()=>this._triggerEl,getFloatingElement:()=>this._panelEl,getArrowElement:()=>null}),this._typeaheadBuffer=``,this._typeaheadTimeout=0,this.#e=!1,this.#t=`bottom-start`,this.#n=4,this.#r=!1,this._onTriggerClick=e=>{this.disabled||(this.toggle(),this.open&&e.detail===0&&requestAnimationFrame(()=>this._focusFirstItem()))},this._onTriggerKeyDown=e=>{this.disabled||(e.key===`ArrowDown`?(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusFirstItem())):e.key===`ArrowUp`&&(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusLastItem())))},this._onPanelKeyDown=e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),this._focusNextItem();break;case`ArrowUp`:e.preventDefault(),this._focusPreviousItem();break;case`Home`:e.preventDefault(),this._focusFirstItem();break;case`End`:e.preventDefault(),this._focusLastItem();break;case`Escape`:e.preventDefault(),this.hide(),this._triggerEl?.focus();break;case`Enter`:case` `:e.preventDefault(),this._selectCurrentItem();break;default:e.key.length===1&&!e.ctrlKey&&!e.metaKey&&this._handleTypeahead(e.key)}},this._onItemClick=t=>{let n=t.target.closest(e(`dropdown-item`));n&&!n.disabled&&this._selectItem(n)},this._onToggle=e=>{e.newState===`closed`&&this.open&&(this.open=!1,this._triggerEl?.setAttribute(`aria-expanded`,`false`))}}static{this.styles=[o,c]}#e;get open(){return this.#e}set open(e){this.#e=e}#t;get placement(){return this.#t}set placement(e){this.#t=e}#n;get distance(){return this.#n}set distance(e){this.#n=e}#r;get disabled(){return this.#r}set disabled(e){this.#r=e}#i;get minWidth(){return this.#i}set minWidth(e){this.#i=e}get _triggerEl(){return this.shadowRoot.querySelector(`.trigger slot`)?.assignedElements()[0]??null}get _panelEl(){return this.shadowRoot.querySelector(`[popover]`)}_getItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()&&!t.disabled):[]}_getAllItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()):[]}_getDuration(e){let t=parseFloat(getComputedStyle(this).getPropertyValue(e));return Number.isNaN(t)?150:t}show(){this.open||this.disabled||this.emit(`show`,{cancelable:!0})&&(this.open=!0)}hide(){this.open&&this.emit(`hide`,{cancelable:!0})&&(this.open=!1)}toggle(){this.open?this.hide():this.show()}updated(e){e.has(`open`)&&this._handleOpenChange()}async _handleOpenChange(){let e=this._panelEl;if(!e)return;let t={placement:this.placement,distance:this.distance,minWidth:this.minWidth};if(this.open){if(e.showPopover(),await this._floating.updatePosition(t),!this.open)return;await this._floating.animateShow(e,this._getDuration(`--show-duration`)),this._floating.startPositioning(t),this._triggerEl?.setAttribute(`aria-expanded`,`true`),this.emit(`after-show`)}else this._floating.stopPositioning(),this._triggerEl?.setAttribute(`aria-expanded`,`false`),await this._floating.animateHide(e,this._getDuration(`--hide-duration`)),e.matches(`:popover-open`)&&e.hidePopover(),this.emit(`after-hide`)}_setActiveItem(e){let t=e.shadowRoot.querySelector(`.item`);if(t){for(let e of this._getAllItems())e.shadowRoot.querySelector(`.item`)?.setAttribute(`tabindex`,`-1`);t.setAttribute(`tabindex`,`0`),t.focus()}}_focusFirstItem(){let e=this._getItems();e.length&&this._setActiveItem(e[0])}_focusLastItem(){let e=this._getItems();e.length&&this._setActiveItem(e[e.length-1])}_getCurrentItem(){return this._getItems().find(e=>{let t=e.shadowRoot.querySelector(`.item`);return t?.getAttribute(`tabindex`)===`0`&&e.shadowRoot.activeElement===t})??null}_focusNextItem(){let e=this._getItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):-1)+1)%e.length];n&&this._setActiveItem(n)}_focusPreviousItem(){let e=this._getItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):0)-1+e.length)%e.length];n&&this._setActiveItem(n)}_handleTypeahead(e){clearTimeout(this._typeaheadTimeout),this._typeaheadBuffer+=e.toLowerCase(),this._typeaheadTimeout=window.setTimeout(()=>{this._typeaheadBuffer=``},500);let t=this._getItems().find(e=>e.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer));t&&this._setActiveItem(t)}_selectCurrentItem(){let e=this._getCurrentItem();e&&this._selectItem(e)}_selectItem(e){e.type===`checkbox`&&(e.checked=!e.checked),this.emit(`select`,{detail:{item:e}}),e.type!==`checkbox`&&(this.hide(),this._triggerEl?.focus())}render(){return n`
|
|
2
2
|
<div
|
|
3
3
|
class="trigger"
|
|
4
4
|
@click=${this._onTriggerClick}
|
|
@@ -19,5 +19,5 @@ import{tagName as e}from"../../registry.js";import{a as t,l as n}from"../../chun
|
|
|
19
19
|
</div>
|
|
20
20
|
<slot name="footer"></slot>
|
|
21
21
|
</div>
|
|
22
|
-
`}};a([i({type:Boolean,reflect:!0})],l.prototype,`open`,null),a([i()],l.prototype,`placement`,null),a([i({type:Number})],l.prototype,`distance`,null),a([i({type:Boolean,reflect:!0})],l.prototype,`disabled`,null);export{l as Dropdown};
|
|
22
|
+
`}};a([i({type:Boolean,reflect:!0})],l.prototype,`open`,null),a([i()],l.prototype,`placement`,null),a([i({type:Number})],l.prototype,`distance`,null),a([i({type:Boolean,reflect:!0})],l.prototype,`disabled`,null),a([i({attribute:`min-width`})],l.prototype,`minWidth`,null);export{l as Dropdown};
|
|
23
23
|
//# sourceMappingURL=dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/html/elements/dropdown/dropdown.css?inline","../../../src/html/elements/dropdown/dropdown.ts"],"sourcesContent":[":host {\n --padding: 0.25rem;\n\n --background: var(--l-color-bg-surface, Canvas);\n --border-radius: 6px;\n --shadow: 0 4px 6px -1px rgb(0 0 0 / 8%), 0 2px 4px -2px rgb(0 0 0 / 6%);\n --show-duration: 150;\n --hide-duration: 150;\n\n display: inline-block;\n position: relative;\n}\n\n.trigger {\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n box-sizing: border-box;\n width: max-content;\n min-width: anchor-size(width);\n padding: var(--padding);\n margin: 0;\n border: 1px solid var(--l-color-border-overlay, light-dark(#e5e7eb, #374151));\n border-radius: var(--border-radius);\n background: var(--background);\n color: var(--l-color-text-primary, CanvasText);\n box-shadow: var(--shadow);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n/* Lightweight separator alternative to <l-divider> — same dimensions, no extra import. */\n::slotted(hr) {\n height: 1px;\n margin-block: var(--padding);\n margin-inline: calc(var(--padding) * -1);\n border: 0;\n background: var(--l-color-divider);\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { tagName } from '../../registry.js';\nimport type { DropdownItem } from '../dropdown-item/dropdown-item.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A dropdown menu anchored to a trigger element.\n *\n * @slot trigger - The element that triggers the dropdown.\n * @slot header - Optional content rendered above the menu items (e.g. a user profile row). Use an `<l-divider>` (or `<hr>`) after it to separate from items.\n * @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator.\n * @slot footer - Optional content rendered below the menu items (e.g. a version label or shortcut row). Use an `<l-divider>` (or `<hr>`) before it to separate from items.\n *\n * @csspart panel - The floating menu container.\n *\n * @cssproperty --background - Panel background color.\n * @cssproperty --border-radius - Panel border radius. Default `8px`.\n * @cssproperty --padding - Panel inner padding. Default `0.25rem`. Slotted `<l-divider>` elements bleed by this amount on each side to span the panel edges.\n * @cssproperty --shadow - Panel box shadow.\n * @cssproperty --show-duration - Show animation duration in ms. Default `150`.\n * @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.\n *\n * @event show - Fired before the dropdown opens. Cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired before the dropdown closes. Cancelable.\n * @event after-hide - Fired after the close animation completes.\n * @event select - Fired when an item is selected. Detail: `{ item: DropdownItem }`.\n */\nexport class Dropdown extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._triggerEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _typeaheadBuffer = '';\n private _typeaheadTimeout = 0;\n\n /** Whether the dropdown is open. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Preferred placement of the panel. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Distance in pixels from the trigger. */\n @property({ type: Number })\n accessor distance = 4;\n\n /** Disables the dropdown trigger. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n private get _triggerEl(): HTMLElement | null {\n const slot = this.shadowRoot!.querySelector<HTMLSlotElement>('.trigger slot');\n return (slot?.assignedElements()[0] as HTMLElement) ?? null;\n }\n\n private get _panelEl(): HTMLElement | null {\n return this.shadowRoot!.querySelector<HTMLElement>('[popover]');\n }\n\n private _getItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase() && !el.disabled,\n );\n }\n\n private _getAllItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase(),\n );\n }\n\n private _getDuration(prop: '--show-duration' | '--hide-duration'): number {\n const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));\n return Number.isNaN(parsed) ? 150 : parsed;\n }\n\n // --- Public API ---\n\n show() {\n if (this.open || this.disabled) return;\n if (this.emit('show', { cancelable: true })) this.open = true;\n }\n\n hide() {\n if (!this.open) return;\n if (this.emit('hide', { cancelable: true })) this.open = false;\n }\n\n toggle() {\n if (this.open) this.hide();\n else this.show();\n }\n\n // --- Lifecycle ---\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n void this._handleOpenChange();\n }\n }\n\n // --- Open/Close ---\n\n private async _handleOpenChange() {\n const panel = this._panelEl;\n if (!panel) return;\n\n const posOpts = { placement: this.placement, distance: this.distance };\n\n if (this.open) {\n panel.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(panel, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._triggerEl?.setAttribute('aria-expanded', 'true');\n this.emit('after-show');\n } else {\n this._floating.stopPositioning();\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n await this._floating.animateHide(panel, this._getDuration('--hide-duration'));\n if (panel.matches(':popover-open')) panel.hidePopover();\n this.emit('after-hide');\n }\n }\n\n // --- Focus management ---\n\n private _setActiveItem(item: DropdownItem) {\n const itemEl = item.shadowRoot!.querySelector<HTMLElement>('.item');\n if (!itemEl) return;\n\n // Reset all items\n for (const i of this._getAllItems()) {\n const el = i.shadowRoot!.querySelector<HTMLElement>('.item');\n el?.setAttribute('tabindex', '-1');\n }\n\n itemEl.setAttribute('tabindex', '0');\n itemEl.focus();\n }\n\n private _focusFirstItem() {\n const items = this._getItems();\n if (items.length) this._setActiveItem(items[0]);\n }\n\n private _focusLastItem() {\n const items = this._getItems();\n if (items.length) this._setActiveItem(items[items.length - 1]);\n }\n\n private _getCurrentItem(): DropdownItem | null {\n const items = this._getItems();\n return (\n items.find((item) => {\n const el = item.shadowRoot!.querySelector<HTMLElement>('.item');\n return el?.getAttribute('tabindex') === '0' && item.shadowRoot!.activeElement === el;\n }) ?? null\n );\n }\n\n private _focusNextItem() {\n const items = this._getItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : -1;\n const next = items[(index + 1) % items.length];\n if (next) this._setActiveItem(next);\n }\n\n private _focusPreviousItem() {\n const items = this._getItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : 0;\n const prev = items[(index - 1 + items.length) % items.length];\n if (prev) this._setActiveItem(prev);\n }\n\n // --- Typeahead ---\n\n private _handleTypeahead(key: string) {\n clearTimeout(this._typeaheadTimeout);\n this._typeaheadBuffer += key.toLowerCase();\n this._typeaheadTimeout = window.setTimeout(() => {\n this._typeaheadBuffer = '';\n }, 500);\n\n const items = this._getItems();\n const match = items.find((item) =>\n item.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer),\n );\n if (match) this._setActiveItem(match);\n }\n\n // --- Event handlers ---\n\n private _onTriggerClick = (e: MouseEvent) => {\n if (this.disabled) return;\n this.toggle();\n // Space/Enter on a native button dispatches click with detail=0; focus the\n // first item so the menu is keyboard-navigable immediately on open.\n if (this.open && e.detail === 0) {\n requestAnimationFrame(() => this._focusFirstItem());\n }\n };\n\n private _onTriggerKeyDown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusFirstItem());\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusLastItem());\n }\n };\n\n private _onPanelKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this._focusNextItem();\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._focusPreviousItem();\n break;\n case 'Home':\n e.preventDefault();\n this._focusFirstItem();\n break;\n case 'End':\n e.preventDefault();\n this._focusLastItem();\n break;\n case 'Escape':\n e.preventDefault();\n this.hide();\n this._triggerEl?.focus();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n this._selectCurrentItem();\n break;\n default:\n if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {\n this._handleTypeahead(e.key);\n }\n }\n };\n\n private _onItemClick = (e: Event) => {\n const item = (e.target as HTMLElement).closest<DropdownItem>(tagName('dropdown-item'));\n if (item && !item.disabled) {\n this._selectItem(item);\n }\n };\n\n private _selectCurrentItem() {\n const current = this._getCurrentItem();\n if (current) this._selectItem(current);\n }\n\n private _selectItem(item: DropdownItem) {\n if (item.type === 'checkbox') {\n item.checked = !item.checked;\n }\n this.emit('select', { detail: { item } });\n if (item.type !== 'checkbox') {\n this.hide();\n this._triggerEl?.focus();\n }\n }\n\n /** Sync `open` when popover=\"auto\" light-dismiss fires. */\n private _onToggle = (e: Event) => {\n const toggleEvent = e as ToggleEvent;\n if (toggleEvent.newState === 'closed' && this.open) {\n this.open = false;\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n }\n };\n\n override render() {\n return html`\n <div\n class=\"trigger\"\n @click=${this._onTriggerClick}\n @keydown=${this._onTriggerKeyDown}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n popover=\"auto\"\n part=\"panel\"\n @keydown=${this._onPanelKeyDown}\n @click=${this._onItemClick}\n @toggle=${this._onToggle}\n >\n <slot name=\"header\"></slot>\n <div role=\"menu\">\n <slot></slot>\n </div>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/html/elements/dropdown/dropdown.css?inline","../../../src/html/elements/dropdown/dropdown.ts"],"sourcesContent":[":host {\n --padding: 0.25rem;\n\n --background: var(--l-color-bg-surface, Canvas);\n --border-radius: 6px;\n --shadow: 0 4px 6px -1px rgb(0 0 0 / 8%), 0 2px 4px -2px rgb(0 0 0 / 6%);\n --show-duration: 150;\n --hide-duration: 150;\n\n display: inline-block;\n position: relative;\n}\n\n.trigger {\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n box-sizing: border-box;\n width: max-content;\n padding: var(--padding);\n margin: 0;\n border: 1px solid var(--l-color-border-overlay, light-dark(#e5e7eb, #374151));\n border-radius: var(--border-radius);\n background: var(--background);\n color: var(--l-color-text-primary, CanvasText);\n box-shadow: var(--shadow);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n/* Lightweight separator alternative to <l-divider> — same dimensions, no extra import. */\n::slotted(hr) {\n height: 1px;\n margin-block: var(--padding);\n margin-inline: calc(var(--padding) * -1);\n border: 0;\n background: var(--l-color-divider);\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { tagName } from '../../registry.js';\nimport type { DropdownItem } from '../dropdown-item/dropdown-item.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A dropdown menu anchored to a trigger element.\n *\n * @slot trigger - The element that triggers the dropdown.\n * @slot header - Optional content rendered above the menu items (e.g. a user profile row). Use an `<l-divider>` (or `<hr>`) after it to separate from items.\n * @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator, or an `<l-dropdown-label>` to caption a group of items.\n * @slot footer - Optional content rendered below the menu items (e.g. a version label or shortcut row). Use an `<l-divider>` (or `<hr>`) before it to separate from items.\n *\n * @csspart panel - The floating menu container.\n *\n * @cssproperty --background - Panel background color.\n * @cssproperty --border-radius - Panel border radius. Default `8px`.\n * @cssproperty --padding - Panel inner padding. Default `0.25rem`. Slotted `<l-divider>` elements bleed by this amount on each side to span the panel edges.\n * @cssproperty --shadow - Panel box shadow.\n * @cssproperty --show-duration - Show animation duration in ms. Default `150`.\n * @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.\n *\n * @event show - Fired before the dropdown opens. Cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired before the dropdown closes. Cancelable.\n * @event after-hide - Fired after the close animation completes.\n * @event select - Fired when an item is selected. Detail: `{ item: DropdownItem }`.\n *\n * @customElement l-dropdown\n */\nexport class Dropdown extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._triggerEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _typeaheadBuffer = '';\n private _typeaheadTimeout = 0;\n\n /** Whether the dropdown is open. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Preferred placement of the panel. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Distance in pixels from the trigger. */\n @property({ type: Number })\n accessor distance = 4;\n\n /** Disables the dropdown trigger. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /**\n * Floor the panel's width at the trigger's width. Set to `trigger` so the\n * panel is never narrower than the trigger; it still grows with its content.\n * Useful for select-like triggers (a date-range or filter button) where the\n * panel should line up with the control. Re-applies if the trigger resizes\n * while open.\n */\n @property({ attribute: 'min-width' })\n accessor minWidth: 'trigger' | undefined;\n\n private get _triggerEl(): HTMLElement | null {\n const slot = this.shadowRoot!.querySelector<HTMLSlotElement>('.trigger slot');\n return (slot?.assignedElements()[0] as HTMLElement) ?? null;\n }\n\n private get _panelEl(): HTMLElement | null {\n return this.shadowRoot!.querySelector<HTMLElement>('[popover]');\n }\n\n private _getItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase() && !el.disabled,\n );\n }\n\n private _getAllItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase(),\n );\n }\n\n private _getDuration(prop: '--show-duration' | '--hide-duration'): number {\n const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));\n return Number.isNaN(parsed) ? 150 : parsed;\n }\n\n // --- Public API ---\n\n show() {\n if (this.open || this.disabled) return;\n if (this.emit('show', { cancelable: true })) this.open = true;\n }\n\n hide() {\n if (!this.open) return;\n if (this.emit('hide', { cancelable: true })) this.open = false;\n }\n\n toggle() {\n if (this.open) this.hide();\n else this.show();\n }\n\n // --- Lifecycle ---\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n void this._handleOpenChange();\n }\n }\n\n // --- Open/Close ---\n\n private async _handleOpenChange() {\n const panel = this._panelEl;\n if (!panel) return;\n\n const posOpts = {\n placement: this.placement,\n distance: this.distance,\n minWidth: this.minWidth,\n };\n\n if (this.open) {\n panel.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(panel, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._triggerEl?.setAttribute('aria-expanded', 'true');\n this.emit('after-show');\n } else {\n this._floating.stopPositioning();\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n await this._floating.animateHide(panel, this._getDuration('--hide-duration'));\n if (panel.matches(':popover-open')) panel.hidePopover();\n this.emit('after-hide');\n }\n }\n\n // --- Focus management ---\n\n private _setActiveItem(item: DropdownItem) {\n const itemEl = item.shadowRoot!.querySelector<HTMLElement>('.item');\n if (!itemEl) return;\n\n // Reset all items\n for (const i of this._getAllItems()) {\n const el = i.shadowRoot!.querySelector<HTMLElement>('.item');\n el?.setAttribute('tabindex', '-1');\n }\n\n itemEl.setAttribute('tabindex', '0');\n itemEl.focus();\n }\n\n private _focusFirstItem() {\n const items = this._getItems();\n if (items.length) this._setActiveItem(items[0]);\n }\n\n private _focusLastItem() {\n const items = this._getItems();\n if (items.length) this._setActiveItem(items[items.length - 1]);\n }\n\n private _getCurrentItem(): DropdownItem | null {\n const items = this._getItems();\n return (\n items.find((item) => {\n const el = item.shadowRoot!.querySelector<HTMLElement>('.item');\n return el?.getAttribute('tabindex') === '0' && item.shadowRoot!.activeElement === el;\n }) ?? null\n );\n }\n\n private _focusNextItem() {\n const items = this._getItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : -1;\n const next = items[(index + 1) % items.length];\n if (next) this._setActiveItem(next);\n }\n\n private _focusPreviousItem() {\n const items = this._getItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : 0;\n const prev = items[(index - 1 + items.length) % items.length];\n if (prev) this._setActiveItem(prev);\n }\n\n // --- Typeahead ---\n\n private _handleTypeahead(key: string) {\n clearTimeout(this._typeaheadTimeout);\n this._typeaheadBuffer += key.toLowerCase();\n this._typeaheadTimeout = window.setTimeout(() => {\n this._typeaheadBuffer = '';\n }, 500);\n\n const items = this._getItems();\n const match = items.find((item) =>\n item.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer),\n );\n if (match) this._setActiveItem(match);\n }\n\n // --- Event handlers ---\n\n private _onTriggerClick = (e: MouseEvent) => {\n if (this.disabled) return;\n this.toggle();\n // Space/Enter on a native button dispatches click with detail=0; focus the\n // first item so the menu is keyboard-navigable immediately on open.\n if (this.open && e.detail === 0) {\n requestAnimationFrame(() => this._focusFirstItem());\n }\n };\n\n private _onTriggerKeyDown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusFirstItem());\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusLastItem());\n }\n };\n\n private _onPanelKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this._focusNextItem();\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._focusPreviousItem();\n break;\n case 'Home':\n e.preventDefault();\n this._focusFirstItem();\n break;\n case 'End':\n e.preventDefault();\n this._focusLastItem();\n break;\n case 'Escape':\n e.preventDefault();\n this.hide();\n this._triggerEl?.focus();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n this._selectCurrentItem();\n break;\n default:\n if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {\n this._handleTypeahead(e.key);\n }\n }\n };\n\n private _onItemClick = (e: Event) => {\n const item = (e.target as HTMLElement).closest<DropdownItem>(tagName('dropdown-item'));\n if (item && !item.disabled) {\n this._selectItem(item);\n }\n };\n\n private _selectCurrentItem() {\n const current = this._getCurrentItem();\n if (current) this._selectItem(current);\n }\n\n private _selectItem(item: DropdownItem) {\n if (item.type === 'checkbox') {\n item.checked = !item.checked;\n }\n this.emit('select', { detail: { item } });\n if (item.type !== 'checkbox') {\n this.hide();\n this._triggerEl?.focus();\n }\n }\n\n /** Sync `open` when popover=\"auto\" light-dismiss fires. */\n private _onToggle = (e: Event) => {\n const toggleEvent = e as ToggleEvent;\n if (toggleEvent.newState === 'closed' && this.open) {\n this.open = false;\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n }\n };\n\n override render() {\n return html`\n <div\n class=\"trigger\"\n @click=${this._onTriggerClick}\n @keydown=${this._onTriggerKeyDown}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n popover=\"auto\"\n part=\"panel\"\n @keydown=${this._onPanelKeyDown}\n @click=${this._onItemClick}\n @toggle=${this._onToggle}\n >\n <slot name=\"header\"></slot>\n <div role=\"menu\">\n <slot></slot>\n </div>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ import { LuxenElement } from '../../shared/luxen-element.js';
|
|
|
7
7
|
* @slot suffix - Trailing content.
|
|
8
8
|
*
|
|
9
9
|
* @cssproperty --color - Text color.
|
|
10
|
+
*
|
|
11
|
+
* @customElement l-dropdown-item
|
|
10
12
|
*/
|
|
11
13
|
export declare class DropdownItem extends LuxenElement {
|
|
12
14
|
static styles: import('lit').CSSResult[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-item.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown-item/dropdown-item.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAO7D
|
|
1
|
+
{"version":3,"file":"dropdown-item.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown-item/dropdown-item.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAO7D;;;;;;;;;;GAUG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAgB,MAAM,4BAAwB;IAE9C,2CAA2C;IAE3C,QAAQ,CAAC,KAAK,SAAM;IAEpB,yBAAyB;IAEzB,QAAQ,CAAC,QAAQ,UAAS;IAE1B,gDAAgD;IAEhD,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAY;IAEhD,4CAA4C;IAE5C,QAAQ,CAAC,OAAO,UAAS;IAEzB,2CAA2C;IAC3C,YAAY,IAAI,MAAM;IAIb,MAAM;CAuChB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{a as t,t as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=e(`:host{display:block}:host([disabled]){pointer-events:none;opacity:.5}.item{cursor:pointer;color:var(--l-color-text-primary,CanvasText);white-space:nowrap;border-radius:4px;outline:none;align-items:center;gap:8px;padding:.375rem .5rem;font-size:.875rem;line-height:1.5;display:flex}.item:focus-visible{background:var(--l-color-bg-state-hover)}@media (hover:hover){.item:hover{background:var(--l-color-bg-state-hover)}}.check{flex-shrink:0;width:16px;display:flex}:host(:not([checked])) .check svg{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0;display:flex}.label{flex:1}`),c=class extends r{static{this.styles=[o,s]}#e=``;get value(){return this.#e}set value(e){this.#e=e}#t=!1;get disabled(){return this.#t}set disabled(e){this.#t=e}#n=`normal`;get type(){return this.#n}set type(e){this.#n=e}#r=!1;get checked(){return this.#r}set checked(e){this.#r=e}getTextLabel(){return(this.textContent??``).trim()}render(){let e=this.type===`checkbox`;return t`
|
|
2
2
|
<div
|
|
3
3
|
class="item"
|
|
4
|
-
role=${
|
|
5
|
-
aria-checked=${
|
|
4
|
+
role=${e?`menuitemcheckbox`:`menuitem`}
|
|
5
|
+
aria-checked=${e?String(this.checked):n}
|
|
6
6
|
aria-disabled=${this.disabled?`true`:n}
|
|
7
7
|
tabindex="-1"
|
|
8
8
|
>
|
|
9
|
-
${t
|
|
9
|
+
${e?t`
|
|
10
10
|
<span
|
|
11
11
|
class="check"
|
|
12
12
|
aria-hidden="true"
|
|
@@ -26,7 +26,7 @@ import{a as e,l as t,n}from"../../chunks/lit.js";import{LuxenElement as r}from".
|
|
|
26
26
|
/>
|
|
27
27
|
</svg>
|
|
28
28
|
</span>
|
|
29
|
-
`:
|
|
29
|
+
`:t` <slot name="prefix"></slot> `}
|
|
30
30
|
<span class="label"><slot></slot></span>
|
|
31
31
|
<slot name="suffix"></slot>
|
|
32
32
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../src/html/elements/dropdown-item/dropdown-item.css?inline","../../../src/html/elements/dropdown-item/dropdown-item.ts"],"sourcesContent":[":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A menu item for use inside `<l-dropdown>`.\n *\n * @slot - Label text.\n * @slot prefix - Leading content (e.g. icon).\n * @slot suffix - Trailing content.\n *\n * @cssproperty --color - Text color.\n */\nexport class DropdownItem extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n /** The value associated with this item. */\n @property()\n accessor value = '';\n\n /** Disables the item. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** The type of item: `normal` or `checkbox`. */\n @property()\n accessor type: 'normal' | 'checkbox' = 'normal';\n\n /** Whether the checkbox item is checked. */\n @property({ type: Boolean, reflect: true })\n accessor checked = false;\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n return (this.textContent ?? '').trim();\n }\n\n override render() {\n const isCheckbox = this.type === 'checkbox';\n\n return html`\n <div\n class=\"item\"\n role=${isCheckbox ? 'menuitemcheckbox' : 'menuitem'}\n aria-checked=${isCheckbox ? String(this.checked) : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n tabindex=\"-1\"\n >\n ${isCheckbox\n ? html`\n <span\n class=\"check\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 8.5L6.5 11.5L12.5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n `\n : html` <slot name=\"prefix\"></slot> `}\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../src/html/elements/dropdown-item/dropdown-item.css?inline","../../../src/html/elements/dropdown-item/dropdown-item.ts"],"sourcesContent":[":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A menu item for use inside `<l-dropdown>`.\n *\n * @slot - Label text.\n * @slot prefix - Leading content (e.g. icon).\n * @slot suffix - Trailing content.\n *\n * @cssproperty --color - Text color.\n *\n * @customElement l-dropdown-item\n */\nexport class DropdownItem extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n /** The value associated with this item. */\n @property()\n accessor value = '';\n\n /** Disables the item. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** The type of item: `normal` or `checkbox`. */\n @property()\n accessor type: 'normal' | 'checkbox' = 'normal';\n\n /** Whether the checkbox item is checked. */\n @property({ type: Boolean, reflect: true })\n accessor checked = false;\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n return (this.textContent ?? '').trim();\n }\n\n override render() {\n const isCheckbox = this.type === 'checkbox';\n\n return html`\n <div\n class=\"item\"\n role=${isCheckbox ? 'menuitemcheckbox' : 'menuitem'}\n aria-checked=${isCheckbox ? String(this.checked) : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n tabindex=\"-1\"\n >\n ${isCheckbox\n ? html`\n <span\n class=\"check\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 8.5L6.5 11.5L12.5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n `\n : html` <slot name=\"prefix\"></slot> `}\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"0PCMA,IAAM,EAAS,EAAU,gmBAAU,CAatB,EAAb,cAAkC,CAAa,oBACpB,CAAC,EAAY,EAAO,IAI5B,OAAR,OAAA,0CAIW,OAAX,UAAA,6CAI8B,aAA9B,MAAA,yCAIU,OAAV,SAAA,yCAGT,cAAuB,CACrB,OAAQ,KAAK,aAAe,IAAI,MAAM,CAGxC,QAAkB,CAChB,IAAM,EAAa,KAAK,OAAS,WAEjC,MAAO,EAAI;;;eAGA,EAAa,mBAAqB,WAAW;uBACrC,EAAa,OAAO,KAAK,QAAQ,CAAG,EAAQ;wBAC3C,KAAK,SAAW,OAAS,EAAQ;;;UAG/C,EACE,CAAI;;;;;;;;;;;;;;;;;;;;cAqBJ,CAAI,gCAAgC;;;;WArD7C,GAAU,CAAA,CAAA,EAAA,UAAA,QAAA,KAAA,IAIV,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,WAAA,KAAA,IAI1C,GAAU,CAAA,CAAA,EAAA,UAAA,OAAA,KAAA,IAIV,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,UAAA,KAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CSSResultGroup } from 'lit';
|
|
2
|
+
import { LuxenElement } from '../../shared/luxen-element.js';
|
|
3
|
+
/**
|
|
4
|
+
* A non-interactive section label for grouping items inside `<l-dropdown>`.
|
|
5
|
+
*
|
|
6
|
+
* @slot - Label text.
|
|
7
|
+
*
|
|
8
|
+
* @cssproperty --color - Text color. Defaults to `var(--l-color-text-tertiary)`.
|
|
9
|
+
*
|
|
10
|
+
* @customElement l-dropdown-label
|
|
11
|
+
*/
|
|
12
|
+
export declare class DropdownLabel extends LuxenElement {
|
|
13
|
+
static styles: CSSResultGroup;
|
|
14
|
+
connectedCallback(): void;
|
|
15
|
+
render(): import('lit').TemplateResult<1>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=dropdown-label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropdown-label.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown-label/dropdown-label.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAM7D;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAgB,MAAM,EAAE,cAAc,CAAwB;IAErD,iBAAiB;IAUjB,MAAM;CAKhB"}
|