luxen-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/css/elements/avatar.css +20 -0
- package/dist/css/elements/badge.css +159 -0
- package/dist/css/elements/button.css +171 -0
- package/dist/css/elements/close-button/circle.css +66 -0
- package/dist/css/elements/close-button/ring.css +71 -0
- package/dist/css/elements/close-button/square.css +70 -0
- package/dist/css/elements/disclosure.css +137 -0
- package/dist/css/elements/divider.css +75 -0
- package/dist/css/elements/input-otp.css +164 -0
- package/dist/css/elements/input-stepper/default.css +245 -0
- package/dist/css/elements/input-stepper/rounded.css +238 -0
- package/dist/css/elements/kbd.css +21 -0
- package/dist/css/elements/progress.css +114 -0
- package/dist/css/elements/select.css +71 -0
- package/dist/css/elements/skeleton.css +89 -0
- package/dist/css/elements/tabs/enclosed.css +148 -0
- package/dist/css/elements/tabs/line.css +138 -0
- package/dist/css/elements/toast.css +260 -0
- package/dist/css/index.css +885 -0
- package/dist/custom-elements.json +14424 -0
- package/dist/define.d.ts +9 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +16 -0
- package/dist/elements/avatar/avatar.css +128 -0
- package/dist/elements/avatar/avatar.d.ts +21 -0
- package/dist/elements/avatar/avatar.d.ts.map +1 -0
- package/dist/elements/avatar/avatar.js +106 -0
- package/dist/elements/avatar/index.d.ts +8 -0
- package/dist/elements/avatar/index.d.ts.map +1 -0
- package/dist/elements/avatar/index.js +4 -0
- package/dist/elements/badge/badge.d.ts +17 -0
- package/dist/elements/badge/badge.d.ts.map +1 -0
- package/dist/elements/badge/badge.js +34 -0
- package/dist/elements/badge/index.d.ts +8 -0
- package/dist/elements/badge/index.d.ts.map +1 -0
- package/dist/elements/badge/index.js +4 -0
- package/dist/elements/carousel/carousel.css +205 -0
- package/dist/elements/carousel/carousel.d.ts +148 -0
- package/dist/elements/carousel/carousel.d.ts.map +1 -0
- package/dist/elements/carousel/carousel.js +473 -0
- package/dist/elements/carousel/index.d.ts +8 -0
- package/dist/elements/carousel/index.d.ts.map +1 -0
- package/dist/elements/carousel/index.js +4 -0
- package/dist/elements/carousel-item/carousel-item.css +11 -0
- package/dist/elements/carousel-item/carousel-item.d.ts +13 -0
- package/dist/elements/carousel-item/carousel-item.d.ts.map +1 -0
- package/dist/elements/carousel-item/carousel-item.js +20 -0
- package/dist/elements/carousel-item/index.d.ts +8 -0
- package/dist/elements/carousel-item/index.d.ts.map +1 -0
- package/dist/elements/carousel-item/index.js +4 -0
- package/dist/elements/dialog/dialog.css +92 -0
- package/dist/elements/dialog/dialog.d.ts +56 -0
- package/dist/elements/dialog/dialog.d.ts.map +1 -0
- package/dist/elements/dialog/dialog.js +204 -0
- package/dist/elements/dialog/dialog.styles.d.ts +8 -0
- package/dist/elements/dialog/dialog.styles.d.ts.map +1 -0
- package/dist/elements/dialog/dialog.styles.js +8 -0
- package/dist/elements/dialog/index.d.ts +8 -0
- package/dist/elements/dialog/index.d.ts.map +1 -0
- package/dist/elements/dialog/index.js +4 -0
- package/dist/elements/divider/divider.d.ts +23 -0
- package/dist/elements/divider/divider.d.ts.map +1 -0
- package/dist/elements/divider/divider.js +49 -0
- package/dist/elements/divider/index.d.ts +8 -0
- package/dist/elements/divider/index.d.ts.map +1 -0
- package/dist/elements/divider/index.js +4 -0
- package/dist/elements/drawer/drawer.css +66 -0
- package/dist/elements/drawer/drawer.d.ts +34 -0
- package/dist/elements/drawer/drawer.d.ts.map +1 -0
- package/dist/elements/drawer/drawer.js +46 -0
- package/dist/elements/drawer/index.d.ts +8 -0
- package/dist/elements/drawer/index.d.ts.map +1 -0
- package/dist/elements/drawer/index.js +4 -0
- package/dist/elements/dropdown/dropdown.css +31 -0
- package/dist/elements/dropdown/dropdown.d.ts +64 -0
- package/dist/elements/dropdown/dropdown.d.ts.map +1 -0
- package/dist/elements/dropdown/dropdown.js +322 -0
- package/dist/elements/dropdown/index.d.ts +8 -0
- package/dist/elements/dropdown/index.d.ts.map +1 -0
- package/dist/elements/dropdown/index.js +4 -0
- package/dist/elements/dropdown-item/dropdown-item.css +51 -0
- package/dist/elements/dropdown-item/dropdown-item.d.ts +25 -0
- package/dist/elements/dropdown-item/dropdown-item.d.ts.map +1 -0
- package/dist/elements/dropdown-item/dropdown-item.js +110 -0
- package/dist/elements/dropdown-item/index.d.ts +8 -0
- package/dist/elements/dropdown-item/index.d.ts.map +1 -0
- package/dist/elements/dropdown-item/index.js +4 -0
- package/dist/elements/icon/icon.css +10 -0
- package/dist/elements/icon/icon.d.ts +19 -0
- package/dist/elements/icon/icon.d.ts.map +1 -0
- package/dist/elements/icon/icon.js +53 -0
- package/dist/elements/icon/index.d.ts +8 -0
- package/dist/elements/icon/index.d.ts.map +1 -0
- package/dist/elements/icon/index.js +4 -0
- package/dist/elements/input-otp/index.d.ts +8 -0
- package/dist/elements/input-otp/index.d.ts.map +1 -0
- package/dist/elements/input-otp/index.js +4 -0
- package/dist/elements/input-otp/input-otp.d.ts +31 -0
- package/dist/elements/input-otp/input-otp.d.ts.map +1 -0
- package/dist/elements/input-otp/input-otp.js +139 -0
- package/dist/elements/input-stepper/index.d.ts +8 -0
- package/dist/elements/input-stepper/index.d.ts.map +1 -0
- package/dist/elements/input-stepper/index.js +4 -0
- package/dist/elements/input-stepper/input-stepper.d.ts +63 -0
- package/dist/elements/input-stepper/input-stepper.d.ts.map +1 -0
- package/dist/elements/input-stepper/input-stepper.js +249 -0
- package/dist/elements/popover/index.d.ts +8 -0
- package/dist/elements/popover/index.d.ts.map +1 -0
- package/dist/elements/popover/index.js +4 -0
- package/dist/elements/popover/popover.css +61 -0
- package/dist/elements/popover/popover.d.ts +62 -0
- package/dist/elements/popover/popover.d.ts.map +1 -0
- package/dist/elements/popover/popover.js +244 -0
- package/dist/elements/rating/index.d.ts +8 -0
- package/dist/elements/rating/index.d.ts.map +1 -0
- package/dist/elements/rating/index.js +4 -0
- package/dist/elements/rating/rating.css +102 -0
- package/dist/elements/rating/rating.d.ts +38 -0
- package/dist/elements/rating/rating.d.ts.map +1 -0
- package/dist/elements/rating/rating.js +193 -0
- package/dist/elements/skeleton/index.d.ts +8 -0
- package/dist/elements/skeleton/index.d.ts.map +1 -0
- package/dist/elements/skeleton/index.js +4 -0
- package/dist/elements/skeleton/skeleton.d.ts +12 -0
- package/dist/elements/skeleton/skeleton.d.ts.map +1 -0
- package/dist/elements/skeleton/skeleton.js +13 -0
- package/dist/elements/spinner/index.d.ts +8 -0
- package/dist/elements/spinner/index.d.ts.map +1 -0
- package/dist/elements/spinner/index.js +4 -0
- package/dist/elements/spinner/spinner.css +28 -0
- package/dist/elements/spinner/spinner.d.ts +16 -0
- package/dist/elements/spinner/spinner.d.ts.map +1 -0
- package/dist/elements/spinner/spinner.js +37 -0
- package/dist/elements/tabs/index.d.ts +8 -0
- package/dist/elements/tabs/index.d.ts.map +1 -0
- package/dist/elements/tabs/index.js +4 -0
- package/dist/elements/tabs/tabs.d.ts +48 -0
- package/dist/elements/tabs/tabs.d.ts.map +1 -0
- package/dist/elements/tabs/tabs.js +210 -0
- package/dist/elements/toast/index.d.ts +9 -0
- package/dist/elements/toast/index.d.ts.map +1 -0
- package/dist/elements/toast/index.js +5 -0
- package/dist/elements/toast/toast.d.ts +72 -0
- package/dist/elements/toast/toast.d.ts.map +1 -0
- package/dist/elements/toast/toast.js +375 -0
- package/dist/elements/tooltip/index.d.ts +8 -0
- package/dist/elements/tooltip/index.d.ts.map +1 -0
- package/dist/elements/tooltip/index.js +4 -0
- package/dist/elements/tooltip/tooltip.css +37 -0
- package/dist/elements/tooltip/tooltip.d.ts +59 -0
- package/dist/elements/tooltip/tooltip.d.ts.map +1 -0
- package/dist/elements/tooltip/tooltip.js +231 -0
- package/dist/elements/tree/index.d.ts +8 -0
- package/dist/elements/tree/index.d.ts.map +1 -0
- package/dist/elements/tree/index.js +4 -0
- package/dist/elements/tree/tree.css +26 -0
- package/dist/elements/tree/tree.d.ts +76 -0
- package/dist/elements/tree/tree.d.ts.map +1 -0
- package/dist/elements/tree/tree.js +432 -0
- package/dist/elements/tree-item/index.d.ts +8 -0
- package/dist/elements/tree-item/index.d.ts.map +1 -0
- package/dist/elements/tree-item/index.js +4 -0
- package/dist/elements/tree-item/tree-item.css +172 -0
- package/dist/elements/tree-item/tree-item.d.ts +74 -0
- package/dist/elements/tree-item/tree-item.d.ts.map +1 -0
- package/dist/elements/tree-item/tree-item.js +301 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/registry.d.ts +22 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +33 -0
- package/dist/shared/controllers/popover.d.ts +44 -0
- package/dist/shared/controllers/popover.d.ts.map +1 -0
- package/dist/shared/controllers/popover.js +359 -0
- package/dist/shared/luxen-element.d.ts +20 -0
- package/dist/shared/luxen-element.d.ts.map +1 -0
- package/dist/shared/luxen-element.js +23 -0
- package/dist/shared/luxen-form-associated-element.d.ts +49 -0
- package/dist/shared/luxen-form-associated-element.d.ts.map +1 -0
- package/dist/shared/luxen-form-associated-element.js +123 -0
- package/dist/shared/styles/host.css +13 -0
- package/dist/shared/styles/host.styles.d.ts +9 -0
- package/dist/shared/styles/host.styles.d.ts.map +1 -0
- package/dist/shared/styles/host.styles.js +9 -0
- package/dist/skills/luxen-ui/SKILL.md +82 -0
- package/dist/skills/luxen-ui/references/avatar.md +259 -0
- package/dist/skills/luxen-ui/references/badge.md +289 -0
- package/dist/skills/luxen-ui/references/button.md +309 -0
- package/dist/skills/luxen-ui/references/close-button.md +104 -0
- package/dist/skills/luxen-ui/references/dialog.md +435 -0
- package/dist/skills/luxen-ui/references/drawer.md +400 -0
- package/dist/skills/luxen-ui/references/progress.md +133 -0
- package/dist/skills/luxen-ui/references/select.md +100 -0
- package/dist/skills/luxen-ui/references/toast.md +396 -0
- package/dist/skills/luxen-ui/references/tree.md +359 -0
- package/package.json +116 -0
- package/postcss-plugin-prefix.js +63 -0
- package/vite-plugin.ts +29 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { unsafeCSS } from 'lit';
|
|
8
|
+
import { property } from 'lit/decorators.js';
|
|
9
|
+
import hostStyles from '../../shared/styles/host.styles';
|
|
10
|
+
import { LuxenDialog } from '../dialog/dialog';
|
|
11
|
+
import dialogStyles from '../dialog/dialog.styles';
|
|
12
|
+
import rawDrawerStyles from './drawer.css?inline';
|
|
13
|
+
const drawerStyles = unsafeCSS(rawDrawerStyles);
|
|
14
|
+
/**
|
|
15
|
+
* A drawer that slides in from a screen edge. Extends `<l-dialog>`.
|
|
16
|
+
*
|
|
17
|
+
* Open and close by toggling the `open` property (or the `--show` / `--hide`
|
|
18
|
+
* Invoker commands). Always opens as modal.
|
|
19
|
+
*
|
|
20
|
+
* @slot - Body content.
|
|
21
|
+
* @slot close - Close button (typically `<button class="l-close">`).
|
|
22
|
+
* @slot footer - Footer actions.
|
|
23
|
+
*
|
|
24
|
+
* @csspart dialog - The native `<dialog>` element.
|
|
25
|
+
* @csspart header - The header wrapper containing the title and close slot.
|
|
26
|
+
* @csspart title - The drawer title heading.
|
|
27
|
+
* @csspart body - The body wrapper around the default slot.
|
|
28
|
+
* @csspart footer - The footer wrapper around the footer slot.
|
|
29
|
+
*
|
|
30
|
+
* @cssproperty --size - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `bottom`). Default `320px`.
|
|
31
|
+
* @cssproperty --border-radius - Drawer border radius on the inner edges. Default `0.75rem`.
|
|
32
|
+
* @cssproperty --show-duration - Open transition duration. Default `200ms`.
|
|
33
|
+
* @cssproperty --hide-duration - Close transition duration. Default `200ms`.
|
|
34
|
+
* @cssproperty --backdrop - Backdrop color.
|
|
35
|
+
*
|
|
36
|
+
* @event show - Fired when the drawer opens. Not cancelable.
|
|
37
|
+
* @event after-show - Fired after the open animation completes.
|
|
38
|
+
* @event hide - Fired when the drawer is about to close. Cancelable — call `event.preventDefault()` to keep it open.
|
|
39
|
+
* @event after-hide - Fired after the close animation completes.
|
|
40
|
+
*/
|
|
41
|
+
export class LuxenDrawer extends LuxenDialog {
|
|
42
|
+
}
|
|
43
|
+
LuxenDrawer.styles = [hostStyles, dialogStyles, drawerStyles];
|
|
44
|
+
__decorate([
|
|
45
|
+
property({ reflect: true })
|
|
46
|
+
], LuxenDrawer.prototype, "placement", void 0);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/drawer/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,cAAc,UAAU,CAAC;AAGzB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,WAAW,CAAC;KACzB;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
--background: var(--l-color-bg-surface, Canvas);
|
|
3
|
+
--radius: 8px;
|
|
4
|
+
--shadow: 0 4px 16px rgb(0 0 0 / 12%);
|
|
5
|
+
--show-duration: 150;
|
|
6
|
+
--hide-duration: 150;
|
|
7
|
+
|
|
8
|
+
display: inline-block;
|
|
9
|
+
position: relative;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.trigger {
|
|
13
|
+
display: contents;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[popover] {
|
|
17
|
+
inset: unset;
|
|
18
|
+
overflow: visible;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
width: max-content;
|
|
21
|
+
min-width: anchor-size(width);
|
|
22
|
+
padding: 4px 0;
|
|
23
|
+
margin: 0;
|
|
24
|
+
border: 1px solid var(--l-color-border, light-dark(#e5e7eb, #374151));
|
|
25
|
+
border-radius: var(--radius);
|
|
26
|
+
background: var(--background);
|
|
27
|
+
color: var(--l-color-text-primary, CanvasText);
|
|
28
|
+
box-shadow: var(--shadow);
|
|
29
|
+
font-size: 0.875rem;
|
|
30
|
+
line-height: 1.5;
|
|
31
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type PropertyValues } from 'lit';
|
|
2
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
3
|
+
import type { Placement } from '@floating-ui/dom';
|
|
4
|
+
/**
|
|
5
|
+
* A dropdown menu anchored to a trigger element.
|
|
6
|
+
*
|
|
7
|
+
* @slot trigger - The element that triggers the dropdown.
|
|
8
|
+
* @slot - Menu content (`l-dropdown-item` elements).
|
|
9
|
+
*
|
|
10
|
+
* @csspart panel - The floating menu container.
|
|
11
|
+
*
|
|
12
|
+
* @cssproperty --background - Panel background color.
|
|
13
|
+
* @cssproperty --radius - Panel border radius. Default `8px`.
|
|
14
|
+
* @cssproperty --shadow - Panel box shadow.
|
|
15
|
+
* @cssproperty --show-duration - Show animation duration in ms. Default `150`.
|
|
16
|
+
* @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.
|
|
17
|
+
*
|
|
18
|
+
* @event show - Fired before the dropdown opens. Cancelable.
|
|
19
|
+
* @event after-show - Fired after the open animation completes.
|
|
20
|
+
* @event hide - Fired before the dropdown closes. Cancelable.
|
|
21
|
+
* @event after-hide - Fired after the close animation completes.
|
|
22
|
+
* @event select - Fired when an item is selected. Detail: `{ item: LuxenDropdownItem }`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class LuxenDropdown extends LuxenElement {
|
|
25
|
+
static styles: import("lit").CSSResult[];
|
|
26
|
+
private _floating;
|
|
27
|
+
private _typeaheadBuffer;
|
|
28
|
+
private _typeaheadTimeout;
|
|
29
|
+
/** Whether the dropdown is open. */
|
|
30
|
+
accessor open: boolean;
|
|
31
|
+
/** Preferred placement of the panel. */
|
|
32
|
+
accessor placement: Placement;
|
|
33
|
+
/** Distance in pixels from the trigger. */
|
|
34
|
+
accessor distance: number;
|
|
35
|
+
/** Disables the dropdown trigger. */
|
|
36
|
+
accessor disabled: boolean;
|
|
37
|
+
private get _triggerEl();
|
|
38
|
+
private get _panelEl();
|
|
39
|
+
private _getItems;
|
|
40
|
+
private _getAllItems;
|
|
41
|
+
private _getDuration;
|
|
42
|
+
show(): void;
|
|
43
|
+
hide(): void;
|
|
44
|
+
toggle(): void;
|
|
45
|
+
updated(changed: PropertyValues<this>): void;
|
|
46
|
+
private _handleOpenChange;
|
|
47
|
+
private _setActiveItem;
|
|
48
|
+
private _focusFirstItem;
|
|
49
|
+
private _focusLastItem;
|
|
50
|
+
private _getCurrentItem;
|
|
51
|
+
private _focusNextItem;
|
|
52
|
+
private _focusPreviousItem;
|
|
53
|
+
private _handleTypeahead;
|
|
54
|
+
private _onTriggerClick;
|
|
55
|
+
private _onTriggerKeyDown;
|
|
56
|
+
private _onPanelKeyDown;
|
|
57
|
+
private _onItemClick;
|
|
58
|
+
private _selectCurrentItem;
|
|
59
|
+
private _selectItem;
|
|
60
|
+
/** Sync `open` when popover="auto" light-dismiss fires. */
|
|
61
|
+
private _onToggle;
|
|
62
|
+
render(): import("lit").TemplateResult<1>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=dropdown.d.ts.map
|
|
@@ -0,0 +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,4BAA4B,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AASlD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,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,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;IAyB/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,CAErB;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;CAqBhB"}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
13
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
14
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
15
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
16
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
17
|
+
};
|
|
18
|
+
var _LuxenDropdown_open_accessor_storage, _LuxenDropdown_placement_accessor_storage, _LuxenDropdown_distance_accessor_storage, _LuxenDropdown_disabled_accessor_storage;
|
|
19
|
+
import { html, unsafeCSS } from 'lit';
|
|
20
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
21
|
+
import { property } from 'lit/decorators.js';
|
|
22
|
+
import { PopoverController } from '../../shared/controllers/popover';
|
|
23
|
+
import { tagName } from '../../registry';
|
|
24
|
+
import hostStyles from '../../shared/styles/host.styles';
|
|
25
|
+
import rawStyles from './dropdown.css?inline';
|
|
26
|
+
const styles = unsafeCSS(rawStyles);
|
|
27
|
+
/**
|
|
28
|
+
* A dropdown menu anchored to a trigger element.
|
|
29
|
+
*
|
|
30
|
+
* @slot trigger - The element that triggers the dropdown.
|
|
31
|
+
* @slot - Menu content (`l-dropdown-item` elements).
|
|
32
|
+
*
|
|
33
|
+
* @csspart panel - The floating menu container.
|
|
34
|
+
*
|
|
35
|
+
* @cssproperty --background - Panel background color.
|
|
36
|
+
* @cssproperty --radius - Panel border radius. Default `8px`.
|
|
37
|
+
* @cssproperty --shadow - Panel box shadow.
|
|
38
|
+
* @cssproperty --show-duration - Show animation duration in ms. Default `150`.
|
|
39
|
+
* @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.
|
|
40
|
+
*
|
|
41
|
+
* @event show - Fired before the dropdown opens. Cancelable.
|
|
42
|
+
* @event after-show - Fired after the open animation completes.
|
|
43
|
+
* @event hide - Fired before the dropdown closes. Cancelable.
|
|
44
|
+
* @event after-hide - Fired after the close animation completes.
|
|
45
|
+
* @event select - Fired when an item is selected. Detail: `{ item: LuxenDropdownItem }`.
|
|
46
|
+
*/
|
|
47
|
+
export class LuxenDropdown extends LuxenElement {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(...arguments);
|
|
50
|
+
this._floating = new PopoverController(this, {
|
|
51
|
+
getTriggerElement: () => this._triggerEl,
|
|
52
|
+
getFloatingElement: () => this._panelEl,
|
|
53
|
+
getArrowElement: () => null,
|
|
54
|
+
});
|
|
55
|
+
this._typeaheadBuffer = '';
|
|
56
|
+
this._typeaheadTimeout = 0;
|
|
57
|
+
_LuxenDropdown_open_accessor_storage.set(this, false);
|
|
58
|
+
_LuxenDropdown_placement_accessor_storage.set(this, 'bottom-start');
|
|
59
|
+
_LuxenDropdown_distance_accessor_storage.set(this, 4);
|
|
60
|
+
_LuxenDropdown_disabled_accessor_storage.set(this, false);
|
|
61
|
+
// --- Event handlers ---
|
|
62
|
+
this._onTriggerClick = () => {
|
|
63
|
+
if (!this.disabled)
|
|
64
|
+
this.toggle();
|
|
65
|
+
};
|
|
66
|
+
this._onTriggerKeyDown = (e) => {
|
|
67
|
+
if (this.disabled)
|
|
68
|
+
return;
|
|
69
|
+
if (e.key === 'ArrowDown') {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
this.show();
|
|
72
|
+
requestAnimationFrame(() => this._focusFirstItem());
|
|
73
|
+
}
|
|
74
|
+
else if (e.key === 'ArrowUp') {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
this.show();
|
|
77
|
+
requestAnimationFrame(() => this._focusLastItem());
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
this._onPanelKeyDown = (e) => {
|
|
81
|
+
switch (e.key) {
|
|
82
|
+
case 'ArrowDown':
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
this._focusNextItem();
|
|
85
|
+
break;
|
|
86
|
+
case 'ArrowUp':
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
this._focusPreviousItem();
|
|
89
|
+
break;
|
|
90
|
+
case 'Home':
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
this._focusFirstItem();
|
|
93
|
+
break;
|
|
94
|
+
case 'End':
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
this._focusLastItem();
|
|
97
|
+
break;
|
|
98
|
+
case 'Escape':
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
this.hide();
|
|
101
|
+
this._triggerEl?.focus();
|
|
102
|
+
break;
|
|
103
|
+
case 'Enter':
|
|
104
|
+
case ' ':
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
this._selectCurrentItem();
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
|
|
110
|
+
this._handleTypeahead(e.key);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
this._onItemClick = (e) => {
|
|
115
|
+
const item = e.target.closest(tagName('dropdown-item'));
|
|
116
|
+
if (item && !item.disabled) {
|
|
117
|
+
this._selectItem(item);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
/** Sync `open` when popover="auto" light-dismiss fires. */
|
|
121
|
+
this._onToggle = (e) => {
|
|
122
|
+
const toggleEvent = e;
|
|
123
|
+
if (toggleEvent.newState === 'closed' && this.open) {
|
|
124
|
+
this.open = false;
|
|
125
|
+
this._triggerEl?.setAttribute('aria-expanded', 'false');
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Whether the dropdown is open. */
|
|
130
|
+
get open() { return __classPrivateFieldGet(this, _LuxenDropdown_open_accessor_storage, "f"); }
|
|
131
|
+
set open(value) { __classPrivateFieldSet(this, _LuxenDropdown_open_accessor_storage, value, "f"); }
|
|
132
|
+
/** Preferred placement of the panel. */
|
|
133
|
+
get placement() { return __classPrivateFieldGet(this, _LuxenDropdown_placement_accessor_storage, "f"); }
|
|
134
|
+
set placement(value) { __classPrivateFieldSet(this, _LuxenDropdown_placement_accessor_storage, value, "f"); }
|
|
135
|
+
/** Distance in pixels from the trigger. */
|
|
136
|
+
get distance() { return __classPrivateFieldGet(this, _LuxenDropdown_distance_accessor_storage, "f"); }
|
|
137
|
+
set distance(value) { __classPrivateFieldSet(this, _LuxenDropdown_distance_accessor_storage, value, "f"); }
|
|
138
|
+
/** Disables the dropdown trigger. */
|
|
139
|
+
get disabled() { return __classPrivateFieldGet(this, _LuxenDropdown_disabled_accessor_storage, "f"); }
|
|
140
|
+
set disabled(value) { __classPrivateFieldSet(this, _LuxenDropdown_disabled_accessor_storage, value, "f"); }
|
|
141
|
+
get _triggerEl() {
|
|
142
|
+
const slot = this.shadowRoot.querySelector('.trigger slot');
|
|
143
|
+
return slot?.assignedElements()[0] ?? null;
|
|
144
|
+
}
|
|
145
|
+
get _panelEl() {
|
|
146
|
+
return this.shadowRoot.querySelector('[popover]');
|
|
147
|
+
}
|
|
148
|
+
_getItems() {
|
|
149
|
+
const menuSlot = this.shadowRoot.querySelector('slot:not([name])');
|
|
150
|
+
if (!menuSlot)
|
|
151
|
+
return [];
|
|
152
|
+
return menuSlot.assignedElements().filter((el) => el.tagName === tagName('dropdown-item').toUpperCase() && !el.disabled);
|
|
153
|
+
}
|
|
154
|
+
_getAllItems() {
|
|
155
|
+
const menuSlot = this.shadowRoot.querySelector('slot:not([name])');
|
|
156
|
+
if (!menuSlot)
|
|
157
|
+
return [];
|
|
158
|
+
return menuSlot.assignedElements().filter((el) => el.tagName === tagName('dropdown-item').toUpperCase());
|
|
159
|
+
}
|
|
160
|
+
_getDuration(prop) {
|
|
161
|
+
const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));
|
|
162
|
+
return Number.isNaN(parsed) ? 150 : parsed;
|
|
163
|
+
}
|
|
164
|
+
// --- Public API ---
|
|
165
|
+
show() {
|
|
166
|
+
if (this.open || this.disabled)
|
|
167
|
+
return;
|
|
168
|
+
if (this.emit('show', { cancelable: true }))
|
|
169
|
+
this.open = true;
|
|
170
|
+
}
|
|
171
|
+
hide() {
|
|
172
|
+
if (!this.open)
|
|
173
|
+
return;
|
|
174
|
+
if (this.emit('hide', { cancelable: true }))
|
|
175
|
+
this.open = false;
|
|
176
|
+
}
|
|
177
|
+
toggle() {
|
|
178
|
+
if (this.open)
|
|
179
|
+
this.hide();
|
|
180
|
+
else
|
|
181
|
+
this.show();
|
|
182
|
+
}
|
|
183
|
+
// --- Lifecycle ---
|
|
184
|
+
updated(changed) {
|
|
185
|
+
if (changed.has('open')) {
|
|
186
|
+
this._handleOpenChange();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// --- Open/Close ---
|
|
190
|
+
async _handleOpenChange() {
|
|
191
|
+
const panel = this._panelEl;
|
|
192
|
+
if (!panel)
|
|
193
|
+
return;
|
|
194
|
+
const posOpts = { placement: this.placement, distance: this.distance };
|
|
195
|
+
if (this.open) {
|
|
196
|
+
panel.showPopover();
|
|
197
|
+
await this._floating.updatePosition(posOpts);
|
|
198
|
+
if (!this.open)
|
|
199
|
+
return;
|
|
200
|
+
await this._floating.animateShow(panel, this._getDuration('--show-duration'));
|
|
201
|
+
this._floating.startPositioning(posOpts);
|
|
202
|
+
this._triggerEl?.setAttribute('aria-expanded', 'true');
|
|
203
|
+
this.emit('after-show');
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this._floating.stopPositioning();
|
|
207
|
+
this._triggerEl?.setAttribute('aria-expanded', 'false');
|
|
208
|
+
await this._floating.animateHide(panel, this._getDuration('--hide-duration'));
|
|
209
|
+
if (panel.matches(':popover-open'))
|
|
210
|
+
panel.hidePopover();
|
|
211
|
+
this.emit('after-hide');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// --- Focus management ---
|
|
215
|
+
_setActiveItem(item) {
|
|
216
|
+
const itemEl = item.shadowRoot.querySelector('.item');
|
|
217
|
+
if (!itemEl)
|
|
218
|
+
return;
|
|
219
|
+
// Reset all items
|
|
220
|
+
for (const i of this._getAllItems()) {
|
|
221
|
+
const el = i.shadowRoot.querySelector('.item');
|
|
222
|
+
el?.setAttribute('tabindex', '-1');
|
|
223
|
+
}
|
|
224
|
+
itemEl.setAttribute('tabindex', '0');
|
|
225
|
+
itemEl.focus();
|
|
226
|
+
}
|
|
227
|
+
_focusFirstItem() {
|
|
228
|
+
const items = this._getItems();
|
|
229
|
+
if (items.length)
|
|
230
|
+
this._setActiveItem(items[0]);
|
|
231
|
+
}
|
|
232
|
+
_focusLastItem() {
|
|
233
|
+
const items = this._getItems();
|
|
234
|
+
if (items.length)
|
|
235
|
+
this._setActiveItem(items[items.length - 1]);
|
|
236
|
+
}
|
|
237
|
+
_getCurrentItem() {
|
|
238
|
+
const items = this._getItems();
|
|
239
|
+
return (items.find((item) => {
|
|
240
|
+
const el = item.shadowRoot.querySelector('.item');
|
|
241
|
+
return el?.getAttribute('tabindex') === '0' && item.shadowRoot.activeElement === el;
|
|
242
|
+
}) ?? null);
|
|
243
|
+
}
|
|
244
|
+
_focusNextItem() {
|
|
245
|
+
const items = this._getItems();
|
|
246
|
+
const current = this._getCurrentItem();
|
|
247
|
+
const index = current ? items.indexOf(current) : -1;
|
|
248
|
+
const next = items[(index + 1) % items.length];
|
|
249
|
+
if (next)
|
|
250
|
+
this._setActiveItem(next);
|
|
251
|
+
}
|
|
252
|
+
_focusPreviousItem() {
|
|
253
|
+
const items = this._getItems();
|
|
254
|
+
const current = this._getCurrentItem();
|
|
255
|
+
const index = current ? items.indexOf(current) : 0;
|
|
256
|
+
const prev = items[(index - 1 + items.length) % items.length];
|
|
257
|
+
if (prev)
|
|
258
|
+
this._setActiveItem(prev);
|
|
259
|
+
}
|
|
260
|
+
// --- Typeahead ---
|
|
261
|
+
_handleTypeahead(key) {
|
|
262
|
+
clearTimeout(this._typeaheadTimeout);
|
|
263
|
+
this._typeaheadBuffer += key.toLowerCase();
|
|
264
|
+
this._typeaheadTimeout = window.setTimeout(() => {
|
|
265
|
+
this._typeaheadBuffer = '';
|
|
266
|
+
}, 500);
|
|
267
|
+
const items = this._getItems();
|
|
268
|
+
const match = items.find((item) => item.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer));
|
|
269
|
+
if (match)
|
|
270
|
+
this._setActiveItem(match);
|
|
271
|
+
}
|
|
272
|
+
_selectCurrentItem() {
|
|
273
|
+
const current = this._getCurrentItem();
|
|
274
|
+
if (current)
|
|
275
|
+
this._selectItem(current);
|
|
276
|
+
}
|
|
277
|
+
_selectItem(item) {
|
|
278
|
+
if (item.type === 'checkbox') {
|
|
279
|
+
item.checked = !item.checked;
|
|
280
|
+
}
|
|
281
|
+
this.emit('select', { detail: { item } });
|
|
282
|
+
if (item.type !== 'checkbox') {
|
|
283
|
+
this.hide();
|
|
284
|
+
this._triggerEl?.focus();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
render() {
|
|
288
|
+
return html `
|
|
289
|
+
<div
|
|
290
|
+
class="trigger"
|
|
291
|
+
@click=${this._onTriggerClick}
|
|
292
|
+
@keydown=${this._onTriggerKeyDown}
|
|
293
|
+
>
|
|
294
|
+
<slot name="trigger"></slot>
|
|
295
|
+
</div>
|
|
296
|
+
<div
|
|
297
|
+
popover="auto"
|
|
298
|
+
part="panel"
|
|
299
|
+
role="menu"
|
|
300
|
+
@keydown=${this._onPanelKeyDown}
|
|
301
|
+
@click=${this._onItemClick}
|
|
302
|
+
@toggle=${this._onToggle}
|
|
303
|
+
>
|
|
304
|
+
<slot></slot>
|
|
305
|
+
</div>
|
|
306
|
+
`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
_LuxenDropdown_open_accessor_storage = new WeakMap(), _LuxenDropdown_placement_accessor_storage = new WeakMap(), _LuxenDropdown_distance_accessor_storage = new WeakMap(), _LuxenDropdown_disabled_accessor_storage = new WeakMap();
|
|
310
|
+
LuxenDropdown.styles = [hostStyles, styles];
|
|
311
|
+
__decorate([
|
|
312
|
+
property({ type: Boolean, reflect: true })
|
|
313
|
+
], LuxenDropdown.prototype, "open", null);
|
|
314
|
+
__decorate([
|
|
315
|
+
property()
|
|
316
|
+
], LuxenDropdown.prototype, "placement", null);
|
|
317
|
+
__decorate([
|
|
318
|
+
property({ type: Number })
|
|
319
|
+
], LuxenDropdown.prototype, "distance", null);
|
|
320
|
+
__decorate([
|
|
321
|
+
property({ type: Boolean, reflect: true })
|
|
322
|
+
], LuxenDropdown.prototype, "disabled", null);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC;AAG3B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,aAAa,CAAC;KAC7B;CACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:host([disabled]) {
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
opacity: 0.5;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.item {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: 8px;
|
|
14
|
+
padding: 6px 16px;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
outline: none;
|
|
17
|
+
font-size: 0.875rem;
|
|
18
|
+
line-height: 1.5;
|
|
19
|
+
color: var(--l-color-text-primary, CanvasText);
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.item:focus-visible {
|
|
24
|
+
background: var(--l-color-bg-state-hover);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@media (hover: hover) {
|
|
28
|
+
.item:hover {
|
|
29
|
+
background: var(--l-color-bg-state-hover);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.check {
|
|
34
|
+
display: flex;
|
|
35
|
+
width: 16px;
|
|
36
|
+
flex-shrink: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:host(:not([checked])) .check svg {
|
|
40
|
+
visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
::slotted([slot='prefix']),
|
|
44
|
+
::slotted([slot='suffix']) {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.label {
|
|
50
|
+
flex: 1;
|
|
51
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
2
|
+
/**
|
|
3
|
+
* A menu item for use inside `<l-dropdown>`.
|
|
4
|
+
*
|
|
5
|
+
* @slot - Label text.
|
|
6
|
+
* @slot prefix - Leading content (e.g. icon).
|
|
7
|
+
* @slot suffix - Trailing content.
|
|
8
|
+
*
|
|
9
|
+
* @cssproperty --color - Text color.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LuxenDropdownItem extends LuxenElement {
|
|
12
|
+
static styles: import("lit").CSSResult[];
|
|
13
|
+
/** The value associated with this item. */
|
|
14
|
+
accessor value: string;
|
|
15
|
+
/** Disables the item. */
|
|
16
|
+
accessor disabled: boolean;
|
|
17
|
+
/** The type of item: `normal` or `checkbox`. */
|
|
18
|
+
accessor type: 'normal' | 'checkbox';
|
|
19
|
+
/** Whether the checkbox item is checked. */
|
|
20
|
+
accessor checked: boolean;
|
|
21
|
+
/** Returns the text label of this item. */
|
|
22
|
+
getTextLabel(): string;
|
|
23
|
+
render(): import("lit").TemplateResult<1>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=dropdown-item.d.ts.map
|
|
@@ -0,0 +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,4BAA4B,CAAC;AAO1D;;;;;;;;GAQG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,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"}
|