@universal-material/web 3.6.33 → 3.7.1

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/select/select.js CHANGED
@@ -4,56 +4,12 @@ import { customElement, property, query, state } from 'lit/decorators.js';
4
4
  import { map } from 'lit/directives/map.js';
5
5
  import { html as staticHtml } from 'lit/static-html.js';
6
6
  import { UmTextFieldBase } from '../shared/text-field-base/text-field-base.js';
7
- import { UmOption } from './option.js';
8
7
  import { SelectNavigationController } from './select-navigation-controller.js';
9
8
  import { styles } from './select.styles.js';
10
9
  import './option.js';
11
10
  let UmSelect = class UmSelect extends UmTextFieldBase {
12
- static { this.styles = [UmTextFieldBase.styles, styles]; }
13
- #list;
14
- #navigationController;
15
- #resizeObserver;
16
- #connected;
17
- /**
18
- * The `value` of the selected option
19
- */
20
- get value() {
21
- return this._nativeSelect.value;
22
- }
23
- set value(value) {
24
- this._nativeSelect.value = value;
25
- if (!this.#connected) {
26
- return;
27
- }
28
- this.elementInternals.setFormValue(value);
29
- for (const option of this._options) {
30
- option._writeNativeSelected();
31
- }
32
- }
33
- /**
34
- * The index of the selected option. When there's no selected option the value is `-1`.
35
- */
36
- get selectedIndex() {
37
- return this._nativeSelect.selectedIndex;
38
- }
39
- set selectedIndex(index) {
40
- this._nativeSelect.selectedIndex = index;
41
- }
42
- /**
43
- * An `Array` containing the selected `UmOption` or empty if there's no selected option. Multiple selection is not supported.
44
- */
45
- get selectedOptions() {
46
- return this._nativeSelect.selectedOptions.length
47
- ? [this._options[this._nativeSelect.selectedIndex]]
48
- : [];
49
- }
50
- get _options() {
51
- const options = Array.from(this.querySelectorAll('u-option'));
52
- return options.filter(o => o instanceof UmOption);
53
- }
54
11
  constructor() {
55
- super();
56
- this._nativeSelect = document.createElement('select');
12
+ super(...arguments);
57
13
  this.#list = (() => {
58
14
  const list = document.createElement('div');
59
15
  list.role = 'listbox';
@@ -64,10 +20,16 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
64
20
  this.#navigationController = new SelectNavigationController(this);
65
21
  this.#resizeObserver = new ResizeObserver(() => this.#setMenuWidthProperty());
66
22
  this.#connected = false;
23
+ this.#syncScheduled = false;
24
+ this.#selectedIndex = -1;
25
+ this.#lastSyncSignature = '';
67
26
  this.menuPositioning = 'relative';
27
+ this.#handleSlotChange = () => {
28
+ this.#syncFromOptions();
29
+ };
68
30
  this.#handleClick = (e) => {
69
31
  this._menu.toggle();
70
- if (!this._menu.open || !this.selectedOptions.length) {
32
+ if (!this._menu.open || this.#selectedIndex === -1) {
71
33
  return;
72
34
  }
73
35
  this.#navigationController.focusMenu(this.selectedOptions[0], 0, e.detail === 0, false);
@@ -76,36 +38,67 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
76
38
  this._button.setAttribute('aria-expanded', 'true');
77
39
  };
78
40
  this.#handleMenuOpened = () => {
79
- if (!this.selectedOptions.length) {
80
- return;
81
- }
82
- const option = this.selectedOptions[0];
83
- option.scrollIntoView({ block: 'nearest' });
41
+ this._options[this.#selectedIndex]?.scrollIntoView({ block: 'nearest' });
84
42
  };
85
43
  this.#handleMenuClose = () => {
86
44
  this._button.setAttribute('aria-expanded', 'false');
87
45
  this.#navigationController.blurMenu();
88
46
  };
89
- this._nativeSelect.setAttribute('tabindex', '-1');
90
- this._nativeSelect.setAttribute('part', 'select');
91
47
  }
