@m3e/option 1.0.6

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/dist/index.js ADDED
@@ -0,0 +1,615 @@
1
+ /**
2
+ * @license MIT
3
+ * Copyright (c) 2025 matraic
4
+ * See LICENSE file in the project root for full license text.
5
+ */
6
+ import { LitElement, html, css, unsafeCSS } from 'lit';
7
+ import { Selected, Disabled, Role, DesignToken, getTextContent, ScrollController } from '@m3e/core';
8
+ import { typeaheadLabel, removeAriaReferencedId, addAriaReferencedId } from '@m3e/core/a11y';
9
+ import { positionAnchor } from '@m3e/core/anchoring';
10
+
11
+ /******************************************************************************
12
+ Copyright (c) Microsoft Corporation.
13
+
14
+ Permission to use, copy, modify, and/or distribute this software for any
15
+ purpose with or without fee is hereby granted.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
18
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
20
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
22
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23
+ PERFORMANCE OF THIS SOFTWARE.
24
+ ***************************************************************************** */
25
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
26
+
27
+
28
+ function __decorate(decorators, target, key, desc) {
29
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
30
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
31
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
32
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
33
+ }
34
+
35
+ function __classPrivateFieldGet(receiver, state, kind, f) {
36
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
37
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
38
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
39
+ }
40
+
41
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
42
+ if (kind === "m") throw new TypeError("Private method is not writable");
43
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
44
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
45
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
46
+ }
47
+
48
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
49
+ var e = new Error(message);
50
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
51
+ };
52
+
53
+ /**
54
+ * @license
55
+ * Copyright 2017 Google LLC
56
+ * SPDX-License-Identifier: BSD-3-Clause
57
+ */
58
+ const t$1=t=>(e,o)=>{ void 0!==o?o.addInitializer((()=>{customElements.define(t,e);})):customElements.define(t,e);};
59
+
60
+ /**
61
+ * @license
62
+ * Copyright 2019 Google LLC
63
+ * SPDX-License-Identifier: BSD-3-Clause
64
+ */
65
+ const t=globalThis,e$3=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s=Symbol(),o$2=new WeakMap;let n$2 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$3&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$2.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$2.set(s,t));}return t}toString(){return this.cssText}};const r$2=t=>new n$2("string"==typeof t?t:t+"",void 0,s),S=(s,o)=>{if(e$3)s.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const e of o){const o=document.createElement("style"),n=t.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$1=e$3?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$2(e)})(t):t;
66
+
67
+ /**
68
+ * @license
69
+ * Copyright 2017 Google LLC
70
+ * SPDX-License-Identifier: BSD-3-Clause
71
+ */const{is:i,defineProperty:e$2,getOwnPropertyDescriptor:h,getOwnPropertyNames:r$1,getOwnPropertySymbols:o$1,getPrototypeOf:n$1}=Object,a=globalThis,c=a.trustedTypes,l=c?c.emptyScript:"",p=a.reactiveElementPolyfillSupport,d=(t,s)=>t,u={toAttribute(t,s){switch(s){case Boolean:t=t?l:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f=(t,s)=>!i(t,s),b={attribute:true,type:String,converter:u,reflect:false,useDefault:false,hasChanged:f};Symbol.metadata??=Symbol("metadata"),a.litPropertyMetadata??=new WeakMap;class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=true),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e$2(this.prototype,t,h);}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d("elementProperties")))return;const t=n$1(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d("properties"))){const t=this.properties,s=[...r$1(t),...o$1(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$1(s));}else void 0!==s&&i.push(c$1(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach((t=>t.hostConnected?.()));}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()));}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null;}}requestUpdate(t,s,i){if(void 0!==t){const e=this.constructor,h=this[t];if(i??=e.getPropertyOptions(t),!((i.hasChanged??f)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(e._$Eu(t,i))))return;this.C(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$EP());}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),true!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),true===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];true!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e);}}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach((t=>t.hostUpdate?.())),this.update(s)):this._$EM();}catch(s){throw t=false,this._$EM(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach((t=>t.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Eq&&=this._$Eq.forEach((t=>this._$ET(t,this[t]))),this._$EM();}updated(t){}firstUpdated(t){}}y.elementStyles=[],y.shadowRootOptions={mode:"open"},y[d("elementProperties")]=new Map,y[d("finalized")]=new Map,p?.({ReactiveElement:y}),(a.reactiveElementVersions??=[]).push("2.1.1");
72
+
73
+ /**
74
+ * @license
75
+ * Copyright 2017 Google LLC
76
+ * SPDX-License-Identifier: BSD-3-Clause
77
+ */const o={attribute:true,type:String,converter:u,reflect:false,hasChanged:f},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),"setter"===n&&((t=Object.create(t)).wrapped=true),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
78
+
79
+ /**
80
+ * @license
81
+ * Copyright 2017 Google LLC
82
+ * SPDX-License-Identifier: BSD-3-Clause
83
+ */
84
+ const e$1=(e,t,c)=>(c.configurable=true,c.enumerable=true,Reflect.decorate&&"object"!=typeof t&&Object.defineProperty(e,t,c),c);
85
+
86
+ /**
87
+ * @license
88
+ * Copyright 2017 Google LLC
89
+ * SPDX-License-Identifier: BSD-3-Clause
90
+ */function e(e,r){return (n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;return e$1(n,s,{get(){return o(this)}})}}
91
+
92
+ var _M3eOptionElement_instances, _M3eOptionElement_value, _M3eOptionElement_textContent, _M3eOptionElement_handleSlotChange;
93
+ /**
94
+ * An option that can be selected.
95
+ *
96
+ * @description
97
+ * The `m3e-option` component represents an individual selectable item within an option list,
98
+ * adhering to Material Design 3 specifications. It provides visual feedback through state layers and ripple effects,
99
+ * supports single and multiple selection modes, and includes comprehensive accessibility features including
100
+ * keyboard navigation and focus management. The component automatically manages its visual appearance based on
101
+ * selection and disabled states, with configurable styling for interactive and non-interactive variants.
102
+ *
103
+ * @tag m3e-option
104
+ *
105
+ * @slot - Renders the label of the option.
106
+ *
107
+ * @attr disabled - Whether the element is disabled.
108
+ * @attr selected - Whether the element is selected.
109
+ * @attr value - A string representing the value of the option.
110
+ *
111
+ * @cssprop --m3e-option-container-height - The height of the option container.
112
+ * @cssprop --m3e-option-color - The text color of the option.
113
+ * @cssprop --m3e-option-container-hover-color - The color for the hover state layer.
114
+ * @cssprop --m3e-option-container-focus-color - The color for the focus state layer.
115
+ * @cssprop --m3e-option-ripple-color - The color of the ripple effect.
116
+ * @cssprop --m3e-option-selected-color - The text color when the option is selected.
117
+ * @cssprop --m3e-option-selected-container-color - The background color when the option is selected.
118
+ * @cssprop --m3e-option-selected-container-hover-color - The hover color for the selected state layer.
119
+ * @cssprop --m3e-option-selected-container-focus-color - The focus color for the selected state layer.
120
+ * @cssprop --m3e-option-selected-ripple-color - The ripple color when the option is selected.
121
+ * @cssprop --m3e-option-disabled-color - The text color when the option is disabled.
122
+ * @cssprop --m3e-option-disabled-opacity - The opacity level applied to the disabled text color.
123
+ * @cssprop --m3e-option-icon-label-space - The spacing between the icon and label.
124
+ * @cssprop --m3e-option-padding-start - The left padding of the option content.
125
+ * @cssprop --m3e-option-padding-end - The right padding of the option content.
126
+ * @cssprop --m3e-option-label-text-font-size - The font size of the option label.
127
+ * @cssprop --m3e-option-label-text-font-weight - The font weight of the option label.
128
+ * @cssprop --m3e-option-label-text-line-height - The line height of the option label.
129
+ * @cssprop --m3e-option-label-text-tracking - The letter spacing of the option label.
130
+ * @cssprop --m3e-option-focus-ring-shape - The corner radius of the focus ring.
131
+ * @cssprop --m3e-option-icon-size - The size of the option icons.
132
+ */
133
+ let M3eOptionElement = class M3eOptionElement extends Selected(Disabled(Role(LitElement, "option"))) {
134
+ constructor() {
135
+ super(...arguments);
136
+ _M3eOptionElement_instances.add(this);
137
+ /** @private */ _M3eOptionElement_value.set(this, void 0);
138
+ /** @private */ _M3eOptionElement_textContent.set(this, "");
139
+ }
140
+ /** A string representing the value of the option. */
141
+ get value() {
142
+ return __classPrivateFieldGet(this, _M3eOptionElement_value, "f") ?? __classPrivateFieldGet(this, _M3eOptionElement_textContent, "f");
143
+ }
144
+ set value(value) {
145
+ __classPrivateFieldSet(this, _M3eOptionElement_value, value, "f");
146
+ }
147
+ /** @internal */
148
+ [(_M3eOptionElement_value = new WeakMap(), _M3eOptionElement_textContent = new WeakMap(), _M3eOptionElement_instances = new WeakSet(), typeaheadLabel)]() {
149
+ return __classPrivateFieldGet(this, _M3eOptionElement_textContent, "f");
150
+ }
151
+ /** Whether the option represents an empty option. */
152
+ get isEmpty() {
153
+ return this.value === "";
154
+ }
155
+ /** @inheritdoc */
156
+ connectedCallback() {
157
+ super.connectedCallback();
158
+ [this.focusRing, this.stateLayer, this._ripple].forEach((x) => x?.attach(this));
159
+ }
160
+ /** @inheritdoc */
161
+ firstUpdated(_changedProperties) {
162
+ super.firstUpdated(_changedProperties);
163
+ [this.focusRing, this.stateLayer, this._ripple].forEach((x) => x?.attach(this));
164
+ }
165
+ /** @inheritdoc */
166
+ update(changedProperties) {
167
+ super.update(changedProperties);
168
+ if (changedProperties.has("selected") && this.selected) {
169
+ const panel = this.closest("[role='listbox']") ?? this.closest("m3e-select");
170
+ if (panel && panel.ariaMultiSelectable !== "true" && !panel.hasAttribute("multi")) {
171
+ panel.querySelectorAll("m3e-option").forEach((x) => {
172
+ if (x !== this && x.selected) {
173
+ x.selected = false;
174
+ }
175
+ });
176
+ }
177
+ }
178
+ }
179
+ /** @inheritdoc */
180
+ render() {
181
+ return html `<div class="base">
182
+ <m3e-state-layer class="state-layer" ?disabled="${this.disabled}"></m3e-state-layer>
183
+ <m3e-focus-ring class="focus-ring" inward ?disabled="${this.disabled}"></m3e-focus-ring>
184
+ <m3e-ripple class="ripple" ?disabled="${this.disabled}"></m3e-ripple>
185
+ <div class="touch" aria-hidden="true"></div>
186
+ <div class="wrapper">
187
+ <m3e-pseudo-checkbox class="leading-icon" ?checked="${this.selected}" ?disabled="${this.disabled}">
188
+ </m3e-pseudo-checkbox>
189
+ <m3e-text-overflow class="label"><slot @slotchange="${__classPrivateFieldGet(this, _M3eOptionElement_instances, "m", _M3eOptionElement_handleSlotChange)}"></slot></m3e-text-overflow>
190
+ <div class="trailing-icon">
191
+ <svg class="check" viewBox="0 -960 960 960" aria-hidden="true">
192
+ <path fill="currentColor" d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z" />
193
+ </svg>
194
+ </div>
195
+ </div>
196
+ </div>`;
197
+ }
198
+ };
199
+ _M3eOptionElement_handleSlotChange = function _M3eOptionElement_handleSlotChange(e) {
200
+ __classPrivateFieldSet(this, _M3eOptionElement_textContent, getTextContent(e.target), "f");
201
+ this.classList.toggle("-empty", this.isEmpty);
202
+ };
203
+ /** The styles of the element. */
204
+ M3eOptionElement.styles = css `
205
+ :host {
206
+ display: block;
207
+ outline: none;
208
+ user-select: none;
209
+ flex: none;
210
+ height: var(--m3e-option-container-height, 3rem);
211
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
212
+ }
213
+ :host(:not([aria-disabled="true"])) .base {
214
+ color: var(--m3e-option-color, ${DesignToken.color.onSurface});
215
+ --m3e-state-layer-hover-color: var(--m3e-option-container-hover-color, ${DesignToken.color.onSurface});
216
+ --m3e-state-layer-focus-color: var(--m3e-option-container-focus-color, ${DesignToken.color.onSurface});
217
+ --m3e-ripple-color: var(--m3e-option-ripple-color, ${DesignToken.color.onSurface});
218
+ }
219
+ :host(:not([aria-disabled="true"]):not(.-empty)[selected]) .base {
220
+ color: var(--m3e-option-selected-color, ${DesignToken.color.onSecondaryContainer});
221
+ background-color: var(--m3e-option-selected-container-color, ${DesignToken.color.secondaryContainer});
222
+ --m3e-state-layer-hover-color: var(
223
+ --m3e-option-selected-container-hover-color,
224
+ ${DesignToken.color.onSecondaryContainer}
225
+ );
226
+ --m3e-state-layer-focus-color: var(
227
+ --m3e-option-selected-container-focus-color,
228
+ ${DesignToken.color.onSecondaryContainer}
229
+ );
230
+ --m3e-ripple-color: var(--m3e-option-selected-ripple-color, ${DesignToken.color.onSecondaryContainer});
231
+ }
232
+ :host(:not([aria-disabled="true"])) {
233
+ cursor: pointer;
234
+ }
235
+ :host([aria-disabled="true"]) .base {
236
+ color: color-mix(
237
+ in srgb,
238
+ var(--m3e-option-disabled-color, ${DesignToken.color.onSurface}) var(--m3e-option-disabled-opacity, 38%),
239
+ transparent
240
+ );
241
+ }
242
+ .base {
243
+ box-sizing: border-box;
244
+ vertical-align: middle;
245
+ display: inline-flex;
246
+ align-items: center;
247
+ position: relative;
248
+ width: 100%;
249
+ height: 100%;
250
+ }
251
+ .touch {
252
+ position: absolute;
253
+ height: 3rem;
254
+ left: 0;
255
+ right: 0;
256
+ }
257
+ .wrapper {
258
+ display: inline-flex;
259
+ align-items: center;
260
+ width: 100%;
261
+ column-gap: var(--m3e-option-icon-label-space, 0.75rem);
262
+ padding-inline-start: var(--_option-padding-start, var(--m3e-option-padding-start, 0.75rem));
263
+ padding-inline-end: var(--m3e-option-padding-end, 0.75rem);
264
+ font-size: var(--m3e-option-label-text-font-size, ${DesignToken.typescale.standard.label.large.fontSize});
265
+ font-weight: var(--m3e-option-label-text-font-weight, ${DesignToken.typescale.standard.label.large.fontWeight});
266
+ line-height: var(--m3e-option-label-text-line-height, ${DesignToken.typescale.standard.label.large.lineHeight});
267
+ letter-spacing: var(--m3e-option-label-text-tracking, ${DesignToken.typescale.standard.label.large.tracking});
268
+ }
269
+ .focus-ring {
270
+ border-radius: var(--m3e-option-focus-ring-shape, ${DesignToken.shape.corner.medium});
271
+ }
272
+ .content {
273
+ flex: 1 1 auto;
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ white-space: nowrap;
277
+ }
278
+ ::slotted([slot="icon"]),
279
+ ::slotted([slot="trailing-icon"]),
280
+ .trailing-icon {
281
+ flex: none;
282
+ width: 1em;
283
+ font-size: var(--m3e-option-icon-size, 1.5rem) !important;
284
+ }
285
+ :host(.-empty) .leading-icon,
286
+ :host(.-empty) .trailing-icon,
287
+ :host(:not(.-multi):not([selected])) .trailing-icon,
288
+ :host(.-multi) .trailing-icon,
289
+ :host(:not(.-multi)) .leading-icon,
290
+ :host(.-hide-selection-indicator) .leading-icon,
291
+ :host(.-hide-selection-indicator) .trailing-icon {
292
+ display: none;
293
+ }
294
+ @media (forced-colors: active) {
295
+ .base {
296
+ background-color: Menu;
297
+ color: MenuText;
298
+ }
299
+ :host([aria-disabled="true"]) .base {
300
+ color: GrayText;
301
+ }
302
+ }
303
+ `;
304
+ __decorate([
305
+ e(".focus-ring")
306
+ ], M3eOptionElement.prototype, "focusRing", void 0);
307
+ __decorate([
308
+ e(".state-layer")
309
+ ], M3eOptionElement.prototype, "stateLayer", void 0);
310
+ __decorate([
311
+ e(".ripple")
312
+ ], M3eOptionElement.prototype, "_ripple", void 0);
313
+ __decorate([
314
+ n()
315
+ ], M3eOptionElement.prototype, "value", null);
316
+ M3eOptionElement = __decorate([
317
+ t$1("m3e-option")
318
+ ], M3eOptionElement);
319
+
320
+ var _M3eOptGroupElement_instances, _M3eOptGroupElement_labelId, _M3eOptGroupElement_label, _M3eOptGroupElement_handleLabelSlotChange;
321
+ var M3eOptGroupElement_1;
322
+ /**
323
+ * Groups options under a subheading.
324
+ *
325
+ * @description
326
+ * The `m3e-optgroup` component organizes related options within an option list,
327
+ * providing visual and semantic grouping through a customizable label. It manages `aria-labelledby`
328
+ * associations automatically and applies Material Design 3 typography and spacing conventions to
329
+ * the group label. The component maintains proper semantic structure by utilizing the ARIA `group` role,
330
+ * ensuring that assistive technologies correctly interpret the hierarchical relationship between the label
331
+ * and contained options.
332
+ *
333
+ * @tag m3e-optgroup
334
+ *
335
+ * @slot - Renders the options of the group.
336
+ * @slot label - Renders the label of the group.
337
+ *
338
+ * @cssprop --m3e-option-height - The height of the group label container.
339
+ * @cssprop --m3e-option-font-size - The font size of the group label.
340
+ * @cssprop --m3e-option-font-weight - The font weight of the group label.
341
+ * @cssprop --m3e-option-line-height - The line height of the group label.
342
+ * @cssprop --m3e-option-tracking - The letter spacing of the group label.
343
+ * @cssprop --m3e-option-padding-end - The right padding of the label.
344
+ * @cssprop --m3e-option-padding-start - The left padding of the label.
345
+ * @cssprop --m3e-option-color - The text color of the group label.
346
+ */
347
+ let M3eOptGroupElement = M3eOptGroupElement_1 = class M3eOptGroupElement extends Role(LitElement, "group") {
348
+ constructor() {
349
+ super(...arguments);
350
+ _M3eOptGroupElement_instances.add(this);
351
+ /** @private */ _M3eOptGroupElement_labelId.set(this, `m3e-optgroup-label-${M3eOptGroupElement_1.__nextId++}`);
352
+ /** @private */ _M3eOptGroupElement_label.set(this, void 0);
353
+ }
354
+ /** @inheritdoc */
355
+ render() {
356
+ return html `<m3e-text-overflow class="label">
357
+ <slot name="label" @slotchange="${__classPrivateFieldGet(this, _M3eOptGroupElement_instances, "m", _M3eOptGroupElement_handleLabelSlotChange)}"></slot>
358
+ </m3e-text-overflow>
359
+ <slot></slot>`;
360
+ }
361
+ };
362
+ _M3eOptGroupElement_labelId = new WeakMap();
363
+ _M3eOptGroupElement_label = new WeakMap();
364
+ _M3eOptGroupElement_instances = new WeakSet();
365
+ _M3eOptGroupElement_handleLabelSlotChange = function _M3eOptGroupElement_handleLabelSlotChange(e) {
366
+ const label = e.target.assignedElements({ flatten: true })[0] ?? undefined;
367
+ if (label === __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f"))
368
+ return;
369
+ if (__classPrivateFieldGet(this, _M3eOptGroupElement_label, "f")?.id) {
370
+ removeAriaReferencedId(this, "aria-labelledby", __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id);
371
+ if (__classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id === __classPrivateFieldGet(this, _M3eOptGroupElement_labelId, "f")) {
372
+ __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id = "";
373
+ }
374
+ }
375
+ __classPrivateFieldSet(this, _M3eOptGroupElement_label, label, "f");
376
+ if (__classPrivateFieldGet(this, _M3eOptGroupElement_label, "f")) {
377
+ __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id = __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id || __classPrivateFieldGet(this, _M3eOptGroupElement_labelId, "f");
378
+ addAriaReferencedId(this, "aria-labelledby", __classPrivateFieldGet(this, _M3eOptGroupElement_label, "f").id);
379
+ }
380
+ };
381
+ /** The styles of the element. */
382
+ M3eOptGroupElement.styles = css `
383
+ :host {
384
+ display: block;
385
+ --_option-padding-start: calc(var(--m3e-option-padding-start, 0.75rem) * 2);
386
+ }
387
+ .label {
388
+ height: var(--m3e-option-height, 3rem);
389
+ font-size: var(--m3e-option-font-size, ${DesignToken.typescale.standard.label.large.fontSize});
390
+ font-weight: var(--m3e-option-font-weight, ${DesignToken.typescale.standard.label.large.fontWeight});
391
+ line-height: var(--m3e-option-line-height, ${DesignToken.typescale.standard.label.large.lineHeight});
392
+ letter-spacing: var(--m3e-option-tracking, ${DesignToken.typescale.standard.label.large.tracking});
393
+ padding-inline-end: var(--m3e-option-padding-end, 0.75rem);
394
+ padding-inline-start: var(--m3e-option-padding-start, 0.75rem);
395
+ color: var(--m3e-option-color, ${DesignToken.color.onSurface});
396
+ flex: none;
397
+ }
398
+ `;
399
+ /** @private */ M3eOptGroupElement.__nextId = 0;
400
+ M3eOptGroupElement = M3eOptGroupElement_1 = __decorate([
401
+ t$1("m3e-optgroup")
402
+ ], M3eOptGroupElement);
403
+
404
+ var _M3eOptionPanelElement_instances, _M3eOptionPanelElement_trigger, _M3eOptionPanelElement_anchor, _M3eOptionPanelElement_anchorCleanup, _M3eOptionPanelElement_documentClickHandler, _M3eOptionPanelElement_scrollController, _M3eOptionPanelElement_toggleHandler, _M3eOptionPanelElement_handleDocumentClick;
405
+ var M3eOptionPanelElement_1;
406
+ /**
407
+ * Presents a list of options on a temporary surface.
408
+ *
409
+ * @description
410
+ * The `m3e-option-panel` component renders a scrollable container for displaying selectable options
411
+ * as a Material Design 3 menu surface. It provides dynamic positioning and anchoring to trigger elements,
412
+ * automatic viewport boundary detection with intelligent repositioning, and smooth enter/exit animations.
413
+ *
414
+ * @tag m3e-option-panel
415
+ *
416
+ * @slot - Renders the contents of the list.
417
+ *
418
+ * @fires beforetoggle - Dispatched before the toggle state changes.
419
+ * @fires toggle - Dispatched after the toggle state has changed.
420
+ *
421
+ * @cssprop --m3e-option-panel-container-shape - Controls the corner radius of the menu container.
422
+ * @cssprop --m3e-option-panel-container-min-width - Minimum width of the menu container.
423
+ * @cssprop --m3e-option-panel-container-max-width - Maximum width of the menu container.
424
+ * @cssprop --m3e-option-panel-container-max-height - Maximum height of the menu container.
425
+ * @cssprop --m3e-option-panel-container-padding-block - Vertical padding inside the menu container.
426
+ * @cssprop --m3e-option-panel-container-color - Background color of the menu container.
427
+ * @cssprop --m3e-option-panel-container-elevation - Box shadow elevation of the menu container.
428
+ * @cssprop --m3e-option-panel-divider-spacing - Vertical spacing around slotted `m3e-divider` elements.
429
+ */
430
+ let M3eOptionPanelElement = M3eOptionPanelElement_1 = class M3eOptionPanelElement extends Role(LitElement, "listbox") {
431
+ constructor() {
432
+ super(...arguments);
433
+ _M3eOptionPanelElement_instances.add(this);
434
+ /** @private */ _M3eOptionPanelElement_trigger.set(this, void 0);
435
+ /** @private */ _M3eOptionPanelElement_anchor.set(this, void 0);
436
+ /** @private */ _M3eOptionPanelElement_anchorCleanup.set(this, void 0);
437
+ /** @private */ _M3eOptionPanelElement_documentClickHandler.set(this, (e) => __classPrivateFieldGet(this, _M3eOptionPanelElement_instances, "m", _M3eOptionPanelElement_handleDocumentClick).call(this, e));
438
+ /** @private */ _M3eOptionPanelElement_scrollController.set(this, new ScrollController(this, {
439
+ target: null,
440
+ callback: () => this.hide(false),
441
+ }));
442
+ /** @private */ _M3eOptionPanelElement_toggleHandler.set(this, (e) => {
443
+ if (e.newState === "closed") {
444
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_anchorCleanup, "f")?.call(this);
445
+ __classPrivateFieldSet(this, _M3eOptionPanelElement_anchorCleanup, undefined, "f");
446
+ }
447
+ });
448
+ }
449
+ /** Whether the menu is open. */
450
+ get isOpen() {
451
+ return __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f") !== undefined;
452
+ }
453
+ /** @inheritdoc */
454
+ connectedCallback() {
455
+ super.connectedCallback();
456
+ this.classList.add("-no-animate");
457
+ this.setAttribute("popover", "manual");
458
+ this.addEventListener("toggle", __classPrivateFieldGet(this, _M3eOptionPanelElement_toggleHandler, "f"));
459
+ document.addEventListener("click", __classPrivateFieldGet(this, _M3eOptionPanelElement_documentClickHandler, "f"));
460
+ }
461
+ /** @inheritdoc */
462
+ disconnectedCallback() {
463
+ super.disconnectedCallback();
464
+ this.removeEventListener("toggle", __classPrivateFieldGet(this, _M3eOptionPanelElement_toggleHandler, "f"));
465
+ document.removeEventListener("click", __classPrivateFieldGet(this, _M3eOptionPanelElement_documentClickHandler, "f"));
466
+ }
467
+ /**
468
+ * Opens the menu.
469
+ * @param {HTMLElement} trigger The element that triggered the menu.
470
+ * @param {HTMLElement | undefined} anchor The element used to position the menu.
471
+ * @returns {Promise<void>} A `Promise` that resolves when the menu is opened.
472
+ */
473
+ async show(trigger, anchor) {
474
+ if (__classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f") && __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f") !== trigger) {
475
+ this.hide();
476
+ }
477
+ __classPrivateFieldSet(this, _M3eOptionPanelElement_anchorCleanup, await positionAnchor(this, anchor ?? trigger, {
478
+ position: "bottom-start",
479
+ inline: true,
480
+ flip: true,
481
+ shift: true,
482
+ }, (x, y, position) => {
483
+ this.classList.toggle("-top", position.includes("top"));
484
+ this.classList.toggle("-bottom", position.includes("bottom"));
485
+ this.style.left = `${x}px`;
486
+ this.style.top = `${y}px`;
487
+ }), "f");
488
+ this.showPopover();
489
+ __classPrivateFieldSet(this, _M3eOptionPanelElement_trigger, trigger, "f");
490
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f").ariaExpanded = "true";
491
+ __classPrivateFieldSet(this, _M3eOptionPanelElement_anchor, anchor, "f");
492
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_scrollController, "f").observe(__classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f"));
493
+ }
494
+ /**
495
+ * Hides the menu.
496
+ * @param {boolean} [restoreFocus=false] Whether to restore focus to the menu's trigger.
497
+ */
498
+ hide(restoreFocus = false) {
499
+ this.hidePopover();
500
+ if (__classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f")) {
501
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f").ariaExpanded = "false";
502
+ if (restoreFocus) {
503
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f").focus();
504
+ }
505
+ __classPrivateFieldGet(this, _M3eOptionPanelElement_scrollController, "f").unobserve(__classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f"));
506
+ __classPrivateFieldSet(this, _M3eOptionPanelElement_trigger, undefined, "f");
507
+ }
508
+ }
509
+ /**
510
+ * Toggles the menu.
511
+ * @param {HTMLElement} trigger The element that triggered the menu.
512
+ * @param {HTMLElement | undefined} anchor The element used to position the menu.
513
+ * @returns {Promise<void>} A `Promise` that resolves when the menu is opened or closed.
514
+ */
515
+ async toggle(trigger, anchor) {
516
+ if (__classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f")) {
517
+ this.hide();
518
+ }
519
+ else {
520
+ await this.show(trigger, anchor);
521
+ }
522
+ }
523
+ /** @inheritdoc */
524
+ render() {
525
+ return html `<slot></slot>`;
526
+ }
527
+ /** @inheritdoc */
528
+ firstUpdated(_changedProperties) {
529
+ super.firstUpdated(_changedProperties);
530
+ requestAnimationFrame(() => this.classList.remove("-no-animate"));
531
+ }
532
+ };
533
+ _M3eOptionPanelElement_trigger = new WeakMap();
534
+ _M3eOptionPanelElement_anchor = new WeakMap();
535
+ _M3eOptionPanelElement_anchorCleanup = new WeakMap();
536
+ _M3eOptionPanelElement_documentClickHandler = new WeakMap();
537
+ _M3eOptionPanelElement_scrollController = new WeakMap();
538
+ _M3eOptionPanelElement_toggleHandler = new WeakMap();
539
+ _M3eOptionPanelElement_instances = new WeakSet();
540
+ _M3eOptionPanelElement_handleDocumentClick = function _M3eOptionPanelElement_handleDocumentClick(e) {
541
+ if (!e.composedPath().some((x) => x instanceof M3eOptionPanelElement_1 || x === __classPrivateFieldGet(this, _M3eOptionPanelElement_trigger, "f") || x === __classPrivateFieldGet(this, _M3eOptionPanelElement_anchor, "f"))) {
542
+ this.hide();
543
+ }
544
+ };
545
+ /** The styles of the element. */
546
+ M3eOptionPanelElement.styles = css `
547
+ :host {
548
+ position: absolute;
549
+ flex-direction: column;
550
+ padding: unset;
551
+ margin: unset;
552
+ border: unset;
553
+ overflow-y: auto;
554
+ scrollbar-width: ${DesignToken.scrollbar.thinWidth};
555
+ scrollbar-color: ${DesignToken.scrollbar.color};
556
+ border-radius: var(--m3e-option-panel-container-shape, ${DesignToken.shape.corner.extraSmall});
557
+ min-width: var(--m3e-option-panel-container-min-width, 7rem);
558
+ max-width: var(--m3e-option-panel-container-max-width, 17.5rem);
559
+ max-height: var(--m3e-option-panel-container-max-height, 17.5rem);
560
+ padding-block: var(--m3e-option-panel-container-padding-block, 0.5rem);
561
+ background-color: var(--m3e-option-panel-container-color, ${DesignToken.color.surfaceContainer});
562
+ box-shadow: var(--m3e-option-panel-container-elevation, ${DesignToken.elevation.level3});
563
+ opacity: 0;
564
+ display: none;
565
+ }
566
+ :host(:not(.-no-animate)) {
567
+ transition: ${unsafeCSS(`opacity ${DesignToken.motion.duration.short2} ${DesignToken.motion.easing.standard},
568
+ transform ${DesignToken.motion.duration.short2} ${DesignToken.motion.easing.standard},
569
+ overlay ${DesignToken.motion.duration.short2} ${DesignToken.motion.easing.standard} allow-discrete,
570
+ display ${DesignToken.motion.duration.short2} ${DesignToken.motion.easing.standard} allow-discrete`)};
571
+ }
572
+ :host {
573
+ transform: scaleY(0.8);
574
+ }
575
+ :host(:popover-open) {
576
+ transform: scaleY(1);
577
+ display: inline-flex;
578
+ opacity: 1;
579
+ }
580
+ :host::backdrop {
581
+ background-color: transparent;
582
+ }
583
+ :host(.-bottom) {
584
+ transform-origin: top;
585
+ }
586
+ :host(.-top) {
587
+ transform-origin: bottom;
588
+ }
589
+ ::slotted(m3e-divider) {
590
+ margin-block: var(--m3e-option-panel-divider-spacing, 0.5rem);
591
+ }
592
+ @starting-style {
593
+ :host(:popover-open) {
594
+ transform: scaleY(0.8);
595
+ }
596
+ }
597
+ @media (prefers-reduced-motion) {
598
+ :host(:not(.-no-animate)) {
599
+ transition: none;
600
+ }
601
+ }
602
+ @media (forced-colors: active) {
603
+ :host {
604
+ background-color: Menu;
605
+ color: MenuText;
606
+ border: 1px solid CanvasText;
607
+ }
608
+ }
609
+ `;
610
+ M3eOptionPanelElement = M3eOptionPanelElement_1 = __decorate([
611
+ t$1("m3e-option-panel")
612
+ ], M3eOptionPanelElement);
613
+
614
+ export { M3eOptGroupElement, M3eOptionElement, M3eOptionPanelElement };
615
+ //# sourceMappingURL=index.js.map