@vollowx/seele 0.8.4 → 0.8.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/package.json +3 -1
- package/src/base/menu.js +22 -17
- package/src/base/select.js +216 -124
- package/src/base/tooltip.js +7 -0
- package/src/m3/item-styles.css.js +1 -1
- package/src/m3/menu-part-styles.css.js +1 -1
- package/src/m3/menu-styles.css.js +1 -1
- package/src/m3/select/select.js +0 -4
- package/src/m3/tooltip-styles.css.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vollowx/seele",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Standard Extensible Elements. A web components library that can be styled and extended freely, pre-providing components in Material Design 3.",
|
|
5
5
|
"author": "vollowx",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"LICENSE",
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
|
+
"customElements": "custom-elements.json",
|
|
21
22
|
"keywords": [
|
|
22
23
|
"web-components",
|
|
23
24
|
"material-design",
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
"lit",
|
|
26
27
|
"ui-components"
|
|
27
28
|
],
|
|
29
|
+
"homepage": "https://docs.seele.v9.nz",
|
|
28
30
|
"repository": {
|
|
29
31
|
"type": "git",
|
|
30
32
|
"url": "https://github.com/vollowx/seele.git"
|
package/src/base/menu.js
CHANGED
|
@@ -3,7 +3,7 @@ import { LitElement, html } from 'lit';
|
|
|
3
3
|
import { property, query } from 'lit/decorators.js';
|
|
4
4
|
import { setFocusVisible } from '../core/focus-visible.js';
|
|
5
5
|
import { Attachable } from './mixins/attachable.js';
|
|
6
|
-
import {
|
|
6
|
+
import { InternalsAttached } from './mixins/internals-attached.js';
|
|
7
7
|
import { PopoverController } from './controllers/popover-controller.js';
|
|
8
8
|
import { ListController } from './controllers/list-controller.js';
|
|
9
9
|
import { MenuActions, getActionFromKey, getUpdatedIndex, scrollItemIntoView, } from './menu-utils.js';
|
|
@@ -13,10 +13,12 @@ const Base = InternalsAttached(Attachable(LitElement));
|
|
|
13
13
|
* @csspart items
|
|
14
14
|
*
|
|
15
15
|
* @fires {Event} select - Fired when a menu item has been selected.
|
|
16
|
+
* @fires {Event} open - Fired when the menu is opened.
|
|
17
|
+
* @fires {Event} close - Fired when the menu is closed.
|
|
16
18
|
*/
|
|
17
19
|
export class Menu extends Base {
|
|
18
20
|
constructor() {
|
|
19
|
-
super();
|
|
21
|
+
super(...arguments);
|
|
20
22
|
this._possibleItemTags = [];
|
|
21
23
|
this._durations = { show: 0, hide: 0 };
|
|
22
24
|
this._scrollPadding = 0;
|
|
@@ -57,32 +59,35 @@ export class Menu extends Base {
|
|
|
57
59
|
},
|
|
58
60
|
focusItem: (item) => {
|
|
59
61
|
item.focused = true;
|
|
60
|
-
|
|
61
|
-
// Somehow setting ariaActiveDescendantElement doesn't actually update it
|
|
62
|
-
this.setAttribute('aria-activedescendant', item.id);
|
|
62
|
+
this.$menu.setAttribute('aria-activedescendant', item.id);
|
|
63
63
|
scrollItemIntoView(this.$menu, item, this._scrollPadding);
|
|
64
64
|
},
|
|
65
65
|
wrapNavigation: () => false,
|
|
66
66
|
});
|
|
67
|
-
this[internals].role = 'menu';
|
|
68
|
-
this.tabIndex = -1;
|
|
69
67
|
}
|
|
68
|
+
static { this.shadowRootOptions = {
|
|
69
|
+
...LitElement.shadowRootOptions,
|
|
70
|
+
delegatesFocus: true,
|
|
71
|
+
}; }
|
|
70
72
|
render() {
|
|
71
|
-
return html `<div
|
|
73
|
+
return html `<div
|
|
74
|
+
part="menu"
|
|
75
|
+
role="menu"
|
|
76
|
+
tabindex="0"
|
|
77
|
+
@keydown=${this.#handleKeyDown.bind(this)}
|
|
78
|
+
@focusout=${this.#handleFocusOut.bind(this)}
|
|
79
|
+
>
|
|
80
|
+
${this.renderItemSlot()}
|
|
81
|
+
</div>`;
|
|
72
82
|
}
|
|
73
83
|
renderItemSlot() {
|
|
74
84
|
return html `<slot part="items"></slot>`;
|
|
75
85
|
}
|
|
76
86
|
connectedCallback() {
|
|
77
87
|
super.connectedCallback();
|
|
78
|
-
this.addEventListener('keydown', this.#handleKeyDown.bind(this));
|
|
79
|
-
this.addEventListener('focusout', this.#handleFocusOut.bind(this));
|
|
80
88
|
if (this.$control) {
|
|
89
|
+
// TODO: Manage $control ARIA attributes
|
|
81
90
|
// TODO: Handle $control change
|
|
82
|
-
this.$control.ariaHasPopup = 'true';
|
|
83
|
-
this.$control.ariaExpanded = 'false';
|
|
84
|
-
this.$control.ariaControlsElements = [this];
|
|
85
|
-
this[internals].ariaLabelledByElements = [this.$control];
|
|
86
91
|
this.$control.addEventListener('focusout', this.#handleFocusOut.bind(this));
|
|
87
92
|
}
|
|
88
93
|
this.listController.items.forEach((item) => {
|
|
@@ -92,8 +97,6 @@ export class Menu extends Base {
|
|
|
92
97
|
}
|
|
93
98
|
disconnectedCallback() {
|
|
94
99
|
super.disconnectedCallback();
|
|
95
|
-
this.removeEventListener('keydown', this.#handleKeyDown.bind(this));
|
|
96
|
-
this.removeEventListener('focusout', this.#handleFocusOut.bind(this));
|
|
97
100
|
if (this.$control) {
|
|
98
101
|
this.$control.removeEventListener('focusout', this.#handleFocusOut.bind(this));
|
|
99
102
|
}
|
|
@@ -101,16 +104,18 @@ export class Menu extends Base {
|
|
|
101
104
|
updated(changed) {
|
|
102
105
|
if (changed.has('open')) {
|
|
103
106
|
if (this.open) {
|
|
107
|
+
this.dispatchEvent(new Event('open', { bubbles: true, composed: true }));
|
|
104
108
|
this.$lastFocused = document.activeElement;
|
|
105
109
|
if (this.$control) {
|
|
106
110
|
this.$control.ariaExpanded = 'true';
|
|
107
111
|
}
|
|
108
112
|
this.popoverController.animateOpen().then(() => {
|
|
109
|
-
this.focus();
|
|
113
|
+
this.$menu.focus();
|
|
110
114
|
this.listController.focusFirstItem();
|
|
111
115
|
});
|
|
112
116
|
}
|
|
113
117
|
else {
|
|
118
|
+
this.dispatchEvent(new Event('close', { bubbles: true, composed: true }));
|
|
114
119
|
this.listController.clearSearch();
|
|
115
120
|
if (this.$control) {
|
|
116
121
|
this.$control.ariaExpanded = 'false';
|
package/src/base/select.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
import { __decorate } from "tslib";
|
|
2
3
|
import { LitElement, isServer, html } from 'lit';
|
|
3
|
-
import { property, query
|
|
4
|
+
import { property, query } from 'lit/decorators.js';
|
|
4
5
|
import { FormAssociated } from './mixins/form-associated.js';
|
|
5
6
|
import { InternalsAttached } from './mixins/internals-attached.js';
|
|
6
7
|
import { PopoverController } from './controllers/popover-controller.js';
|
|
7
8
|
import { ListController } from './controllers/list-controller.js';
|
|
8
9
|
import { MenuActions, getActionFromKey, getUpdatedIndex, scrollItemIntoView, } from './menu-utils.js';
|
|
10
|
+
const VALUE = Symbol('value');
|
|
9
11
|
const Base = FormAssociated(InternalsAttached(LitElement));
|
|
10
12
|
/**
|
|
11
13
|
* @csspart field
|
|
@@ -23,15 +25,22 @@ export class Select extends Base {
|
|
|
23
25
|
this._possibleItemTags = [];
|
|
24
26
|
this._durations = { show: 0, hide: 0 };
|
|
25
27
|
this._scrollPadding = 0;
|
|
26
|
-
this.value = '';
|
|
27
|
-
this.displayValue = '';
|
|
28
|
-
this.placeholder = '';
|
|
29
|
-
this.open = false;
|
|
30
|
-
this.required = false;
|
|
31
28
|
this.quick = false;
|
|
29
|
+
this.required = false;
|
|
30
|
+
this.error = false;
|
|
32
31
|
this.align = 'bottom-start';
|
|
33
32
|
this.alignStrategy = 'absolute';
|
|
34
33
|
this.offset = 0;
|
|
34
|
+
/**
|
|
35
|
+
* Text to display in the field. Only set for SSR.
|
|
36
|
+
*/
|
|
37
|
+
this.displayText = '';
|
|
38
|
+
this[_a] = '';
|
|
39
|
+
this.open = false;
|
|
40
|
+
this.lastUserSetValue = null;
|
|
41
|
+
this.lastUserSetSelectedIndex = null;
|
|
42
|
+
this.lastSelectedOption = null;
|
|
43
|
+
this.lastSelectedOptionRecords = [];
|
|
35
44
|
this.popoverController = new PopoverController(this, {
|
|
36
45
|
popover: () => this.$menu,
|
|
37
46
|
trigger: () => this.$field,
|
|
@@ -66,6 +75,102 @@ export class Select extends Base {
|
|
|
66
75
|
},
|
|
67
76
|
wrapNavigation: () => false,
|
|
68
77
|
});
|
|
78
|
+
this.#dispatchChangeEvent = () => {
|
|
79
|
+
this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
80
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
81
|
+
};
|
|
82
|
+
this.#handleOptionClick = (event) => {
|
|
83
|
+
const target = event.target;
|
|
84
|
+
const item = target.closest(this._possibleItemTags.join(','));
|
|
85
|
+
if (item && this.listController.items.includes(item)) {
|
|
86
|
+
if (this.selectItem(item)) {
|
|
87
|
+
this.#dispatchChangeEvent();
|
|
88
|
+
}
|
|
89
|
+
this.open = false;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
this.#handleFocusOut = (event) => {
|
|
93
|
+
const relatedTarget = event.relatedTarget;
|
|
94
|
+
if (!this.contains(relatedTarget) && !this.$menu.contains(relatedTarget)) {
|
|
95
|
+
this.open = false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
static { _a = VALUE; }
|
|
100
|
+
static { this.shadowRootOptions = {
|
|
101
|
+
...LitElement.shadowRootOptions,
|
|
102
|
+
delegatesFocus: true,
|
|
103
|
+
}; }
|
|
104
|
+
get value() {
|
|
105
|
+
return this[VALUE];
|
|
106
|
+
}
|
|
107
|
+
set value(value) {
|
|
108
|
+
if (isServer)
|
|
109
|
+
return;
|
|
110
|
+
this.lastUserSetValue = value;
|
|
111
|
+
this.select(value);
|
|
112
|
+
}
|
|
113
|
+
get options() {
|
|
114
|
+
return this.listController.items;
|
|
115
|
+
}
|
|
116
|
+
get selectedIndex() {
|
|
117
|
+
const selectedOptions = this.getSelectedOptions() ?? [];
|
|
118
|
+
if (selectedOptions.length > 0) {
|
|
119
|
+
return selectedOptions[0][1];
|
|
120
|
+
}
|
|
121
|
+
return -1;
|
|
122
|
+
}
|
|
123
|
+
set selectedIndex(index) {
|
|
124
|
+
this.lastUserSetSelectedIndex = index;
|
|
125
|
+
this.selectIndex(index);
|
|
126
|
+
}
|
|
127
|
+
get selectedOptions() {
|
|
128
|
+
return (this.getSelectedOptions() ?? []).map(([option]) => option);
|
|
129
|
+
}
|
|
130
|
+
connectedCallback() {
|
|
131
|
+
super.connectedCallback();
|
|
132
|
+
this.addEventListener('focusout', this.#handleFocusOut);
|
|
133
|
+
this.addEventListener('click', this.#handleOptionClick);
|
|
134
|
+
}
|
|
135
|
+
disconnectedCallback() {
|
|
136
|
+
super.disconnectedCallback();
|
|
137
|
+
this.removeEventListener('focusout', this.#handleFocusOut);
|
|
138
|
+
this.removeEventListener('click', this.#handleOptionClick);
|
|
139
|
+
}
|
|
140
|
+
async firstUpdated(changed) {
|
|
141
|
+
// If this has been handled on update already due to SSR, try again.
|
|
142
|
+
if (!this.lastSelectedOptionRecords.length) {
|
|
143
|
+
this.initUserSelection();
|
|
144
|
+
}
|
|
145
|
+
// Case for when the DOM is streaming, there are no children, and a child
|
|
146
|
+
// has [selected] set on it, we need to wait for DOM to render something.
|
|
147
|
+
if (!this.lastSelectedOptionRecords.length &&
|
|
148
|
+
!isServer &&
|
|
149
|
+
!this.options.length) {
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
this.updateValueAndDisplayText();
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
super.firstUpdated(changed);
|
|
155
|
+
}
|
|
156
|
+
update(changed) {
|
|
157
|
+
if (!this.hasUpdated) {
|
|
158
|
+
this.initUserSelection();
|
|
159
|
+
}
|
|
160
|
+
super.update(changed);
|
|
161
|
+
}
|
|
162
|
+
updated(changed) {
|
|
163
|
+
super.updated(changed);
|
|
164
|
+
if (changed.has('open')) {
|
|
165
|
+
if (this.open) {
|
|
166
|
+
this.popoverController.animateOpen();
|
|
167
|
+
this.#focusSelectedItemOrFirst();
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.popoverController.animateClose();
|
|
171
|
+
this.listController.clearSearch();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
69
174
|
}
|
|
70
175
|
render() {
|
|
71
176
|
return html `${this.renderField()} ${this.renderMenu()}`;
|
|
@@ -96,50 +201,7 @@ export class Select extends Base {
|
|
|
96
201
|
`;
|
|
97
202
|
}
|
|
98
203
|
renderFieldContent() {
|
|
99
|
-
return html `<span part="value"
|
|
100
|
-
>${this.displayValue || this.placeholder}</span
|
|
101
|
-
>`;
|
|
102
|
-
}
|
|
103
|
-
connectedCallback() {
|
|
104
|
-
super.connectedCallback();
|
|
105
|
-
if (isServer)
|
|
106
|
-
return;
|
|
107
|
-
this.addEventListener('click', this.#handleOptionClick);
|
|
108
|
-
this.addEventListener('focusout', this.#handleFocusOut);
|
|
109
|
-
}
|
|
110
|
-
disconnectedCallback() {
|
|
111
|
-
super.disconnectedCallback();
|
|
112
|
-
this.removeEventListener('click', this.#handleOptionClick);
|
|
113
|
-
this.removeEventListener('focusout', this.#handleFocusOut);
|
|
114
|
-
}
|
|
115
|
-
updated(changed) {
|
|
116
|
-
super.updated(changed);
|
|
117
|
-
if (changed.has('value')) {
|
|
118
|
-
this.#updateDisplayValue();
|
|
119
|
-
this.#updateSelection();
|
|
120
|
-
}
|
|
121
|
-
if (changed.has('open')) {
|
|
122
|
-
if (this.open) {
|
|
123
|
-
this.popoverController.animateOpen();
|
|
124
|
-
// Focus current item when opening
|
|
125
|
-
const index = this.listController.items.findIndex((item) => (item.value || item.innerText) === this.value);
|
|
126
|
-
if (index >= 0) {
|
|
127
|
-
this.listController._focusItem(this.listController.items[index]);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
this.listController.focusFirstItem();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
this.popoverController.animateClose();
|
|
135
|
-
this.listController.clearSearch();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
toggle() {
|
|
140
|
-
if (this.disabled)
|
|
141
|
-
return;
|
|
142
|
-
this.open = !this.open;
|
|
204
|
+
return html `<span part="value">${this.displayText || html ` `}</span>`;
|
|
143
205
|
}
|
|
144
206
|
handleFieldKeydown(event) {
|
|
145
207
|
if (this.disabled)
|
|
@@ -159,11 +221,13 @@ export class Select extends Base {
|
|
|
159
221
|
case MenuActions.PageDown:
|
|
160
222
|
event.preventDefault();
|
|
161
223
|
const nextIndex = getUpdatedIndex(currentIndex, maxIndex, action);
|
|
162
|
-
this
|
|
224
|
+
this.listController._focusItem(items[nextIndex]);
|
|
163
225
|
return;
|
|
164
226
|
case MenuActions.CloseSelect:
|
|
165
227
|
event.preventDefault();
|
|
166
|
-
this
|
|
228
|
+
if (this.selectItem(items[currentIndex])) {
|
|
229
|
+
this.#dispatchChangeEvent();
|
|
230
|
+
}
|
|
167
231
|
// intentional fallthrough
|
|
168
232
|
case MenuActions.Close:
|
|
169
233
|
event.preventDefault();
|
|
@@ -179,99 +243,115 @@ export class Select extends Base {
|
|
|
179
243
|
return;
|
|
180
244
|
}
|
|
181
245
|
}
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
#selectOption(index) {
|
|
189
|
-
const items = this.listController.items;
|
|
190
|
-
if (index >= 0 && index < items.length) {
|
|
191
|
-
const item = items[index];
|
|
192
|
-
const newValue = item.value || item.innerText;
|
|
193
|
-
if (this.value !== newValue) {
|
|
194
|
-
this.value = newValue;
|
|
195
|
-
// According to https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event#event_type
|
|
196
|
-
// the change and input events are just Event and should not include detail.
|
|
197
|
-
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
198
|
-
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
246
|
+
selectItem(item) {
|
|
247
|
+
const selectedOptions = this.getSelectedOptions() ?? [];
|
|
248
|
+
selectedOptions.forEach(([option]) => {
|
|
249
|
+
if (item !== option) {
|
|
250
|
+
option.selected = false;
|
|
199
251
|
}
|
|
200
|
-
|
|
201
|
-
|
|
252
|
+
});
|
|
253
|
+
item.selected = true;
|
|
254
|
+
return this.updateValueAndDisplayText();
|
|
202
255
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (item && this.listController.items.includes(item)) {
|
|
207
|
-
const index = this.listController.items.indexOf(item);
|
|
208
|
-
this.#selectOption(index);
|
|
256
|
+
initUserSelection() {
|
|
257
|
+
if (this.lastUserSetValue && !this.lastSelectedOptionRecords.length) {
|
|
258
|
+
this.select(this.lastUserSetValue);
|
|
209
259
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
260
|
+
else if (this.lastUserSetSelectedIndex !== null &&
|
|
261
|
+
!this.lastSelectedOptionRecords.length) {
|
|
262
|
+
this.selectIndex(this.lastUserSetSelectedIndex);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
this.updateValueAndDisplayText();
|
|
215
266
|
}
|
|
216
267
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.displayValue = selectedItem.innerText;
|
|
268
|
+
updateValueAndDisplayText() {
|
|
269
|
+
const selectedOptions = this.getSelectedOptions() ?? [];
|
|
270
|
+
let changed = false;
|
|
271
|
+
if (selectedOptions.length) {
|
|
272
|
+
const [firstSelectedOption] = selectedOptions[0];
|
|
273
|
+
changed = this.lastSelectedOption !== firstSelectedOption;
|
|
274
|
+
this.lastSelectedOption = firstSelectedOption;
|
|
275
|
+
this[VALUE] = firstSelectedOption.value;
|
|
276
|
+
this.displayText = firstSelectedOption.innerText;
|
|
227
277
|
}
|
|
228
|
-
else
|
|
229
|
-
this.
|
|
278
|
+
else {
|
|
279
|
+
changed = this.lastSelectedOption !== null;
|
|
280
|
+
this.lastSelectedOption = null;
|
|
281
|
+
this[VALUE] = '';
|
|
282
|
+
this.displayText = '';
|
|
230
283
|
}
|
|
284
|
+
return changed;
|
|
231
285
|
}
|
|
232
|
-
|
|
233
|
-
#updateSelection() {
|
|
286
|
+
getSelectedOptions() {
|
|
234
287
|
const items = this.listController.items;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
item.selected
|
|
288
|
+
const records = [];
|
|
289
|
+
items.forEach((item, index) => {
|
|
290
|
+
if (item.selected) {
|
|
291
|
+
records.push([item, index]);
|
|
292
|
+
}
|
|
238
293
|
});
|
|
294
|
+
this.lastSelectedOptionRecords = records;
|
|
295
|
+
return records.length ? records : null;
|
|
296
|
+
}
|
|
297
|
+
#dispatchChangeEvent;
|
|
298
|
+
#handleOptionClick;
|
|
299
|
+
#handleFocusOut;
|
|
300
|
+
#focusSelectedItemOrFirst() {
|
|
301
|
+
const selectedOptions = this.getSelectedOptions();
|
|
302
|
+
if (selectedOptions && selectedOptions.length > 0) {
|
|
303
|
+
const [item] = selectedOptions[0];
|
|
304
|
+
this.listController._focusItem(item);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
this.listController.focusFirstItem();
|
|
308
|
+
}
|
|
239
309
|
}
|
|
240
|
-
// TODO: Handle multiple selected items
|
|
241
310
|
handleSlotChange() {
|
|
242
|
-
|
|
243
|
-
if (!this.value
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
311
|
+
// When slots change, check for initially selected items if value is not set
|
|
312
|
+
if (!this.value) {
|
|
313
|
+
this.updateValueAndDisplayText();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
formResetCallback() {
|
|
317
|
+
this.reset();
|
|
318
|
+
}
|
|
319
|
+
formStateRestoreCallback(state) {
|
|
320
|
+
this.value = state;
|
|
321
|
+
}
|
|
322
|
+
select(value) {
|
|
323
|
+
const item = this.options.find((option) => option.value === value);
|
|
324
|
+
if (item) {
|
|
325
|
+
this.selectItem(item);
|
|
252
326
|
}
|
|
253
|
-
|
|
254
|
-
|
|
327
|
+
}
|
|
328
|
+
selectIndex(index) {
|
|
329
|
+
const item = this.options[index];
|
|
330
|
+
if (item) {
|
|
331
|
+
this.selectItem(item);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
reset() {
|
|
335
|
+
for (const option of this.options) {
|
|
336
|
+
option.selected = option.hasAttribute('selected');
|
|
337
|
+
}
|
|
338
|
+
this.updateValueAndDisplayText();
|
|
339
|
+
}
|
|
340
|
+
toggle() {
|
|
341
|
+
if (this.disabled)
|
|
342
|
+
return;
|
|
343
|
+
this.open = !this.open;
|
|
255
344
|
}
|
|
256
345
|
}
|
|
257
346
|
__decorate([
|
|
258
|
-
property({
|
|
259
|
-
], Select.prototype, "
|
|
260
|
-
__decorate([
|
|
261
|
-
state()
|
|
262
|
-
], Select.prototype, "displayValue", void 0);
|
|
263
|
-
__decorate([
|
|
264
|
-
property({ type: String })
|
|
265
|
-
], Select.prototype, "placeholder", void 0);
|
|
266
|
-
__decorate([
|
|
267
|
-
property({ type: Boolean, reflect: true })
|
|
268
|
-
], Select.prototype, "open", void 0);
|
|
347
|
+
property({ type: Boolean })
|
|
348
|
+
], Select.prototype, "quick", void 0);
|
|
269
349
|
__decorate([
|
|
270
350
|
property({ type: Boolean, reflect: true })
|
|
271
351
|
], Select.prototype, "required", void 0);
|
|
272
352
|
__decorate([
|
|
273
353
|
property({ type: Boolean, reflect: true })
|
|
274
|
-
], Select.prototype, "
|
|
354
|
+
], Select.prototype, "error", void 0);
|
|
275
355
|
__decorate([
|
|
276
356
|
property({ reflect: true })
|
|
277
357
|
], Select.prototype, "align", void 0);
|
|
@@ -281,6 +361,18 @@ __decorate([
|
|
|
281
361
|
__decorate([
|
|
282
362
|
property({ type: Number, reflect: true })
|
|
283
363
|
], Select.prototype, "offset", void 0);
|
|
364
|
+
__decorate([
|
|
365
|
+
property({ attribute: 'display-text' })
|
|
366
|
+
], Select.prototype, "displayText", void 0);
|
|
367
|
+
__decorate([
|
|
368
|
+
property()
|
|
369
|
+
], Select.prototype, "value", null);
|
|
370
|
+
__decorate([
|
|
371
|
+
property({ type: Number, attribute: 'selected-index' })
|
|
372
|
+
], Select.prototype, "selectedIndex", null);
|
|
373
|
+
__decorate([
|
|
374
|
+
property({ type: Boolean, reflect: true })
|
|
375
|
+
], Select.prototype, "open", void 0);
|
|
284
376
|
__decorate([
|
|
285
377
|
query('[part="field"]')
|
|
286
378
|
], Select.prototype, "$field", void 0);
|
package/src/base/tooltip.js
CHANGED
|
@@ -7,6 +7,9 @@ import { InternalsAttached, internals } from './mixins/internals-attached.js';
|
|
|
7
7
|
import { PopoverController } from './controllers/popover-controller.js';
|
|
8
8
|
let lastHidingTime = 0;
|
|
9
9
|
const Base = Attachable(InternalsAttached(LitElement));
|
|
10
|
+
/**
|
|
11
|
+
* TODO: Check if $control controls a menu/popover and keep hidden when it is open.
|
|
12
|
+
*/
|
|
10
13
|
export class Tooltip extends Base {
|
|
11
14
|
// Different from those in the popoverController, these timers are used to
|
|
12
15
|
// manage the delay before showing/hiding the tooltip.
|
|
@@ -23,6 +26,7 @@ export class Tooltip extends Base {
|
|
|
23
26
|
this._durations = { show: 100, hide: 100 };
|
|
24
27
|
this.align = 'top';
|
|
25
28
|
this.offset = 4;
|
|
29
|
+
this.forceInvisible = false;
|
|
26
30
|
// Different from those in the popoverController, these timers are used to
|
|
27
31
|
// manage the delay before showing/hiding the tooltip.
|
|
28
32
|
this.#openTimer = null;
|
|
@@ -134,6 +138,9 @@ __decorate([
|
|
|
134
138
|
__decorate([
|
|
135
139
|
property({ type: Number, reflect: true })
|
|
136
140
|
], Tooltip.prototype, "offset", void 0);
|
|
141
|
+
__decorate([
|
|
142
|
+
property({ type: Boolean, reflect: true })
|
|
143
|
+
], Tooltip.prototype, "forceInvisible", void 0);
|
|
137
144
|
__decorate([
|
|
138
145
|
query('slot')
|
|
139
146
|
], Tooltip.prototype, "$slot", void 0);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const itemStyles = css `:host{border-radius:inherit;box-sizing:border-box;font:var(--md-sys-typography-body-large);text-overflow:ellipsis;-webkit-user-select:none;user-select:none;flex:1;align-items:center;gap:16px;min-height:48px;padding:12px;display:flex;position:relative
|
|
2
|
+
export const itemStyles = css `:host{border-radius:inherit;box-sizing:border-box;font:var(--md-sys-typography-body-large);text-overflow:ellipsis;-webkit-user-select:none;user-select:none;flex:1;align-items:center;gap:16px;min-height:48px;padding:12px;display:flex;position:relative}:host([multiline]){min-height:72px}[name=container]{border-radius:inherit}[name=container]::slotted(*){position:absolute;inset:0}.default-slot{display:inline}.default-slot,.text ::slotted(*){text-overflow:ellipsis;overflow:hidden}.text{flex-direction:column;flex:1;display:flex;overflow:hidden}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const menuPartStyles = css `[part=menu]{background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-shadow-2);box-sizing:border-box;color:var(--md-sys-color-on-surface);height:inherit;max-height:inherit;max-width:inherit;min-width:inherit;opacity:0;-webkit-user-select:none;user-select:none;z-index:1000;border-radius:16px;padding:4px;inset:auto;overflow-y:auto;transform:scaleY(.4)}:host(:state(closed)) [part=menu]{display:none}:host(:state(opening)) [part=menu]{opacity:1;transition:opacity 67ms,transform var(--md-sys-motion-exp-effects-slow-duration)var(--md-sys-motion-exp-effects-slow);display:block;transform:scaleY(1)}:host(:state(opened)) [part=menu]{opacity:1;display:block;transform:scaleY(1)}:host(:state(closing)) [part=menu]{opacity:0;transition:opacity var(--md-sys-motion-exp-effects-default-duration),transform var(--md-sys-motion-exp-effects-default-duration)var(--md-sys-motion-exp-effects-default);transform:scaleY(.4)}[part=items]{opacity:0;flex-direction:column;gap:2px;display:flex}:host(:state(opening)) [part=items]{opacity:1;transition:opacity 67ms linear 67ms}:host(:state(opened)) [part=items]{opacity:1}:host(:state(closing)) [part=items]{opacity:0;transition:opacity 67ms}`;
|
|
2
|
+
export const menuPartStyles = css `[part=menu]{background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-shadow-2);box-sizing:border-box;color:var(--md-sys-color-on-surface);height:inherit;max-height:inherit;max-width:inherit;min-width:inherit;opacity:0;-webkit-user-select:none;user-select:none;z-index:1000;border-radius:16px;outline:0;padding:4px;inset:auto;overflow-y:auto;transform:scaleY(.4)}:host(:state(closed)) [part=menu]{display:none}:host(:state(opening)) [part=menu]{opacity:1;transition:opacity 67ms,transform var(--md-sys-motion-exp-effects-slow-duration)var(--md-sys-motion-exp-effects-slow);display:block;transform:scaleY(1)}:host(:state(opened)) [part=menu]{opacity:1;display:block;transform:scaleY(1)}:host(:state(closing)) [part=menu]{opacity:0;transition:opacity var(--md-sys-motion-exp-effects-default-duration),transform var(--md-sys-motion-exp-effects-default-duration)var(--md-sys-motion-exp-effects-default);transform:scaleY(.4)}[part=items]{opacity:0;flex-direction:column;gap:2px;display:flex}:host(:state(opening)) [part=items]{opacity:1;transition:opacity 67ms linear 67ms}:host(:state(opened)) [part=items]{opacity:1}:host(:state(closing)) [part=items]{opacity:0;transition:opacity 67ms}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const menuStyles = css `:host{
|
|
2
|
+
export const menuStyles = css `:host{min-width:112px;display:contents}:host([alignstrategy=fixed]){position:fixed}`;
|
package/src/m3/select/select.js
CHANGED
|
@@ -13,7 +13,6 @@ export class M3Select extends Select {
|
|
|
13
13
|
this._scrollPadding = 4;
|
|
14
14
|
this.label = '';
|
|
15
15
|
this.supportingText = '';
|
|
16
|
-
this.error = false;
|
|
17
16
|
this.fieldFocused = false;
|
|
18
17
|
}
|
|
19
18
|
}
|
|
@@ -23,9 +22,6 @@ __decorate([
|
|
|
23
22
|
__decorate([
|
|
24
23
|
property({ type: String })
|
|
25
24
|
], M3Select.prototype, "supportingText", void 0);
|
|
26
|
-
__decorate([
|
|
27
|
-
property({ type: Boolean, reflect: true })
|
|
28
|
-
], M3Select.prototype, "error", void 0);
|
|
29
25
|
__decorate([
|
|
30
26
|
state()
|
|
31
27
|
], M3Select.prototype, "fieldFocused", void 0);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const tooltipStyles = css `:host{background-color:var(--md-sys-color-inverse-surface);box-sizing:border-box;color:#0000;font:var(--md-sys-typography-body-small);max-width:var(--_max-width,300px);opacity:0;pointer-events:none;z-index:
|
|
2
|
+
export const tooltipStyles = css `:host{background-color:var(--md-sys-color-inverse-surface);box-sizing:border-box;color:#0000;font:var(--md-sys-typography-body-small);max-width:var(--_max-width,300px);opacity:0;pointer-events:none;z-index:800;border-radius:4px;align-items:center;width:max-content;min-height:24px;padding:4px 8px;display:flex;position:absolute;top:0;left:0;transform:scaleY(.4)}:host(:state(closed)){display:none}:host(:state(opening):not([forceinvisible])){color:var(--md-sys-color-inverse-on-surface);opacity:1;pointer-events:auto;transition:color linear 67ms 67ms,opacity var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast),transform var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast);transform:scaleY(1)}:host(:state(opened):not([forceinvisible])){color:var(--md-sys-color-inverse-on-surface);opacity:1;pointer-events:auto;transform:scaleY(1)}:host(:state(closing):not([forceinvisible])){color:#0000;opacity:0;transition:color linear 67ms,opacity var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast),transform var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast);transform:scaleY(.4)}`;
|