92
- #setMenuWidthProperty() {
93
- this.style.setProperty('--_menu-width', `${this.clientWidth}px`);
48
+ static { this.styles = [UmTextFieldBase.styles, styles]; }
49
+ #list;
50
+ #navigationController;
51
+ #resizeObserver;
52
+ #connected;
53
+ #syncScheduled;
54
+ #selectedIndex;
55
+ #lastSyncSignature;
56
+ /**
57
+ * The `value` of the selected option
58
+ */
59
+ get value() {
60
+ return this._options[this.#selectedIndex]?.value ?? '';
61
+ }
62
+ set value(value) {
63
+ this.#commitIndex(this._options.findIndex(o => o.value === value));
64
+ }
65
+ /**
66
+ * The index of the selected option. When there's no selected option the value is `-1`.
67
+ */
68
+ get selectedIndex() {
69
+ return this.#selectedIndex;
70
+ }
71
+ set selectedIndex(index) {
72
+ const len = this._options.length;
73
+ this.#commitIndex(index >= 0 && index < len ? index : -1);
74
+ }
75
+ get _options() {
76
+ return Array.from(this.querySelectorAll(':scope > u-option'));
77
+ }
78
+ get _menuItems() {
79
+ return this._options;
80
+ }
81
+ get selectedOptions() {
82
+ const option = this._options[this.#selectedIndex];
83
+ return option ? [option] : [];
94
84
  }
95
85
  renderControl() {
96
86
  return staticHtml `
97
87
  <button
98
88
  class="button"
99
89
  role="combobox"
90
+ aria-haspopup="listbox"
91
+ aria-controls="list"
100
92
  aria-expanded="false"
101
- aria-owns="select"
102
93
  ?disabled=${this.disabled}></button>
103
- <div class="input"></div>`;
94
+ <div class="input">
95
+ <span class="display"></span>
96
+ </div>`;
104
97
  }
105
98
  renderAfterContent() {
106
99
  return html `
107
100
  <u-menu positioning="${this.menuPositioning}">
108
- <slot @slotchange=${this._renderOptionRelatedElements}></slot>
101
+ <slot @slotchange=${this.#handleSlotChange}></slot>
109
102
  </u-menu>
110
103
  `;
111
104
  }
@@ -115,18 +108,6 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
115
108
  <path d="M480-360 280-560h400L480-360Z"/>
116
109
  </svg>`;
117
110
  }
118
- updated(changedProperties) {
119
- super.updated(changedProperties);
120
- this.empty = !this.selectedOptions[0]?.textContent?.trim();
121
- this.elementInternals.setFormValue(this._nativeSelect.value || null);
122
- }
123
- attributeChangedCallback(name, _old, value) {
124
- super.attributeChangedCallback(name, _old, value);
125
- if (name !== 'disabled') {
126
- return;
127
- }
128
- this._nativeSelect.disabled = value === null;
129
- }
130
111
  connectedCallback() {
131
112
  super.connectedCallback();
132
113
  this.#connected = true;
@@ -136,6 +117,117 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
136
117
  super.disconnectedCallback();
137
118
  this.#detach();
138
119
  }
120
+ formResetCallback() {
121
+ for (const o of this._options) {
122
+ o.selected = o.defaultSelected;
123
+ }
124
+ this.#syncFromOptions();
125
+ }
126
+ formStateRestoreCallback(inFormState) {
127
+ this.value = inFormState ?? '';
128
+ }
129
+ _scheduleSync() {
130
+ if (this.#syncScheduled || !this.#connected) {
131
+ return;
132
+ }
133
+ this.#syncScheduled = true;
134
+ queueMicrotask(() => {
135
+ try {
136
+ if (this.#computeSignature() !== this.#lastSyncSignature) {
137
+ this.#syncFromOptions();
138
+ }
139
+ }
140
+ finally {
141
+ this.#syncScheduled = false;
142
+ }
143
+ });
144
+ }
145
+ _setSelectedByUser(option) {
146
+ const previousIndex = this.#selectedIndex;
147
+ const newIndex = this._options.indexOf(option);
148
+ if (newIndex < 0) {
149
+ return;
150
+ }
151
+ this.#commitIndex(newIndex);
152
+ if (previousIndex !== newIndex) {
153
+ this.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
154
+ this.dispatchEvent(new Event('change', { bubbles: true }));
155
+ }
156
+ this._menu.close();
157
+ }
158
+ /** Re-renderiza display e listbox a11y quando o textContent de uma option muda. */
159
+ _renderOptionRelatedElements() {
160
+ this.#renderAccessibilityList();
161
+ this.#updateDisplay();
162
+ }
163
+ #commitIndex(index) {
164
+ const options = this._options;
165
+ const target = index >= 0 ? options[index] : null;
166
+ for (const o of options) {
167
+ o.selected = o === target;
168
+ }
169
+ this.#selectedIndex = target ? index : -1;
170
+ this.#lastSyncSignature = this.#computeSignature();
171
+ this.#emitState();
172
+ }
173
+ #syncFromOptions() {
174
+ const options = this._options;
175
+ let lastSelected = -1;
176
+ // last-wins
177
+ for (let i = 0; i < options.length; i++) {
178
+ if (!options[i].selected) {
179
+ continue;
180
+ }
181
+ if (lastSelected >= 0) {
182
+ options[lastSelected].selected = false;
183
+ }
184
+ lastSelected = i;
185
+ }
186
+ if (lastSelected < 0 && options.length > 0) {
187
+ const firstEnabled = options.findIndex(o => !o.disabled);
188
+ if (firstEnabled >= 0) {
189
+ options[firstEnabled].selected = true;
190
+ lastSelected = firstEnabled;
191
+ }
192
+ }
193
+ this.#selectedIndex = lastSelected;
194
+ this.#lastSyncSignature = this.#computeSignature();
195
+ this.#emitState();
196
+ }
197
+ #computeSignature() {
198
+ return this._options
199
+ .map(o => `${o.selected ? 1 : 0}:${o.disabled ? 1 : 0}:${o.value}`)
200
+ .join('|');
201
+ }
202
+ #emitState() {
203
+ this.elementInternals.setFormValue(this.value || null);
204
+ this.#renderAccessibilityList();
205
+ this.#updateDisplay();
206
+ this.#updateEmpty();
207
+ this.requestUpdate();
208
+ }
209
+ #updateEmpty() {
210
+ const o = this._options[this.#selectedIndex];
211
+ this.empty = !o?.textContent?.trim();
212
+ }
213
+ #renderAccessibilityList() {
214
+ const selectedIdx = this.#selectedIndex;
215
+ render(map(this._options, (option, index) => html `<div role="option"
216
+ id=${`item-${index + 1}`}
217
+ aria-selected=${index === selectedIdx ? 'true' : 'false'}>
218
+ ${option.textContent}
219
+ </div>`), this.#list);
220
+ }
221
+ #updateDisplay() {
222
+ if (!this._input) {
223
+ return;
224
+ }
225
+ this._input.textContent = this._options[this.#selectedIndex]?.textContent?.trim() ?? '';
226
+ }
227
+ #setMenuWidthProperty() {
228
+ this.style.setProperty('--_menu-width', `${this.clientWidth}px`);
229
+ }
230
+ #handleSlotChange;
139
231
  #handleClick;
