luxen-ui 0.24.0 → 0.26.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/README.md +1 -0
- package/bin/cli.mjs +16 -1
- package/cdn/custom-elements.json +295 -169
- package/cdn/elements/alert-dialog/alert-dialog.d.ts +3 -2
- package/cdn/elements/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/cdn/elements/alert-dialog/alert-dialog.js.map +1 -1
- package/cdn/elements/avatar/avatar.js +1 -1
- package/cdn/elements/avatar/avatar.js.map +1 -1
- package/cdn/elements/carousel/carousel.js +1 -1
- package/cdn/elements/carousel/carousel.js.map +1 -1
- package/cdn/elements/combobox/combobox.d.ts.map +1 -1
- package/cdn/elements/combobox/combobox.js +2 -1
- package/cdn/elements/combobox/combobox.js.map +1 -1
- package/cdn/elements/dialog/dialog.d.ts +2 -1
- package/cdn/elements/dialog/dialog.d.ts.map +1 -1
- package/cdn/elements/dialog/dialog.js.map +1 -1
- package/cdn/elements/dialog/dialog.styles.js +1 -1
- package/cdn/elements/dialog/dialog.styles.js.map +1 -1
- package/cdn/elements/drawer/drawer.d.ts +7 -7
- package/cdn/elements/drawer/drawer.js +1 -1
- package/cdn/elements/drawer/drawer.js.map +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
- package/cdn/elements/input-otp/input-otp.d.ts +2 -2
- package/cdn/elements/input-otp/input-otp.js.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.js +1 -1
- package/cdn/elements/prose-editor/prose-editor.js.map +1 -1
- package/cdn/elements/rating/rating.js +1 -1
- package/cdn/elements/rating/rating.js.map +1 -1
- package/cdn/elements/select/select.d.ts.map +1 -1
- package/cdn/elements/select/select.js +2 -1
- package/cdn/elements/select/select.js.map +1 -1
- package/cdn/elements/slider/slider.js +1 -1
- package/cdn/elements/slider/slider.js.map +1 -1
- package/cdn/elements/stories-viewer/stories-viewer.js +1 -1
- package/cdn/elements/stories-viewer/stories-viewer.js.map +1 -1
- package/cdn/elements/table/table.meta.d.ts +55 -0
- package/cdn/elements/table/table.meta.d.ts.map +1 -0
- package/cdn/elements/table/table.meta.js +0 -0
- package/cdn/elements/tag/tag.js +1 -1
- package/cdn/elements/tag/tag.js.map +1 -1
- package/cdn/elements/tree/tree.js +1 -1
- package/cdn/elements/tree/tree.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +1 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/shared/controllers/listbox-nav.d.ts +7 -0
- package/cdn/shared/controllers/listbox-nav.d.ts.map +1 -1
- package/cdn/shared/controllers/listbox-nav.js +1 -1
- package/cdn/shared/controllers/listbox-nav.js.map +1 -1
- package/cdn/shared/styles/button-core.styles.js +1 -1
- package/cdn/shared/styles/button-core.styles.js.map +1 -1
- package/cdn/shared/styles/checkbox-appearance.styles.js +1 -1
- package/cdn/shared/styles/checkbox-appearance.styles.js.map +1 -1
- package/cdn/shared/styles/picker-core.styles.js +1 -1
- package/cdn/shared/styles/picker-core.styles.js.map +1 -1
- package/cdn/standalone.css +392 -86
- package/cdn/standalone.js +38 -28
- package/cdn/standalone.js.map +1 -1
- package/cdn/styles/base.css +11 -0
- package/cdn/styles/elements/breadcrumb.css +2 -2
- package/cdn/styles/elements/button.css +2 -2
- package/cdn/styles/elements/checkbox.css +2 -2
- package/cdn/styles/elements/close-button/circle.css +2 -2
- package/cdn/styles/elements/close-button/ring.css +2 -2
- package/cdn/styles/elements/close-button/square.css +2 -2
- package/cdn/styles/elements/disclosure.css +2 -2
- package/cdn/styles/elements/input-otp.css +20 -4
- package/cdn/styles/elements/input-stepper/default.css +2 -2
- package/cdn/styles/elements/input-stepper/pill.css +2 -2
- package/cdn/styles/elements/input-stepper/rounded.css +2 -2
- package/cdn/styles/elements/input.css +50 -17
- package/cdn/styles/elements/prose-editor.css +26 -11
- package/cdn/styles/elements/radio-group.css +2 -2
- package/cdn/styles/elements/radio.css +2 -2
- package/cdn/styles/elements/segmented-control.css +2 -2
- package/cdn/styles/elements/select.css +26 -5
- package/cdn/styles/elements/story.css +2 -2
- package/cdn/styles/elements/switch.css +2 -2
- package/cdn/styles/elements/table.css +186 -0
- package/cdn/styles/elements/tabs/enclosed.css +4 -4
- package/cdn/styles/elements/tabs/line.css +4 -4
- package/cdn/styles/elements/textarea.css +23 -9
- package/cdn/styles/preset.css +21 -2
- package/cdn/styles/tokens/aliases.css +6 -2
- package/cdn/styles/tokens/forms.css +4 -0
- package/cdn/styles/tokens.css +10 -2
- package/dist/css/base.css +11 -0
- package/dist/css/elements/breadcrumb.css +2 -2
- package/dist/css/elements/button.css +2 -2
- package/dist/css/elements/checkbox.css +2 -2
- package/dist/css/elements/close-button/circle.css +2 -2
- package/dist/css/elements/close-button/ring.css +2 -2
- package/dist/css/elements/close-button/square.css +2 -2
- package/dist/css/elements/disclosure.css +2 -2
- package/dist/css/elements/input-otp.css +20 -4
- package/dist/css/elements/input-stepper/default.css +2 -2
- package/dist/css/elements/input-stepper/pill.css +2 -2
- package/dist/css/elements/input-stepper/rounded.css +2 -2
- package/dist/css/elements/input.css +50 -17
- package/dist/css/elements/prose-editor.css +26 -11
- package/dist/css/elements/radio-group.css +2 -2
- package/dist/css/elements/radio.css +2 -2
- package/dist/css/elements/segmented-control.css +2 -2
- package/dist/css/elements/select.css +26 -5
- package/dist/css/elements/story.css +2 -2
- package/dist/css/elements/switch.css +2 -2
- package/dist/css/elements/table.css +186 -0
- package/dist/css/elements/tabs/enclosed.css +4 -4
- package/dist/css/elements/tabs/line.css +4 -4
- package/dist/css/elements/textarea.css +23 -9
- package/dist/css/preset.css +21 -2
- package/dist/css/tokens/aliases.css +6 -2
- package/dist/css/tokens/forms.css +4 -0
- package/dist/css/tokens.css +10 -2
- package/dist/custom-elements.json +295 -169
- package/dist/elements/alert-dialog/alert-dialog.d.ts +3 -2
- package/dist/elements/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/dist/elements/alert-dialog/alert-dialog.js +3 -2
- package/dist/elements/avatar/avatar.css +2 -2
- package/dist/elements/carousel/carousel.css +18 -0
- package/dist/elements/combobox/combobox.css +9 -0
- package/dist/elements/combobox/combobox.d.ts.map +1 -1
- package/dist/elements/combobox/combobox.js +1 -0
- package/dist/elements/dialog/dialog.css +12 -0
- package/dist/elements/dialog/dialog.d.ts +2 -1
- package/dist/elements/dialog/dialog.d.ts.map +1 -1
- package/dist/elements/dialog/dialog.js +2 -1
- package/dist/elements/drawer/drawer.css +11 -1
- package/dist/elements/drawer/drawer.d.ts +7 -7
- package/dist/elements/drawer/drawer.js +7 -7
- package/dist/elements/dropdown-item/dropdown-item.css +5 -4
- package/dist/elements/input-otp/input-otp.d.ts +2 -2
- package/dist/elements/input-otp/input-otp.js +2 -2
- package/dist/elements/prose-editor/prose-editor.css +5 -3
- package/dist/elements/rating/rating.css +9 -10
- package/dist/elements/select/select.css +10 -9
- package/dist/elements/select/select.d.ts.map +1 -1
- package/dist/elements/select/select.js +1 -0
- package/dist/elements/slider/slider.css +5 -1
- package/dist/elements/stories-viewer/stories-viewer.css +10 -2
- package/dist/elements/table/table.meta.d.ts +55 -0
- package/dist/elements/table/table.meta.d.ts.map +1 -0
- package/dist/elements/table/table.meta.js +65 -0
- package/dist/elements/tag/tag.css +4 -4
- package/dist/elements/tree/tree.css +3 -3
- package/dist/elements/tree-item/tree-item.css +5 -3
- package/dist/metadata/alert-dialog.json +90 -85
- package/dist/metadata/alert.json +22 -22
- package/dist/metadata/avatar.json +26 -26
- package/dist/metadata/badge.json +13 -13
- package/dist/metadata/breadcrumb.json +9 -9
- package/dist/metadata/button.json +40 -40
- package/dist/metadata/carousel.json +133 -133
- package/dist/metadata/checkbox.json +13 -13
- package/dist/metadata/close-button.json +15 -15
- package/dist/metadata/color-scheme-icon.json +13 -13
- package/dist/metadata/combobox.json +77 -94
- package/dist/metadata/dialog.json +49 -44
- package/dist/metadata/disclosure.json +17 -17
- package/dist/metadata/divider.json +12 -12
- package/dist/metadata/drawer.json +61 -61
- package/dist/metadata/dropdown-item.json +50 -50
- package/dist/metadata/dropdown.json +32 -32
- package/dist/metadata/form-field.json +15 -15
- package/dist/metadata/icon.json +8 -8
- package/dist/metadata/index.json +1761 -1765
- package/dist/metadata/input-group.json +5 -5
- package/dist/metadata/input-otp.json +17 -17
- package/dist/metadata/input-stepper.json +24 -24
- package/dist/metadata/input.json +31 -31
- package/dist/metadata/popover.json +49 -49
- package/dist/metadata/progress.json +15 -15
- package/dist/metadata/prose-editor.json +110 -116
- package/dist/metadata/radio.json +15 -15
- package/dist/metadata/rating.json +25 -47
- package/dist/metadata/segmented-control.json +24 -46
- package/dist/metadata/select.json +81 -98
- package/dist/metadata/skeleton.json +12 -12
- package/dist/metadata/slider.json +60 -78
- package/dist/metadata/spinner.json +5 -5
- package/dist/metadata/sticky-bar.json +13 -13
- package/dist/metadata/stories-viewer.json +105 -105
- package/dist/metadata/stories.json +17 -17
- package/dist/metadata/story.json +41 -41
- package/dist/metadata/switch.json +9 -9
- package/dist/metadata/table.json +88 -0
- package/dist/metadata/tabs.json +26 -26
- package/dist/metadata/tag.json +50 -50
- package/dist/metadata/textarea.json +28 -28
- package/dist/metadata/toast.json +16 -16
- package/dist/metadata/tooltip.json +49 -49
- package/dist/metadata/tree-item.json +73 -73
- package/dist/metadata/tree.json +39 -39
- package/dist/shared/controllers/listbox-nav.d.ts +7 -0
- package/dist/shared/controllers/listbox-nav.d.ts.map +1 -1
- package/dist/shared/controllers/listbox-nav.js +12 -0
- package/dist/shared/styles/button-core.css +2 -2
- package/dist/shared/styles/checkbox-appearance.css +2 -2
- package/dist/shared/styles/picker-core.css +31 -7
- package/dist/templates/elements/alert-dialog.md +19 -18
- package/dist/templates/elements/alert.md +4 -4
- package/dist/templates/elements/avatar.md +9 -9
- package/dist/templates/elements/badge.md +4 -4
- package/dist/templates/elements/breadcrumb.md +4 -4
- package/dist/templates/elements/button.md +8 -8
- package/dist/templates/elements/carousel.md +32 -32
- package/dist/templates/elements/checkbox.md +4 -4
- package/dist/templates/elements/close-button.md +2 -2
- package/dist/templates/elements/color-scheme-icon.md +13 -13
- package/dist/templates/elements/combobox.md +19 -19
- package/dist/templates/elements/dialog.md +11 -10
- package/dist/templates/elements/disclosure.md +3 -3
- package/dist/templates/elements/divider.md +2 -2
- package/dist/templates/elements/drawer.md +15 -15
- package/dist/templates/elements/dropdown.md +15 -15
- package/dist/templates/elements/form-field.md +3 -3
- package/dist/templates/elements/icon.md +1 -1
- package/dist/templates/elements/input-otp.md +5 -5
- package/dist/templates/elements/input-stepper.md +4 -4
- package/dist/templates/elements/input.md +15 -8
- package/dist/templates/elements/popover.md +8 -8
- package/dist/templates/elements/progress.md +3 -3
- package/dist/templates/elements/prose-editor.md +38 -39
- package/dist/templates/elements/radio.md +6 -6
- package/dist/templates/elements/rating.md +5 -13
- package/dist/templates/elements/segmented-control.md +4 -4
- package/dist/templates/elements/select.md +23 -23
- package/dist/templates/elements/skeleton.md +2 -2
- package/dist/templates/elements/slider.md +13 -13
- package/dist/templates/elements/spinner.md +1 -1
- package/dist/templates/elements/sticky-bar.md +2 -2
- package/dist/templates/elements/stories-viewer.md +29 -29
- package/dist/templates/elements/stories.md +4 -4
- package/dist/templates/elements/story.md +11 -11
- package/dist/templates/elements/switch.md +5 -5
- package/dist/templates/elements/table.md +210 -0
- package/dist/templates/elements/tabs.md +4 -4
- package/dist/templates/elements/tag.md +14 -14
- package/dist/templates/elements/textarea.md +8 -8
- package/dist/templates/elements/toast.md +4 -4
- package/dist/templates/elements/tooltip.md +9 -9
- package/dist/templates/elements/tree-item.md +18 -18
- package/dist/templates/elements/tree.md +13 -13
- package/dist/templates/foundations/focus.md +303 -0
- package/elements.json +9 -0
- package/package.json +1 -1
- package/postcss-plugin-prefix.js +2 -2
- package/templates/SKILL.md.tpl +1 -0
- package/templates/choosing-elements.md.tpl +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/html/elements/combobox/combobox.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/html/elements/combobox/combobox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"../../chunks/lit.js";import{n as t,r as n,t as r}from"../../chunks/decorate.js";import{t as i}from"../../chunks/unsafe-html.js";import{a,t as o}from"../../chunks/lit-html.js";import{LuxenFormAssociatedElement as s}from"../../shared/luxen-form-associated-element.js";import{PopoverController as c}from"../../shared/controllers/popover.js";import{ListboxNavController as l}from"../../shared/controllers/listbox-nav.js";import{DatalistObserverController as u}from"../../shared/controllers/datalist-observer.js";import{LocalizeController as d}from"../../shared/localize.js";import{RichHighlighter as f,highlightText as p,normalize as m}from"../../shared/highlight.js";import{cls as h,uniqueId as g}from"../../registry.js";import{adoptRichContentStyles as _,richOptionLabel as v}from"../../shared/rich-option.js";import y from"../../shared/styles/host.styles.js";import b from"../../shared/styles/visually-hidden.styles.js";import x from"../../shared/styles/select-item-suffix.styles.js";import S from"../../shared/styles/picker-core.styles.js";var C=e(`.control{block-size:var(--height);cursor:text;gap:.25rem}.input{min-inline-size:0;color:var(--l-form-control-value-color);font:inherit;background:0 0;border:0;outline:none;flex:1}.input::placeholder{color:var(--l-form-control-placeholder-color)}.actions{flex:none;align-self:stretch;align-items:center;display:flex}.chevron{cursor:pointer}@media (hover:hover){.chevron:hover{color:var(--l-form-control-value-color)}}.option{align-items:center;gap:var(--l-menu-item-gap);min-block-size:var(--l-menu-item-min-height);padding-block:var(--l-menu-item-padding-block);padding-inline:var(--l-menu-item-padding-inline) calc(var(--l-menu-item-padding-inline) + 1.5rem);border-radius:var(--l-menu-item-border-radius);color:var(--l-color-text-primary);cursor:pointer;display:flex;position:relative}.option[aria-selected=true]{background-color:var(--l-color-bg-state-hover)}.option[data-current]:after{content:"";background-color:var(--l-form-control-activated-color);block-size:1em;inline-size:1em;-webkit-mask:var(--_check-icon) center / contain no-repeat;mask:var(--_check-icon) center / contain no-repeat;position:absolute;inset-inline-end:.5rem}.option .l-select-item-media{flex:none;align-items:center;font-size:1.25em;display:inline-flex}.option .l-select-item-text{flex-direction:column;min-inline-size:0;display:flex}.option .l-select-item-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.option .l-select-item-description{color:var(--l-color-text-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:.85em;overflow:hidden}`),w=(e,t)=>{if(!t)return!0;let n=m(e.label);return m(t).split(/\s+/).filter(Boolean).every(e=>n.includes(e))},T=class extends Event{constructor(e){super(`change`,{bubbles:!0,composed:!1,cancelable:!1}),this.value=e}},E=class extends Event{constructor(e){super(`input`,{bubbles:!0,composed:!1,cancelable:!1}),this.value=e}},D=class extends s{constructor(...e){super(...e),this._localize=new d(this),this._listId=g(`combobox-list`),this._richHighlighter=new f,this._floating=new c(this,{getTriggerElement:()=>this._controlEl,getFloatingElement:()=>this._panelEl,getArrowElement:()=>null}),this._nav=new l(this,{listboxId:this._listId,getCount:()=>this._filtered.length,isDisabled:e=>this._filtered[e]?.disabled??!1,isOpen:()=>this._open,open:()=>this.show(),getOptionElements:()=>this.shadowRoot?.querySelectorAll(`.option`)}),this._options=new u(this,()=>this._syncItems()),this.#e=``,this.#t=``,this.#n=``,this.#r=`md`,this.#i=!1,this.#a=!1,this.#o=!0,this.#s=`bottom-start`,this.filter=w,this.#c=!1,this.#l=``,this.#u=[],this._onKeyDown=e=>{if(!this._nav.onKeyDown(e))switch(e.key){case`Enter`:this._open&&(e.preventDefault(),this._commitActiveOrCustom());break;case`Escape`:this._open?(e.preventDefault(),this.hide()):(this.value||this._inputEl?.value)&&this._clear();break;case`Tab`:this._open&&this._nav.activeIndex>=0&&this._commitActiveOrCustom()}},this._onInput=e=>{this._query=e.target.value,this._nav.reset(),this._open||this.show(),this.dispatchEvent(new E(this._query))},this._onControlPointerDown=e=>{e.target.closest(`.clear-button`)||(e.target!==this._inputEl&&(e.preventDefault(),this._inputEl?.focus()),this._open?e.target.closest(`.chevron`)&&this.hide():this.show())},this._onFocusOut=e=>{let t=e.relatedTarget;t&&this.shadowRoot?.contains(t)||(this.hasInteracted=!0,this._updateValidity(),this.hide())}}static{this.styles=[y,b,x,S,C]}#e;get value(){return this.#e}set value(e){this.#e=e}#t;get placeholder(){return this.#t}set placeholder(e){this.#t=e}#n;get label(){return this.#n}set label(e){this.#n=e}#r;get size(){return this.#r}set size(e){this.#r=e}#i;get withClear(){return this.#i}set withClear(e){this.#i=e}#a;get allowCustom(){return this.#a}set allowCustom(e){this.#a=e}#o;get highlight(){return this.#o}set highlight(e){this.#o=e}#s;get placement(){return this.#s}set placement(e){this.#s=e}#c;get _open(){return this.#c}set _open(e){this.#c=e}#l;get _query(){return this.#l}set _query(e){this.#l=e}#u;get _items(){return this.#u}set _items(e){this.#u=e}get _controlEl(){return this.shadowRoot?.querySelector(`.control`)??null}get _panelEl(){return this.shadowRoot?.querySelector(`.panel`)??null}get _inputEl(){return this.shadowRoot?.querySelector(`.input`)??null}connectedCallback(){super.connectedCallback(),this._syncItems(),this._defaultFormValue=this.value,this._syncFormValue(this.value)}updated(e){e.has(`value`)&&(this._syncFormValue(this.value),this._updateValidity(),this._open||this._resetDisplay())}formResetCallback(){this.value=this._defaultFormValue,this._query=``,this._nav.reset(),super.formResetCallback(),this._resetDisplay()}formStateRestoreCallback(e){this.value=e,this._syncFormValue(e)}_readItems(){let e=this.querySelector(`datalist`),t=e?Array.from(e.options):[];this._items=t.map(e=>{let t=e.childElementCount>0,n=v(e);return{value:e.value,label:n,disabled:e.disabled,html:t?e.innerHTML:void 0}}),_(this.shadowRoot,this._items)}_syncItems(){let e=this._open?this._filtered[this._nav.activeIndex]:void 0,t=this._inputEl?.value,n=t===void 0||t===this._labelForValue(this.value);this._readItems(),this._open?this._nav.setActive(e?this._filtered.findIndex(t=>t.value===e.value):-1):n&&this._resetDisplay()}_labelForValue(e){return this._items.find(t=>t.value===e)?.label??(this.allowCustom?e:``)}get _filtered(){return this._items.filter(e=>this.filter(e,this._query))}_resetDisplay(){let e=this._inputEl;e&&(e.value=this._labelForValue(this.value))}_updateValidity(){this.required&&!this.value?this.setValidity({valueMissing:!0},this._localize.term(`selectOption`),this._inputEl??void 0):this.setValidity({})}show(){this._open||this.disabled||(this._readItems(),this.dispatchEvent(new Event(`show`,{cancelable:!0}))&&(this._open=!0,this.value&&!this._query&&this._nav.setActive(this._filtered.findIndex(e=>e.value===this.value)),this.updateComplete.then(()=>{this._panelEl?.showPopover?.(),this._floating.startPositioning({placement:this.placement,distance:4,minWidth:`trigger`})})))}hide(){if(!this._open||!this.dispatchEvent(new Event(`hide`,{cancelable:!0})))return;this._open=!1,this._nav.reset();let e=this._panelEl;e?.matches?.(`:popover-open`)&&e.hidePopover?.(),this._floating.stopPositioning(),this._resetDisplay()}_commit(e){if(e.disabled)return;this.value=e.value,this._query=``,this.hasInteracted=!0;let t=this._inputEl;t&&(t.value=e.label),this._syncFormValue(this.value),this._updateValidity(),this.dispatchEvent(new T(this.value)),this.hide(),t?.focus()}_commitActiveOrCustom(){let e=this._filtered,t=this._nav.activeIndex;if(t>=0&&e[t]){this._commit(e[t]);return}let n=this._inputEl;this.allowCustom&&n&&(this.value=n.value,this._syncFormValue(this.value),this._updateValidity(),this.dispatchEvent(new T(this.value)),this.hide())}_clear(){this.value=``,this._query=``,this._nav.reset(),this._inputEl&&(this._inputEl.value=``),this._syncFormValue(``),this._updateValidity(),this.dispatchEvent(new T(``)),this._inputEl?.focus()}_highlight(e){return this.highlight?p(e,this._query):e}_highlightRich(e){return this.highlight?this._richHighlighter.highlight(e,this._query):e}render(){let e=this._filtered,t=this._nav.activeDescendant,n=this._nav.activeIndex,r=this.required&&!this.value&&this.hasInteracted,s=this._open?e.length===0?this._localize.term(`noResults`):`${e.length} ${this._localize.term(`suggestions`)}`:``;return a`
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{n as t,r as n,t as r}from"../../chunks/decorate.js";import{t as i}from"../../chunks/unsafe-html.js";import{a,t as o}from"../../chunks/lit-html.js";import{LuxenFormAssociatedElement as s}from"../../shared/luxen-form-associated-element.js";import{PopoverController as c}from"../../shared/controllers/popover.js";import{ListboxNavController as l}from"../../shared/controllers/listbox-nav.js";import{DatalistObserverController as u}from"../../shared/controllers/datalist-observer.js";import{LocalizeController as d}from"../../shared/localize.js";import{RichHighlighter as f,highlightText as p,normalize as m}from"../../shared/highlight.js";import{cls as h,uniqueId as g}from"../../registry.js";import{adoptRichContentStyles as _,richOptionLabel as v}from"../../shared/rich-option.js";import y from"../../shared/styles/host.styles.js";import b from"../../shared/styles/visually-hidden.styles.js";import x from"../../shared/styles/select-item-suffix.styles.js";import S from"../../shared/styles/picker-core.styles.js";var C=e(`.control{block-size:var(--height);cursor:text;gap:.25rem}.input{min-inline-size:0;color:var(--l-form-control-value-color);font:inherit;background:0 0;border:0;outline:none;flex:1}.input::placeholder{color:var(--l-form-control-placeholder-color)}.actions{flex:none;align-self:stretch;align-items:center;display:flex}.chevron{cursor:pointer}@media (hover:hover){.chevron:hover{color:var(--l-form-control-value-color)}}.option{align-items:center;gap:var(--l-menu-item-gap);min-block-size:var(--l-menu-item-min-height);padding-block:var(--l-menu-item-padding-block);padding-inline:var(--l-menu-item-padding-inline) calc(var(--l-menu-item-padding-inline) + 1.5rem);border-radius:var(--l-menu-item-border-radius);color:var(--l-color-text-primary);cursor:pointer;display:flex;position:relative}.option[aria-selected=true]{background-color:var(--l-color-bg-state-hover)}.listbox[data-nav=keyboard] .option[aria-selected=true]{outline:var(--l-focus-ring-width) solid var(--l-focus-ring-color);outline-offset:calc(var(--l-focus-ring-width) * -1)}.option[data-current]:after{content:"";background-color:var(--l-form-control-activated-color);block-size:1em;inline-size:1em;-webkit-mask:var(--_check-icon) center / contain no-repeat;mask:var(--_check-icon) center / contain no-repeat;position:absolute;inset-inline-end:.5rem}.option .l-select-item-media{flex:none;align-items:center;font-size:1.25em;display:inline-flex}.option .l-select-item-text{flex-direction:column;min-inline-size:0;display:flex}.option .l-select-item-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.option .l-select-item-description{color:var(--l-color-text-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:.85em;overflow:hidden}`),w=(e,t)=>{if(!t)return!0;let n=m(e.label);return m(t).split(/\s+/).filter(Boolean).every(e=>n.includes(e))},T=class extends Event{constructor(e){super(`change`,{bubbles:!0,composed:!1,cancelable:!1}),this.value=e}},E=class extends Event{constructor(e){super(`input`,{bubbles:!0,composed:!1,cancelable:!1}),this.value=e}},D=class extends s{constructor(...e){super(...e),this._localize=new d(this),this._listId=g(`combobox-list`),this._richHighlighter=new f,this._floating=new c(this,{getTriggerElement:()=>this._controlEl,getFloatingElement:()=>this._panelEl,getArrowElement:()=>null}),this._nav=new l(this,{listboxId:this._listId,getCount:()=>this._filtered.length,isDisabled:e=>this._filtered[e]?.disabled??!1,isOpen:()=>this._open,open:()=>this.show(),getOptionElements:()=>this.shadowRoot?.querySelectorAll(`.option`)}),this._options=new u(this,()=>this._syncItems()),this.#e=``,this.#t=``,this.#n=``,this.#r=`md`,this.#i=!1,this.#a=!1,this.#o=!0,this.#s=`bottom-start`,this.filter=w,this.#c=!1,this.#l=``,this.#u=[],this._onKeyDown=e=>{if(!this._nav.onKeyDown(e))switch(e.key){case`Enter`:this._open&&(e.preventDefault(),this._commitActiveOrCustom());break;case`Escape`:this._open?(e.preventDefault(),this.hide()):(this.value||this._inputEl?.value)&&this._clear();break;case`Tab`:this._open&&this._nav.activeIndex>=0&&this._commitActiveOrCustom()}},this._onInput=e=>{this._query=e.target.value,this._nav.reset(),this._open||this.show(),this.dispatchEvent(new E(this._query))},this._onControlPointerDown=e=>{e.target.closest(`.clear-button`)||(e.target!==this._inputEl&&(e.preventDefault(),this._inputEl?.focus()),this._open?e.target.closest(`.chevron`)&&this.hide():this.show())},this._onFocusOut=e=>{let t=e.relatedTarget;t&&this.shadowRoot?.contains(t)||(this.hasInteracted=!0,this._updateValidity(),this.hide())}}static{this.styles=[y,b,x,S,C]}#e;get value(){return this.#e}set value(e){this.#e=e}#t;get placeholder(){return this.#t}set placeholder(e){this.#t=e}#n;get label(){return this.#n}set label(e){this.#n=e}#r;get size(){return this.#r}set size(e){this.#r=e}#i;get withClear(){return this.#i}set withClear(e){this.#i=e}#a;get allowCustom(){return this.#a}set allowCustom(e){this.#a=e}#o;get highlight(){return this.#o}set highlight(e){this.#o=e}#s;get placement(){return this.#s}set placement(e){this.#s=e}#c;get _open(){return this.#c}set _open(e){this.#c=e}#l;get _query(){return this.#l}set _query(e){this.#l=e}#u;get _items(){return this.#u}set _items(e){this.#u=e}get _controlEl(){return this.shadowRoot?.querySelector(`.control`)??null}get _panelEl(){return this.shadowRoot?.querySelector(`.panel`)??null}get _inputEl(){return this.shadowRoot?.querySelector(`.input`)??null}connectedCallback(){super.connectedCallback(),this._syncItems(),this._defaultFormValue=this.value,this._syncFormValue(this.value)}updated(e){e.has(`value`)&&(this._syncFormValue(this.value),this._updateValidity(),this._open||this._resetDisplay())}formResetCallback(){this.value=this._defaultFormValue,this._query=``,this._nav.reset(),super.formResetCallback(),this._resetDisplay()}formStateRestoreCallback(e){this.value=e,this._syncFormValue(e)}_readItems(){let e=this.querySelector(`datalist`),t=e?Array.from(e.options):[];this._items=t.map(e=>{let t=e.childElementCount>0,n=v(e);return{value:e.value,label:n,disabled:e.disabled,html:t?e.innerHTML:void 0}}),_(this.shadowRoot,this._items)}_syncItems(){let e=this._open?this._filtered[this._nav.activeIndex]:void 0,t=this._inputEl?.value,n=t===void 0||t===this._labelForValue(this.value);this._readItems(),this._open?this._nav.setActive(e?this._filtered.findIndex(t=>t.value===e.value):-1):n&&this._resetDisplay()}_labelForValue(e){return this._items.find(t=>t.value===e)?.label??(this.allowCustom?e:``)}get _filtered(){return this._items.filter(e=>this.filter(e,this._query))}_resetDisplay(){let e=this._inputEl;e&&(e.value=this._labelForValue(this.value))}_updateValidity(){this.required&&!this.value?this.setValidity({valueMissing:!0},this._localize.term(`selectOption`),this._inputEl??void 0):this.setValidity({})}show(){this._open||this.disabled||(this._readItems(),this.dispatchEvent(new Event(`show`,{cancelable:!0}))&&(this._open=!0,this.value&&!this._query&&this._nav.setActive(this._filtered.findIndex(e=>e.value===this.value)),this.updateComplete.then(()=>{this._panelEl?.showPopover?.(),this._floating.startPositioning({placement:this.placement,distance:4,minWidth:`trigger`})})))}hide(){if(!this._open||!this.dispatchEvent(new Event(`hide`,{cancelable:!0})))return;this._open=!1,this._nav.reset();let e=this._panelEl;e?.matches?.(`:popover-open`)&&e.hidePopover?.(),this._floating.stopPositioning(),this._resetDisplay()}_commit(e){if(e.disabled)return;this.value=e.value,this._query=``,this.hasInteracted=!0;let t=this._inputEl;t&&(t.value=e.label),this._syncFormValue(this.value),this._updateValidity(),this.dispatchEvent(new T(this.value)),this.hide(),t?.focus()}_commitActiveOrCustom(){let e=this._filtered,t=this._nav.activeIndex;if(t>=0&&e[t]){this._commit(e[t]);return}let n=this._inputEl;this.allowCustom&&n&&(this.value=n.value,this._syncFormValue(this.value),this._updateValidity(),this.dispatchEvent(new T(this.value)),this.hide())}_clear(){this.value=``,this._query=``,this._nav.reset(),this._inputEl&&(this._inputEl.value=``),this._syncFormValue(``),this._updateValidity(),this.dispatchEvent(new T(``)),this._inputEl?.focus()}_highlight(e){return this.highlight?p(e,this._query):e}_highlightRich(e){return this.highlight?this._richHighlighter.highlight(e,this._query):e}render(){let e=this._filtered,t=this._nav.activeDescendant,n=this._nav.activeIndex,r=this.required&&!this.value&&this.hasInteracted,s=this._open?e.length===0?this._localize.term(`noResults`):`${e.length} ${this._localize.term(`suggestions`)}`:``;return a`
|
|
2
2
|
<div
|
|
3
3
|
class="base"
|
|
4
4
|
part="base"
|
|
@@ -56,6 +56,7 @@ import{i as e}from"../../chunks/lit.js";import{n as t,r as n,t as r}from"../../c
|
|
|
56
56
|
role="listbox"
|
|
57
57
|
id=${this._listId}
|
|
58
58
|
aria-label=${this.label||this._localize.term(`suggestions`)}
|
|
59
|
+
data-nav=${this._nav.keyboard?`keyboard`:`pointer`}
|
|
59
60
|
@pointermove=${this._nav.onPointerMove}
|
|
60
61
|
@pointerleave=${this._nav.onPointerLeave}
|
|
61
62
|
>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":["unsafeCSS","rawStyles","hostStyles","visuallyHiddenStyles","suffixStyles","pickerCoreStyles","nothing","unsafeHTML","_decorate","property","state","r","r$1","__decorate","o","A","host_styles_default","visually_hidden_styles_default","select_item_suffix_styles_default","picker_core_styles_default","styles","defaultFilter","query","label","normalize","item","kw","ComboboxChangeEvent","value","ComboboxInputEvent","Combobox","LuxenFormAssociatedElement","_args","LocalizeController","uniqueId","RichHighlighter","PopoverController","ListboxNavController","i","DatalistObserverController","#_value_accessor_storage","#_placeholder_accessor_storage","#_label_accessor_storage","#_size_accessor_storage","#_withClear_accessor_storage","#_allowCustom_accessor_storage","#_highlight_accessor_storage","#_placement_accessor_storage","#__open_accessor_storage","#__query_accessor_storage","#__items_accessor_storage","next","changed","state","list","opts","rich","richOptionLabel","adoptRichContentStyles","active","displayed","untouched","input","panel","filtered","highlightText","markup","activeId","activeIndex","invalid","status","cls"],"sources":["../../../src/html/elements/combobox/combobox.css?inline","../../../src/html/elements/combobox/combobox.ts"],"sourcesContent":["/* Knobs, size scale, field frame, chevron, clear, listbox popover and the\n shared option bits come from shared/styles/picker-core.css (loaded first).\n This file holds what is specific to the editable combobox. */\n\n/*\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n 🅲🅾🅽🆃🆁🅾🅻 (trigger)\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n*/\n\n.control {\n gap: 0.25rem;\n block-size: var(--height);\n cursor: text;\n}\n\n.input {\n flex: 1;\n min-inline-size: 0;\n border: 0;\n background: transparent;\n color: var(--l-form-control-value-color);\n font: inherit;\n outline: none;\n}\n\n.input::placeholder {\n color: var(--l-form-control-placeholder-color);\n}\n\n/* The clear button and the chevron sit side by side, square against square —\n the row's gap only separates them from the input. */\n.actions {\n flex: none;\n display: flex;\n align-self: stretch;\n align-items: center;\n}\n\n/* The chevron toggles the list (see _onControlPointerDown). */\n.chevron {\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .chevron:hover {\n color: var(--l-form-control-value-color);\n }\n}\n\n/*\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n 🅾🅿🆃🅸🅾🅽🆂\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n*/\n\n.option {\n display: flex;\n align-items: center;\n gap: var(--l-menu-item-gap);\n min-block-size: var(--l-menu-item-min-height);\n padding-block: var(--l-menu-item-padding-block);\n /* Inline-end room for the checkmark of the committed value. It sits at the\n end, not in an inline-start column like l-select: a reserved start column\n would indent every row even when nothing is selected yet. */\n padding-inline: var(--l-menu-item-padding-inline) calc(var(--l-menu-item-padding-inline) + 1.5rem);\n position: relative;\n border-radius: var(--l-menu-item-border-radius);\n color: var(--l-color-text-primary);\n cursor: pointer;\n}\n\n/* The active option takes the same tint as a hovered l-dropdown-item. The\n mouse moves the active option too (ListboxNavController.onPointerMove), so\n hover and keyboard share this single highlight instead of tinting two rows. */\n.option[aria-selected='true'] {\n background-color: var(--l-color-bg-state-hover);\n}\n\n/* Checkmark on the currently committed value. */\n.option[data-current]::after {\n content: '';\n position: absolute;\n inset-inline-end: 0.5rem;\n inline-size: 1em;\n block-size: 1em;\n background-color: var(--l-form-control-activated-color);\n mask: var(--_check-icon) center / contain no-repeat;\n}\n\n/* Rich options — same authoring classes as l-select, copied straight into the\n row, so an option is rich by its content alone. */\n.option .l-select-item-media {\n flex: none;\n display: inline-flex;\n align-items: center;\n font-size: 1.25em;\n}\n\n.option .l-select-item-text {\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.option .l-select-item-title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option .l-select-item-description {\n font-size: 0.85em;\n color: var(--l-color-text-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport type { TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { LuxenFormAssociatedElement } from '../../shared/luxen-form-associated-element.js';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { ListboxNavController } from '../../shared/controllers/listbox-nav.js';\nimport { DatalistObserverController } from '../../shared/controllers/datalist-observer.js';\nimport { LocalizeController } from '../../shared/localize.js';\nimport { RichHighlighter, highlightText, normalize } from '../../shared/highlight.js';\nimport { cls, uniqueId } from '../../registry.js';\nimport { adoptRichContentStyles, richOptionLabel } from '../../shared/rich-option.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport visuallyHiddenStyles from '../../shared/styles/visually-hidden.styles.js';\nimport suffixStyles from '../../shared/styles/select-item-suffix.styles.js';\nimport pickerCoreStyles from '../../shared/styles/picker-core.styles.js';\nimport rawStyles from './combobox.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\n/** A single option read from the `<datalist>`. */\nexport interface ComboboxItem {\n value: string;\n /** Plain text used for filtering and the input display. */\n label: string;\n disabled: boolean;\n /** Rich inner markup (from a non-empty `<option>`), projected into the row. */\n html?: string;\n}\n\n/** Default filter: accent/case-insensitive, every space-separated keyword must match. */\nexport type ComboboxFilter = (item: ComboboxItem, query: string) => boolean;\n\nconst defaultFilter: ComboboxFilter = (item, query) => {\n if (!query) return true;\n const label = normalize(item.label);\n return normalize(query)\n .split(/\\s+/)\n .filter(Boolean)\n .every((kw) => label.includes(kw));\n};\n\n/** Fired when an option is committed (selected). Bubbles; not composed. */\nexport class ComboboxChangeEvent extends Event {\n readonly value: string;\n constructor(value: string) {\n super('change', { bubbles: true, composed: false, cancelable: false });\n this.value = value;\n }\n}\n\n/** Fired as the user types (filter query changes). Bubbles; not composed. */\nexport class ComboboxInputEvent extends Event {\n /** The current query text. */\n readonly value: string;\n constructor(value: string) {\n super('input', { bubbles: true, composed: false, cancelable: false });\n this.value = value;\n }\n}\n\ninterface ComboboxEventMap {\n change: ComboboxChangeEvent;\n input: ComboboxInputEvent;\n}\n\n/**\n * A text input paired with a filterable list of options (the ARIA combobox\n * pattern). Options are authored as a native `<datalist>` of `<option>` —\n * the same authoring surface as `l-select`. Form-associated.\n *\n * @summary A searchable text input with a filtered list of options.\n *\n * @example\n * ```html\n * <l-combobox label=\"Country\" name=\"country\" placeholder=\"Search…\">\n * <datalist>\n * <option value=\"us\">United States</option>\n * <option value=\"fr\">France</option>\n * </datalist>\n * </l-combobox>\n * ```\n *\n * @event change - Fired when an option is selected. Bubbles. Not cancelable. Properties: `value: string`.\n * @event input - Fired as the user types. Bubbles. Not cancelable. Properties: `value: string` (the query).\n * @event show - Fired before the list opens. Cancelable.\n * @event hide - Fired before the list closes. Cancelable.\n *\n * @csspart base - The host wrapper.\n * @csspart control - The input control row (input + clear + chevron).\n * @csspart input - The text input.\n * @csspart panel - The floating popover panel.\n * @csspart listbox - The options container.\n * @csspart option - Each option row.\n * @csspart empty - The \"no results\" message.\n *\n * @cssproperty [--height=var(--l-form-control-height)] - Control height. The clear button and the chevron\n * each take a square of this height (borders excluded), so their hit area and spacing follow it.\n * @cssproperty [--l-form-control-icon-size=1em] - Glyph size of the clear button and the chevron (global form-control\n * token; set it here or on any ancestor). Changes the glyph only — the hit area follows `--height`.\n * @cssproperty --chevron-icon - Chevron glyph as a `url()`. Masked, so its color comes from the control, not the image.\n * @cssproperty --clear-icon - Clear button glyph as a `url()`.\n * @cssproperty [--border-radius] - Control + panel radius.\n * @cssproperty [--background] - Panel background.\n *\n * @cssClass .l-select-item-media - Rich option: leading image or icon.\n * @cssClass .l-select-item-text - Rich option: column holding the title and the description.\n * @cssClass .l-select-item-title - Rich option: title, truncated with an ellipsis. Used as the label when the option has no `label`.\n * @cssClass .l-select-item-description - Rich option: secondary line, shown in the listbox only.\n * @cssClass .l-select-item-suffix - Rich option: trailing badge, count or status icon on the title's line. Kept out of the input and the filter.\n *\n * @customElement l-combobox\n */\n// oxlint-disable-next-line typescript/no-unsafe-declaration-merging -- typed addEventListener overloads merged below; no uninitialized properties.\nexport class Combobox extends LuxenFormAssociatedElement {\n // Rich option markup is copied into the shadow root, out of reach of the\n // global stylesheets: suffixStyles lays out the `.l-select-item-suffix` zone,\n // and `_readItems` adopts the styles of the light-DOM elements (l-badge) the\n // options actually contain.\n static override styles = [\n hostStyles,\n visuallyHiddenStyles,\n suffixStyles,\n pickerCoreStyles,\n styles,\n ];\n\n private _localize = new LocalizeController(this);\n private readonly _listId = uniqueId('combobox-list');\n private readonly _richHighlighter = new RichHighlighter();\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._controlEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _nav = new ListboxNavController(this, {\n listboxId: this._listId,\n getCount: () => this._filtered.length,\n isDisabled: (i) => this._filtered[i]?.disabled ?? false,\n isOpen: () => this._open,\n open: () => this.show(),\n getOptionElements: () => this.shadowRoot?.querySelectorAll<HTMLElement>('.option'),\n });\n\n // The `<datalist>` is light DOM the consumer owns and rewrites in place;\n // re-read it so the input tracks the options it was given.\n private _options = new DatalistObserverController(this, () => this._syncItems());\n\n /** Selected value (the chosen option's `value`). */\n @property({ reflect: true })\n accessor value = '';\n\n /** Placeholder text in the input. */\n @property()\n accessor placeholder = '';\n\n /** Accessible label for the input. */\n @property()\n accessor label = '';\n\n /** Control size. */\n @property({ reflect: true })\n accessor size: ComboboxSize = 'md';\n\n /** Show a button to clear the value. */\n @property({ type: Boolean, reflect: true, attribute: 'with-clear' })\n accessor withClear = false;\n\n /** Accept a typed value that matches no option. */\n @property({ type: Boolean, reflect: true, attribute: 'allow-custom' })\n accessor allowCustom = false;\n\n /**\n * Wrap the matching substring of each option in `<mark>` — the label of a\n * plain option, the title and description of a rich one.\n */\n @property({ type: Boolean })\n accessor highlight = true;\n\n /** Panel placement relative to the control. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Override the option filter. `(item, query) => boolean`. */\n filter: ComboboxFilter = defaultFilter;\n\n @state() private accessor _open = false;\n @state() private accessor _query = '';\n @state() private accessor _items: ComboboxItem[] = [];\n\n private get _controlEl() {\n return this.shadowRoot?.querySelector<HTMLElement>('.control') ?? null;\n }\n private get _panelEl() {\n return this.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n }\n private get _inputEl() {\n return this.shadowRoot?.querySelector<HTMLInputElement>('.input') ?? null;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n // Sync rather than plain-read: the observer is disconnected while detached,\n // so options may have been re-labelled behind our back and the input — which\n // holds its own text, not a render of `_items` — would stay on the old one.\n this._syncItems();\n this._defaultFormValue = this.value;\n this._syncFormValue(this.value);\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('value')) {\n this._syncFormValue(this.value);\n this._updateValidity();\n if (!this._open) this._resetDisplay();\n }\n }\n\n override formResetCallback() {\n this.value = this._defaultFormValue;\n this._query = '';\n this._nav.reset();\n super.formResetCallback();\n this._resetDisplay();\n }\n\n override formStateRestoreCallback(state: string) {\n this.value = state;\n this._syncFormValue(state);\n }\n\n // --- Items (read from the light-DOM <datalist>) ---\n\n private _readItems() {\n const list = this.querySelector('datalist');\n const opts = list ? Array.from(list.options) : [];\n this._items = opts.map((o) => {\n const rich = o.childElementCount > 0;\n const label = richOptionLabel(o);\n return { value: o.value, label, disabled: o.disabled, html: rich ? o.innerHTML : undefined };\n });\n adoptRichContentStyles(this.shadowRoot, this._items);\n }\n\n /**\n * Re-read the options after the light DOM changed underneath us.\n *\n * The input carries its own text rather than a render of `_items`, so it has\n * to be refreshed by hand — but only when it is still showing the label we put\n * there. Anything else in it is the user's (a query typed while the panel\n * stayed closed, because a consumer vetoed `show`) and must survive. A closed\n * panel is not on its own proof that nobody is typing.\n *\n * Open, the input is theirs by definition; what needs care there is the active\n * option, addressed by position in `_filtered` — re-anchor it on the option the\n * user had highlighted, or a list that grows or shrinks commits a different one.\n */\n private _syncItems() {\n const active = this._open ? this._filtered[this._nav.activeIndex] : undefined;\n const displayed = this._inputEl?.value;\n const untouched = displayed === undefined || displayed === this._labelForValue(this.value);\n this._readItems();\n if (!this._open) {\n if (untouched) this._resetDisplay();\n return;\n }\n this._nav.setActive(active ? this._filtered.findIndex((i) => i.value === active.value) : -1);\n }\n\n private _labelForValue(value: string): string {\n return this._items.find((i) => i.value === value)?.label ?? (this.allowCustom ? value : '');\n }\n\n private get _filtered(): ComboboxItem[] {\n return this._items.filter((i) => this.filter(i, this._query));\n }\n\n private _resetDisplay() {\n const input = this._inputEl;\n if (input) input.value = this._labelForValue(this.value);\n }\n\n // --- Validity ---\n\n private _updateValidity() {\n if (this.required && !this.value) {\n this.setValidity(\n { valueMissing: true },\n this._localize.term('selectOption'),\n this._inputEl ?? undefined,\n );\n } else {\n this.setValidity({});\n }\n }\n\n // --- Open / close ---\n\n show() {\n if (this._open || this.disabled) return;\n this._readItems();\n if (!this.dispatchEvent(new Event('show', { cancelable: true }))) return;\n this._open = true;\n // Pre-activate the chosen option so a screen reader announces the current\n // selection when the list opens (only when not actively filtering).\n if (this.value && !this._query) {\n this._nav.setActive(this._filtered.findIndex((i) => i.value === this.value));\n }\n this.updateComplete.then(() => {\n const panel = this._panelEl;\n panel?.showPopover?.();\n this._floating.startPositioning({\n placement: this.placement,\n distance: 4,\n minWidth: 'trigger',\n });\n });\n }\n\n hide() {\n if (!this._open) return;\n if (!this.dispatchEvent(new Event('hide', { cancelable: true }))) return;\n this._open = false;\n this._nav.reset();\n const panel = this._panelEl;\n if (panel?.matches?.(':popover-open')) panel.hidePopover?.();\n this._floating.stopPositioning();\n this._resetDisplay();\n }\n\n // --- Selection ---\n\n private _commit(item: ComboboxItem) {\n if (item.disabled) return;\n this.value = item.value;\n this._query = '';\n this.hasInteracted = true;\n const input = this._inputEl;\n if (input) input.value = item.label;\n this._syncFormValue(this.value);\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(this.value));\n this.hide();\n input?.focus();\n }\n\n private _commitActiveOrCustom() {\n const filtered = this._filtered;\n const active = this._nav.activeIndex;\n if (active >= 0 && filtered[active]) {\n this._commit(filtered[active]);\n return;\n }\n const input = this._inputEl;\n if (this.allowCustom && input) {\n this.value = input.value;\n this._syncFormValue(this.value);\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(this.value));\n this.hide();\n }\n }\n\n private _clear() {\n this.value = '';\n this._query = '';\n this._nav.reset();\n if (this._inputEl) this._inputEl.value = '';\n this._syncFormValue('');\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(''));\n this._inputEl?.focus();\n }\n\n // --- Keyboard (navigation delegated to ListboxNavController) ---\n\n private _onKeyDown = (e: KeyboardEvent) => {\n // Arrow Up/Down move aria-activedescendant. Home/End are left to the input's\n // text cursor (APG editable combobox).\n if (this._nav.onKeyDown(e)) return;\n switch (e.key) {\n case 'Enter':\n if (this._open) {\n e.preventDefault();\n this._commitActiveOrCustom();\n }\n break;\n case 'Escape':\n if (this._open) {\n e.preventDefault();\n this.hide();\n } else if (this.value || this._inputEl?.value) {\n this._clear();\n }\n break;\n case 'Tab':\n if (this._open && this._nav.activeIndex >= 0) this._commitActiveOrCustom();\n break;\n default:\n break;\n }\n };\n\n private _onInput = (e: Event) => {\n this._query = (e.target as HTMLInputElement).value;\n this._nav.reset();\n if (!this._open) this.show();\n this.dispatchEvent(new ComboboxInputEvent(this._query));\n };\n\n private _onControlPointerDown = (e: PointerEvent) => {\n // Toggle on clicking the control chrome (not while typing).\n if ((e.target as HTMLElement).closest('.clear-button')) return;\n // A click on the chrome (chevron, padding, prefix) focuses the input, like a\n // native select. Otherwise focus stays on the page, the input never sees a\n // focusout, and an outside click or Tab can no longer close the list.\n if (e.target !== this._inputEl) {\n e.preventDefault();\n this._inputEl?.focus();\n }\n // The chevron toggles, like a native select's arrow: it closes an open list.\n // Anywhere else on the control only opens it, so clicking into the text to\n // move the caret never dismisses the suggestions.\n if (this._open) {\n if ((e.target as HTMLElement).closest('.chevron')) this.hide();\n return;\n }\n this.show();\n };\n\n private _onFocusOut = (e: FocusEvent) => {\n const next = e.relatedTarget as Node | null;\n if (next && this.shadowRoot?.contains(next)) return;\n this.hasInteracted = true;\n this._updateValidity();\n this.hide();\n };\n\n // --- Render ---\n\n private _highlight(label: string): TemplateResult | string {\n return this.highlight ? highlightText(label, this._query) : label;\n }\n\n private _highlightRich(markup: string): string {\n return this.highlight ? this._richHighlighter.highlight(markup, this._query) : markup;\n }\n\n override render() {\n const filtered = this._filtered;\n const activeId = this._nav.activeDescendant;\n const activeIndex = this._nav.activeIndex;\n const invalid = this.required && !this.value && this.hasInteracted;\n const status = !this._open\n ? ''\n : filtered.length === 0\n ? this._localize.term('noResults')\n : `${filtered.length} ${this._localize.term('suggestions')}`;\n\n return html`\n <div\n class=\"base\"\n part=\"base\"\n @focusout=${this._onFocusOut}\n >\n <div\n class=\"control\"\n part=\"control\"\n @pointerdown=${this._onControlPointerDown}\n >\n <slot name=\"prefix\"></slot>\n <input\n class=\"input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n .placeholder=${this.placeholder}\n ?disabled=${this.disabled}\n aria-label=${this.label || nothing}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open ? 'true' : 'false'}\n aria-controls=${this._listId}\n aria-activedescendant=${activeId ?? nothing}\n aria-required=${this.required ? 'true' : nothing}\n aria-invalid=${invalid ? 'true' : nothing}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n />\n <span class=\"actions\">\n ${\n this.withClear && (this.value || this._query)\n ? html`<button\n class=\"clear-button\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=${this._localize.term('clear')}\n @click=${this._clear}\n ></button>`\n : nothing\n }\n <span\n class=\"chevron\"\n aria-hidden=\"true\"\n ></span>\n </span>\n </div>\n\n <div\n class=\"panel\"\n part=\"panel\"\n popover=\"manual\"\n >\n <ul\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=${this._listId}\n aria-label=${this.label || this._localize.term('suggestions')}\n @pointermove=${this._nav.onPointerMove}\n @pointerleave=${this._nav.onPointerLeave}\n >\n ${filtered.map(\n (item, i) =>\n html`<li\n class=\"option\"\n part=\"option\"\n id=${this._nav.optionId(i)}\n role=\"option\"\n aria-selected=${i === activeIndex ? 'true' : 'false'}\n aria-disabled=${item.disabled ? 'true' : nothing}\n data-current=${item.value === this.value ? '' : nothing}\n @pointerdown=${(e: Event) => e.preventDefault()}\n @click=${() => this._commit(item)}\n >\n ${\n item.html\n ? unsafeHTML(this._highlightRich(item.html))\n : html`<span class=\"option-label\">${this._highlight(item.label)}</span>`\n }\n </li>`,\n )}\n </ul>\n ${\n filtered.length === 0\n ? html`<div\n class=\"empty\"\n part=\"empty\"\n >\n ${this._localize.term('noResults')}\n </div>`\n : nothing\n }\n </div>\n\n <div\n class=${cls('visually-hidden')}\n aria-live=\"polite\"\n >\n ${status}\n </div>\n </div>\n `;\n }\n}\n\n// Typed addEventListener for the colliding `change` / `input` names.\nexport interface Combobox {\n addEventListener<K extends keyof ComboboxEventMap>(\n type: K,\n listener: (this: Combobox, ev: ComboboxEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof ComboboxEventMap>(\n type: K,\n listener: (this: Combobox, ev: ComboboxEventMap[K]) => void,\n options?: boolean | EventListenerOptions,\n ): void;\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"combobox.js","names":["unsafeCSS","rawStyles","hostStyles","visuallyHiddenStyles","suffixStyles","pickerCoreStyles","nothing","unsafeHTML","_decorate","property","state","r","r$1","__decorate","o","A","host_styles_default","visually_hidden_styles_default","select_item_suffix_styles_default","picker_core_styles_default","styles","defaultFilter","query","label","normalize","item","kw","ComboboxChangeEvent","value","ComboboxInputEvent","Combobox","LuxenFormAssociatedElement","_args","LocalizeController","uniqueId","RichHighlighter","PopoverController","ListboxNavController","i","DatalistObserverController","#_value_accessor_storage","#_placeholder_accessor_storage","#_label_accessor_storage","#_size_accessor_storage","#_withClear_accessor_storage","#_allowCustom_accessor_storage","#_highlight_accessor_storage","#_placement_accessor_storage","#__open_accessor_storage","#__query_accessor_storage","#__items_accessor_storage","next","changed","state","list","opts","rich","richOptionLabel","adoptRichContentStyles","active","displayed","untouched","input","panel","filtered","highlightText","markup","activeId","activeIndex","invalid","status","cls"],"sources":["../../../src/html/elements/combobox/combobox.css?inline","../../../src/html/elements/combobox/combobox.ts"],"sourcesContent":["/* Knobs, size scale, field frame, chevron, clear, listbox popover and the\n shared option bits come from shared/styles/picker-core.css (loaded first).\n This file holds what is specific to the editable combobox. */\n\n/*\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n 🅲🅾🅽🆃🆁🅾🅻 (trigger)\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n*/\n\n.control {\n gap: 0.25rem;\n block-size: var(--height);\n cursor: text;\n}\n\n.input {\n flex: 1;\n min-inline-size: 0;\n border: 0;\n background: transparent;\n color: var(--l-form-control-value-color);\n font: inherit;\n outline: none;\n}\n\n.input::placeholder {\n color: var(--l-form-control-placeholder-color);\n}\n\n/* The clear button and the chevron sit side by side, square against square —\n the row's gap only separates them from the input. */\n.actions {\n flex: none;\n display: flex;\n align-self: stretch;\n align-items: center;\n}\n\n/* The chevron toggles the list (see _onControlPointerDown). */\n.chevron {\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .chevron:hover {\n color: var(--l-form-control-value-color);\n }\n}\n\n/*\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n 🅾🅿🆃🅸🅾🅽🆂\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n*/\n\n.option {\n display: flex;\n align-items: center;\n gap: var(--l-menu-item-gap);\n min-block-size: var(--l-menu-item-min-height);\n padding-block: var(--l-menu-item-padding-block);\n /* Inline-end room for the checkmark of the committed value. It sits at the\n end, not in an inline-start column like l-select: a reserved start column\n would indent every row even when nothing is selected yet. */\n padding-inline: var(--l-menu-item-padding-inline) calc(var(--l-menu-item-padding-inline) + 1.5rem);\n position: relative;\n border-radius: var(--l-menu-item-border-radius);\n color: var(--l-color-text-primary);\n cursor: pointer;\n}\n\n/* The active option takes the same tint as a hovered l-dropdown-item. The\n mouse moves the active option too (ListboxNavController.onPointerMove), so\n hover and keyboard share this single highlight instead of tinting two rows. */\n.option[aria-selected='true'] {\n background-color: var(--l-color-bg-state-hover);\n}\n\n/* Moved there with the arrow keys: the active option is where the keyboard\n is, though DOM focus stays on the input (aria-activedescendant), so it draws\n the focus ring itself — inside, like a menu item. A tint alone is the hover\n look, barely 1.1:1, and forced colors drops it. */\n.listbox[data-nav='keyboard'] .option[aria-selected='true'] {\n outline: var(--l-focus-ring-width) solid var(--l-focus-ring-color);\n outline-offset: calc(var(--l-focus-ring-width) * -1);\n}\n\n/* Checkmark on the currently committed value. */\n.option[data-current]::after {\n content: '';\n position: absolute;\n inset-inline-end: 0.5rem;\n inline-size: 1em;\n block-size: 1em;\n background-color: var(--l-form-control-activated-color);\n mask: var(--_check-icon) center / contain no-repeat;\n}\n\n/* Rich options — same authoring classes as l-select, copied straight into the\n row, so an option is rich by its content alone. */\n.option .l-select-item-media {\n flex: none;\n display: inline-flex;\n align-items: center;\n font-size: 1.25em;\n}\n\n.option .l-select-item-text {\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.option .l-select-item-title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option .l-select-item-description {\n font-size: 0.85em;\n color: var(--l-color-text-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport type { TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { LuxenFormAssociatedElement } from '../../shared/luxen-form-associated-element.js';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { ListboxNavController } from '../../shared/controllers/listbox-nav.js';\nimport { DatalistObserverController } from '../../shared/controllers/datalist-observer.js';\nimport { LocalizeController } from '../../shared/localize.js';\nimport { RichHighlighter, highlightText, normalize } from '../../shared/highlight.js';\nimport { cls, uniqueId } from '../../registry.js';\nimport { adoptRichContentStyles, richOptionLabel } from '../../shared/rich-option.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport visuallyHiddenStyles from '../../shared/styles/visually-hidden.styles.js';\nimport suffixStyles from '../../shared/styles/select-item-suffix.styles.js';\nimport pickerCoreStyles from '../../shared/styles/picker-core.styles.js';\nimport rawStyles from './combobox.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\n/** A single option read from the `<datalist>`. */\nexport interface ComboboxItem {\n value: string;\n /** Plain text used for filtering and the input display. */\n label: string;\n disabled: boolean;\n /** Rich inner markup (from a non-empty `<option>`), projected into the row. */\n html?: string;\n}\n\n/** Default filter: accent/case-insensitive, every space-separated keyword must match. */\nexport type ComboboxFilter = (item: ComboboxItem, query: string) => boolean;\n\nconst defaultFilter: ComboboxFilter = (item, query) => {\n if (!query) return true;\n const label = normalize(item.label);\n return normalize(query)\n .split(/\\s+/)\n .filter(Boolean)\n .every((kw) => label.includes(kw));\n};\n\n/** Fired when an option is committed (selected). Bubbles; not composed. */\nexport class ComboboxChangeEvent extends Event {\n readonly value: string;\n constructor(value: string) {\n super('change', { bubbles: true, composed: false, cancelable: false });\n this.value = value;\n }\n}\n\n/** Fired as the user types (filter query changes). Bubbles; not composed. */\nexport class ComboboxInputEvent extends Event {\n /** The current query text. */\n readonly value: string;\n constructor(value: string) {\n super('input', { bubbles: true, composed: false, cancelable: false });\n this.value = value;\n }\n}\n\ninterface ComboboxEventMap {\n change: ComboboxChangeEvent;\n input: ComboboxInputEvent;\n}\n\n/**\n * A text input paired with a filterable list of options (the ARIA combobox\n * pattern). Options are authored as a native `<datalist>` of `<option>` —\n * the same authoring surface as `l-select`. Form-associated.\n *\n * @summary A searchable text input with a filtered list of options.\n *\n * @example\n * ```html\n * <l-combobox label=\"Country\" name=\"country\" placeholder=\"Search…\">\n * <datalist>\n * <option value=\"us\">United States</option>\n * <option value=\"fr\">France</option>\n * </datalist>\n * </l-combobox>\n * ```\n *\n * @event change - Fired when an option is selected. Bubbles. Not cancelable. Properties: `value: string`.\n * @event input - Fired as the user types. Bubbles. Not cancelable. Properties: `value: string` (the query).\n * @event show - Fired before the list opens. Cancelable.\n * @event hide - Fired before the list closes. Cancelable.\n *\n * @csspart base - The host wrapper.\n * @csspart control - The input control row (input + clear + chevron).\n * @csspart input - The text input.\n * @csspart panel - The floating popover panel.\n * @csspart listbox - The options container.\n * @csspart option - Each option row.\n * @csspart empty - The \"no results\" message.\n *\n * @cssproperty [--height=var(--l-form-control-height)] - Control height. The clear button and the chevron\n * each take a square of this height (borders excluded), so their hit area and spacing follow it.\n * @cssproperty [--l-form-control-icon-size=1em] - Glyph size of the clear button and the chevron (global form-control\n * token; set it here or on any ancestor). Changes the glyph only — the hit area follows `--height`.\n * @cssproperty --chevron-icon - Chevron glyph as a `url()`. Masked, so its color comes from the control, not the image.\n * @cssproperty --clear-icon - Clear button glyph as a `url()`.\n * @cssproperty [--border-radius] - Control + panel radius.\n * @cssproperty [--background] - Panel background.\n *\n * @cssClass .l-select-item-media - Rich option: leading image or icon.\n * @cssClass .l-select-item-text - Rich option: column holding the title and the description.\n * @cssClass .l-select-item-title - Rich option: title, truncated with an ellipsis. Used as the label when the option has no `label`.\n * @cssClass .l-select-item-description - Rich option: secondary line, shown in the listbox only.\n * @cssClass .l-select-item-suffix - Rich option: trailing badge, count or status icon on the title's line. Kept out of the input and the filter.\n *\n * @customElement l-combobox\n */\n// oxlint-disable-next-line typescript/no-unsafe-declaration-merging -- typed addEventListener overloads merged below; no uninitialized properties.\nexport class Combobox extends LuxenFormAssociatedElement {\n // Rich option markup is copied into the shadow root, out of reach of the\n // global stylesheets: suffixStyles lays out the `.l-select-item-suffix` zone,\n // and `_readItems` adopts the styles of the light-DOM elements (l-badge) the\n // options actually contain.\n static override styles = [\n hostStyles,\n visuallyHiddenStyles,\n suffixStyles,\n pickerCoreStyles,\n styles,\n ];\n\n private _localize = new LocalizeController(this);\n private readonly _listId = uniqueId('combobox-list');\n private readonly _richHighlighter = new RichHighlighter();\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._controlEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _nav = new ListboxNavController(this, {\n listboxId: this._listId,\n getCount: () => this._filtered.length,\n isDisabled: (i) => this._filtered[i]?.disabled ?? false,\n isOpen: () => this._open,\n open: () => this.show(),\n getOptionElements: () => this.shadowRoot?.querySelectorAll<HTMLElement>('.option'),\n });\n\n // The `<datalist>` is light DOM the consumer owns and rewrites in place;\n // re-read it so the input tracks the options it was given.\n private _options = new DatalistObserverController(this, () => this._syncItems());\n\n /** Selected value (the chosen option's `value`). */\n @property({ reflect: true })\n accessor value = '';\n\n /** Placeholder text in the input. */\n @property()\n accessor placeholder = '';\n\n /** Accessible label for the input. */\n @property()\n accessor label = '';\n\n /** Control size. */\n @property({ reflect: true })\n accessor size: ComboboxSize = 'md';\n\n /** Show a button to clear the value. */\n @property({ type: Boolean, reflect: true, attribute: 'with-clear' })\n accessor withClear = false;\n\n /** Accept a typed value that matches no option. */\n @property({ type: Boolean, reflect: true, attribute: 'allow-custom' })\n accessor allowCustom = false;\n\n /**\n * Wrap the matching substring of each option in `<mark>` — the label of a\n * plain option, the title and description of a rich one.\n */\n @property({ type: Boolean })\n accessor highlight = true;\n\n /** Panel placement relative to the control. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Override the option filter. `(item, query) => boolean`. */\n filter: ComboboxFilter = defaultFilter;\n\n @state() private accessor _open = false;\n @state() private accessor _query = '';\n @state() private accessor _items: ComboboxItem[] = [];\n\n private get _controlEl() {\n return this.shadowRoot?.querySelector<HTMLElement>('.control') ?? null;\n }\n private get _panelEl() {\n return this.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n }\n private get _inputEl() {\n return this.shadowRoot?.querySelector<HTMLInputElement>('.input') ?? null;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n // Sync rather than plain-read: the observer is disconnected while detached,\n // so options may have been re-labelled behind our back and the input — which\n // holds its own text, not a render of `_items` — would stay on the old one.\n this._syncItems();\n this._defaultFormValue = this.value;\n this._syncFormValue(this.value);\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('value')) {\n this._syncFormValue(this.value);\n this._updateValidity();\n if (!this._open) this._resetDisplay();\n }\n }\n\n override formResetCallback() {\n this.value = this._defaultFormValue;\n this._query = '';\n this._nav.reset();\n super.formResetCallback();\n this._resetDisplay();\n }\n\n override formStateRestoreCallback(state: string) {\n this.value = state;\n this._syncFormValue(state);\n }\n\n // --- Items (read from the light-DOM <datalist>) ---\n\n private _readItems() {\n const list = this.querySelector('datalist');\n const opts = list ? Array.from(list.options) : [];\n this._items = opts.map((o) => {\n const rich = o.childElementCount > 0;\n const label = richOptionLabel(o);\n return { value: o.value, label, disabled: o.disabled, html: rich ? o.innerHTML : undefined };\n });\n adoptRichContentStyles(this.shadowRoot, this._items);\n }\n\n /**\n * Re-read the options after the light DOM changed underneath us.\n *\n * The input carries its own text rather than a render of `_items`, so it has\n * to be refreshed by hand — but only when it is still showing the label we put\n * there. Anything else in it is the user's (a query typed while the panel\n * stayed closed, because a consumer vetoed `show`) and must survive. A closed\n * panel is not on its own proof that nobody is typing.\n *\n * Open, the input is theirs by definition; what needs care there is the active\n * option, addressed by position in `_filtered` — re-anchor it on the option the\n * user had highlighted, or a list that grows or shrinks commits a different one.\n */\n private _syncItems() {\n const active = this._open ? this._filtered[this._nav.activeIndex] : undefined;\n const displayed = this._inputEl?.value;\n const untouched = displayed === undefined || displayed === this._labelForValue(this.value);\n this._readItems();\n if (!this._open) {\n if (untouched) this._resetDisplay();\n return;\n }\n this._nav.setActive(active ? this._filtered.findIndex((i) => i.value === active.value) : -1);\n }\n\n private _labelForValue(value: string): string {\n return this._items.find((i) => i.value === value)?.label ?? (this.allowCustom ? value : '');\n }\n\n private get _filtered(): ComboboxItem[] {\n return this._items.filter((i) => this.filter(i, this._query));\n }\n\n private _resetDisplay() {\n const input = this._inputEl;\n if (input) input.value = this._labelForValue(this.value);\n }\n\n // --- Validity ---\n\n private _updateValidity() {\n if (this.required && !this.value) {\n this.setValidity(\n { valueMissing: true },\n this._localize.term('selectOption'),\n this._inputEl ?? undefined,\n );\n } else {\n this.setValidity({});\n }\n }\n\n // --- Open / close ---\n\n show() {\n if (this._open || this.disabled) return;\n this._readItems();\n if (!this.dispatchEvent(new Event('show', { cancelable: true }))) return;\n this._open = true;\n // Pre-activate the chosen option so a screen reader announces the current\n // selection when the list opens (only when not actively filtering).\n if (this.value && !this._query) {\n this._nav.setActive(this._filtered.findIndex((i) => i.value === this.value));\n }\n this.updateComplete.then(() => {\n const panel = this._panelEl;\n panel?.showPopover?.();\n this._floating.startPositioning({\n placement: this.placement,\n distance: 4,\n minWidth: 'trigger',\n });\n });\n }\n\n hide() {\n if (!this._open) return;\n if (!this.dispatchEvent(new Event('hide', { cancelable: true }))) return;\n this._open = false;\n this._nav.reset();\n const panel = this._panelEl;\n if (panel?.matches?.(':popover-open')) panel.hidePopover?.();\n this._floating.stopPositioning();\n this._resetDisplay();\n }\n\n // --- Selection ---\n\n private _commit(item: ComboboxItem) {\n if (item.disabled) return;\n this.value = item.value;\n this._query = '';\n this.hasInteracted = true;\n const input = this._inputEl;\n if (input) input.value = item.label;\n this._syncFormValue(this.value);\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(this.value));\n this.hide();\n input?.focus();\n }\n\n private _commitActiveOrCustom() {\n const filtered = this._filtered;\n const active = this._nav.activeIndex;\n if (active >= 0 && filtered[active]) {\n this._commit(filtered[active]);\n return;\n }\n const input = this._inputEl;\n if (this.allowCustom && input) {\n this.value = input.value;\n this._syncFormValue(this.value);\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(this.value));\n this.hide();\n }\n }\n\n private _clear() {\n this.value = '';\n this._query = '';\n this._nav.reset();\n if (this._inputEl) this._inputEl.value = '';\n this._syncFormValue('');\n this._updateValidity();\n this.dispatchEvent(new ComboboxChangeEvent(''));\n this._inputEl?.focus();\n }\n\n // --- Keyboard (navigation delegated to ListboxNavController) ---\n\n private _onKeyDown = (e: KeyboardEvent) => {\n // Arrow Up/Down move aria-activedescendant. Home/End are left to the input's\n // text cursor (APG editable combobox).\n if (this._nav.onKeyDown(e)) return;\n switch (e.key) {\n case 'Enter':\n if (this._open) {\n e.preventDefault();\n this._commitActiveOrCustom();\n }\n break;\n case 'Escape':\n if (this._open) {\n e.preventDefault();\n this.hide();\n } else if (this.value || this._inputEl?.value) {\n this._clear();\n }\n break;\n case 'Tab':\n if (this._open && this._nav.activeIndex >= 0) this._commitActiveOrCustom();\n break;\n default:\n break;\n }\n };\n\n private _onInput = (e: Event) => {\n this._query = (e.target as HTMLInputElement).value;\n this._nav.reset();\n if (!this._open) this.show();\n this.dispatchEvent(new ComboboxInputEvent(this._query));\n };\n\n private _onControlPointerDown = (e: PointerEvent) => {\n // Toggle on clicking the control chrome (not while typing).\n if ((e.target as HTMLElement).closest('.clear-button')) return;\n // A click on the chrome (chevron, padding, prefix) focuses the input, like a\n // native select. Otherwise focus stays on the page, the input never sees a\n // focusout, and an outside click or Tab can no longer close the list.\n if (e.target !== this._inputEl) {\n e.preventDefault();\n this._inputEl?.focus();\n }\n // The chevron toggles, like a native select's arrow: it closes an open list.\n // Anywhere else on the control only opens it, so clicking into the text to\n // move the caret never dismisses the suggestions.\n if (this._open) {\n if ((e.target as HTMLElement).closest('.chevron')) this.hide();\n return;\n }\n this.show();\n };\n\n private _onFocusOut = (e: FocusEvent) => {\n const next = e.relatedTarget as Node | null;\n if (next && this.shadowRoot?.contains(next)) return;\n this.hasInteracted = true;\n this._updateValidity();\n this.hide();\n };\n\n // --- Render ---\n\n private _highlight(label: string): TemplateResult | string {\n return this.highlight ? highlightText(label, this._query) : label;\n }\n\n private _highlightRich(markup: string): string {\n return this.highlight ? this._richHighlighter.highlight(markup, this._query) : markup;\n }\n\n override render() {\n const filtered = this._filtered;\n const activeId = this._nav.activeDescendant;\n const activeIndex = this._nav.activeIndex;\n const invalid = this.required && !this.value && this.hasInteracted;\n const status = !this._open\n ? ''\n : filtered.length === 0\n ? this._localize.term('noResults')\n : `${filtered.length} ${this._localize.term('suggestions')}`;\n\n return html`\n <div\n class=\"base\"\n part=\"base\"\n @focusout=${this._onFocusOut}\n >\n <div\n class=\"control\"\n part=\"control\"\n @pointerdown=${this._onControlPointerDown}\n >\n <slot name=\"prefix\"></slot>\n <input\n class=\"input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n .placeholder=${this.placeholder}\n ?disabled=${this.disabled}\n aria-label=${this.label || nothing}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open ? 'true' : 'false'}\n aria-controls=${this._listId}\n aria-activedescendant=${activeId ?? nothing}\n aria-required=${this.required ? 'true' : nothing}\n aria-invalid=${invalid ? 'true' : nothing}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n />\n <span class=\"actions\">\n ${\n this.withClear && (this.value || this._query)\n ? html`<button\n class=\"clear-button\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=${this._localize.term('clear')}\n @click=${this._clear}\n ></button>`\n : nothing\n }\n <span\n class=\"chevron\"\n aria-hidden=\"true\"\n ></span>\n </span>\n </div>\n\n <div\n class=\"panel\"\n part=\"panel\"\n popover=\"manual\"\n >\n <ul\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=${this._listId}\n aria-label=${this.label || this._localize.term('suggestions')}\n data-nav=${this._nav.keyboard ? 'keyboard' : 'pointer'}\n @pointermove=${this._nav.onPointerMove}\n @pointerleave=${this._nav.onPointerLeave}\n >\n ${filtered.map(\n (item, i) =>\n html`<li\n class=\"option\"\n part=\"option\"\n id=${this._nav.optionId(i)}\n role=\"option\"\n aria-selected=${i === activeIndex ? 'true' : 'false'}\n aria-disabled=${item.disabled ? 'true' : nothing}\n data-current=${item.value === this.value ? '' : nothing}\n @pointerdown=${(e: Event) => e.preventDefault()}\n @click=${() => this._commit(item)}\n >\n ${\n item.html\n ? unsafeHTML(this._highlightRich(item.html))\n : html`<span class=\"option-label\">${this._highlight(item.label)}</span>`\n }\n </li>`,\n )}\n </ul>\n ${\n filtered.length === 0\n ? html`<div\n class=\"empty\"\n part=\"empty\"\n >\n ${this._localize.term('noResults')}\n </div>`\n : nothing\n }\n </div>\n\n <div\n class=${cls('visually-hidden')}\n aria-live=\"polite\"\n >\n ${status}\n </div>\n </div>\n `;\n }\n}\n\n// Typed addEventListener for the colliding `change` / `input` names.\nexport interface Combobox {\n addEventListener<K extends keyof ComboboxEventMap>(\n type: K,\n listener: (this: Combobox, ev: ComboboxEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof ComboboxEventMap>(\n type: K,\n listener: (this: Combobox, ev: ComboboxEventMap[K]) => void,\n options?: boolean | EventListenerOptions,\n ): void;\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n}\n"],"mappings":"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"}
|
|
@@ -23,8 +23,9 @@ import { LuxenElement } from '../../shared/luxen-element.js';
|
|
|
23
23
|
* @cssproperty [--show-duration=200ms] - Open transition duration.
|
|
24
24
|
* @cssproperty [--hide-duration=200ms] - Close transition duration.
|
|
25
25
|
* @cssproperty [--easing=cubic-bezier(0.32, 0.72, 0, 1)] - Timing function of the open and close transitions, backdrop included.
|
|
26
|
-
* @cssproperty --backdrop - Backdrop color.
|
|
26
|
+
* @cssproperty [--backdrop=var(--l-backdrop)] - Backdrop color.
|
|
27
27
|
* @cssproperty [--backdrop-blur=0] - Backdrop blur amount (any CSS length). `0` means no blur; set e.g. `4px` for a subtle frost.
|
|
28
|
+
* @cssproperty [--shadow=none] - Drop shadow of the dialog panel (any `box-shadow` value). Raise it when the backdrop is light, where the panel edge would otherwise fade into the page.
|
|
28
29
|
*
|
|
29
30
|
* @event show - Fired when the dialog is about to open. Cancelable — call `event.preventDefault()` to keep it closed.
|
|
30
31
|
* @event after-show - Fired after the open animation completes. Not cancelable.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAkC7D
|
|
1
|
+
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dialog/dialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAkC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,MAAO,SAAQ,YAAY;IACtC,MAAM,CAAC,MAAM,4BAAwB;IAErC,oFAAoF;IAEpF,KAAK,SAAM;IAEX,kCAAkC;IAElC,IAAI,UAAS;IAEb,0CAA0C;IAE1C,YAAY,UAAS;IAErB,uDAAuD;IAEvD,aAAa,UAAS;IAMtB,OAAO,CAAC,MAAM,CAAyC;IAGvD,MAAM,EAAG,iBAAiB,CAAC;IAI3B,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAc;IAMvD,SAAS,KAAK,KAAK,IAAI,MAAM,CAE5B;IACD,SAAS,KAAK,OAAO,IAAI,MAAM,CAE9B;IAED,OAAO,CAAC,gBAAgB,CAA4B;IAEpD,OAAO,CAAC,gBAAgB,CAEtB;IAIF,iBAAiB,SAGhB;IAED,oBAAoB,SAGnB;IAED,YAAY,SAOX;IAED,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,QA8BpC;IAOD,OAAO,CAAC,UAAU;IAclB,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,QAI3B;IAED,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,eAAe,CAAC,CAAY;IAEpC,OAAO,CAAC,aAAa;YAcP,UAAU;IAWxB,SAAS,CAAC,aAAa,SAGtB;IAED,MAAM,oCAmCL;IAID,SAAS,CAAC,YAAY,oCASrB;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","names":["hostStyles","styles","nothing","_decorate","property","query","n","e","b","A","host_styles_default","dialog_styles_default","supportsClosedBy","SCROLL_LOCK_SHEET","sheet","Dialog","LuxenElement","_args","HasSlotController","changed","ShowEvent","HideEvent","clickedBackdrop","r","anims","a","name","AfterShowEvent","AfterHideEvent","closedby","__decorate"],"sources":["../../../src/html/elements/dialog/dialog.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { HasSlotController } from '../../shared/controllers/has-slot-controller.js';\nimport { ShowEvent, AfterShowEvent, HideEvent, AfterHideEvent } from '../../events/index.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport styles from './dialog.styles.js';\n\ninterface CommandEventLike extends Event {\n command: string;\n source: Element | null;\n}\n\nconst supportsClosedBy =\n typeof HTMLDialogElement !== 'undefined' && 'closedBy' in HTMLDialogElement.prototype;\n\n// Native <dialog> doesn't lock body scroll. Inject a global rule that uses\n// `:has()` to freeze the root scroll container whenever any modal l-dialog\n// is open. Purely declarative — no manual lock/unlock bookkeeping.\n// Symbol guard makes the injection idempotent across HMR reloads.\n//\n// `scrollbar-gutter: stable` only applies to centered modals — it prevents\n// the page behind from shifting horizontally when the scrollbar disappears.\n// Edge-attached modals (drawers) opt out via `data-modal=\"edge\"`: a reserved\n// gutter would push the drawer off the actual viewport edge.\nconst SCROLL_LOCK_SHEET = Symbol.for('luxen-dialog-scroll-lock');\nif (typeof document !== 'undefined' && !(SCROLL_LOCK_SHEET in document)) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n html:has([data-modal]) { overflow: hidden; }\n html:has([data-modal=\"centered\"]) { scrollbar-gutter: stable; }\n `);\n document.adoptedStyleSheets.push(sheet);\n Object.defineProperty(document, SCROLL_LOCK_SHEET, { value: sheet });\n}\n\n/**\n * A modal dialog rendered in the top layer via the native `<dialog>` element.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). There are no public `show()` / `close()` methods.\n *\n * @slot - Body content.\n * @slot title - Custom heading element. Overrides the default `<h2>` rendered from the `title` property. Also provides the dialog's accessible name.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The dialog title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty [--width=31rem] - Dialog width.\n * @cssproperty [--border-radius=6px] - Dialog border radius.\n * @cssproperty [--padding=1.5rem] - Padding applied to the header, footer, and inline-padding of the body. Set to `0` to remove all internal spacing (e.g. for edge-to-edge media).\n * @cssproperty [--show-duration=200ms] - Open transition duration.\n * @cssproperty [--hide-duration=200ms] - Close transition duration.\n * @cssproperty [--easing=cubic-bezier(0.32, 0.72, 0, 1)] - Timing function of the open and close transitions, backdrop included.\n * @cssproperty --backdrop - Backdrop color.\n * @cssproperty [--backdrop-blur=0] - Backdrop blur amount (any CSS length). `0` means no blur; set e.g. `4px` for a subtle frost.\n *\n * @event show - Fired when the dialog is about to open. Cancelable — call `event.preventDefault()` to keep it closed.\n * @event after-show - Fired after the open animation completes. Not cancelable.\n * @event hide - Fired when the dialog is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes. Not cancelable.\n *\n * @command --show - Sets `open = true`.\n * @command --hide - Sets `open = false`.\n *\n * @customElement l-dialog\n */\nexport class Dialog extends LuxenElement {\n static styles = [hostStyles, styles];\n\n /** Dialog title rendered in the header and used as the dialog's accessible name. */\n @property()\n title = '';\n\n /** Whether the dialog is open. */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /** Close when the backdrop is clicked. */\n @property({ type: Boolean, reflect: true, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /** Hide the header entirely (title and close slot). */\n @property({ type: Boolean, reflect: true, attribute: 'without-header' })\n withoutHeader = false;\n\n // Tracks whether the footer slot has content, so the footer row can collapse\n // when empty (toggles `data-empty` below). A controller drives this because\n // `:host(:has(> [slot='footer']))` is invalid — `:has()` can't be nested in\n // `:host()`, so browsers drop the whole rule.\n private _slots = new HasSlotController(this, 'footer');\n\n @query('dialog')\n dialog!: HTMLDialogElement;\n\n // Drives the scroll-lock stylesheet: `centered` reserves the scrollbar\n // gutter (no page shift); `edge` skips it (drawers sit flush to the edge).\n protected _modalKind: 'centered' | 'edge' = 'centered';\n\n // Subclass seams (defaults keep `l-dialog` unchanged). `alert-dialog`\n // overrides these to expose `role=\"alertdialog\"` and wire `aria-describedby`\n // to the body. `_bodyId` drives both the body's `id` and `aria-describedby`,\n // so the association can't drift; an empty string emits neither.\n protected get _role(): string {\n return '';\n }\n protected get _bodyId(): string {\n return '';\n }\n\n private _mouseDownTarget: EventTarget | null = null;\n\n private _commandListener: EventListenerObject = {\n handleEvent: (e: Event) => this._onCommand(e as CommandEventLike),\n };\n\n // --- Lifecycle ---\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('command', this._commandListener);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('command', this._commandListener);\n }\n\n firstUpdated() {\n this.dialog.addEventListener('cancel', (e) => this._onCancel(e));\n this.dialog.addEventListener('close', () => this._onNativeClose());\n this.dialog.addEventListener('mousedown', (e) => {\n this._mouseDownTarget = e.target;\n });\n this.dialog.addEventListener('click', (e) => this._onDialogClick(e));\n }\n\n updated(changed: PropertyValues<this>) {\n if (!changed.has('open')) return;\n\n if (this.open && !this.dialog.open) {\n // Opening — cancelable. Revert the property if consumer prevents.\n if (!this.dispatchEvent(new ShowEvent())) {\n // Defer the revert so it lands outside the current update cycle and\n // doesn't schedule a new update from inside updated().\n queueMicrotask(() => {\n this.open = false;\n });\n return;\n }\n this.setAttribute('data-modal', this._modalKind);\n this.dialog.showModal();\n this._focusInitial();\n void this._emitAfter('after-show');\n } else if (!this.open && this.dialog.open) {\n // Closing — cancelable. Revert the property if consumer prevents.\n if (!this.dispatchEvent(new HideEvent())) {\n // Defer the revert so it lands outside the current update cycle and\n // doesn't schedule a new update from inside updated().\n queueMicrotask(() => {\n this.open = true;\n });\n return;\n }\n this.dialog.close();\n // `after-hide` is emitted from `_onNativeClose` (runs for every close path).\n }\n }\n\n // --- Event handlers ---\n\n // Custom commands on a custom element must start with `--`.\n // Built-in commands like \"close\" are reserved for native elements\n // and won't fire here.\n private _onCommand(e: CommandEventLike) {\n switch (e.command) {\n case '--hide':\n this.open = false;\n break;\n case '--show':\n this.open = true;\n break;\n }\n }\n\n // Fires on Escape and on `closedby=\"any\"` close requests.\n // Does NOT fire when script calls `.close()`, so `updated()`'s cancelable\n // `hide` emit doesn't collide with this one.\n protected _onCancel(e: Event) {\n if (!this.dispatchEvent(new HideEvent())) {\n e.preventDefault();\n }\n }\n\n private _onNativeClose() {\n this.open = false;\n this.removeAttribute('data-modal');\n void this._emitAfter('after-hide');\n }\n\n private _onDialogClick(e: MouseEvent) {\n // With `dialog { padding: 0 }`, `e.target === this.dialog` only fires\n // for backdrop clicks. The mousedown guard prevents drag-out dismissal.\n const clickedBackdrop = e.target === this.dialog && this._mouseDownTarget === this.dialog;\n this._mouseDownTarget = null;\n if (!clickedBackdrop) return;\n\n if (this.lightDismiss) {\n // When `supportsClosedBy`, the native `closedby=\"any\"` already closed.\n if (!supportsClosedBy) this.open = false;\n return;\n }\n this._nudgeDismiss();\n }\n\n private _nudgeAnimation?: Animation;\n\n private _nudgeDismiss() {\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n this._nudgeAnimation?.cancel();\n this._nudgeAnimation = this.dialog.animate(\n [{ transform: 'scale(1)' }, { transform: 'scale(1.02)' }, { transform: 'scale(1)' }],\n { duration: 250, easing: 'ease-in-out' },\n );\n }\n\n // Awaits every active animation on the dialog (transitions + @keyframes)\n // and then emits. Resolves immediately when no animations are running,\n // which covers `prefers-reduced-motion` and consumers that zero the\n // duration custom properties — cases where `transitionend` never fires.\n // Waits one frame first so @starting-style transitions have registered.\n private async _emitAfter(name: 'after-show' | 'after-hide') {\n await new Promise((r) => requestAnimationFrame(() => r(null)));\n const anims = this.dialog.getAnimations({ subtree: false });\n await Promise.all(anims.map((a) => a.finished.catch(() => {})));\n if ((name === 'after-show') !== this.open) return;\n this.dispatchEvent(name === 'after-show' ? new AfterShowEvent() : new AfterHideEvent());\n }\n\n // Firefox/Safari don't reliably resolve `[autofocus]` when `<dialog>`\n // is in shadow DOM and the target is in light DOM. Resolve it manually.\n // Subclasses (alert-dialog) override to fall back to a shadow-DOM target.\n protected _focusInitial() {\n const target = this.querySelector<HTMLElement>('[autofocus]');\n target?.focus({ preventScroll: true });\n }\n\n render() {\n const closedby = this.lightDismiss && supportsClosedBy ? 'any' : nothing;\n return html`\n <dialog\n part=\"dialog\"\n role=${this._role || nothing}\n closedby=${closedby}\n aria-labelledby=${this.withoutHeader ? nothing : 'title-area'}\n aria-label=${this.title || nothing}\n aria-describedby=${this._bodyId || nothing}\n >\n ${\n this.withoutHeader\n ? nothing\n : html`\n <header part=\"header\">\n <slot\n name=\"title\"\n id=\"title-area\"\n >\n ${this.title ? html`<h2 part=\"title\">${this.title}</h2>` : nothing}\n </slot>\n <slot name=\"close\"></slot>\n </header>\n `\n }\n <div\n part=\"body\"\n id=${this._bodyId || nothing}\n >\n <slot></slot>\n </div>\n ${this.renderFooter()}\n </dialog>\n `;\n }\n\n // Footer row. Overridden by subclasses (alert-dialog) to render their own\n // actions in place of the default `footer` slot.\n protected renderFooter() {\n return html`\n <footer\n part=\"footer\"\n ?data-empty=${!this._slots.test('footer')}\n >\n <slot name=\"footer\"></slot>\n </footer>\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dialog.js","names":["hostStyles","styles","nothing","_decorate","property","query","n","e","b","A","host_styles_default","dialog_styles_default","supportsClosedBy","SCROLL_LOCK_SHEET","sheet","Dialog","LuxenElement","_args","HasSlotController","changed","ShowEvent","HideEvent","clickedBackdrop","r","anims","a","name","AfterShowEvent","AfterHideEvent","closedby","__decorate"],"sources":["../../../src/html/elements/dialog/dialog.ts"],"sourcesContent":["import { html, nothing, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { HasSlotController } from '../../shared/controllers/has-slot-controller.js';\nimport { ShowEvent, AfterShowEvent, HideEvent, AfterHideEvent } from '../../events/index.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport styles from './dialog.styles.js';\n\ninterface CommandEventLike extends Event {\n command: string;\n source: Element | null;\n}\n\nconst supportsClosedBy =\n typeof HTMLDialogElement !== 'undefined' && 'closedBy' in HTMLDialogElement.prototype;\n\n// Native <dialog> doesn't lock body scroll. Inject a global rule that uses\n// `:has()` to freeze the root scroll container whenever any modal l-dialog\n// is open. Purely declarative — no manual lock/unlock bookkeeping.\n// Symbol guard makes the injection idempotent across HMR reloads.\n//\n// `scrollbar-gutter: stable` only applies to centered modals — it prevents\n// the page behind from shifting horizontally when the scrollbar disappears.\n// Edge-attached modals (drawers) opt out via `data-modal=\"edge\"`: a reserved\n// gutter would push the drawer off the actual viewport edge.\nconst SCROLL_LOCK_SHEET = Symbol.for('luxen-dialog-scroll-lock');\nif (typeof document !== 'undefined' && !(SCROLL_LOCK_SHEET in document)) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n html:has([data-modal]) { overflow: hidden; }\n html:has([data-modal=\"centered\"]) { scrollbar-gutter: stable; }\n `);\n document.adoptedStyleSheets.push(sheet);\n Object.defineProperty(document, SCROLL_LOCK_SHEET, { value: sheet });\n}\n\n/**\n * A modal dialog rendered in the top layer via the native `<dialog>` element.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). There are no public `show()` / `close()` methods.\n *\n * @slot - Body content.\n * @slot title - Custom heading element. Overrides the default `<h2>` rendered from the `title` property. Also provides the dialog's accessible name.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The dialog title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty [--width=31rem] - Dialog width.\n * @cssproperty [--border-radius=6px] - Dialog border radius.\n * @cssproperty [--padding=1.5rem] - Padding applied to the header, footer, and inline-padding of the body. Set to `0` to remove all internal spacing (e.g. for edge-to-edge media).\n * @cssproperty [--show-duration=200ms] - Open transition duration.\n * @cssproperty [--hide-duration=200ms] - Close transition duration.\n * @cssproperty [--easing=cubic-bezier(0.32, 0.72, 0, 1)] - Timing function of the open and close transitions, backdrop included.\n * @cssproperty [--backdrop=var(--l-backdrop)] - Backdrop color.\n * @cssproperty [--backdrop-blur=0] - Backdrop blur amount (any CSS length). `0` means no blur; set e.g. `4px` for a subtle frost.\n * @cssproperty [--shadow=none] - Drop shadow of the dialog panel (any `box-shadow` value). Raise it when the backdrop is light, where the panel edge would otherwise fade into the page.\n *\n * @event show - Fired when the dialog is about to open. Cancelable — call `event.preventDefault()` to keep it closed.\n * @event after-show - Fired after the open animation completes. Not cancelable.\n * @event hide - Fired when the dialog is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes. Not cancelable.\n *\n * @command --show - Sets `open = true`.\n * @command --hide - Sets `open = false`.\n *\n * @customElement l-dialog\n */\nexport class Dialog extends LuxenElement {\n static styles = [hostStyles, styles];\n\n /** Dialog title rendered in the header and used as the dialog's accessible name. */\n @property()\n title = '';\n\n /** Whether the dialog is open. */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /** Close when the backdrop is clicked. */\n @property({ type: Boolean, reflect: true, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /** Hide the header entirely (title and close slot). */\n @property({ type: Boolean, reflect: true, attribute: 'without-header' })\n withoutHeader = false;\n\n // Tracks whether the footer slot has content, so the footer row can collapse\n // when empty (toggles `data-empty` below). A controller drives this because\n // `:host(:has(> [slot='footer']))` is invalid — `:has()` can't be nested in\n // `:host()`, so browsers drop the whole rule.\n private _slots = new HasSlotController(this, 'footer');\n\n @query('dialog')\n dialog!: HTMLDialogElement;\n\n // Drives the scroll-lock stylesheet: `centered` reserves the scrollbar\n // gutter (no page shift); `edge` skips it (drawers sit flush to the edge).\n protected _modalKind: 'centered' | 'edge' = 'centered';\n\n // Subclass seams (defaults keep `l-dialog` unchanged). `alert-dialog`\n // overrides these to expose `role=\"alertdialog\"` and wire `aria-describedby`\n // to the body. `_bodyId` drives both the body's `id` and `aria-describedby`,\n // so the association can't drift; an empty string emits neither.\n protected get _role(): string {\n return '';\n }\n protected get _bodyId(): string {\n return '';\n }\n\n private _mouseDownTarget: EventTarget | null = null;\n\n private _commandListener: EventListenerObject = {\n handleEvent: (e: Event) => this._onCommand(e as CommandEventLike),\n };\n\n // --- Lifecycle ---\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('command', this._commandListener);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('command', this._commandListener);\n }\n\n firstUpdated() {\n this.dialog.addEventListener('cancel', (e) => this._onCancel(e));\n this.dialog.addEventListener('close', () => this._onNativeClose());\n this.dialog.addEventListener('mousedown', (e) => {\n this._mouseDownTarget = e.target;\n });\n this.dialog.addEventListener('click', (e) => this._onDialogClick(e));\n }\n\n updated(changed: PropertyValues<this>) {\n if (!changed.has('open')) return;\n\n if (this.open && !this.dialog.open) {\n // Opening — cancelable. Revert the property if consumer prevents.\n if (!this.dispatchEvent(new ShowEvent())) {\n // Defer the revert so it lands outside the current update cycle and\n // doesn't schedule a new update from inside updated().\n queueMicrotask(() => {\n this.open = false;\n });\n return;\n }\n this.setAttribute('data-modal', this._modalKind);\n this.dialog.showModal();\n this._focusInitial();\n void this._emitAfter('after-show');\n } else if (!this.open && this.dialog.open) {\n // Closing — cancelable. Revert the property if consumer prevents.\n if (!this.dispatchEvent(new HideEvent())) {\n // Defer the revert so it lands outside the current update cycle and\n // doesn't schedule a new update from inside updated().\n queueMicrotask(() => {\n this.open = true;\n });\n return;\n }\n this.dialog.close();\n // `after-hide` is emitted from `_onNativeClose` (runs for every close path).\n }\n }\n\n // --- Event handlers ---\n\n // Custom commands on a custom element must start with `--`.\n // Built-in commands like \"close\" are reserved for native elements\n // and won't fire here.\n private _onCommand(e: CommandEventLike) {\n switch (e.command) {\n case '--hide':\n this.open = false;\n break;\n case '--show':\n this.open = true;\n break;\n }\n }\n\n // Fires on Escape and on `closedby=\"any\"` close requests.\n // Does NOT fire when script calls `.close()`, so `updated()`'s cancelable\n // `hide` emit doesn't collide with this one.\n protected _onCancel(e: Event) {\n if (!this.dispatchEvent(new HideEvent())) {\n e.preventDefault();\n }\n }\n\n private _onNativeClose() {\n this.open = false;\n this.removeAttribute('data-modal');\n void this._emitAfter('after-hide');\n }\n\n private _onDialogClick(e: MouseEvent) {\n // With `dialog { padding: 0 }`, `e.target === this.dialog` only fires\n // for backdrop clicks. The mousedown guard prevents drag-out dismissal.\n const clickedBackdrop = e.target === this.dialog && this._mouseDownTarget === this.dialog;\n this._mouseDownTarget = null;\n if (!clickedBackdrop) return;\n\n if (this.lightDismiss) {\n // When `supportsClosedBy`, the native `closedby=\"any\"` already closed.\n if (!supportsClosedBy) this.open = false;\n return;\n }\n this._nudgeDismiss();\n }\n\n private _nudgeAnimation?: Animation;\n\n private _nudgeDismiss() {\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n this._nudgeAnimation?.cancel();\n this._nudgeAnimation = this.dialog.animate(\n [{ transform: 'scale(1)' }, { transform: 'scale(1.02)' }, { transform: 'scale(1)' }],\n { duration: 250, easing: 'ease-in-out' },\n );\n }\n\n // Awaits every active animation on the dialog (transitions + @keyframes)\n // and then emits. Resolves immediately when no animations are running,\n // which covers `prefers-reduced-motion` and consumers that zero the\n // duration custom properties — cases where `transitionend` never fires.\n // Waits one frame first so @starting-style transitions have registered.\n private async _emitAfter(name: 'after-show' | 'after-hide') {\n await new Promise((r) => requestAnimationFrame(() => r(null)));\n const anims = this.dialog.getAnimations({ subtree: false });\n await Promise.all(anims.map((a) => a.finished.catch(() => {})));\n if ((name === 'after-show') !== this.open) return;\n this.dispatchEvent(name === 'after-show' ? new AfterShowEvent() : new AfterHideEvent());\n }\n\n // Firefox/Safari don't reliably resolve `[autofocus]` when `<dialog>`\n // is in shadow DOM and the target is in light DOM. Resolve it manually.\n // Subclasses (alert-dialog) override to fall back to a shadow-DOM target.\n protected _focusInitial() {\n const target = this.querySelector<HTMLElement>('[autofocus]');\n target?.focus({ preventScroll: true });\n }\n\n render() {\n const closedby = this.lightDismiss && supportsClosedBy ? 'any' : nothing;\n return html`\n <dialog\n part=\"dialog\"\n role=${this._role || nothing}\n closedby=${closedby}\n aria-labelledby=${this.withoutHeader ? nothing : 'title-area'}\n aria-label=${this.title || nothing}\n aria-describedby=${this._bodyId || nothing}\n >\n ${\n this.withoutHeader\n ? nothing\n : html`\n <header part=\"header\">\n <slot\n name=\"title\"\n id=\"title-area\"\n >\n ${this.title ? html`<h2 part=\"title\">${this.title}</h2>` : nothing}\n </slot>\n <slot name=\"close\"></slot>\n </header>\n `\n }\n <div\n part=\"body\"\n id=${this._bodyId || nothing}\n >\n <slot></slot>\n </div>\n ${this.renderFooter()}\n </dialog>\n `;\n }\n\n // Footer row. Overridden by subclasses (alert-dialog) to render their own\n // actions in place of the default `footer` slot.\n protected renderFooter() {\n return html`\n <footer\n part=\"footer\"\n ?data-empty=${!this._slots.test('footer')}\n >\n <slot name=\"footer\"></slot>\n </footer>\n `;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"../../chunks/lit.js";var t=e(`:host{--width:31rem;--border-radius:6px;--padding:1.5rem;--header-padding:var(--padding);--footer-padding:var(--padding);--show-duration:.2s;--hide-duration:.2s;--easing:cubic-bezier(.32, .72, 0, 1);--backdrop:var(--l-backdrop);--backdrop-blur:0;display:contents}dialog{box-sizing:border-box;width:var(--width);max-inline-size:min(90vw, var(--width));border-radius:var(--border-radius);background-color:var(--l-color-surface-overlay);max-block-size:min(80dvb,100%);color:var(--l-color-text-primary);opacity:0;transition-property:opacity,display,overlay;transition-duration:var(--hide-duration);transition-timing-function:var(--easing);transition-behavior:allow-discrete
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";var t=e(`:host{--width:31rem;--border-radius:6px;--padding:1.5rem;--header-padding:var(--padding);--footer-padding:var(--padding);--show-duration:.2s;--hide-duration:.2s;--easing:cubic-bezier(.32, .72, 0, 1);--backdrop:var(--l-backdrop);--backdrop-blur:0;--shadow:none;display:contents}dialog{box-sizing:border-box;width:var(--width);max-inline-size:min(90vw, var(--width));border-radius:var(--border-radius);background-color:var(--l-color-surface-overlay);max-block-size:min(80dvb,100%);color:var(--l-color-text-primary);box-shadow:var(--shadow);border:0;margin:auto;padding:0;position:fixed;inset:0}@media (forced-colors:active){dialog{outline:1px solid canvastext}}dialog{opacity:0;transition-property:opacity,display,overlay;transition-duration:var(--hide-duration);transition-timing-function:var(--easing);transition-behavior:allow-discrete}dialog::backdrop{background:var(--backdrop);-webkit-backdrop-filter:blur(var(--backdrop-blur));backdrop-filter:blur(var(--backdrop-blur));opacity:0;transition-property:opacity,display,overlay;transition-duration:var(--hide-duration);transition-timing-function:var(--easing);transition-behavior:allow-discrete}dialog[open]{opacity:1;transition-duration:var(--show-duration);grid-template-rows:auto minmax(0,1fr) auto;display:grid}dialog[open]::backdrop{opacity:1;transition-duration:var(--show-duration)}@starting-style{dialog[open],dialog[open]::backdrop{opacity:0}}[part=header]{padding:var(--header-padding);justify-content:space-between;align-items:center;gap:1rem;display:flex}[part=title]{font-size:1.125rem;font-weight:var(--l-font-weight-semibold);margin:0;line-height:1.4}[part=body]{padding-inline:var(--padding);grid-row:2;overflow-y:auto}[part=footer]{padding:var(--footer-padding);grid-row:3;place-content:end;gap:.5rem;display:flex}[part=footer][data-empty]{display:none}[part=body]:has(~[part=footer][data-empty]){padding-block-end:var(--padding)}:host([without-header]) [part=body]{padding-block-start:var(--padding)}::slotted(menu[slot=footer]){display:contents}@media (prefers-reduced-motion:reduce){:host{--show-duration:0s;--hide-duration:0s}}`);export{t as default};
|
|
2
2
|
//# sourceMappingURL=dialog.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.styles.js","names":["unsafeCSS","raw","r","dialog_styles_default"],"sources":["../../../src/html/elements/dialog/dialog.css?inline","../../../src/html/elements/dialog/dialog.styles.ts"],"sourcesContent":[":host {\n --width: 31rem;\n --border-radius: 6px;\n --padding: 1.5rem;\n --header-padding: var(--padding);\n --footer-padding: var(--padding);\n --show-duration: 200ms;\n --hide-duration: 200ms;\n /* Fast start, soft landing: the surface is nearly in place early, the\n tail only settles it. */\n --easing: cubic-bezier(0.32, 0.72, 0, 1);\n --backdrop: var(--l-backdrop);\n --backdrop-blur: 0;\n\n display: contents;\n}\n\ndialog {\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n width: var(--width);\n max-inline-size: min(90vw, var(--width));\n max-block-size: min(80dvb, 100%);\n margin: auto;\n padding: 0;\n border: 0;\n border-radius: var(--border-radius);\n background-color: var(--l-color-surface-overlay);\n color: var(--l-color-text-primary);\n\n /* EXIT STATE */\n opacity: 0;\n\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-timing-function: var(--easing);\n transition-behavior: allow-discrete;\n\n /* The backdrop does not inherit the dialog's opacity: without its own\n transition it pops in and out at full strength. */\n &::backdrop {\n background: var(--backdrop);\n backdrop-filter: blur(var(--backdrop-blur));\n opacity: 0;\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-timing-function: var(--easing);\n transition-behavior: allow-discrete;\n }\n\n /* OPEN STATE */\n /* grid layout pins header/footer; the middle row (body) scrolls via\n overflow on [part='body'] and minmax(0, 1fr) allowing it to shrink. */\n &[open] {\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n &[open]::backdrop {\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n /* BEFORE-OPEN STATE */\n @starting-style {\n &[open],\n &[open]::backdrop {\n opacity: 0;\n }\n }\n}\n\n[part='header'] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 1rem;\n padding: var(--header-padding);\n}\n\n[part='title'] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: var(--l-font-weight-semibold);\n line-height: 1.4;\n}\n\n/* Pin body and footer so the layout stays correct when [without-header]\n removes the header and only two children auto-place into the grid. */\n[part='body'] {\n grid-row: 2;\n padding-inline: var(--padding);\n overflow-y: auto;\n}\n\n[part='footer'] {\n grid-row: 3;\n display: flex;\n place-content: end;\n gap: 0.5rem;\n padding: var(--footer-padding);\n}\n\n/* Collapse the footer row when nothing is slotted into it, so an empty\n dialog/drawer reserves no space at the bottom. `data-empty` is toggled by the\n HasSlotController in dialog.ts: `:host(:has(...))` can't be used because\n `:has()` is invalid inside `:host()` and the whole rule is dropped by the\n browser. */\n[part='footer'][data-empty] {\n display: none;\n}\n\n/* With the footer collapsed, the body has to provide its own block-end padding\n (normally inherited visually from the footer padding below it). */\n[part='body']:has(~ [part='footer'][data-empty]) {\n padding-block-end: var(--padding);\n}\n\n/* Without a header, the body has to provide its own block-start padding\n (normally inherited visually from the header padding above it). */\n:host([without-header]) [part='body'] {\n padding-block-start: var(--padding);\n}\n\n::slotted(menu[slot='footer']) {\n display: contents;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport raw from './dialog.css?inline';\n\n/**\n * Wrapper module: imported by both `dialog.ts` and `drawer.ts`.\n * `unsafeCSS()` is called once here so both importers share the same\n * `CSSResult` instance (one constructed `CSSStyleSheet`, not two).\n */\nexport default unsafeCSS(raw);\n"],"mappings":"A,wCCQA,IAAAG,EAAeH,EAAUC,
|
|
1
|
+
{"version":3,"file":"dialog.styles.js","names":["unsafeCSS","raw","r","dialog_styles_default"],"sources":["../../../src/html/elements/dialog/dialog.css?inline","../../../src/html/elements/dialog/dialog.styles.ts"],"sourcesContent":[":host {\n --width: 31rem;\n --border-radius: 6px;\n --padding: 1.5rem;\n --header-padding: var(--padding);\n --footer-padding: var(--padding);\n --show-duration: 200ms;\n --hide-duration: 200ms;\n /* Fast start, soft landing: the surface is nearly in place early, the\n tail only settles it. */\n --easing: cubic-bezier(0.32, 0.72, 0, 1);\n --backdrop: var(--l-backdrop);\n --backdrop-blur: 0;\n /* No shadow by default: on the standard backdrop the contrast already lifts\n the surface. A lighter backdrop needs one to keep the edge readable. */\n --shadow: none;\n\n display: contents;\n}\n\ndialog {\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n width: var(--width);\n max-inline-size: min(90vw, var(--width));\n max-block-size: min(80dvb, 100%);\n margin: auto;\n padding: 0;\n border: 0;\n border-radius: var(--border-radius);\n background-color: var(--l-color-surface-overlay);\n color: var(--l-color-text-primary);\n box-shadow: var(--shadow);\n\n /* Forced colors repaint the panel and the page with the same Canvas color\n and drop every box-shadow (the --shadow ring included), so a borderless\n panel loses its edge entirely. An outline survives, takes no layout space\n and follows the border radius; CanvasText is the system foreground. */\n @media (forced-colors: active) {\n outline: 1px solid CanvasText;\n }\n\n /* EXIT STATE */\n opacity: 0;\n\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-timing-function: var(--easing);\n transition-behavior: allow-discrete;\n\n /* The backdrop does not inherit the dialog's opacity: without its own\n transition it pops in and out at full strength. */\n &::backdrop {\n background: var(--backdrop);\n backdrop-filter: blur(var(--backdrop-blur));\n opacity: 0;\n transition-property: opacity, display, overlay;\n transition-duration: var(--hide-duration);\n transition-timing-function: var(--easing);\n transition-behavior: allow-discrete;\n }\n\n /* OPEN STATE */\n /* grid layout pins header/footer; the middle row (body) scrolls via\n overflow on [part='body'] and minmax(0, 1fr) allowing it to shrink. */\n &[open] {\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n &[open]::backdrop {\n opacity: 1;\n transition-duration: var(--show-duration);\n }\n\n /* BEFORE-OPEN STATE */\n @starting-style {\n &[open],\n &[open]::backdrop {\n opacity: 0;\n }\n }\n}\n\n[part='header'] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 1rem;\n padding: var(--header-padding);\n}\n\n[part='title'] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: var(--l-font-weight-semibold);\n line-height: 1.4;\n}\n\n/* Pin body and footer so the layout stays correct when [without-header]\n removes the header and only two children auto-place into the grid. */\n[part='body'] {\n grid-row: 2;\n padding-inline: var(--padding);\n overflow-y: auto;\n}\n\n[part='footer'] {\n grid-row: 3;\n display: flex;\n place-content: end;\n gap: 0.5rem;\n padding: var(--footer-padding);\n}\n\n/* Collapse the footer row when nothing is slotted into it, so an empty\n dialog/drawer reserves no space at the bottom. `data-empty` is toggled by the\n HasSlotController in dialog.ts: `:host(:has(...))` can't be used because\n `:has()` is invalid inside `:host()` and the whole rule is dropped by the\n browser. */\n[part='footer'][data-empty] {\n display: none;\n}\n\n/* With the footer collapsed, the body has to provide its own block-end padding\n (normally inherited visually from the footer padding below it). */\n[part='body']:has(~ [part='footer'][data-empty]) {\n padding-block-end: var(--padding);\n}\n\n/* Without a header, the body has to provide its own block-start padding\n (normally inherited visually from the header padding above it). */\n:host([without-header]) [part='body'] {\n padding-block-start: var(--padding);\n}\n\n::slotted(menu[slot='footer']) {\n display: contents;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n","import { unsafeCSS } from 'lit';\nimport raw from './dialog.css?inline';\n\n/**\n * Wrapper module: imported by both `dialog.ts` and `drawer.ts`.\n * `unsafeCSS()` is called once here so both importers share the same\n * `CSSResult` instance (one constructed `CSSStyleSheet`, not two).\n */\nexport default unsafeCSS(raw);\n"],"mappings":"A,wCCQA,IAAAG,EAAeH,EAAUC,qjEAAG,E"}
|
|
@@ -16,13 +16,13 @@ import { Dialog } from '../dialog/dialog.js';
|
|
|
16
16
|
* @csspart body - The body wrapper around the default slot.
|
|
17
17
|
* @csspart footer - The footer wrapper around the footer slot.
|
|
18
18
|
*
|
|
19
|
-
* @cssproperty --size - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `top`/`bottom`).
|
|
20
|
-
* @cssproperty --border-radius - Drawer border radius on the inner edges (all corners when `inset`).
|
|
21
|
-
* @cssproperty --inset-gap - Gap between the drawer and the viewport edges when `inset` is set.
|
|
22
|
-
* @cssproperty --shadow - Drop shadow applied to the floating panel when `inset` is set. Set to `none` to remove it.
|
|
23
|
-
* @cssproperty --show-duration - Open transition duration.
|
|
24
|
-
* @cssproperty --hide-duration - Close transition duration.
|
|
25
|
-
* @cssproperty --easing - Timing function of the open and close transitions, backdrop included.
|
|
19
|
+
* @cssproperty [--size=320px] - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `top`/`bottom`).
|
|
20
|
+
* @cssproperty [--border-radius=0.375rem] - Drawer border radius on the inner edges (all corners when `inset`).
|
|
21
|
+
* @cssproperty [--inset-gap=1rem] - Gap between the drawer and the viewport edges when `inset` is set.
|
|
22
|
+
* @cssproperty [--shadow=var(--l-shadow-lg)] - Drop shadow applied to the floating panel when `inset` is set (an edge drawer casts none). Set to `none` to remove it.
|
|
23
|
+
* @cssproperty [--show-duration=300ms] - Open transition duration.
|
|
24
|
+
* @cssproperty [--hide-duration=200ms] - Close transition duration.
|
|
25
|
+
* @cssproperty [--easing=cubic-bezier(0.32, 0.72, 0, 1)] - Timing function of the open and close transitions, backdrop included.
|
|
26
26
|
* @cssproperty --backdrop - Backdrop color.
|
|
27
27
|
*
|
|
28
28
|
* @event show - Fired when the drawer is about to open. Cancelable — call `event.preventDefault()` to keep it closed.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"../../chunks/lit.js";import{r as t,t as n}from"../../chunks/decorate.js";import r from"../../shared/styles/host.styles.js";import{Dialog as i}from"../dialog/dialog.js";import a from"../dialog/dialog.styles.js";var o=e(`:host{--size:320px;--border-radius:.375rem;--inset-gap:1rem;--shadow:var(--l-shadow-lg);--show-duration:.3s}@media (prefers-reduced-motion:reduce){:host{--show-duration:0s;--hide-duration:0s}}dialog{width:min(var(--size), 100dvw);max-inline-size:100dvw;height:100dvh;border-radius:0 var(--border-radius) var(--border-radius) 0;opacity:1;max-block-size:100dvh;margin:0;transition-property:translate,display,overlay;inset:0;translate:-100%}dialog[open]{translate:0}@starting-style{dialog[open]{translate:-100%}}:host([placement=end]) dialog{border-radius:var(--border-radius) 0 0 var(--border-radius);margin-inline-start:auto;translate:100%}:host([placement=end]) dialog[open]{translate:0}@starting-style{:host([placement=end]) dialog[open]{translate:100%}}:host([placement=bottom]) dialog{width:100dvw;max-inline-size:100dvw;height:min(var(--size), 100dvh);border-radius:var(--border-radius) var(--border-radius) 0 0;max-block-size:100dvh;margin-block-start:auto;translate:0 100%}:host([placement=bottom]) dialog[open]{translate:0}@starting-style{:host([placement=bottom]) dialog[open]{translate:0 100%}}:host([placement=top]) dialog{width:100dvw;max-inline-size:100dvw;height:min(var(--size), 100dvh);border-radius:0 0 var(--border-radius) var(--border-radius);max-block-size:100dvh;translate:0 -100%}:host([placement=top]) dialog[open]{translate:0}@starting-style{:host([placement=top]) dialog[open]{translate:0 -100%}}:host([inset]) dialog{border-radius:var(--border-radius)
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{r as t,t as n}from"../../chunks/decorate.js";import r from"../../shared/styles/host.styles.js";import{Dialog as i}from"../dialog/dialog.js";import a from"../dialog/dialog.styles.js";var o=e(`:host{--size:320px;--border-radius:.375rem;--inset-gap:1rem;--shadow:var(--l-shadow-lg);--show-duration:.3s}@media (prefers-reduced-motion:reduce){:host{--show-duration:0s;--hide-duration:0s}}dialog{width:min(var(--size), 100dvw);max-inline-size:100dvw;height:100dvh;border-radius:0 var(--border-radius) var(--border-radius) 0;opacity:1;max-block-size:100dvh;margin:0;transition-property:translate,display,overlay;inset:0;translate:-100%}dialog[open]{translate:0}@starting-style{dialog[open]{translate:-100%}}:host([placement=end]) dialog{border-radius:var(--border-radius) 0 0 var(--border-radius);margin-inline-start:auto;translate:100%}:host([placement=end]) dialog[open]{translate:0}@starting-style{:host([placement=end]) dialog[open]{translate:100%}}:host([placement=bottom]) dialog{width:100dvw;max-inline-size:100dvw;height:min(var(--size), 100dvh);border-radius:var(--border-radius) var(--border-radius) 0 0;max-block-size:100dvh;margin-block-start:auto;translate:0 100%}:host([placement=bottom]) dialog[open]{translate:0}@starting-style{:host([placement=bottom]) dialog[open]{translate:0 100%}}:host([placement=top]) dialog{width:100dvw;max-inline-size:100dvw;height:min(var(--size), 100dvh);border-radius:0 0 var(--border-radius) var(--border-radius);max-block-size:100dvh;translate:0 -100%}:host([placement=top]) dialog[open]{translate:0}@starting-style{:host([placement=top]) dialog[open]{translate:0 -100%}}:host([inset]) dialog{border-radius:var(--border-radius)}:host(:not([inset])) dialog{box-shadow:none}:host([inset]:not([placement])) dialog,:host([inset][placement=start]) dialog,:host([inset][placement=end]) dialog{height:calc(100dvh - 2 * var(--inset-gap));inset-block:var(--inset-gap)}:host([inset][placement=top]) dialog,:host([inset][placement=bottom]) dialog{width:calc(100dvw - 2 * var(--inset-gap));inset-inline:var(--inset-gap)}:host([inset]:not([placement])) dialog,:host([inset][placement=start]) dialog{inset-inline-start:var(--inset-gap)}:host([inset]:not([placement])) dialog:not([open]),:host([inset][placement=start]) dialog:not([open]){translate:calc(-100% - var(--inset-gap)) 0}@starting-style{:host([inset]:not([placement])) dialog[open],:host([inset][placement=start]) dialog[open]{translate:calc(-100% - var(--inset-gap)) 0}}:host([inset][placement=end]) dialog{margin-inline-start:0;inset-inline-start:auto;inset-inline-end:var(--inset-gap)}:host([inset][placement=end]) dialog:not([open]){translate:calc(100% + var(--inset-gap)) 0}@starting-style{:host([inset][placement=end]) dialog[open]{translate:calc(100% + var(--inset-gap)) 0}}:host([inset][placement=top]) dialog{inset-block-start:var(--inset-gap)}:host([inset][placement=top]) dialog:not([open]){translate:0 calc(-100% - var(--inset-gap))}@starting-style{:host([inset][placement=top]) dialog[open]{translate:0 calc(-100% - var(--inset-gap))}}:host([inset][placement=bottom]) dialog{margin-block-start:0;inset-block-start:auto;inset-block-end:var(--inset-gap)}:host([inset][placement=bottom]) dialog:not([open]){translate:0 calc(100% + var(--inset-gap))}@starting-style{:host([inset][placement=bottom]) dialog[open]{translate:0 calc(100% + var(--inset-gap))}}`),s=class extends i{constructor(...e){super(...e),this._modalKind=`edge`,this.inset=!1}static{this.styles=[r,a,o]}};n([t({reflect:!0})],s.prototype,`placement`,void 0),n([t({type:Boolean,reflect:!0})],s.prototype,`inset`,void 0);export{s as Drawer};
|
|
2
2
|
//# sourceMappingURL=drawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer.js","names":["unsafeCSS","rawDrawerStyles","hostStyles","dialogStyles","_decorate","property","r","n","__decorate","host_styles_default","dialog_styles_default","drawerStyles","Drawer","Dialog","_args"],"sources":["../../../src/html/elements/drawer/drawer.css?inline","../../../src/html/elements/drawer/drawer.ts"],"sourcesContent":[":host {\n --size: 320px;\n --border-radius: 0.375rem;\n --inset-gap: 1rem;\n --shadow: var(--l-shadow-lg);\n /* A slide travels much further than the dialog's fade. */\n --show-duration: 300ms;\n}\n\n/* Restated: this sheet comes after dialog.css, so the default above would\n otherwise win over its reduced-motion override. */\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n\n/* Override dialog's opacity fade with a slide from the inline-start edge. */\ndialog {\n inset: 0;\n margin: 0;\n width: min(var(--size), 100dvw);\n max-inline-size: 100dvw;\n height: 100dvh;\n max-block-size: 100dvh;\n border-radius: 0 var(--border-radius) var(--border-radius) 0;\n opacity: 1;\n translate: -100% 0;\n transition-property: translate, display, overlay;\n}\n\ndialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n dialog[open] {\n translate: -100% 0;\n }\n}\n\n/* Inline-end edge */\n:host([placement='end']) dialog {\n border-radius: var(--border-radius) 0 0 var(--border-radius);\n margin-inline-start: auto;\n translate: 100% 0;\n}\n\n:host([placement='end']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='end']) dialog[open] {\n translate: 100% 0;\n }\n}\n\n/* Block-end (bottom) edge */\n:host([placement='bottom']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n margin-block-start: auto;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n translate: 0 100%;\n}\n\n:host([placement='bottom']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='bottom']) dialog[open] {\n translate: 0 100%;\n }\n}\n\n/* Block-start (top) edge */\n:host([placement='top']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n border-radius: 0 0 var(--border-radius) var(--border-radius);\n translate: 0 -100%;\n}\n\n:host([placement='top']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='top']) dialog[open] {\n translate: 0 -100%;\n }\n}\n\n/* Inset: float the drawer away from the viewport edges with a uniform gap and\n round every corner. The off-screen translate grows by the gap so the panel\n still clears the viewport edge during the slide (it no longer sits flush). */\n:host([inset]) dialog {\n border-radius: var(--border-radius);\n
|
|
1
|
+
{"version":3,"file":"drawer.js","names":["unsafeCSS","rawDrawerStyles","hostStyles","dialogStyles","_decorate","property","r","n","__decorate","host_styles_default","dialog_styles_default","drawerStyles","Drawer","Dialog","_args"],"sources":["../../../src/html/elements/drawer/drawer.css?inline","../../../src/html/elements/drawer/drawer.ts"],"sourcesContent":[":host {\n --size: 320px;\n --border-radius: 0.375rem;\n --inset-gap: 1rem;\n --shadow: var(--l-shadow-lg);\n /* A slide travels much further than the dialog's fade. */\n --show-duration: 300ms;\n}\n\n/* Restated: this sheet comes after dialog.css, so the default above would\n otherwise win over its reduced-motion override. */\n@media (prefers-reduced-motion: reduce) {\n :host {\n --show-duration: 0ms;\n --hide-duration: 0ms;\n }\n}\n\n/* Override dialog's opacity fade with a slide from the inline-start edge. */\ndialog {\n inset: 0;\n margin: 0;\n width: min(var(--size), 100dvw);\n max-inline-size: 100dvw;\n height: 100dvh;\n max-block-size: 100dvh;\n border-radius: 0 var(--border-radius) var(--border-radius) 0;\n opacity: 1;\n translate: -100% 0;\n transition-property: translate, display, overlay;\n}\n\ndialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n dialog[open] {\n translate: -100% 0;\n }\n}\n\n/* Inline-end edge */\n:host([placement='end']) dialog {\n border-radius: var(--border-radius) 0 0 var(--border-radius);\n margin-inline-start: auto;\n translate: 100% 0;\n}\n\n:host([placement='end']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='end']) dialog[open] {\n translate: 100% 0;\n }\n}\n\n/* Block-end (bottom) edge */\n:host([placement='bottom']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n margin-block-start: auto;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n translate: 0 100%;\n}\n\n:host([placement='bottom']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='bottom']) dialog[open] {\n translate: 0 100%;\n }\n}\n\n/* Block-start (top) edge */\n:host([placement='top']) dialog {\n width: 100dvw;\n max-inline-size: 100dvw;\n height: min(var(--size), 100dvh);\n max-block-size: 100dvh;\n border-radius: 0 0 var(--border-radius) var(--border-radius);\n translate: 0 -100%;\n}\n\n:host([placement='top']) dialog[open] {\n translate: 0 0;\n}\n\n@starting-style {\n :host([placement='top']) dialog[open] {\n translate: 0 -100%;\n }\n}\n\n/* Inset: float the drawer away from the viewport edges with a uniform gap and\n round every corner. The off-screen translate grows by the gap so the panel\n still clears the viewport edge during the slide (it no longer sits flush). */\n:host([inset]) dialog {\n border-radius: var(--border-radius);\n}\n\n/* dialog.css casts --shadow on every panel. An edge drawer sits flush against\n the viewport and its backdrop already separates it, so it keeps no shadow:\n --shadow only applies once the panel floats ([inset]).\n The property is reset here, not the variable: `:host(:not([inset])) {\n --shadow: none }` would lose to any `l-drawer { --shadow: … }` in the page\n (outer styles beat :host rules), so a consumer tuning the shadow of their\n inset drawers would put it on every edge drawer too. */\n:host(:not([inset])) dialog {\n box-shadow: none;\n}\n\n/* Inline-edge drawers (start/end): inset the block edges, shrink height to fit. */\n:host([inset]:not([placement])) dialog,\n:host([inset][placement='start']) dialog,\n:host([inset][placement='end']) dialog {\n height: calc(100dvh - 2 * var(--inset-gap));\n inset-block: var(--inset-gap);\n}\n\n/* Block-edge drawers (top/bottom): inset the inline edges, shrink width to fit. */\n:host([inset][placement='top']) dialog,\n:host([inset][placement='bottom']) dialog {\n width: calc(100dvw - 2 * var(--inset-gap));\n inset-inline: var(--inset-gap);\n}\n\n/* Inline-start edge: gap on the start side. */\n:host([inset]:not([placement])) dialog,\n:host([inset][placement='start']) dialog {\n inset-inline-start: var(--inset-gap);\n}\n\n:host([inset]:not([placement])) dialog:not([open]),\n:host([inset][placement='start']) dialog:not([open]) {\n translate: calc(-100% - var(--inset-gap)) 0;\n}\n\n@starting-style {\n :host([inset]:not([placement])) dialog[open],\n :host([inset][placement='start']) dialog[open] {\n translate: calc(-100% - var(--inset-gap)) 0;\n }\n}\n\n/* Inline-end edge: gap on the end side (override the base auto margin). */\n:host([inset][placement='end']) dialog {\n inset-inline-start: auto;\n inset-inline-end: var(--inset-gap);\n margin-inline-start: 0;\n}\n\n:host([inset][placement='end']) dialog:not([open]) {\n translate: calc(100% + var(--inset-gap)) 0;\n}\n\n@starting-style {\n :host([inset][placement='end']) dialog[open] {\n translate: calc(100% + var(--inset-gap)) 0;\n }\n}\n\n/* Block-start (top) edge: gap on the top side. */\n:host([inset][placement='top']) dialog {\n inset-block-start: var(--inset-gap);\n}\n\n:host([inset][placement='top']) dialog:not([open]) {\n translate: 0 calc(-100% - var(--inset-gap));\n}\n\n@starting-style {\n :host([inset][placement='top']) dialog[open] {\n translate: 0 calc(-100% - var(--inset-gap));\n }\n}\n\n/* Block-end (bottom) edge: gap on the bottom side (override the base auto margin). */\n:host([inset][placement='bottom']) dialog {\n inset-block-start: auto;\n inset-block-end: var(--inset-gap);\n margin-block-start: 0;\n}\n\n:host([inset][placement='bottom']) dialog:not([open]) {\n translate: 0 calc(100% + var(--inset-gap));\n}\n\n@starting-style {\n :host([inset][placement='bottom']) dialog[open] {\n translate: 0 calc(100% + var(--inset-gap));\n }\n}\n","import { unsafeCSS } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport { Dialog } from '../dialog/dialog.js';\nimport dialogStyles from '../dialog/dialog.styles.js';\nimport rawDrawerStyles from './drawer.css?inline';\n\nconst drawerStyles = unsafeCSS(rawDrawerStyles);\n\n/**\n * A drawer that slides in from a screen edge. Extends `<l-dialog>`.\n *\n * Open and close by toggling the `open` property (or the `--show` / `--hide`\n * Invoker commands). Always opens as modal.\n *\n * @slot - Body content.\n * @slot title - Custom heading element. Overrides the default `<h2>` rendered from the `title` property. Also provides the dialog's accessible name.\n * @slot close - Close button (typically `<button class=\"l-close\">`).\n * @slot footer - Footer actions.\n *\n * @csspart dialog - The native `<dialog>` element.\n * @csspart header - The header wrapper containing the title and close slot.\n * @csspart title - The drawer title heading.\n * @csspart body - The body wrapper around the default slot.\n * @csspart footer - The footer wrapper around the footer slot.\n *\n * @cssproperty [--size=320px] - Drawer size on the axis perpendicular to its edge (width for `start`/`end`, height for `top`/`bottom`).\n * @cssproperty [--border-radius=0.375rem] - Drawer border radius on the inner edges (all corners when `inset`).\n * @cssproperty [--inset-gap=1rem] - Gap between the drawer and the viewport edges when `inset` is set.\n * @cssproperty [--shadow=var(--l-shadow-lg)] - Drop shadow applied to the floating panel when `inset` is set (an edge drawer casts none). Set to `none` to remove it.\n * @cssproperty [--show-duration=300ms] - Open transition duration.\n * @cssproperty [--hide-duration=200ms] - Close transition duration.\n * @cssproperty [--easing=cubic-bezier(0.32, 0.72, 0, 1)] - Timing function of the open and close transitions, backdrop included.\n * @cssproperty --backdrop - Backdrop color.\n *\n * @event show - Fired when the drawer is about to open. Cancelable — call `event.preventDefault()` to keep it closed.\n * @event after-show - Fired after the open animation completes. Not cancelable.\n * @event hide - Fired when the drawer is about to close. Cancelable — call `event.preventDefault()` to keep it open.\n * @event after-hide - Fired after the close animation completes. Not cancelable.\n *\n * @command --show - Sets `open = true`.\n * @command --hide - Sets `open = false`.\n *\n * @customElement l-drawer\n */\nexport class Drawer extends Dialog {\n static override styles = [hostStyles, dialogStyles, drawerStyles];\n\n // Edge-attached: opt out of the centered modal's stable scrollbar gutter,\n // which would otherwise push the drawer off the actual viewport edge.\n protected override _modalKind = 'edge' as const;\n\n /** Edge the drawer slides in from. Defaults to the start (inline-start) edge. */\n @property({ reflect: true })\n placement?: 'start' | 'end' | 'top' | 'bottom';\n\n /** Detach the drawer from the viewport edges, floating it with a uniform gap and rounded corners. */\n @property({ type: Boolean, reflect: true })\n inset = false;\n}\n"],"mappings":"A,qOCOA,IAAMW,EAAeX,EAAUC,ylGAAe,EAsCjCW,EAAb,cAA4BC,CAAO,C,8BAKD,KAAA,WAAA,OAQxB,KAAA,MAAA,E,QAZiB,KAAA,OAAA,CAACX,EAAYC,EAAcQ,CAAY,C,CAalE,EANGP,EAAA,CAAAC,EAAS,CAAE,QAAS,EAAK,CAAC,CAAA,EAAAO,EAAA,UAAA,YAAA,IAAA,EAAA,EAI1BR,EAAA,CAAAC,EAAS,CAAE,KAAM,QAAS,QAAS,EAAK,CAAC,CAAA,EAAAO,EAAA,UAAA,QAAA,IAAA,EAAA,E"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"../../chunks/lit.js";import{LuxenElement as t}from"../../shared/luxen-element.js";import{n,r,t as i}from"../../chunks/decorate.js";import{a,t as o}from"../../chunks/lit-html.js";import{PopoverController as s}from"../../shared/controllers/popover.js";import{tagName as c}from"../../registry.js";import l from"../../shared/styles/host.styles.js";import u from"../../shared/styles/menu-panel.styles.js";var d=e(`:host{display:block}:host([disabled]){pointer-events:none;opacity:.5}.item{align-items:center;gap:var(--l-menu-item-gap);min-block-size:var(--l-menu-item-min-height);padding:var(--l-menu-item-padding-block) var(--l-menu-item-padding-inline);cursor:pointer;border-radius:var(--l-menu-item-border-radius);font-size:var(--l-popover-font-size);line-height:var(--l-popover-line-height);color:var(--l-color-text-primary);white-space:nowrap;text-align:start;outline:none;display:flex}.item:focus-visible{background:var(--l-color-bg-state-hover);outline:
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{LuxenElement as t}from"../../shared/luxen-element.js";import{n,r,t as i}from"../../chunks/decorate.js";import{a,t as o}from"../../chunks/lit-html.js";import{PopoverController as s}from"../../shared/controllers/popover.js";import{tagName as c}from"../../registry.js";import l from"../../shared/styles/host.styles.js";import u from"../../shared/styles/menu-panel.styles.js";var d=e(`:host{display:block}:host([disabled]){pointer-events:none;opacity:.5}.item{align-items:center;gap:var(--l-menu-item-gap);min-block-size:var(--l-menu-item-min-height);padding:var(--l-menu-item-padding-block) var(--l-menu-item-padding-inline);cursor:pointer;border-radius:var(--l-menu-item-border-radius);font-size:var(--l-popover-font-size);line-height:var(--l-popover-line-height);color:var(--l-color-text-primary);white-space:nowrap;text-align:start;outline:none;display:flex}.item:focus-visible{background:var(--l-color-bg-state-hover);outline:var(--l-focus-ring-width) solid var(--l-focus-ring-color);outline-offset:calc(var(--l-focus-ring-width) * -1)}@media (hover:hover){.item:hover{background:var(--l-color-bg-state-hover)}}:host([submenu-open]) .item{background:var(--l-color-bg-state-hover)}:host([variant=destructive]) .item{color:var(--l-color-text-danger)}:host([variant=destructive]) .item:focus-visible{background:var(--l-color-bg-fill-danger-soft);outline-color:var(--l-color-text-danger)}@media (hover:hover){:host([variant=destructive]) .item:hover{background:var(--l-color-bg-fill-danger-soft)}}.check{flex-shrink:0;width:16px;display:flex}.submenu-indicator{background-color:currentColor;flex-shrink:0;block-size:16px;inline-size:16px;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50%/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50%/contain no-repeat}:host(:dir(rtl)) .submenu-indicator{scale:-1 1}:host(:not([checked])) .check svg{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0;display:flex}.label{flex:1}`),f=class extends t{constructor(...e){super(...e),this._submenuFloating=new s(this,{getTriggerElement:()=>this,getFloatingElement:()=>this._submenuEl,getArrowElement:()=>null}),this.#e=``,this.#t=!1,this.#n=`normal`,this.#r=void 0,this.#i=!1,this.#a=!1,this.#o=`start`,this.#s=!1,this._onSubmenuSlotChange=e=>{let t=e.target;this._hasSubmenu=t.assignedElements().some(e=>e.tagName===c(`dropdown-item`).toUpperCase())}}static{this.styles=[l,u,d]}#e;get value(){return this.#e}set value(e){this.#e=e}#t;get disabled(){return this.#t}set disabled(e){this.#t=e}#n;get type(){return this.#n}set type(e){this.#n=e}#r;get variant(){return this.#r}set variant(e){this.#r=e}#i;get checked(){return this.#i}set checked(e){this.#i=e}#a;get submenuOpen(){return this.#a}set submenuOpen(e){this.#a=e}#o;get checkPlacement(){return this.#o}set checkPlacement(e){this.#o=e}#s;get _hasSubmenu(){return this.#s}set _hasSubmenu(e){this.#s=e}get hasSubmenu(){return this._hasSubmenu}connectedCallback(){super.connectedCallback(),this.hasAttribute(`role`)||this.setAttribute(`role`,`none`)}get _submenuEl(){return this.shadowRoot.querySelector(`.submenu`)}getTextLabel(){let e=this.shadowRoot?.querySelector(`slot:not([name])`);return e?e.assignedNodes({flatten:!0}).map(e=>e.textContent??``).join(``).trim():(this.textContent??``).trim()}getSubmenuItems(){let e=this.shadowRoot?.querySelector(`slot[name="submenu"]`);return e?e.assignedElements().filter(e=>e.tagName===c(`dropdown-item`).toUpperCase()&&!e.disabled):[]}openSubmenu(){!this._hasSubmenu||this.disabled||this.submenuOpen||(this.submenuOpen=!0)}closeSubmenu(){for(let e of this.getSubmenuItems())e.closeSubmenu();this.submenuOpen&&=!1}updated(e){e.has(`submenuOpen`)&&this._handleSubmenuOpenChange()}async _handleSubmenuOpenChange(){let e=this._submenuEl;if(!e)return;let t={placement:getComputedStyle(this).direction===`rtl`?`left-start`:`right-start`,distance:0,skidding:-parseFloat(getComputedStyle(e).paddingTop||`0`)};if(this.submenuOpen){if(!this.isConnected||(e.showPopover(),await this._submenuFloating.updatePosition(t),!this.submenuOpen))return;await this._submenuFloating.animateShow(e),this._submenuFloating.startPositioning(t)}else{if(!e.matches(`:popover-open`))return;this._submenuFloating.stopPositioning(),await this._submenuFloating.animateHide(e),e.matches(`:popover-open`)&&e.hidePopover()}}_renderCheck(){return a`
|
|
2
2
|
<span
|
|
3
3
|
class="check"
|
|
4
4
|
aria-hidden="true"
|