luxen-ui 0.1.1 → 0.2.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/cdn/chunks/decorate.js +2 -0
- package/cdn/chunks/decorate.js.map +1 -0
- package/cdn/chunks/lit.js +3 -0
- package/cdn/chunks/lit.js.map +1 -0
- package/cdn/custom-elements.json +14499 -0
- package/cdn/define.d.ts +9 -0
- package/cdn/define.d.ts.map +1 -0
- package/cdn/define.js +2 -0
- package/cdn/define.js.map +1 -0
- package/cdn/elements/avatar/avatar.d.ts +21 -0
- package/cdn/elements/avatar/avatar.d.ts.map +1 -0
- package/cdn/elements/avatar/avatar.js +18 -0
- package/cdn/elements/avatar/avatar.js.map +1 -0
- package/cdn/elements/avatar/index.d.ts +8 -0
- package/cdn/elements/avatar/index.d.ts.map +1 -0
- package/cdn/elements/avatar/index.js +2 -0
- package/cdn/elements/avatar/index.js.map +1 -0
- package/cdn/elements/badge/badge.d.ts +17 -0
- package/cdn/elements/badge/badge.d.ts.map +1 -0
- package/cdn/elements/badge/badge.js +2 -0
- package/cdn/elements/badge/badge.js.map +1 -0
- package/cdn/elements/badge/index.d.ts +8 -0
- package/cdn/elements/badge/index.d.ts.map +1 -0
- package/cdn/elements/badge/index.js +2 -0
- package/cdn/elements/badge/index.js.map +1 -0
- package/cdn/elements/carousel/carousel.d.ts +148 -0
- package/cdn/elements/carousel/carousel.d.ts.map +1 -0
- package/cdn/elements/carousel/carousel.js +87 -0
- package/cdn/elements/carousel/carousel.js.map +1 -0
- package/cdn/elements/carousel/index.d.ts +8 -0
- package/cdn/elements/carousel/index.d.ts.map +1 -0
- package/cdn/elements/carousel/index.js +2 -0
- package/cdn/elements/carousel/index.js.map +1 -0
- package/cdn/elements/carousel-item/carousel-item.d.ts +13 -0
- package/cdn/elements/carousel-item/carousel-item.d.ts.map +1 -0
- package/cdn/elements/carousel-item/carousel-item.js +2 -0
- package/cdn/elements/carousel-item/carousel-item.js.map +1 -0
- package/cdn/elements/carousel-item/index.d.ts +8 -0
- package/cdn/elements/carousel-item/index.d.ts.map +1 -0
- package/cdn/elements/carousel-item/index.js +2 -0
- package/cdn/elements/carousel-item/index.js.map +1 -0
- package/cdn/elements/dialog/dialog.d.ts +57 -0
- package/cdn/elements/dialog/dialog.d.ts.map +1 -0
- package/cdn/elements/dialog/dialog.js +18 -0
- package/cdn/elements/dialog/dialog.js.map +1 -0
- package/cdn/elements/dialog/dialog.styles.d.ts +8 -0
- package/cdn/elements/dialog/dialog.styles.d.ts.map +1 -0
- package/cdn/elements/dialog/dialog.styles.js +2 -0
- package/cdn/elements/dialog/dialog.styles.js.map +1 -0
- package/cdn/elements/dialog/index.d.ts +8 -0
- package/cdn/elements/dialog/index.d.ts.map +1 -0
- package/cdn/elements/dialog/index.js +2 -0
- package/cdn/elements/dialog/index.js.map +1 -0
- package/cdn/elements/divider/divider.d.ts +23 -0
- package/cdn/elements/divider/divider.d.ts.map +1 -0
- package/cdn/elements/divider/divider.js +2 -0
- package/cdn/elements/divider/divider.js.map +1 -0
- package/cdn/elements/divider/index.d.ts +8 -0
- package/cdn/elements/divider/index.d.ts.map +1 -0
- package/cdn/elements/divider/index.js +2 -0
- package/cdn/elements/divider/index.js.map +1 -0
- package/cdn/elements/drawer/drawer.d.ts +34 -0
- package/cdn/elements/drawer/drawer.d.ts.map +1 -0
- package/cdn/elements/drawer/drawer.js +2 -0
- package/cdn/elements/drawer/drawer.js.map +1 -0
- package/cdn/elements/drawer/index.d.ts +8 -0
- package/cdn/elements/drawer/index.d.ts.map +1 -0
- package/cdn/elements/drawer/index.js +2 -0
- package/cdn/elements/drawer/index.js.map +1 -0
- package/cdn/elements/dropdown/dropdown.d.ts +64 -0
- package/cdn/elements/dropdown/dropdown.d.ts.map +1 -0
- package/cdn/elements/dropdown/dropdown.js +20 -0
- package/cdn/elements/dropdown/dropdown.js.map +1 -0
- package/cdn/elements/dropdown/index.d.ts +8 -0
- package/cdn/elements/dropdown/index.d.ts.map +1 -0
- package/cdn/elements/dropdown/index.js +2 -0
- package/cdn/elements/dropdown/index.js.map +1 -0
- package/cdn/elements/dropdown-item/dropdown-item.d.ts +25 -0
- package/cdn/elements/dropdown-item/dropdown-item.d.ts.map +1 -0
- package/cdn/elements/dropdown-item/dropdown-item.js +34 -0
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -0
- package/cdn/elements/dropdown-item/index.d.ts +8 -0
- package/cdn/elements/dropdown-item/index.d.ts.map +1 -0
- package/cdn/elements/dropdown-item/index.js +2 -0
- package/cdn/elements/dropdown-item/index.js.map +1 -0
- package/cdn/elements/icon/icon.d.ts +18 -0
- package/cdn/elements/icon/icon.d.ts.map +1 -0
- package/cdn/elements/icon/icon.js +7 -0
- package/cdn/elements/icon/icon.js.map +1 -0
- package/cdn/elements/icon/index.d.ts +8 -0
- package/cdn/elements/icon/index.d.ts.map +1 -0
- package/cdn/elements/icon/index.js +2 -0
- package/cdn/elements/icon/index.js.map +1 -0
- package/cdn/elements/input-otp/index.d.ts +8 -0
- package/cdn/elements/input-otp/index.d.ts.map +1 -0
- package/cdn/elements/input-otp/index.js +2 -0
- package/cdn/elements/input-otp/index.js.map +1 -0
- package/cdn/elements/input-otp/input-otp.d.ts +31 -0
- package/cdn/elements/input-otp/input-otp.d.ts.map +1 -0
- package/cdn/elements/input-otp/input-otp.js +2 -0
- package/cdn/elements/input-otp/input-otp.js.map +1 -0
- package/cdn/elements/input-stepper/index.d.ts +8 -0
- package/cdn/elements/input-stepper/index.d.ts.map +1 -0
- package/cdn/elements/input-stepper/index.js +2 -0
- package/cdn/elements/input-stepper/index.js.map +1 -0
- package/cdn/elements/input-stepper/input-stepper.d.ts +66 -0
- package/cdn/elements/input-stepper/input-stepper.d.ts.map +1 -0
- package/cdn/elements/input-stepper/input-stepper.js +2 -0
- package/cdn/elements/input-stepper/input-stepper.js.map +1 -0
- package/cdn/elements/popover/index.d.ts +8 -0
- package/cdn/elements/popover/index.d.ts.map +1 -0
- package/cdn/elements/popover/index.js +2 -0
- package/cdn/elements/popover/index.js.map +1 -0
- package/cdn/elements/popover/popover.d.ts +64 -0
- package/cdn/elements/popover/popover.d.ts.map +1 -0
- package/cdn/elements/popover/popover.js +17 -0
- package/cdn/elements/popover/popover.js.map +1 -0
- package/cdn/elements/rating/index.d.ts +8 -0
- package/cdn/elements/rating/index.d.ts.map +1 -0
- package/cdn/elements/rating/index.js +2 -0
- package/cdn/elements/rating/index.js.map +1 -0
- package/cdn/elements/rating/rating.d.ts +38 -0
- package/cdn/elements/rating/rating.d.ts.map +1 -0
- package/cdn/elements/rating/rating.js +41 -0
- package/cdn/elements/rating/rating.js.map +1 -0
- package/cdn/elements/skeleton/index.d.ts +8 -0
- package/cdn/elements/skeleton/index.d.ts.map +1 -0
- package/cdn/elements/skeleton/index.js +2 -0
- package/cdn/elements/skeleton/index.js.map +1 -0
- package/cdn/elements/skeleton/skeleton.d.ts +12 -0
- package/cdn/elements/skeleton/skeleton.d.ts.map +1 -0
- package/cdn/elements/skeleton/skeleton.js +2 -0
- package/cdn/elements/skeleton/skeleton.js.map +1 -0
- package/cdn/elements/spinner/index.d.ts +8 -0
- package/cdn/elements/spinner/index.d.ts.map +1 -0
- package/cdn/elements/spinner/index.js +2 -0
- package/cdn/elements/spinner/index.js.map +1 -0
- package/cdn/elements/spinner/spinner.d.ts +16 -0
- package/cdn/elements/spinner/spinner.d.ts.map +1 -0
- package/cdn/elements/spinner/spinner.js +18 -0
- package/cdn/elements/spinner/spinner.js.map +1 -0
- package/cdn/elements/tabs/index.d.ts +8 -0
- package/cdn/elements/tabs/index.d.ts.map +1 -0
- package/cdn/elements/tabs/index.js +2 -0
- package/cdn/elements/tabs/index.js.map +1 -0
- package/cdn/elements/tabs/tabs.d.ts +48 -0
- package/cdn/elements/tabs/tabs.d.ts.map +1 -0
- package/cdn/elements/tabs/tabs.js +2 -0
- package/cdn/elements/tabs/tabs.js.map +1 -0
- package/cdn/elements/toast/index.d.ts +9 -0
- package/cdn/elements/toast/index.d.ts.map +1 -0
- package/cdn/elements/toast/index.js +2 -0
- package/cdn/elements/toast/index.js.map +1 -0
- package/cdn/elements/toast/toast.d.ts +72 -0
- package/cdn/elements/toast/toast.d.ts.map +1 -0
- package/cdn/elements/toast/toast.js +2 -0
- package/cdn/elements/toast/toast.js.map +1 -0
- package/cdn/elements/tooltip/index.d.ts +8 -0
- package/cdn/elements/tooltip/index.d.ts.map +1 -0
- package/cdn/elements/tooltip/index.js +2 -0
- package/cdn/elements/tooltip/index.js.map +1 -0
- package/cdn/elements/tooltip/tooltip.d.ts +59 -0
- package/cdn/elements/tooltip/tooltip.d.ts.map +1 -0
- package/cdn/elements/tooltip/tooltip.js +17 -0
- package/cdn/elements/tooltip/tooltip.js.map +1 -0
- package/cdn/elements/tree/index.d.ts +8 -0
- package/cdn/elements/tree/index.d.ts.map +1 -0
- package/cdn/elements/tree/index.js +2 -0
- package/cdn/elements/tree/index.js.map +1 -0
- package/cdn/elements/tree/tree.d.ts +76 -0
- package/cdn/elements/tree/tree.d.ts.map +1 -0
- package/cdn/elements/tree/tree.js +14 -0
- package/cdn/elements/tree/tree.js.map +1 -0
- package/cdn/elements/tree-item/index.d.ts +8 -0
- package/cdn/elements/tree-item/index.d.ts.map +1 -0
- package/cdn/elements/tree-item/index.js +2 -0
- package/cdn/elements/tree-item/index.js.map +1 -0
- package/cdn/elements/tree-item/tree-item.d.ts +74 -0
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -0
- package/cdn/elements/tree-item/tree-item.js +83 -0
- package/cdn/elements/tree-item/tree-item.js.map +1 -0
- package/cdn/index.d.ts +6 -0
- package/cdn/index.d.ts.map +1 -0
- package/cdn/index.js +1 -0
- package/cdn/registry.d.ts +22 -0
- package/cdn/registry.d.ts.map +1 -0
- package/cdn/registry.js +2 -0
- package/cdn/registry.js.map +1 -0
- package/cdn/shared/controllers/popover.d.ts +45 -0
- package/cdn/shared/controllers/popover.d.ts.map +1 -0
- package/cdn/shared/controllers/popover.js +2 -0
- package/cdn/shared/controllers/popover.js.map +1 -0
- package/cdn/shared/luxen-element.d.ts +20 -0
- package/cdn/shared/luxen-element.d.ts.map +1 -0
- package/cdn/shared/luxen-element.js +2 -0
- package/cdn/shared/luxen-element.js.map +1 -0
- package/cdn/shared/luxen-form-associated-element.d.ts +49 -0
- package/cdn/shared/luxen-form-associated-element.d.ts.map +1 -0
- package/cdn/shared/luxen-form-associated-element.js +2 -0
- package/cdn/shared/luxen-form-associated-element.js.map +1 -0
- package/cdn/shared/styles/host.styles.d.ts +9 -0
- package/cdn/shared/styles/host.styles.d.ts.map +1 -0
- package/cdn/shared/styles/host.styles.js +2 -0
- package/cdn/shared/styles/host.styles.js.map +1 -0
- package/cdn/styles/elements/avatar.css +20 -0
- package/cdn/styles/elements/badge.css +159 -0
- package/cdn/styles/elements/button.css +171 -0
- package/cdn/styles/elements/close-button/circle.css +66 -0
- package/cdn/styles/elements/close-button/ring.css +71 -0
- package/cdn/styles/elements/close-button/square.css +70 -0
- package/cdn/styles/elements/disclosure.css +137 -0
- package/cdn/styles/elements/divider.css +75 -0
- package/cdn/styles/elements/input-otp.css +164 -0
- package/cdn/styles/elements/input-stepper/default.css +248 -0
- package/cdn/styles/elements/input-stepper/rounded.css +241 -0
- package/cdn/styles/elements/kbd.css +21 -0
- package/cdn/styles/elements/progress.css +114 -0
- package/cdn/styles/elements/select.css +71 -0
- package/cdn/styles/elements/skeleton.css +89 -0
- package/cdn/styles/elements/tabs/enclosed.css +148 -0
- package/cdn/styles/elements/tabs/line.css +138 -0
- package/cdn/styles/elements/toast.css +260 -0
- package/cdn/styles/index.css +885 -0
- package/cdn/vite-env.d.js +0 -0
- package/dist/css/elements/input-stepper/default.css +19 -16
- package/dist/css/elements/input-stepper/rounded.css +14 -11
- package/dist/custom-elements.json +299 -224
- package/dist/elements/dialog/dialog.css +4 -3
- package/dist/elements/dialog/dialog.d.ts +1 -0
- package/dist/elements/dialog/dialog.d.ts.map +1 -1
- package/dist/elements/dialog/dialog.js +1 -0
- package/dist/elements/input-stepper/input-stepper.d.ts +3 -0
- package/dist/elements/input-stepper/input-stepper.d.ts.map +1 -1
- package/dist/elements/input-stepper/input-stepper.js +3 -0
- package/dist/elements/popover/popover.css +7 -2
- package/dist/elements/popover/popover.d.ts +3 -1
- package/dist/elements/popover/popover.d.ts.map +1 -1
- package/dist/elements/popover/popover.js +15 -4
- package/dist/shared/controllers/popover.d.ts +1 -0
- package/dist/shared/controllers/popover.d.ts.map +1 -1
- package/dist/shared/controllers/popover.js +2 -1
- package/package.json +12 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import{uniqueId as e}from"../../registry.js";import{c as t,i as n,n as r}from"../../chunks/lit.js";import{LuxenElement as i}from"../../shared/luxen-element.js";import{a,t as o}from"../../chunks/decorate.js";import s from"../../shared/styles/host.styles.js";import{PopoverController as c}from"../../shared/controllers/popover.js";var l=t(`:host{--background:var(--l-color-bg-surface,Canvas);--color:inherit;--border-radius:8px;--max-width:320px;--shadow:0 4px 16px #0000001f;--arrow-size:8px;--show-duration:.15s;--hide-duration:.15s;--_border-color:var(--l-color-border,var(--lightningcss-light,#e5e7eb)var(--lightningcss-dark,#374151));display:contents}[popover]{inset:unset;isolation:isolate;box-sizing:border-box;width:max-content;max-width:var(--max-width);border:1px solid var(--_border-color);border-radius:var(--border-radius);background:var(--background);color:var(--color);box-shadow:var(--shadow);padding:12px 16px;font-size:.875rem;line-height:1.5;overflow:visible}:host([full-width]) [popover]{width:100vw;max-width:none}i{width:var(--arrow-size);height:var(--arrow-size);background:var(--background);z-index:-1;display:block;position:absolute;transform:rotate(45deg)}:host([data-placement^=top]) i{border-right:1px solid var(--_border-color);border-bottom:1px solid var(--_border-color)}:host([data-placement^=bottom]) i{border-top:1px solid var(--_border-color);border-left:1px solid var(--_border-color)}:host([data-placement^=left]) i{border-right:1px solid var(--_border-color);border-top:1px solid var(--_border-color)}:host([data-placement^=right]) i{border-left:1px solid var(--_border-color);border-bottom:1px solid var(--_border-color)}`),u=class extends i{constructor(...t){super(...t),this._popoverId=e(`popover`),this._floating=new c(this,{getTriggerElement:()=>this._trigger,getFloatingElement:()=>this._popoverEl,getArrowElement:()=>this._arrowEl,onPlacementChange:e=>{this.dataset.placement=e}}),this.#e=``,this.#t=`bottom`,this.#n=8,this.#r=!1,this.#i=!1,this.#a=!1,this.#o=`click`,this._onPointerEnter=()=>{this._hasTrigger(`hover`)&&(this._floating.cleanupSafePolygon(),this.show())},this._onPointerLeave=e=>{!this._hasTrigger(`hover`)||!this.open||this._floating.handlePointerLeave(e,()=>this.hide())},this._onFocusIn=()=>{this._hasTrigger(`focus`)&&this.show()},this._onFocusOut=()=>{this._hasTrigger(`focus`)&&this.hide()},this._onClick=()=>{this._hasTrigger(`click`)&&this.toggle()},this._onKeyDown=e=>{this.open&&e.key===`Escape`&&(e.stopPropagation(),this.hide())},this._onToggle=e=>{e.newState===`closed`&&this.open&&(this.open=!1)}}static{this.styles=[s,l]}#e;get for(){return this.#e}set for(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 open(){return this.#r}set open(e){this.#r=e}#i;get withoutArrow(){return this.#i}set withoutArrow(e){this.#i=e}#a;get fullWidth(){return this.#a}set fullWidth(e){this.#a=e}#o;get trigger(){return this.#o}set trigger(e){this.#o=e}_hasTrigger(e){return this.trigger.split(` `).includes(e)}get _trigger(){return this.for?this.getRootNode().getElementById(this.for):null}get _popoverEl(){return this.shadowRoot.querySelector(`[popover]`)}get _arrowEl(){return this.withoutArrow?null:this.shadowRoot.querySelector(`i`)}_getDuration(e){let t=parseFloat(getComputedStyle(this).getPropertyValue(e));return Number.isNaN(t)?150:t}connectedCallback(){super.connectedCallback(),requestAnimationFrame(()=>this._addTriggerListeners())}disconnectedCallback(){super.disconnectedCallback(),this._removeTriggerListeners()}updated(e){e.has(`open`)&&this._handleOpenChange(),e.has(`for`)&&(this._removeTriggerListeners(e.get(`for`)),this._addTriggerListeners())}show(){this.open||=!0}hide(){this.open&&=!1}toggle(){this.open=!this.open}async _handleOpenChange(){let e=this._popoverEl;if(!e)return;let t={placement:this.placement,distance:this.distance,fullWidth:this.fullWidth};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._trigger?.setAttribute(`aria-expanded`,`true`),this._trigger?.setAttribute(`aria-controls`,this._popoverId)}else this._floating.stopPositioning(),this._floating.cleanupSafePolygon(),this._trigger?.setAttribute(`aria-expanded`,`false`),this._trigger?.removeAttribute(`aria-controls`),await this._floating.animateHide(e,this._getDuration(`--hide-duration`)),e.matches(`:popover-open`)&&e.hidePopover()}_addTriggerListeners(){this._floating.addTriggerListeners({onPointerEnter:this._onPointerEnter,onPointerLeave:this._onPointerLeave,onFocusIn:this._onFocusIn,onFocusOut:this._onFocusOut,onClick:this._onClick,onKeyDown:this._onKeyDown})}_removeTriggerListeners(e){let t=e?this.getRootNode().getElementById(e):void 0;this._floating.removeTriggerListeners(t)}render(){return n`
|
|
2
|
+
<div
|
|
3
|
+
id=${this._popoverId}
|
|
4
|
+
popover="auto"
|
|
5
|
+
part="body"
|
|
6
|
+
@toggle=${this._onToggle}
|
|
7
|
+
>
|
|
8
|
+
${this.withoutArrow?r:n`
|
|
9
|
+
<i
|
|
10
|
+
part="arrow"
|
|
11
|
+
role="presentation"
|
|
12
|
+
></i>
|
|
13
|
+
`}
|
|
14
|
+
<slot></slot>
|
|
15
|
+
</div>
|
|
16
|
+
`}};o([a()],u.prototype,`for`,null),o([a()],u.prototype,`placement`,null),o([a({type:Number})],u.prototype,`distance`,null),o([a({type:Boolean,reflect:!0})],u.prototype,`open`,null),o([a({type:Boolean,reflect:!0,attribute:`without-arrow`})],u.prototype,`withoutArrow`,null),o([a({type:Boolean,reflect:!0,attribute:`full-width`})],u.prototype,`fullWidth`,null),o([a()],u.prototype,`trigger`,null);export{u as LuxenPopover};
|
|
17
|
+
//# sourceMappingURL=popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.js","names":[],"sources":["../../../src/html/elements/popover/popover.css?inline","../../../src/html/elements/popover/popover.ts"],"sourcesContent":[":host {\n --background: var(--l-color-bg-surface, Canvas);\n --color: inherit;\n --border-radius: 8px;\n --max-width: 320px;\n --shadow: 0 4px 16px rgb(0 0 0 / 12%);\n --arrow-size: 8px;\n --show-duration: 150ms;\n --hide-duration: 150ms;\n\n --_border-color: var(--l-color-border, light-dark(#e5e7eb, #374151));\n\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n isolation: isolate;\n box-sizing: border-box;\n width: max-content;\n max-width: var(--max-width);\n padding: 12px 16px;\n border: 1px solid var(--_border-color);\n border-radius: var(--border-radius);\n background: var(--background);\n color: var(--color);\n font-size: 0.875rem;\n line-height: 1.5;\n box-shadow: var(--shadow);\n}\n\n:host([full-width]) [popover] {\n width: 100vw;\n max-width: none;\n}\n\ni {\n position: absolute;\n display: block;\n width: var(--arrow-size);\n height: var(--arrow-size);\n background: var(--background);\n transform: rotate(45deg);\n z-index: -1;\n}\n\n:host([data-placement^='top']) i {\n border-right: 1px solid var(--_border-color);\n border-bottom: 1px solid var(--_border-color);\n}\n\n:host([data-placement^='bottom']) i {\n border-top: 1px solid var(--_border-color);\n border-left: 1px solid var(--_border-color);\n}\n\n:host([data-placement^='left']) i {\n border-right: 1px solid var(--_border-color);\n border-top: 1px solid var(--_border-color);\n}\n\n:host([data-placement^='right']) i {\n border-left: 1px solid var(--_border-color);\n border-bottom: 1px solid var(--_border-color);\n}\n","import { html, nothing, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover';\nimport { uniqueId } from '../../registry';\nimport hostStyles from '../../shared/styles/host.styles';\nimport rawStyles from './popover.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * @summary A popover that displays interactive content anchored to a trigger.\n * @customElement l-popover\n *\n * @slot - Popover content.\n *\n * @csspart body - The popover container.\n * @csspart arrow - The directional arrow element.\n *\n * @cssproperty --background - Background color. Default: `Canvas`.\n * @cssproperty --color - Text color. Default: inherited.\n * @cssproperty --border-radius - Border radius. Default `8px`.\n * @cssproperty --max-width - Maximum width. Default `320px`.\n * @cssproperty --shadow - Box shadow.\n * @cssproperty --arrow-size - Arrow size. Default `8px`.\n * @cssproperty --show-duration - Show animation duration. Default `150ms`.\n * @cssproperty --hide-duration - Hide animation duration. Default `150ms`.\n */\nexport class LuxenPopover extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _popoverId = uniqueId('popover');\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._trigger,\n getFloatingElement: () => this._popoverEl,\n getArrowElement: () => this._arrowEl,\n onPlacementChange: (p) => {\n this.dataset.placement = p;\n },\n });\n\n /** The HTML id of the element triggering the popover. */\n @property()\n accessor for = '';\n\n /** The preferred placement of the popover. */\n @property()\n accessor placement: Placement = 'bottom';\n\n /** The distance in pixels from the target element. */\n @property({ type: Number })\n accessor distance = 8;\n\n /** Whether or not the popover is visible. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Hide the directional arrow. */\n @property({ type: Boolean, reflect: true, attribute: 'without-arrow' })\n accessor withoutArrow = false;\n\n /** Stretch the popover to the viewport width. Useful for mega menus. */\n @property({ type: Boolean, reflect: true, attribute: 'full-width' })\n accessor fullWidth = false;\n\n /** Space-separated list of trigger modes: `click`, `hover`, `focus`, `manual`. */\n @property()\n accessor trigger = 'click';\n\n private _hasTrigger(type: string) {\n return this.trigger.split(' ').includes(type);\n }\n\n private get _trigger(): HTMLElement | null {\n return this.for ? (this.getRootNode() as Document | ShadowRoot).getElementById(this.for) : null;\n }\n\n private get _popoverEl(): HTMLElement {\n return this.shadowRoot!.querySelector('[popover]')!;\n }\n\n private get _arrowEl(): HTMLElement | null {\n return this.withoutArrow ? null : this.shadowRoot!.querySelector('i');\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 override connectedCallback() {\n super.connectedCallback();\n requestAnimationFrame(() => this._addTriggerListeners());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._removeTriggerListeners();\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n this._handleOpenChange();\n }\n if (changed.has('for')) {\n this._removeTriggerListeners(changed.get('for') as string);\n this._addTriggerListeners();\n }\n }\n\n show() {\n if (!this.open) this.open = true;\n }\n\n hide() {\n if (this.open) this.open = false;\n }\n\n toggle() {\n this.open = !this.open;\n }\n\n private async _handleOpenChange() {\n const popover = this._popoverEl;\n if (!popover) return;\n\n const posOpts = {\n placement: this.placement,\n distance: this.distance,\n fullWidth: this.fullWidth,\n };\n\n if (this.open) {\n popover.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(popover, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._trigger?.setAttribute('aria-expanded', 'true');\n this._trigger?.setAttribute('aria-controls', this._popoverId);\n } else {\n this._floating.stopPositioning();\n this._floating.cleanupSafePolygon();\n this._trigger?.setAttribute('aria-expanded', 'false');\n this._trigger?.removeAttribute('aria-controls');\n await this._floating.animateHide(popover, this._getDuration('--hide-duration'));\n if (popover.matches(':popover-open')) popover.hidePopover();\n }\n }\n\n // --- Trigger event handlers ---\n\n private _onPointerEnter = () => {\n if (!this._hasTrigger('hover')) return;\n this._floating.cleanupSafePolygon();\n this.show();\n };\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (!this._hasTrigger('hover') || !this.open) return;\n this._floating.handlePointerLeave(e, () => this.hide());\n };\n\n private _onFocusIn = () => {\n if (this._hasTrigger('focus')) this.show();\n };\n private _onFocusOut = () => {\n if (this._hasTrigger('focus')) this.hide();\n };\n private _onClick = () => {\n if (this._hasTrigger('click')) this.toggle();\n };\n\n private _onKeyDown = (e: KeyboardEvent) => {\n if (this.open && e.key === 'Escape') {\n e.stopPropagation();\n this.hide();\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 }\n };\n\n private _addTriggerListeners() {\n this._floating.addTriggerListeners({\n onPointerEnter: this._onPointerEnter,\n onPointerLeave: this._onPointerLeave,\n onFocusIn: this._onFocusIn,\n onFocusOut: this._onFocusOut,\n onClick: this._onClick,\n onKeyDown: this._onKeyDown,\n });\n }\n\n private _removeTriggerListeners(forId?: string) {\n const trigger = forId\n ? (this.getRootNode() as Document | ShadowRoot).getElementById(forId)\n : undefined;\n this._floating.removeTriggerListeners(trigger);\n }\n\n override render() {\n return html`\n <div\n id=${this._popoverId}\n popover=\"auto\"\n part=\"body\"\n @toggle=${this._onToggle}\n >\n ${this.withoutArrow\n ? nothing\n : html`\n <i\n part=\"arrow\"\n role=\"presentation\"\n ></i>\n `}\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"yUCSA,IAAM,EAAS,6yCAAoB,CAoBtB,EAAb,cAAkC,CAAa,+CAGxB,EAAS,UAAU,gBAEpB,IAAI,EAAkB,KAAM,CAC9C,sBAAyB,KAAK,SAC9B,uBAA0B,KAAK,WAC/B,oBAAuB,KAAK,SAC5B,kBAAoB,GAAM,CACxB,KAAK,QAAQ,UAAY,GAE5B,CAAC,SAIa,WAIiB,iBAIZ,UAIJ,WAIQ,WAIH,WAIF,iCAqFa,CACzB,KAAK,YAAY,QAAQ,GAC9B,KAAK,UAAU,oBAAoB,CACnC,KAAK,MAAM,wBAGc,GAAoB,CACzC,CAAC,KAAK,YAAY,QAAQ,EAAI,CAAC,KAAK,MACxC,KAAK,UAAU,mBAAmB,MAAS,KAAK,MAAM,CAAC,sBAG9B,CACrB,KAAK,YAAY,QAAQ,EAAE,KAAK,MAAM,uBAEhB,CACtB,KAAK,YAAY,QAAQ,EAAE,KAAK,MAAM,oBAEnB,CACnB,KAAK,YAAY,QAAQ,EAAE,KAAK,QAAQ,kBAGxB,GAAqB,CACrC,KAAK,MAAQ,EAAE,MAAQ,WACzB,EAAE,iBAAiB,CACnB,KAAK,MAAM,kBAKM,GAAa,CACZ,EACJ,WAAa,UAAY,KAAK,OAC5C,KAAK,KAAO,wBA5JS,CAAC,EAAY,EAAO,QAepC,KAAA,4CAIA,WAAA,kDAIA,UAAA,iDAIA,MAAA,6CAIA,cAAA,qDAIA,WAAA,kDAIA,SAAA,yCAET,YAAoB,EAAc,CAChC,OAAO,KAAK,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAK,CAG/C,IAAY,UAA+B,CACzC,OAAO,KAAK,IAAO,KAAK,aAAa,CAA2B,eAAe,KAAK,IAAI,CAAG,KAG7F,IAAY,YAA0B,CACpC,OAAO,KAAK,WAAY,cAAc,YAAY,CAGpD,IAAY,UAA+B,CACzC,OAAO,KAAK,aAAe,KAAO,KAAK,WAAY,cAAc,IAAI,CAGvE,aAAqB,EAAqD,CACxE,IAAM,EAAS,WAAW,iBAAiB,KAAK,CAAC,iBAAiB,EAAK,CAAC,CACxE,OAAO,OAAO,MAAM,EAAO,CAAG,IAAM,EAGtC,mBAA6B,CAC3B,MAAM,mBAAmB,CACzB,0BAA4B,KAAK,sBAAsB,CAAC,CAG1D,sBAAgC,CAC9B,MAAM,sBAAsB,CAC5B,KAAK,yBAAyB,CAGhC,QAAiB,EAA+B,CAC1C,EAAQ,IAAI,OAAO,EACrB,KAAK,mBAAmB,CAEtB,EAAQ,IAAI,MAAM,GACpB,KAAK,wBAAwB,EAAQ,IAAI,MAAM,CAAW,CAC1D,KAAK,sBAAsB,EAI/B,MAAO,CACL,AAAgB,KAAK,OAAO,GAG9B,MAAO,CACL,AAAe,KAAK,OAAO,GAG7B,QAAS,CACP,KAAK,KAAO,CAAC,KAAK,KAGpB,MAAc,mBAAoB,CAChC,IAAM,EAAU,KAAK,WACrB,GAAI,CAAC,EAAS,OAEd,IAAM,EAAU,CACd,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,UAAW,KAAK,UACjB,CAED,GAAI,KAAK,KAAM,CAGb,GAFA,EAAQ,aAAa,CACrB,MAAM,KAAK,UAAU,eAAe,EAAQ,CACxC,CAAC,KAAK,KAAM,OAChB,MAAM,KAAK,UAAU,YAAY,EAAS,KAAK,aAAa,kBAAkB,CAAC,CAC/E,KAAK,UAAU,iBAAiB,EAAQ,CACxC,KAAK,UAAU,aAAa,gBAAiB,OAAO,CACpD,KAAK,UAAU,aAAa,gBAAiB,KAAK,WAAW,MAE7D,KAAK,UAAU,iBAAiB,CAChC,KAAK,UAAU,oBAAoB,CACnC,KAAK,UAAU,aAAa,gBAAiB,QAAQ,CACrD,KAAK,UAAU,gBAAgB,gBAAgB,CAC/C,MAAM,KAAK,UAAU,YAAY,EAAS,KAAK,aAAa,kBAAkB,CAAC,CAC3E,EAAQ,QAAQ,gBAAgB,EAAE,EAAQ,aAAa,CA0C/D,sBAA+B,CAC7B,KAAK,UAAU,oBAAoB,CACjC,eAAgB,KAAK,gBACrB,eAAgB,KAAK,gBACrB,UAAW,KAAK,WAChB,WAAY,KAAK,YACjB,QAAS,KAAK,SACd,UAAW,KAAK,WACjB,CAAC,CAGJ,wBAAgC,EAAgB,CAC9C,IAAM,EAAU,EACX,KAAK,aAAa,CAA2B,eAAe,EAAM,CACnE,IAAA,GACJ,KAAK,UAAU,uBAAuB,EAAQ,CAGhD,QAAkB,CAChB,MAAO,EAAI;;aAEF,KAAK,WAAW;;;kBAGX,KAAK,UAAU;;UAEvB,KAAK,aACH,EACA,CAAI;;;;;cAKF;;;WAnLX,GAAU,CAAA,CAAA,EAAA,UAAA,MAAA,KAAA,IAIV,GAAU,CAAA,CAAA,EAAA,UAAA,YAAA,KAAA,IAIV,EAAS,CAAE,KAAM,OAAQ,CAAC,CAAA,CAAA,EAAA,UAAA,WAAA,KAAA,IAI1B,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,OAAA,KAAA,IAI1C,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,UAAW,gBAAiB,CAAC,CAAA,CAAA,EAAA,UAAA,eAAA,KAAA,IAItE,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,UAAW,aAAc,CAAC,CAAA,CAAA,EAAA,UAAA,YAAA,KAAA,IAInE,GAAU,CAAA,CAAA,EAAA,UAAA,UAAA,KAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/rating/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 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/rating/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenRating } from './rating';\nexport * from './rating';\ndefine('rating', LuxenRating);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-rating': LuxenRating;\n }\n}\n"],"mappings":"mFAGA,EAAO,SAAU,EAAY"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LuxenFormAssociatedElement } from '../../shared/luxen-form-associated-element';
|
|
2
|
+
/**
|
|
3
|
+
* A star rating component using CSS mask-image.
|
|
4
|
+
*
|
|
5
|
+
* @summary Displays a star rating, optionally interactive.
|
|
6
|
+
*
|
|
7
|
+
* @csspart label - The label element shown in edit mode.
|
|
8
|
+
*
|
|
9
|
+
* @cssproperty --icon-size - The size of each icon. Defaults to `20px`.
|
|
10
|
+
* @cssproperty --active-color - The fill color for rated icons. Defaults to `gold`.
|
|
11
|
+
* @cssproperty --inactive-color - The fill color for empty icons. Defaults to `#ddd`.
|
|
12
|
+
* @cssproperty --spacing - The spacing between icons. Defaults to `0px`.
|
|
13
|
+
* @cssproperty --icon - Custom SVG shape as a `url()`. Defaults to a 5-pointed star.
|
|
14
|
+
*
|
|
15
|
+
* @event {{ name: string, value: string, checked: boolean, sourceEvent: Event }} change - Emitted when the rating value changes in edit mode.
|
|
16
|
+
*/
|
|
17
|
+
export declare class LuxenRating extends LuxenFormAssociatedElement {
|
|
18
|
+
static styles: import('lit').CSSResult[];
|
|
19
|
+
private currentLabel;
|
|
20
|
+
private previewedValue;
|
|
21
|
+
accessor editMode: boolean;
|
|
22
|
+
accessor labels: string[];
|
|
23
|
+
accessor value: number;
|
|
24
|
+
accessor length: number;
|
|
25
|
+
/** Optional callback returning a CSS `url()` string for a given position (1-based). */
|
|
26
|
+
getIcon?: (value: number) => string;
|
|
27
|
+
connectedCallback(): void;
|
|
28
|
+
formResetCallback(): void;
|
|
29
|
+
formStateRestoreCallback(state: string, _mode: 'restore' | 'autocomplete'): void;
|
|
30
|
+
firstUpdated(): void;
|
|
31
|
+
private setLabelForValue;
|
|
32
|
+
private getRatingStyle;
|
|
33
|
+
render(): import('lit').TemplateResult<1>;
|
|
34
|
+
private previewValue;
|
|
35
|
+
private clearPreview;
|
|
36
|
+
private onClick;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=rating.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rating.d.ts","sourceRoot":"","sources":["../../../src/html/elements/rating/rating.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAMxF;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAY,SAAQ,0BAA0B;IACzD,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,cAAc,CAAK;IAG3B,QAAQ,CAAC,QAAQ,UAAS;IAU1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAM;IAG/B,QAAQ,CAAC,KAAK,SAAK;IAGnB,QAAQ,CAAC,MAAM,SAAK;IAEpB,uFAAuF;IACvF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAE3B,iBAAiB;IAMjB,iBAAiB;IAKjB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,cAAc;IAKzE,YAAY;IAIrB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IAkBb,MAAM;IAuDf,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,OAAO;CAgBhB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import{c as e,i as t,n}from"../../chunks/lit.js";import{a as r,t as i}from"../../chunks/decorate.js";import a from"../../shared/styles/host.styles.js";import{LuxenFormAssociatedElement as o}from"../../shared/luxen-form-associated-element.js";var s=e(`:host{--icon-size:20px;--active-color:gold;--inactive-color:#ddd;--spacing:0px;--_icon:var(--icon,url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='2 2 20 19.02'><path d='M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z'/></svg>"));align-items:center;display:inline-flex}.rating{height:var(--icon-size);background:linear-gradient(to right, var(--active-color) var(--_fill,0%), var(--inactive-color) var(--_fill,0%));-webkit-mask-size:var(--icon-size) var(--icon-size);mask-size:var(--icon-size) var(--icon-size);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.rating-edit{gap:var(--spacing);display:inline-flex}.icon-wrapper{cursor:pointer}.icon-wrapper input{clip:rect(0, 0, 0, 0);border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.icon{width:var(--icon-size);height:var(--icon-size);-webkit-mask-image:var(--_icon);mask-image:var(--_icon);background:var(--inactive-color);pointer-events:none;transition:scale .2s;display:block;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.icon.active{background:var(--active-color)}.icon-wrapper:hover .icon{scale:1.2}.icon-wrapper:has(input:focus-visible) .icon{outline:2px solid var(--active-color);outline-offset:2px;border-radius:2px}:host([edit-mode]) .wrapper:focus-within{outline:2px solid var(--active-color);outline-offset:2px;border-radius:2px}:host([disabled]){opacity:.5;pointer-events:none}.wrapper{white-space:nowrap;align-items:center;display:flex}.rating-label{flex:1;margin-inline-start:8px;font-size:1rem;line-height:1}`),c=class extends o{constructor(...e){super(...e),this.currentLabel=``,this.previewedValue=0,this.#e=!1,this.#t=[],this.#n=0,this.#r=5}static{this.styles=[a,s]}#e;get editMode(){return this.#e}set editMode(e){this.#e=e}#t;get labels(){return this.#t}set labels(e){this.#t=e}#n;get value(){return this.#n}set value(e){this.#n=e}#r;get length(){return this.#r}set length(e){this.#r=e}connectedCallback(){super.connectedCallback(),this._defaultFormValue=String(this.value),this._syncFormValue(this._defaultFormValue)}formResetCallback(){this.value=Number(this._defaultFormValue),super.formResetCallback()}formStateRestoreCallback(e,t){this.value=Number(e),this._syncFormValue(e)}firstUpdated(){this.setLabelForValue(this.value)}setLabelForValue(e){let t=typeof e==`string`?parseInt(e,10):e;this.currentLabel=t?this.labels?.[t-1]??``:``,this.requestUpdate()}getRatingStyle(){let e=this.length,t=e>0?this.value/e*100:0,n=Array.from({length:e},(e,t)=>this.getIcon?.(t+1)??`var(--_icon)`),r=Array.from({length:e},(e,t)=>t===0?`0 0`:`calc(${t} * calc(var(--icon-size) + var(--spacing))) 0`);return[`width: calc(${e} * var(--icon-size) + ${e-1} * var(--spacing))`,`--_fill: ${t}%`,`mask-image: ${n.join(`, `)}`,`mask-position: ${r.join(`, `)}`].join(`; `)}render(){if(!this.editMode)return t`<div
|
|
2
|
+
class="rating"
|
|
3
|
+
style=${this.getRatingStyle()}
|
|
4
|
+
></div>`;let e=this.previewedValue||this.value;return t`
|
|
5
|
+
<div
|
|
6
|
+
class="wrapper"
|
|
7
|
+
@focusout=${this.clearPreview}
|
|
8
|
+
>
|
|
9
|
+
<div class="rating-edit">
|
|
10
|
+
${Array.from({length:this.length},(r,i)=>{let a=i+1,o=this.getIcon?.(a);return t`
|
|
11
|
+
<label
|
|
12
|
+
class="icon-wrapper"
|
|
13
|
+
@pointerover=${()=>this.previewValue(a)}
|
|
14
|
+
@pointerout=${this.clearPreview}
|
|
15
|
+
>
|
|
16
|
+
<input
|
|
17
|
+
type="radio"
|
|
18
|
+
name=${this.name??n}
|
|
19
|
+
value="${a}"
|
|
20
|
+
aria-label="${this.labels?.[i]??`${a} ${a===1?`star`:`stars`}`}"
|
|
21
|
+
?checked="${this.value===a}"
|
|
22
|
+
?disabled="${this.disabled}"
|
|
23
|
+
@click=${this.onClick}
|
|
24
|
+
@focusin=${()=>this.previewValue(a)}
|
|
25
|
+
/>
|
|
26
|
+
<span
|
|
27
|
+
class="icon ${a<=e?`active`:``}"
|
|
28
|
+
style=${o?`mask-image: ${o}`:n}
|
|
29
|
+
></span>
|
|
30
|
+
</label>
|
|
31
|
+
`})}
|
|
32
|
+
</div>
|
|
33
|
+
${this.labels?.length?t`<div
|
|
34
|
+
class="rating-label"
|
|
35
|
+
part="label"
|
|
36
|
+
>
|
|
37
|
+
${this.currentLabel}
|
|
38
|
+
</div>`:n}
|
|
39
|
+
</div>
|
|
40
|
+
`}previewValue(e){this.previewedValue=e,this.setLabelForValue(e)}clearPreview(e){if(e){let t=e.relatedTarget;if(t&&this.shadowRoot?.contains(t))return}this.previewedValue=0,this.setLabelForValue(this.value)}onClick(e){let t=e.currentTarget,n=Number(t.value);this.value=n===this.value?0:n,this.hasInteracted=!0,this._syncFormValue(String(this.value)),this.emit(`change`,{detail:{name:this.name,value:String(this.value),checked:this.value>0,sourceEvent:e}})}};i([r({type:Boolean,reflect:!0,attribute:`edit-mode`})],c.prototype,`editMode`,null),i([r({type:Array,reflect:!0,converter:{fromAttribute:e=>e.split(`|`),toAttribute:e=>e.length?e.join(`|`):null}})],c.prototype,`labels`,null),i([r({type:Number,reflect:!0})],c.prototype,`value`,null),i([r({type:Number,reflect:!0})],c.prototype,`length`,null);export{c as LuxenRating};
|
|
41
|
+
//# sourceMappingURL=rating.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rating.js","names":[],"sources":["../../../src/html/elements/rating/rating.css?inline","../../../src/html/elements/rating/rating.ts"],"sourcesContent":[":host {\n --icon-size: 20px;\n --active-color: gold;\n --inactive-color: #ddd;\n --spacing: 0px;\n --_icon: var(\n --icon,\n url(\"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='2 2 20 19.02'><path d='M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z'/></svg>\")\n );\n\n display: inline-flex;\n align-items: center;\n}\n\n/* — Read-only mode — */\n\n.rating {\n height: var(--icon-size);\n background: linear-gradient(\n to right,\n var(--active-color) var(--_fill, 0%),\n var(--inactive-color) var(--_fill, 0%)\n );\n mask-size: var(--icon-size) var(--icon-size);\n mask-repeat: no-repeat;\n}\n\n/* — Edit mode — */\n\n.rating-edit {\n display: inline-flex;\n gap: var(--spacing);\n}\n\n.icon-wrapper {\n cursor: pointer;\n}\n\n.icon-wrapper input {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n\n.icon {\n display: block;\n width: var(--icon-size);\n height: var(--icon-size);\n mask-image: var(--_icon);\n mask-size: contain;\n mask-repeat: no-repeat;\n background: var(--inactive-color);\n transition: scale 0.2s ease;\n pointer-events: none;\n}\n\n.icon.active {\n background: var(--active-color);\n}\n\n.icon-wrapper:hover .icon {\n scale: 1.2;\n}\n\n.icon-wrapper:has(input:focus-visible) .icon {\n outline: 2px solid var(--active-color);\n outline-offset: 2px;\n border-radius: 2px;\n}\n\n:host([edit-mode]) .wrapper:focus-within {\n outline: 2px solid var(--active-color);\n outline-offset: 2px;\n border-radius: 2px;\n}\n\n/* — Disabled — */\n\n:host([disabled]) {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* — Label — */\n\n.wrapper {\n display: flex;\n align-items: center;\n white-space: nowrap;\n}\n\n.rating-label {\n margin-inline-start: 8px;\n flex: 1;\n font-size: 1rem;\n line-height: 1;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { LuxenFormAssociatedElement } from '../../shared/luxen-form-associated-element';\nimport hostStyles from '../../shared/styles/host.styles';\nimport rawStyles from './rating.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A star rating component using CSS mask-image.\n *\n * @summary Displays a star rating, optionally interactive.\n *\n * @csspart label - The label element shown in edit mode.\n *\n * @cssproperty --icon-size - The size of each icon. Defaults to `20px`.\n * @cssproperty --active-color - The fill color for rated icons. Defaults to `gold`.\n * @cssproperty --inactive-color - The fill color for empty icons. Defaults to `#ddd`.\n * @cssproperty --spacing - The spacing between icons. Defaults to `0px`.\n * @cssproperty --icon - Custom SVG shape as a `url()`. Defaults to a 5-pointed star.\n *\n * @event {{ name: string, value: string, checked: boolean, sourceEvent: Event }} change - Emitted when the rating value changes in edit mode.\n */\nexport class LuxenRating extends LuxenFormAssociatedElement {\n static override styles = [hostStyles, styles];\n\n private currentLabel = '';\n private previewedValue = 0;\n\n @property({ type: Boolean, reflect: true, attribute: 'edit-mode' })\n accessor editMode = false;\n\n @property({\n type: Array,\n reflect: true,\n converter: {\n fromAttribute: (value: string) => value.split('|'),\n toAttribute: (value: string[]) => (value.length ? value.join('|') : null),\n },\n })\n accessor labels: string[] = [];\n\n @property({ type: Number, reflect: true })\n accessor value = 0;\n\n @property({ type: Number, reflect: true })\n accessor length = 5;\n\n /** Optional callback returning a CSS `url()` string for a given position (1-based). */\n getIcon?: (value: number) => string;\n\n override connectedCallback() {\n super.connectedCallback();\n this._defaultFormValue = String(this.value);\n this._syncFormValue(this._defaultFormValue);\n }\n\n override formResetCallback() {\n this.value = Number(this._defaultFormValue);\n super.formResetCallback();\n }\n\n override formStateRestoreCallback(state: string, _mode: 'restore' | 'autocomplete') {\n this.value = Number(state);\n this._syncFormValue(state);\n }\n\n override firstUpdated() {\n this.setLabelForValue(this.value);\n }\n\n private setLabelForValue(value: number | string) {\n const intValue = typeof value === 'string' ? parseInt(value, 10) : value;\n this.currentLabel = intValue ? (this.labels?.[intValue - 1] ?? '') : '';\n this.requestUpdate();\n }\n\n private getRatingStyle() {\n const max = this.length;\n const fillPct = max > 0 ? (this.value / max) * 100 : 0;\n const step = 'calc(var(--icon-size) + var(--spacing))';\n\n const icons = Array.from({ length: max }, (_, i) => this.getIcon?.(i + 1) ?? 'var(--_icon)');\n const positions = Array.from({ length: max }, (_, i) =>\n i === 0 ? '0 0' : `calc(${i} * ${step}) 0`,\n );\n\n return [\n `width: calc(${max} * var(--icon-size) + ${max - 1} * var(--spacing))`,\n `--_fill: ${fillPct}%`,\n `mask-image: ${icons.join(', ')}`,\n `mask-position: ${positions.join(', ')}`,\n ].join('; ');\n }\n\n override render() {\n if (!this.editMode) {\n return html`<div\n class=\"rating\"\n style=${this.getRatingStyle()}\n ></div>`;\n }\n\n const activeCount = this.previewedValue || this.value;\n\n return html`\n <div\n class=\"wrapper\"\n @focusout=${this.clearPreview}\n >\n <div class=\"rating-edit\">\n ${Array.from({ length: this.length }, (_, i) => {\n const v = i + 1;\n const icon = this.getIcon?.(v);\n return html`\n <label\n class=\"icon-wrapper\"\n @pointerover=${() => this.previewValue(v)}\n @pointerout=${this.clearPreview}\n >\n <input\n type=\"radio\"\n name=${this.name ?? nothing}\n value=\"${v}\"\n aria-label=\"${this.labels?.[i] ?? `${v} ${v === 1 ? 'star' : 'stars'}`}\"\n ?checked=\"${this.value === v}\"\n ?disabled=\"${this.disabled}\"\n @click=${this.onClick}\n @focusin=${() => this.previewValue(v)}\n />\n <span\n class=\"icon ${v <= activeCount ? 'active' : ''}\"\n style=${icon ? `mask-image: ${icon}` : nothing}\n ></span>\n </label>\n `;\n })}\n </div>\n ${this.labels?.length\n ? html`<div\n class=\"rating-label\"\n part=\"label\"\n >\n ${this.currentLabel}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n private previewValue(value: number) {\n this.previewedValue = value;\n this.setLabelForValue(value);\n }\n\n private clearPreview(event?: FocusEvent) {\n if (event) {\n const related = event.relatedTarget as Node | null;\n if (related && this.shadowRoot?.contains(related)) return;\n }\n this.previewedValue = 0;\n this.setLabelForValue(this.value);\n }\n\n private onClick(event: Event) {\n const target = event.currentTarget as HTMLInputElement;\n const clickedValue = Number(target.value);\n this.value = clickedValue === this.value ? 0 : clickedValue;\n this.hasInteracted = true;\n this._syncFormValue(String(this.value));\n\n this.emit('change', {\n detail: {\n name: this.name,\n value: String(this.value),\n checked: this.value > 0,\n sourceEvent: event,\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/skeleton/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 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/skeleton/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenSkeleton } from './skeleton';\nexport * from './skeleton';\ndefine('skeleton', LuxenSkeleton);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-skeleton': LuxenSkeleton;\n }\n}\n"],"mappings":"uFAGA,EAAO,WAAY,EAAc"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
2
|
+
/**
|
|
3
|
+
* @summary A skeleton loading placeholder.
|
|
4
|
+
* @customElement l-skeleton
|
|
5
|
+
*
|
|
6
|
+
* @cssproperty --width - Width of the skeleton
|
|
7
|
+
* @cssproperty --height - Height of the skeleton
|
|
8
|
+
*/
|
|
9
|
+
export declare class LuxenSkeleton extends LuxenElement {
|
|
10
|
+
createRenderRoot(): this;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/html/elements/skeleton/skeleton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAY;IACpC,gBAAgB;CAG1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.js","names":[],"sources":["../../../src/html/elements/skeleton/skeleton.ts"],"sourcesContent":["import { LuxenElement } from '../../shared/luxen-element';\n\n/**\n * @summary A skeleton loading placeholder.\n * @customElement l-skeleton\n *\n * @cssproperty --width - Width of the skeleton\n * @cssproperty --height - Height of the skeleton\n */\nexport class LuxenSkeleton extends LuxenElement {\n override createRenderRoot() {\n return this;\n }\n}\n"],"mappings":"6DASA,IAAa,EAAb,cAAmC,CAAa,CAC9C,kBAA4B,CAC1B,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/spinner/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,cAAc,WAAW,CAAC;AAG1B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,YAAY,CAAC;KAC3B;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/spinner/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenSpinner } from './spinner';\nexport * from './spinner';\ndefine('spinner', LuxenSpinner);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-spinner': LuxenSpinner;\n }\n}\n"],"mappings":"qFAGA,EAAO,UAAW,EAAa"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
2
|
+
/**
|
|
3
|
+
* @summary A spinner component for indicating loading state.
|
|
4
|
+
* @customElement l-spinner
|
|
5
|
+
*
|
|
6
|
+
* @csspart base - The SVG container element.
|
|
7
|
+
*
|
|
8
|
+
* @cssproperty --size - The size of the spinner (width and height). Defaults to `1em`.
|
|
9
|
+
* @cssproperty --indicator-color - The color of the spinner.
|
|
10
|
+
* @cssproperty --speed - The duration of one full spin cycle.
|
|
11
|
+
*/
|
|
12
|
+
export declare class LuxenSpinner extends LuxenElement {
|
|
13
|
+
static styles: import('lit').CSSResult[];
|
|
14
|
+
render(): import('lit').TemplateResult<1>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/html/elements/spinner/spinner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAM1D;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAgB,MAAM,4BAAwB;IAErC,MAAM;CAmBhB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{c as e,i as t}from"../../chunks/lit.js";import{LuxenElement as n}from"../../shared/luxen-element.js";import r from"../../shared/styles/host.styles.js";var i=e(`:host{--size:1em;--indicator-color:currentColor;--speed:.75s;width:var(--size);height:var(--size);color:var(--indicator-color);flex:none;display:inline-flex}svg{fill:currentColor;width:100%;height:100%}.spinner{transform-origin:50%;animation:spin var(--speed) linear infinite}@keyframes spin{to{transform:rotate(360deg)}}`),a=class extends n{static{this.styles=[r,i]}render(){return t`
|
|
2
|
+
<svg
|
|
3
|
+
part="base"
|
|
4
|
+
role="progressbar"
|
|
5
|
+
aria-label="Loading"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
|
|
10
|
+
opacity=".25"
|
|
11
|
+
/>
|
|
12
|
+
<path
|
|
13
|
+
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
|
|
14
|
+
class="spinner"
|
|
15
|
+
/>
|
|
16
|
+
</svg>
|
|
17
|
+
`}};export{a as LuxenSpinner};
|
|
18
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","names":[],"sources":["../../../src/html/elements/spinner/spinner.css?inline","../../../src/html/elements/spinner/spinner.ts"],"sourcesContent":[":host {\n --size: 1em;\n --indicator-color: currentColor;\n --speed: 0.75s;\n\n flex: none;\n display: inline-flex;\n width: var(--size);\n height: var(--size);\n color: var(--indicator-color);\n}\n\nsvg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n}\n\n.spinner {\n transform-origin: center;\n animation: spin var(--speed) linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n","import { html, unsafeCSS } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element';\nimport hostStyles from '../../shared/styles/host.styles';\nimport rawStyles from './spinner.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * @summary A spinner component for indicating loading state.\n * @customElement l-spinner\n *\n * @csspart base - The SVG container element.\n *\n * @cssproperty --size - The size of the spinner (width and height). Defaults to `1em`.\n * @cssproperty --indicator-color - The color of the spinner.\n * @cssproperty --speed - The duration of one full spin cycle.\n */\nexport class LuxenSpinner extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n override render() {\n return html`\n <svg\n part=\"base\"\n role=\"progressbar\"\n aria-label=\"Loading\"\n viewBox=\"0 0 24 24\"\n >\n <path\n d=\"M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z\"\n opacity=\".25\"\n />\n <path\n d=\"M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z\"\n class=\"spinner\"\n />\n </svg>\n `;\n }\n}\n"],"mappings":"8JCKA,IAAM,EAAS,sUAAoB,CAYtB,EAAb,cAAkC,CAAa,oBACpB,CAAC,EAAY,EAAO,CAE7C,QAAkB,CAChB,MAAO,EAAI"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tabs/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,cAAc,QAAQ,CAAC;AAGvB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,QAAQ,EAAE,SAAS,CAAC;KACrB;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/tabs/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenTabs } from './tabs';\nexport * from './tabs';\ndefine('tabs', LuxenTabs);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-tabs': LuxenTabs;\n }\n}\n"],"mappings":"+EAGA,EAAO,OAAQ,EAAU"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
2
|
+
export type TabsVariant = 'enclosed' | 'line';
|
|
3
|
+
export type TabsOrientation = 'horizontal' | 'vertical';
|
|
4
|
+
/**
|
|
5
|
+
* @summary A tabs component that progressively enhances light DOM markup
|
|
6
|
+
* with ARIA roles, keyboard navigation, and animated indicators.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```html
|
|
10
|
+
* <l-tabs variant="enclosed">
|
|
11
|
+
* <div>
|
|
12
|
+
* <button>Tab 1</button>
|
|
13
|
+
* <button>Tab 2</button>
|
|
14
|
+
* </div>
|
|
15
|
+
* <div>Content 1</div>
|
|
16
|
+
* <div>Content 2</div>
|
|
17
|
+
* </l-tabs>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @event change - Fired when the active tab changes. Detail: `{ index: number, name: string | null }`.
|
|
21
|
+
*
|
|
22
|
+
* @customElement l-tabs
|
|
23
|
+
*/
|
|
24
|
+
export declare class LuxenTabs extends LuxenElement {
|
|
25
|
+
createRenderRoot(): this;
|
|
26
|
+
private _instanceId;
|
|
27
|
+
private _tablistEl;
|
|
28
|
+
private _tabs;
|
|
29
|
+
private _panels;
|
|
30
|
+
/** Visual variant. */
|
|
31
|
+
variant: TabsVariant;
|
|
32
|
+
/** Index of the active tab (0-based). */
|
|
33
|
+
value: string;
|
|
34
|
+
/** Stretch tabs to fill container width. */
|
|
35
|
+
fullWidth: boolean;
|
|
36
|
+
/** Tab orientation. */
|
|
37
|
+
orientation: TabsOrientation;
|
|
38
|
+
connectedCallback(): void;
|
|
39
|
+
disconnectedCallback(): void;
|
|
40
|
+
updated(changed: Map<string, unknown>): void;
|
|
41
|
+
private _setup;
|
|
42
|
+
private _teardown;
|
|
43
|
+
private _selectTab;
|
|
44
|
+
private _updateIndicator;
|
|
45
|
+
private _onClick;
|
|
46
|
+
private _onKeyDown;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tabs/tabs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,UAAU,CAAC;AAExD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,SAAU,SAAQ,YAAY;IAChC,gBAAgB;IAIzB,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,OAAO,CAAqB;IAEpC,sBAAsB;IAEtB,OAAO,EAAE,WAAW,CAAU;IAE9B,yCAAyC;IAEzC,KAAK,SAAO;IAEZ,4CAA4C;IAE5C,SAAS,UAAS;IAElB,uBAAuB;IAEvB,WAAW,EAAE,eAAe,CAAgB;IAInC,iBAAiB;IAMjB,oBAAoB;IAKpB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAW9C,OAAO,CAAC,MAAM;IAoDd,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,QAAQ,CAQd;IAEF,OAAO,CAAC,UAAU,CAkChB;CACH"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{uniqueId as e}from"../../registry.js";import{LuxenElement as t}from"../../shared/luxen-element.js";import{a as n,t as r}from"../../chunks/decorate.js";var i=class extends t{constructor(...t){super(...t),this._instanceId=e(`tabs`),this._tablistEl=null,this._tabs=[],this._panels=[],this.variant=`line`,this.value=`0`,this.fullWidth=!1,this.orientation=`horizontal`,this._onClick=e=>{let t=e.target.closest(`[role="tab"]`);if(!t)return;let n=this._tabs.indexOf(t);n>=0&&(this._selectTab(n),t.focus())},this._onKeyDown=e=>{let t=e.target;if(t.getAttribute(`role`)!==`tab`)return;let n=this.orientation===`horizontal`,r=n?`ArrowLeft`:`ArrowUp`,i=n?`ArrowRight`:`ArrowDown`,a=this._tabs.indexOf(t);switch(e.key){case i:e.preventDefault(),a=(a+1)%this._tabs.length,this._selectTab(a),this._tabs[a].focus();break;case r:e.preventDefault(),a=(a-1+this._tabs.length)%this._tabs.length,this._selectTab(a),this._tabs[a].focus();break;case`Home`:e.preventDefault(),this._selectTab(0),this._tabs[0].focus();break;case`End`:e.preventDefault(),this._selectTab(this._tabs.length-1),this._tabs[this._tabs.length-1].focus();break}}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),requestAnimationFrame(()=>this._setup())}disconnectedCallback(){super.disconnectedCallback(),this._teardown()}updated(e){e.has(`value`)&&this._tabs.length&&this._selectTab(Number(this.value),!1),e.has(`orientation`)&&this._tablistEl&&this._tablistEl.setAttribute(`aria-orientation`,this.orientation)}_setup(){let e=Array.from(this.children);if(e.length<2)return;this._tablistEl=e[0],this._tablistEl.setAttribute(`role`,`tablist`),this._tablistEl.setAttribute(`aria-orientation`,this.orientation),this._tabs=Array.from(this._tablistEl.querySelectorAll(`button`)),this._panels=e.slice(1);let t=Number(this.value)||0;for(let e=0;e<this._tabs.length;e++){let n=this._tabs[e],r=this._panels[e],i=n.getAttribute(`name`)??String(e),a=`${this._instanceId}-tab-${i}`,o=`${this._instanceId}-panel-${i}`;n.setAttribute(`role`,`tab`),n.setAttribute(`id`,a),n.setAttribute(`aria-selected`,String(e===t)),n.setAttribute(`tabindex`,e===t?`0`:`-1`),r&&(n.setAttribute(`aria-controls`,o),r.setAttribute(`role`,`tabpanel`),r.setAttribute(`id`,o),r.setAttribute(`aria-labelledby`,a),r.setAttribute(`tabindex`,`0`),e===t?r.hidden=!1:r.hidden=!0)}this._tablistEl.addEventListener(`click`,this._onClick),this._tablistEl.addEventListener(`keydown`,this._onKeyDown),requestAnimationFrame(()=>this._updateIndicator())}_teardown(){this._tablistEl?.removeEventListener(`click`,this._onClick),this._tablistEl?.removeEventListener(`keydown`,this._onKeyDown)}_selectTab(e,t=!0){if(!(e<0||e>=this._tabs.length)){for(let t=0;t<this._tabs.length;t++){let n=this._tabs[t],r=this._panels[t],i=t===e;n.setAttribute(`aria-selected`,String(i)),n.setAttribute(`tabindex`,i?`0`:`-1`),r&&(r.hidden=!i)}if(this.value=String(e),this._updateIndicator(),t){let t=this._tabs[e]?.getAttribute(`name`)??null;this.emit(`change`,{detail:{index:e,name:t}})}}}_updateIndicator(){if(!this._tablistEl)return;let e=this._tabs[Number(this.value)];e&&(this.orientation===`vertical`?(this._tablistEl.style.setProperty(`--_indicator-top`,`${e.offsetTop}px`),this._tablistEl.style.setProperty(`--_indicator-height`,`${e.offsetHeight}px`)):(this._tablistEl.style.setProperty(`--_indicator-left`,`${e.offsetLeft}px`),this._tablistEl.style.setProperty(`--_indicator-width`,`${e.offsetWidth}px`)))}};r([n({reflect:!0})],i.prototype,`variant`,void 0),r([n({reflect:!0})],i.prototype,`value`,void 0),r([n({type:Boolean,reflect:!0,attribute:`full-width`})],i.prototype,`fullWidth`,void 0),r([n({reflect:!0})],i.prototype,`orientation`,void 0);export{i as LuxenTabs};
|
|
2
|
+
//# sourceMappingURL=tabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.js","names":[],"sources":["../../../src/html/elements/tabs/tabs.ts"],"sourcesContent":["import { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element';\nimport { uniqueId } from '../../registry';\n\nexport type TabsVariant = 'enclosed' | 'line';\nexport type TabsOrientation = 'horizontal' | 'vertical';\n\n/**\n * @summary A tabs component that progressively enhances light DOM markup\n * with ARIA roles, keyboard navigation, and animated indicators.\n *\n * @example\n * ```html\n * <l-tabs variant=\"enclosed\">\n * <div>\n * <button>Tab 1</button>\n * <button>Tab 2</button>\n * </div>\n * <div>Content 1</div>\n * <div>Content 2</div>\n * </l-tabs>\n * ```\n *\n * @event change - Fired when the active tab changes. Detail: `{ index: number, name: string | null }`.\n *\n * @customElement l-tabs\n */\nexport class LuxenTabs extends LuxenElement {\n override createRenderRoot() {\n return this;\n }\n\n private _instanceId = uniqueId('tabs');\n private _tablistEl: HTMLElement | null = null;\n private _tabs: HTMLButtonElement[] = [];\n private _panels: HTMLElement[] = [];\n\n /** Visual variant. */\n @property({ reflect: true })\n variant: TabsVariant = 'line';\n\n /** Index of the active tab (0-based). */\n @property({ reflect: true })\n value = '0';\n\n /** Stretch tabs to fill container width. */\n @property({ type: Boolean, reflect: true, attribute: 'full-width' })\n fullWidth = false;\n\n /** Tab orientation. */\n @property({ reflect: true })\n orientation: TabsOrientation = 'horizontal';\n\n // --- Lifecycle ---\n\n override connectedCallback() {\n super.connectedCallback();\n // Defer setup to let light DOM children parse\n requestAnimationFrame(() => this._setup());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._teardown();\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('value') && this._tabs.length) {\n this._selectTab(Number(this.value), false);\n }\n if (changed.has('orientation') && this._tablistEl) {\n this._tablistEl.setAttribute('aria-orientation', this.orientation);\n }\n }\n\n // --- Setup / Teardown ---\n\n private _setup() {\n const children = Array.from(this.children) as HTMLElement[];\n if (children.length < 2) return;\n\n // First child is the tablist container\n this._tablistEl = children[0];\n this._tablistEl.setAttribute('role', 'tablist');\n this._tablistEl.setAttribute('aria-orientation', this.orientation);\n\n // Buttons inside tablist become tabs\n this._tabs = Array.from(this._tablistEl.querySelectorAll('button'));\n\n // Remaining children become panels\n this._panels = children.slice(1);\n\n const activeIndex = Number(this.value) || 0;\n\n // Enhance tabs\n for (let i = 0; i < this._tabs.length; i++) {\n const tab = this._tabs[i];\n const panel = this._panels[i];\n const name = tab.getAttribute('name') ?? String(i);\n const tabId = `${this._instanceId}-tab-${name}`;\n const panelId = `${this._instanceId}-panel-${name}`;\n\n tab.setAttribute('role', 'tab');\n tab.setAttribute('id', tabId);\n tab.setAttribute('aria-selected', String(i === activeIndex));\n tab.setAttribute('tabindex', i === activeIndex ? '0' : '-1');\n\n if (panel) {\n tab.setAttribute('aria-controls', panelId);\n panel.setAttribute('role', 'tabpanel');\n panel.setAttribute('id', panelId);\n panel.setAttribute('aria-labelledby', tabId);\n panel.setAttribute('tabindex', '0');\n if (i !== activeIndex) {\n panel.hidden = true;\n } else {\n panel.hidden = false;\n }\n }\n }\n\n // Attach listeners\n this._tablistEl.addEventListener('click', this._onClick);\n this._tablistEl.addEventListener('keydown', this._onKeyDown);\n\n // Initial indicator position\n requestAnimationFrame(() => this._updateIndicator());\n }\n\n private _teardown() {\n this._tablistEl?.removeEventListener('click', this._onClick);\n this._tablistEl?.removeEventListener('keydown', this._onKeyDown);\n }\n\n // --- Tab selection ---\n\n private _selectTab(index: number, emitEvent = true) {\n if (index < 0 || index >= this._tabs.length) return;\n\n for (let i = 0; i < this._tabs.length; i++) {\n const tab = this._tabs[i];\n const panel = this._panels[i];\n const isActive = i === index;\n\n tab.setAttribute('aria-selected', String(isActive));\n tab.setAttribute('tabindex', isActive ? '0' : '-1');\n\n if (panel) {\n panel.hidden = !isActive;\n }\n }\n\n this.value = String(index);\n this._updateIndicator();\n\n if (emitEvent) {\n const name = this._tabs[index]?.getAttribute('name') ?? null;\n this.emit('change', { detail: { index, name } });\n }\n }\n\n // --- Indicator ---\n\n private _updateIndicator() {\n if (!this._tablistEl) return;\n const activeTab = this._tabs[Number(this.value)];\n if (!activeTab) return;\n\n const isVertical = this.orientation === 'vertical';\n\n if (isVertical) {\n this._tablistEl.style.setProperty('--_indicator-top', `${activeTab.offsetTop}px`);\n this._tablistEl.style.setProperty('--_indicator-height', `${activeTab.offsetHeight}px`);\n } else {\n this._tablistEl.style.setProperty('--_indicator-left', `${activeTab.offsetLeft}px`);\n this._tablistEl.style.setProperty('--_indicator-width', `${activeTab.offsetWidth}px`);\n }\n }\n\n // --- Event handlers ---\n\n private _onClick = (e: Event) => {\n const tab = (e.target as HTMLElement).closest<HTMLButtonElement>('[role=\"tab\"]');\n if (!tab) return;\n const index = this._tabs.indexOf(tab);\n if (index >= 0) {\n this._selectTab(index);\n tab.focus();\n }\n };\n\n private _onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement;\n if (target.getAttribute('role') !== 'tab') return;\n\n const isHorizontal = this.orientation === 'horizontal';\n const prevKey = isHorizontal ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isHorizontal ? 'ArrowRight' : 'ArrowDown';\n\n let index = this._tabs.indexOf(target as HTMLButtonElement);\n\n switch (e.key) {\n case nextKey:\n e.preventDefault();\n index = (index + 1) % this._tabs.length;\n this._selectTab(index);\n this._tabs[index].focus();\n break;\n case prevKey:\n e.preventDefault();\n index = (index - 1 + this._tabs.length) % this._tabs.length;\n this._selectTab(index);\n this._tabs[index].focus();\n break;\n case 'Home':\n e.preventDefault();\n this._selectTab(0);\n this._tabs[0].focus();\n break;\n case 'End':\n e.preventDefault();\n this._selectTab(this._tabs.length - 1);\n this._tabs[this._tabs.length - 1].focus();\n break;\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/toast/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACrD,cAAc,SAAS,CAAC;AAIxB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,SAAS,EAAE,UAAU,CAAC;QACtB,cAAc,EAAE,cAAc,CAAC;KAChC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/toast/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenToast, LuxenToastItem } from './toast';\nexport * from './toast';\ndefine('toast', LuxenToast);\ndefine('toast-item', LuxenToastItem);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-toast': LuxenToast;\n 'l-toast-item': LuxenToastItem;\n }\n}\n"],"mappings":"qGAGA,EAAO,QAAS,EAAW,CAC3B,EAAO,aAAc,EAAe"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Element {
|
|
4
|
+
/** @see https://developer.mozilla.org/en-US/docs/Web/API/Element/setHTML */
|
|
5
|
+
setHTML(input: string, options?: Record<string, unknown>): void;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Minimal custom element for toast items — no render, no shadow DOM. */
|
|
9
|
+
export declare class LuxenToastItem extends HTMLElement {
|
|
10
|
+
}
|
|
11
|
+
interface ToastOptionsBase {
|
|
12
|
+
/** Optional heading text displayed above the message. */
|
|
13
|
+
heading?: string;
|
|
14
|
+
/** Override the element's variant for this toast. */
|
|
15
|
+
variant?: string;
|
|
16
|
+
/** Override auto-dismiss duration (ms) for this toast. 0 = no auto-dismiss. */
|
|
17
|
+
duration?: number;
|
|
18
|
+
/** Iconify icon name (e.g. 'lucide:check'). Replaces the accent bar. */
|
|
19
|
+
icon?: string;
|
|
20
|
+
/** Show a countdown progress bar at the bottom. Default `false`. */
|
|
21
|
+
timer?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export type ToastOptions = (ToastOptionsBase & {
|
|
24
|
+
text: string;
|
|
25
|
+
html?: never;
|
|
26
|
+
}) | (ToastOptionsBase & {
|
|
27
|
+
text?: never;
|
|
28
|
+
/** HTML content (sanitized via the Sanitizer API). */ html: string;
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* @summary A toast notification container that generates toast items internally.
|
|
32
|
+
* @customElement l-toast
|
|
33
|
+
*
|
|
34
|
+
* @event show - Emitted when a toast begins to show. Cancelable.
|
|
35
|
+
* @event after-show - Emitted after the show animation completes.
|
|
36
|
+
* @event hide - Emitted when a toast begins to hide. Cancelable.
|
|
37
|
+
* @event after-hide - Emitted after the hide animation completes and toast is removed.
|
|
38
|
+
*
|
|
39
|
+
* @cssproperty --gap - Gap between stacked toast items.
|
|
40
|
+
* @cssproperty --width - Width of the toast stack.
|
|
41
|
+
* @cssproperty --show-duration - Duration of the show animation.
|
|
42
|
+
* @cssproperty --hide-duration - Duration of the hide animation.
|
|
43
|
+
*/
|
|
44
|
+
export declare class LuxenToast extends LuxenElement {
|
|
45
|
+
/** Use light DOM — no Shadow DOM. */
|
|
46
|
+
createRenderRoot(): this;
|
|
47
|
+
/** Position of the toast stack on the screen. */
|
|
48
|
+
placement: 'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end';
|
|
49
|
+
/** Default auto-dismiss delay in milliseconds. 0 disables auto-dismiss. */
|
|
50
|
+
duration: number;
|
|
51
|
+
/** Default variant for toast items: info, success, warning, danger. */
|
|
52
|
+
variant: string;
|
|
53
|
+
private _timers;
|
|
54
|
+
private _positionCache;
|
|
55
|
+
private _documentHidden;
|
|
56
|
+
connectedCallback(): void;
|
|
57
|
+
disconnectedCallback(): void;
|
|
58
|
+
/** Create and show a toast notification. */
|
|
59
|
+
toast(options: ToastOptions): HTMLElement;
|
|
60
|
+
private _startTimer;
|
|
61
|
+
private _pauseTimer;
|
|
62
|
+
private _resumeTimer;
|
|
63
|
+
private _hideToast;
|
|
64
|
+
private _capturePositions;
|
|
65
|
+
private _animatePositions;
|
|
66
|
+
private _onVisibilityChange;
|
|
67
|
+
private _onKeyDown;
|
|
68
|
+
}
|
|
69
|
+
/** Show a toast notification. Auto-creates `<l-toast>` if none exists in the DOM. */
|
|
70
|
+
export declare function toast(options: ToastOptions): HTMLElement;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=toast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/html/elements/toast/toast.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI1D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO;QACf,4EAA4E;QAC5E,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KACjE;CACF;AAED,yEAAyE;AACzE,qBAAa,cAAe,SAAQ,WAAW;CAAG;AAElD,UAAU,gBAAgB;IACxB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GACpB,CAAC,gBAAgB,GAAG;IAAsC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,GACvF,CAAC,gBAAgB,GAAG;IAClB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,sDAAsD,CAAC,IAAI,EAAE,MAAM,CAAC;CACrE,CAAC,CAAC;AASP;;;;;;;;;;;;;GAaG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,qCAAqC;IAC5B,gBAAgB;IAIzB,iDAAiD;IACpB,SAAS,EAClC,WAAW,GACX,YAAY,GACZ,SAAS,GACT,cAAc,GACd,eAAe,GACf,YAAY,CAAa;IAE7B,2EAA2E;IAChC,QAAQ,SAAQ;IAE3D,uEAAuE;IAC1C,OAAO,SAAM;IAE1C,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,eAAe,CAAS;IAEvB,iBAAiB;IAWjB,oBAAoB;IAM7B,4CAA4C;IAC5C,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAqLzC,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,UAAU;IAgDlB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,mBAAmB,CAQzB;IAIF,OAAO,CAAC,UAAU,CAShB;CACH;AAkBD,qFAAqF;AACrF,wBAAgB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAExD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{cls as e,tagName as t,uniqueId as n}from"../../registry.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{a as i,t as a}from"../../chunks/decorate.js";var o=class extends HTMLElement{},s=class extends r{constructor(...e){super(...e),this.placement=`top-end`,this.duration=5e3,this.variant=``,this._timers=new WeakMap,this._positionCache=new WeakMap,this._documentHidden=!1,this._onVisibilityChange=()=>{this._documentHidden=document.hidden;let e=this.querySelectorAll(`:scope > ${t(`toast-item`)}`);if(document.hidden)for(let t of e)this._pauseTimer(t);else for(let t of e)this._resumeTimer(t)},this._onKeyDown=e=>{if(e.key!==`Escape`||!this.matches(`:popover-open`))return;let n=this.querySelector(`:scope > ${t(`toast-item`)}:last-of-type`);n&&(e.preventDefault(),this._hideToast(n))}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.popover=`manual`,this.setAttribute(`role`,`log`),this.setAttribute(`aria-live`,`polite`),this.setAttribute(`aria-relevant`,`additions`),document.addEventListener(`keydown`,this._onKeyDown),document.addEventListener(`visibilitychange`,this._onVisibilityChange)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(`keydown`,this._onKeyDown),document.removeEventListener(`visibilitychange`,this._onVisibilityChange)}toast(r){let{heading:i,variant:a=this.variant,duration:o=this.duration}=r,s=n(`toast`),c=document.createElement(t(`toast-item`));if(a&&c.setAttribute(`variant`,a),c.setAttribute(`role`,a===`danger`?`alert`:`status`),c.setAttribute(`aria-atomic`,`true`),r.icon){let t=document.createElement(`iconify-icon`);t.setAttribute(`icon`,r.icon),t.setAttribute(`width`,`20`),t.setAttribute(`height`,`20`),t.setAttribute(`aria-hidden`,`true`),t.className=e(`toast-icon`),c.appendChild(t)}else{let t=document.createElement(`div`);t.className=e(`toast-accent`),t.setAttribute(`aria-hidden`,`true`),c.appendChild(t)}let l=document.createElement(`div`);l.className=e(`toast-content`);let u=document.createElement(`div`);if(i){let t=document.createElement(`div`);t.id=`${s}-heading`,t.className=`${e(`toast-heading`)} font-medium`,t.textContent=i,u.appendChild(t),c.setAttribute(`aria-labelledby`,`${s}-heading`)}let d=document.createElement(`div`);d.id=`${s}-message`,d.className=e(`toast-message`),`html`in r&&r.html?d.setHTML(r.html):d.textContent=r.text??``,u.appendChild(d),c.setAttribute(i?`aria-describedby`:`aria-labelledby`,`${s}-message`),l.appendChild(u),c.appendChild(l);let f=document.createElement(`button`);if(f.type=`button`,f.className=e(`close`),f.setAttribute(`data-appearance`,`ring`),f.setAttribute(`aria-label`,`Close`),f.addEventListener(`click`,()=>this._hideToast(c)),c.appendChild(f),r.timer&&o>0&&isFinite(o)){let t=document.createElement(`div`);t.className=e(`toast-timer`),t.setAttribute(`aria-hidden`,`true`),t.style.setProperty(`--_timer-duration`,`${o}ms`),c.appendChild(t)}if(this._capturePositions(),this.placement.includes(`bottom`)?this.appendChild(c):this.prepend(c),this.matches(`:popover-open`)||this.showPopover(),!this.emit(`show`,{cancelable:!0,detail:{toast:c}}))return c.remove(),c;requestAnimationFrame(()=>{c.setAttribute(`showing`,``),this._animatePositions();let e=t=>{t.target===c&&(c.removeEventListener(`transitionend`,e),this.emit(`after-show`,{detail:{toast:c}}))};c.addEventListener(`transitionend`,e)}),o>0&&isFinite(o)&&this._startTimer(c,o),c.addEventListener(`pointerenter`,()=>this._pauseTimer(c)),c.addEventListener(`pointerleave`,()=>this._resumeTimer(c)),c.addEventListener(`focusin`,()=>this._pauseTimer(c)),c.addEventListener(`focusout`,()=>this._resumeTimer(c));let p=null,m=!1;c.addEventListener(`pointerdown`,e=>{e.button===0&&(e.target.closest(`button, a, [role="button"]`)||(p={x:e.clientX,y:e.clientY},m=!1,c.setPointerCapture(e.pointerId),c.style.transition=`none`))});let h=e=>this.placement.endsWith(`-start`)?Math.min(e,0):this.placement.endsWith(`-end`)?Math.max(e,0):e;return c.addEventListener(`pointermove`,e=>{if(!p)return;let t=h(e.clientX-p.x),n=e.clientY-p.y,r=e.pointerType===`touch`?10:2;if(!(!m&&Math.abs(t)<r)){if(!m&&Math.abs(n)>Math.abs(t)){p=null;return}m=!0,this._pauseTimer(c),c.style.transform=`translateX(${t}px)`,c.style.opacity=`${1-Math.abs(t)/300}`}}),c.addEventListener(`pointerup`,e=>{if(!p)return;let t=h(e.clientX-p.x);if(p=null,c.style.transition=``,m&&Math.abs(t)>50){let e=t>0?1:-1;c.style.transform=`translateX(${e*120}%)`,c.style.opacity=`0`,c.addEventListener(`transitionend`,()=>this._hideToast(c),{once:!0})}else c.style.transform=``,c.style.opacity=``,m&&this._resumeTimer(c);m=!1}),c}_startTimer(e,t){let n=window.setTimeout(()=>this._hideToast(e),t);this._timers.set(e,{remaining:t,startTime:performance.now(),timeoutId:n,paused:!1})}_pauseTimer(t){let n=this._timers.get(t);if(!n||n.paused)return;clearTimeout(n.timeoutId),n.remaining-=performance.now()-n.startTime,n.paused=!0;let r=t.querySelector(`.${e(`toast-timer`)}`);if(r)for(let e of r.getAnimations())e.pause()}_resumeTimer(t){let n=this._timers.get(t);if(!n||!n.paused||n.remaining<=0||this._documentHidden)return;n.startTime=performance.now(),n.timeoutId=window.setTimeout(()=>this._hideToast(t),n.remaining),n.paused=!1;let r=t.querySelector(`.${e(`toast-timer`)}`);if(r)for(let e of r.getAnimations())e.play()}_hideToast(e){let n=this._timers.get(e);if(n&&(clearTimeout(n.timeoutId),this._timers.delete(e)),!e.hasAttribute(`showing`)||!this.emit(`hide`,{cancelable:!0,detail:{toast:e}}))return;this._capturePositions(),e.removeAttribute(`showing`);let r=()=>{e.remove(),this._animatePositions(),this.emit(`after-hide`,{detail:{toast:e}}),this.querySelectorAll(`:scope > ${t(`toast-item`)}`).length===0&&this.matches(`:popover-open`)&&this.hidePopover()};if(parseFloat(getComputedStyle(e).transitionDuration)===0)r();else{let t=n=>{n.target===e&&(e.removeEventListener(`transitionend`,t),r())};e.addEventListener(`transitionend`,t)}}_capturePositions(){let e=this.querySelectorAll(`:scope > ${t(`toast-item`)}`);for(let t of e)this._positionCache.set(t,t.getBoundingClientRect())}_animatePositions(){if(window.matchMedia(`(prefers-reduced-motion: reduce)`).matches)return;let e=this.querySelectorAll(`:scope > ${t(`toast-item`)}`);for(let t of e){let e=this._positionCache.get(t);if(!e)continue;let n=t.getBoundingClientRect(),r=e.top-n.top;Math.abs(r)<1||t.animate([{transform:`translateY(${r}px)`},{transform:`translateY(0)`}],{duration:200,easing:`cubic-bezier(0.2, 0, 0, 1)`})}}};a([i({reflect:!0})],s.prototype,`placement`,void 0),a([i({type:Number,reflect:!0})],s.prototype,`duration`,void 0),a([i({reflect:!0})],s.prototype,`variant`,void 0);export{s as LuxenToast,o as LuxenToastItem};
|
|
2
|
+
//# sourceMappingURL=toast.js.map
|