140
232
  #handleMenuClick(e) {
141
233
  e.stopPropagation();
@@ -147,9 +239,7 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
147
239
  this.#resizeObserver.observe(this);
148
240
  this._renderOptionRelatedElements();
149
241
  await this.updateComplete;
150
- this._nativeSelect.disabled = this.hasAttribute('disabled');
151
242
  this.#navigationController.attach(this);
152
- this._input.appendChild(this._nativeSelect);
153
243
  this._input.appendChild(this.#list);
154
244
  this._button.addEventListener('click', this.#handleClick);
155
245
  this._menu.anchorElement = this._container;
@@ -157,10 +247,10 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
157
247
  this._menu.addEventListener('open', this.#handleMenuOpen);
158
248
  this._menu.addEventListener('opened', this.#handleMenuOpened);
159
249
  this._menu.addEventListener('close', this.#handleMenuClose);
250
+ this.#syncFromOptions();
160
251
  }
161
252
  #detach() {
162
253
  this.#resizeObserver.disconnect();
163
- this._nativeSelect.remove();
164
254
  this.#list.remove();
165
255
  this.#navigationController.detach();
166
256
  this.#connected = false;
@@ -170,36 +260,7 @@ let UmSelect = class UmSelect extends UmTextFieldBase {
170
260
  this._menu.removeEventListener('opened', this.#handleMenuOpened);
171
261
  this._menu.removeEventListener('close', this.#handleMenuClose);
172
262
  }
173
- _renderOptionRelatedElements() {
174
- this.#renderNativeOptions();
175
- this.#renderAccessibilityList();
176
- this._updateEmpty();
177
- this._syncSelectedOptions();
178
- }
179
- _updateEmpty() {
180
- this.empty = !this.selectedOptions[0]?.textContent?.trim();
181
- }
182
- get _menuItems() {
183
- return this._options;
184
- }
185
- #renderNativeOptions() {
186
- render(map(this._options, option => html `<option value=${option.value} ?selected=${option.selected}>${option.textContent}</option>`), this._nativeSelect);
187
- }
188
- #renderAccessibilityList() {
189
- render(map(this._options, (option, index) => html `<div role="option" id="${`item-${index + 1}`}">${option.textContent}</div>`), this.#list);
190
- }
191
- _syncSelectedOptions() {
192
- for (let i = 0; i < this._options.length; i++) {
193
- const option = this._options[i];
194
- const nativeOption = this._nativeSelect.children[i];
195
- option.selected = nativeOption.selected;
196
- option._nativeOption = nativeOption;
197
- }
198
- }
199
263
  };
200
- __decorate([
201
- state()
202
- ], UmSelect.prototype, "value", null);
203
264
  __decorate([
204
265
  query('u-menu', true)
205
266
  ], UmSelect.prototype, "_menu", void 0);
@@ -212,6 +273,9 @@ __decorate([
212
273
  __decorate([
213
274
  property({ reflect: true, attribute: 'menu-positioning' })
214
275
  ], UmSelect.prototype, "menuPositioning", void 0);
276
+ __decorate([
277
+ state()
278
+ ], UmSelect.prototype, "value", null);
215
279
  __decorate([
216
280
  state()
217
281
  ], UmSelect.prototype, "selectedIndex", null);
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select/select.ts"],"names":[],"mappings":"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","sourcesContent":["import { PropertyValues } from '@lit/reactive-element';\n\nimport { html, render, svg, TemplateResult } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { map } from 'lit/directives/map.js';\nimport { html as staticHtml } from 'lit/static-html.js';\n\nimport { UmMenu } from '../menu/menu.js';\nimport { UmMenuField } from '../shared/menu-field/menu-field.js';\nimport { UmTextFieldBase } from '../shared/text-field-base/text-field-base.js';\nimport { UmOption } from './option.js';\nimport { SelectNavigationController } from './select-navigation-controller.js';\nimport { styles } from './select.styles.js';\n\nimport './option.js';\n\n@customElement('u-select')\nexport class UmSelect extends UmTextFieldBase implements UmMenuField {\n static override styles = [UmTextFieldBase.styles, styles];\n\n _nativeSelect = document.createElement('select');\n\n readonly #list: HTMLElement = (() => {\n const list = document.createElement('div');\n list.role = 'listbox';\n list.id = 'list';\n list.className = 'list';\n\n return list;\n })();\n\n readonly #navigationController = new SelectNavigationController(this);\n readonly #resizeObserver = new ResizeObserver(() => this.#setMenuWidthProperty());\n #connected = false;\n\n /**\n * The `value` of the selected option\n */\n @state()\n get value(): string {\n return this._nativeSelect.value;\n }\n\n set value(value: string) {\n this._nativeSelect.value = value;\n\n if (!this.#connected) {\n return;\n }\n\n this.elementInternals.setFormValue(value);\n\n for (const option of this._options) {\n option._writeNativeSelected();\n }\n }\n\n @query('u-menu', true) _menu!: UmMenu;\n @query('.button', true) _button!: HTMLButtonElement;\n @query('.input', true) _input!: HTMLElement;\n\n @property({ reflect: true, attribute: 'menu-positioning' }) menuPositioning: 'relative' | 'fixed' = 'relative';\n\n /**\n * The index of the selected option. When there's no selected option the value is `-1`.\n */\n @state()\n get selectedIndex(): number {\n return this._nativeSelect.selectedIndex;\n }\n\n set selectedIndex(index: number) {\n this._nativeSelect.selectedIndex = index;\n }\n\n /**\n * An `Array` containing the selected `UmOption` or empty if there's no selected option. Multiple selection is not supported.\n */\n get selectedOptions(): UmOption[] {\n return this._nativeSelect.selectedOptions.length\n ? [this._options[this._nativeSelect.selectedIndex]]\n : [];\n }\n\n get _options(): UmOption[] {\n const options = Array.from(this.querySelectorAll<HTMLElement>('u-option'));\n\n return options.filter(o => o instanceof UmOption);\n }\n\n constructor() {\n super();\n\n this._nativeSelect.setAttribute('tabindex', '-1');\n this._nativeSelect.setAttribute('part', 'select');\n }\n\n #setMenuWidthProperty(): void {\n this.style.setProperty('--_menu-width', `${this.clientWidth}px`);\n }\n\n protected override renderControl(): TemplateResult {\n return staticHtml`\n <button \n class=\"button\"\n role=\"combobox\"\n aria-expanded=\"false\"\n aria-owns=\"select\"\n ?disabled=${this.disabled}></button>\n <div class=\"input\"></div>`;\n }\n\n protected override renderAfterContent(): TemplateResult {\n return html`\n <u-menu positioning=\"${this.menuPositioning}\">\n <slot @slotchange=${this._renderOptionRelatedElements}></slot>\n </u-menu>\n `;\n }\n\n protected override renderDefaultTrailingIcon(): TemplateResult {\n return svg`\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 -960 960 960\" width=\"1em\" fill=\"currentColor\">\n <path d=\"M480-360 280-560h400L480-360Z\"/>\n </svg>`;\n }\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n this.empty = !this.selectedOptions[0]?.textContent?.trim();\n this.elementInternals.setFormValue(this._nativeSelect.value || null);\n }\n\n override attributeChangedCallback(name: string, _old: string | null, value: string | null) {\n super.attributeChangedCallback(name, _old, value);\n\n if (name !== 'disabled') {\n return;\n }\n\n this._nativeSelect.disabled = value === null;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n\n this.#connected = true;\n this.#attach();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n this.#detach();\n }\n\n readonly #handleClick = (e: MouseEvent) => {\n this._menu.toggle();\n\n if (!this._menu.open || !this.selectedOptions.length) {\n return;\n }\n\n this.#navigationController.focusMenu(this.selectedOptions[0], 0, e.detail === 0, false);\n };\n\n #handleMenuClick(e: Event) {\n e.stopPropagation();\n }\n\n readonly #handleMenuOpen = () => {\n this._button.setAttribute('aria-expanded', 'true');\n };\n\n readonly #handleMenuOpened = () => {\n if (!this.selectedOptions.length) {\n return;\n }\n\n const option = this.selectedOptions[0];\n option.scrollIntoView({ block: 'nearest' });\n };\n\n readonly #handleMenuClose = () => {\n this._button.setAttribute('aria-expanded', 'false');\n this.#navigationController.blurMenu();\n };\n\n async #attach(): Promise<void> {\n this.#resizeObserver.observe(this);\n this._renderOptionRelatedElements();\n\n await this.updateComplete;\n\n this._nativeSelect.disabled = this.hasAttribute('disabled');\n\n this.#navigationController.attach(this);\n\n this._input.appendChild(this._nativeSelect);\n this._input.appendChild(this.#list);\n this._button.addEventListener('click', this.#handleClick);\n\n this._menu.anchorElement = this._container;\n this._menu.addEventListener('click', this.#handleMenuClick);\n this._menu.addEventListener('open', this.#handleMenuOpen);\n this._menu.addEventListener('opened', this.#handleMenuOpened);\n this._menu.addEventListener('close', this.#handleMenuClose);\n }\n\n #detach(): void {\n this.#resizeObserver.disconnect();\n this._nativeSelect.remove();\n this.#list.remove();\n this.#navigationController.detach();\n this.#connected = false;\n this._button.removeEventListener('click', this.#handleClick);\n this._menu.removeEventListener('click', this.#handleMenuClick);\n this._menu.removeEventListener('open', this.#handleMenuOpen);\n this._menu.removeEventListener('opened', this.#handleMenuOpened);\n this._menu.removeEventListener('close', this.#handleMenuClose);\n }\n\n _renderOptionRelatedElements() {\n this.#renderNativeOptions();\n this.#renderAccessibilityList();\n this._updateEmpty();\n this._syncSelectedOptions();\n }\n\n _updateEmpty(): void {\n this.empty = !this.selectedOptions[0]?.textContent?.trim();\n }\n\n get _menuItems(): UmOption[] {\n return this._options;\n }\n\n #renderNativeOptions() {\n render(\n map(\n this._options,\n option =>\n html`<option value=${option.value} ?selected=${option.selected}>${option.textContent}</option>`),\n this._nativeSelect);\n }\n\n #renderAccessibilityList() {\n render(\n map(\n this._options,\n (option, index) =>\n html`<div role=\"option\" id=\"${`item-${index + 1}`}\">${option.textContent}</div>`),\n this.#list);\n }\n\n _syncSelectedOptions() {\n\n for (let i = 0; i < this._options.length; i++) {\n const option = this._options[i];\n const nativeOption = this._nativeSelect.children[i] as HTMLOptionElement;\n option.selected = nativeOption.selected;\n option._nativeOption = nativeOption;\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'u-select': UmSelect;\n }\n}\n"]}
1
+ {"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select/select.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, render, svg, TemplateResult } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { map } from 'lit/directives/map.js';\nimport { html as staticHtml } from 'lit/static-html.js';\n\nimport { UmMenu } from '../menu/menu.js';\nimport { UmMenuField } from '../shared/menu-field/menu-field.js';\nimport { UmTextFieldBase } from '../shared/text-field-base/text-field-base.js';\nimport { UmOption } from './option.js';\nimport { SelectNavigationController } from './select-navigation-controller.js';\nimport { styles } from './select.styles.js';\n\nimport './option.js';\n\n@customElement('u-select')\nexport class UmSelect extends UmTextFieldBase implements UmMenuField {\n static override styles = [UmTextFieldBase.styles, styles];\n\n readonly #list: HTMLElement = (() => {\n const list = document.createElement('div');\n list.role = 'listbox';\n list.id = 'list';\n list.className = 'list';\n\n return list;\n })();\n\n readonly #navigationController = new SelectNavigationController(this);\n readonly #resizeObserver = new ResizeObserver(() => this.#setMenuWidthProperty());\n\n #connected = false;\n #syncScheduled = false;\n #selectedIndex = -1;\n #lastSyncSignature = '';\n\n @query('u-menu', true) _menu!: UmMenu;\n @query('.button', true) _button!: HTMLButtonElement;\n @query('.input', true) _input!: HTMLElement;\n\n @property({ reflect: true, attribute: 'menu-positioning' }) menuPositioning: 'relative' | 'fixed' = 'relative';\n\n /**\n * The `value` of the selected option\n */\n\n @state()\n get value(): string {\n return this._options[this.#selectedIndex]?.value ?? '';\n }\n\n set value(value: string) {\n this.#commitIndex(this._options.findIndex(o => o.value === value));\n }\n\n /**\n * The index of the selected option. When there's no selected option the value is `-1`.\n */\n @state()\n get selectedIndex(): number {\n return this.#selectedIndex;\n }\n\n set selectedIndex(index: number) {\n const len = this._options.length;\n this.#commitIndex(index >= 0 && index < len ? index : -1);\n }\n\n get _options(): UmOption[] {\n return Array.from(this.querySelectorAll<UmOption>(':scope > u-option'));\n }\n\n get _menuItems(): UmOption[] {\n return this._options;\n }\n\n get selectedOptions(): UmOption[] {\n const option = this._options[this.#selectedIndex];\n return option ? [option] : [];\n }\n\n protected override renderControl(): TemplateResult {\n return staticHtml`\n <button \n class=\"button\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-controls=\"list\"\n aria-expanded=\"false\"\n ?disabled=${this.disabled}></button>\n <div class=\"input\">\n <span class=\"display\"></span>\n </div>`;\n }\n\n protected override renderAfterContent(): TemplateResult {\n return html`\n <u-menu positioning=\"${this.menuPositioning}\">\n <slot @slotchange=${this.#handleSlotChange}></slot>\n </u-menu>\n `;\n }\n\n protected override renderDefaultTrailingIcon(): TemplateResult {\n return svg`\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"1em\" viewBox=\"0 -960 960 960\" width=\"1em\" fill=\"currentColor\">\n <path d=\"M480-360 280-560h400L480-360Z\"/>\n </svg>`;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n\n this.#connected = true;\n this.#attach();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n this.#detach();\n }\n\n formResetCallback(): void {\n for (const o of this._options) {\n o.selected = o.defaultSelected;\n }\n\n this.#syncFromOptions();\n }\n\n formStateRestoreCallback(inFormState: string | null): void {\n this.value = inFormState ?? '';\n }\n\n _scheduleSync(): void {\n if (this.#syncScheduled || !this.#connected) {\n return;\n }\n\n this.#syncScheduled = true;\n queueMicrotask(() => {\n try {\n if (this.#computeSignature() !== this.#lastSyncSignature) {\n this.#syncFromOptions();\n }\n } finally {\n this.#syncScheduled = false;\n }\n });\n }\n\n _setSelectedByUser(option: UmOption): void {\n const previousIndex = this.#selectedIndex;\n const newIndex = this._options.indexOf(option);\n\n if (newIndex < 0) {\n return;\n }\n\n this.#commitIndex(newIndex);\n\n if (previousIndex !== newIndex) {\n this.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));\n this.dispatchEvent(new Event('change', { bubbles: true }));\n }\n\n this._menu.close();\n }\n\n /** Re-renderiza display e listbox a11y quando o textContent de uma option muda. */\n _renderOptionRelatedElements(): void {\n this.#renderAccessibilityList();\n this.#updateDisplay();\n }\n\n #commitIndex(index: number): void {\n const options = this._options;\n const target = index >= 0 ? options[index] : null;\n\n for (const o of options) {\n o.selected = o === target;\n }\n\n this.#selectedIndex = target ? index : -1;\n this.#lastSyncSignature = this.#computeSignature();\n this.#emitState();\n }\n\n #syncFromOptions(): void {\n const options = this._options;\n let lastSelected = -1;\n\n // last-wins\n for (let i = 0; i < options.length; i++) {\n if (!options[i].selected) {\n continue;\n }\n\n if (lastSelected >= 0) {\n options[lastSelected].selected = false;\n }\n\n lastSelected = i;\n }\n\n if (lastSelected < 0 && options.length > 0) {\n const firstEnabled = options.findIndex(o => !o.disabled);\n\n if (firstEnabled >= 0) {\n options[firstEnabled].selected = true;\n lastSelected = firstEnabled;\n }\n }\n\n this.#selectedIndex = lastSelected;\n this.#lastSyncSignature = this.#computeSignature();\n this.#emitState();\n }\n\n #computeSignature(): string {\n return this._options\n .map(o => `${o.selected ? 1 : 0}:${o.disabled ? 1 : 0}:${o.value}`)\n .join('|');\n }\n\n #emitState(): void {\n this.elementInternals.setFormValue(this.value || null);\n this.#renderAccessibilityList();\n this.#updateDisplay();\n this.#updateEmpty();\n this.requestUpdate();\n }\n\n #updateEmpty(): void {\n const o = this._options[this.#selectedIndex];\n this.empty = !o?.textContent?.trim();\n }\n\n #renderAccessibilityList(): void {\n const selectedIdx = this.#selectedIndex;\n render(\n map(this._options, (option, index) =>\n html`<div role=\"option\"\n id=${`item-${index + 1}`}\n aria-selected=${index === selectedIdx ? 'true' : 'false'}>\n ${option.textContent}\n </div>`),\n this.#list);\n }\n\n #updateDisplay(): void {\n if (!this._input) {\n return;\n }\n\n this._input.textContent = this._options[this.#selectedIndex]?.textContent?.trim() ?? '';\n }\n\n #setMenuWidthProperty(): void {\n this.style.setProperty('--_menu-width', `${this.clientWidth}px`);\n }\n\n readonly #handleSlotChange = (): void => {\n this.#syncFromOptions();\n };\n\n readonly #handleClick = (e: MouseEvent) => {\n this._menu.toggle();\n\n if (!this._menu.open || this.#selectedIndex === -1) {\n return;\n }\n\n this.#navigationController.focusMenu(this.selectedOptions[0], 0, e.detail === 0, false);\n };\n\n #handleMenuClick(e: Event) {\n e.stopPropagation();\n }\n\n readonly #handleMenuOpen = () => {\n this._button.setAttribute('aria-expanded', 'true');\n };\n\n readonly #handleMenuOpened = () => {\n this._options[this.#selectedIndex]?.scrollIntoView({ block: 'nearest' });\n };\n\n readonly #handleMenuClose = () => {\n this._button.setAttribute('aria-expanded', 'false');\n this.#navigationController.blurMenu();\n };\n\n async #attach(): Promise<void> {\n this.#resizeObserver.observe(this);\n this._renderOptionRelatedElements();\n\n await this.updateComplete;\n\n this.#navigationController.attach(this);\n\n this._input.appendChild(this.#list);\n this._button.addEventListener('click', this.#handleClick);\n\n this._menu.anchorElement = this._container;\n this._menu.addEventListener('click', this.#handleMenuClick);\n this._menu.addEventListener('open', this.#handleMenuOpen);\n this._menu.addEventListener('opened', this.#handleMenuOpened);\n this._menu.addEventListener('close', this.#handleMenuClose);\n\n this.#syncFromOptions();\n }\n\n #detach(): void {\n this.#resizeObserver.disconnect();\n this.#list.remove();\n this.#navigationController.detach();\n this.#connected = false;\n this._button.removeEventListener('click', this.#handleClick);\n this._menu.removeEventListener('click', this.#handleMenuClick);\n this._menu.removeEventListener('open', this.#handleMenuOpen);\n this._menu.removeEventListener('opened', this.#handleMenuOpened);\n this._menu.removeEventListener('close', this.#handleMenuClose);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'u-select': UmSelect;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"select.styles.d.ts","sourceRoot":"","sources":["../../src/select/select.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,yBAoClB,CAAC"}
1
+ {"version":3,"file":"select.styles.d.ts","sourceRoot":"","sources":["../../src/select/select.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,yBA0ClB,CAAC"}
@@ -35,5 +35,11 @@ export const styles = css `
35
35
  margin: -1px;
36
36
  overflow: hidden;
37
37
  }
38
+
39
+ .input {
40
+ text-overflow: ellipsis;
41
+ white-space: nowrap;
42
+ overflow: hidden;
43
+ }
38
44
  `;
39
45
  //# sourceMappingURL=select.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"select.styles.js","sourceRoot":"","sources":["../../src/select/select.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCzB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css `\n u-menu {\n display: block;\n width: 100%;\n }\n u-menu::part(menu) {\n width: var(--_menu-width);\n max-width: none;\n }\n\n :host(:not([disabled])) .button {\n cursor: pointer;\n }\n\n .button {\n position: absolute;\n inset: 0;\n margin: 0;\n padding: 0;\n background: transparent;\n border: none;\n appearance: none;\n }\n\n select {\n pointer-events: none;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .list {\n width: 2px;\n height: 2px;\n margin: -1px;\n overflow: hidden;\n }\n`;\n"]}
1
+ {"version":3,"file":"select.styles.js","sourceRoot":"","sources":["../../src/select/select.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CzB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css `\n u-menu {\n display: block;\n width: 100%;\n }\n u-menu::part(menu) {\n width: var(--_menu-width);\n max-width: none;\n }\n\n :host(:not([disabled])) .button {\n cursor: pointer;\n }\n\n .button {\n position: absolute;\n inset: 0;\n margin: 0;\n padding: 0;\n background: transparent;\n border: none;\n appearance: none;\n }\n\n select {\n pointer-events: none;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .list {\n width: 2px;\n height: 2px;\n margin: -1px;\n overflow: hidden;\n }\n\n .input {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n }\n`;\n"]}