@vollowx/seele 0.12.8 → 0.12.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +3 -3
- package/src/base/list-item.js +1 -1
- package/src/base/list.js +6 -6
- package/src/base/select.js +54 -54
- package/src/base/tab-panel.js +4 -4
- package/src/base/tab.js +4 -4
- package/src/base/tabs.js +67 -67
- package/src/base/toggle-button.js +3 -3
- package/src/base/tooltip.js +3 -3
- package/src/m3/field/field.js +6 -6
- package/src/m3/focus-ring/focus-ring.js +16 -19
- package/src/m3/list/list-item.js +17 -17
- package/src/m3/list/list.js +3 -3
- package/src/m3/menu/menu.js +3 -3
- package/src/m3/select/filled-select.js +1 -1
- package/src/m3/select/outlined-select.js +1 -1
- package/src/m3/select/select.js +3 -3
- package/src/m3/slider/slider.js +6 -6
- package/src/m3/toolbar/toolbar.js +10 -10
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ It also provides styled components in the following design guideline(s):
|
|
|
12
12
|
|
|
13
13
|
- [Material You Expressive](https://m3.material.io/)
|
|
14
14
|
|
|
15
|
-
Documentations and demos are at [seele
|
|
15
|
+
Documentations and demos are at [tideover.cc/seele/](https://tideover.cc/seele/).
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vollowx/seele",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.9",
|
|
4
4
|
"description": "A extensible Web Components library, with Material Design 3 components pre-provided.",
|
|
5
5
|
"author": "vollowx",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@custom-elements-manifest/analyzer": "^0.11.0",
|
|
49
|
-
"@swc/core": "^1.15.
|
|
49
|
+
"@swc/core": "^1.15.43",
|
|
50
50
|
"@types/bun": "^1.3.14",
|
|
51
51
|
"@web/dev-server": "^0.4.6",
|
|
52
52
|
"@web/dev-server-esbuild": "^1.0.5",
|
|
53
53
|
"chokidar": "^5.0.0",
|
|
54
54
|
"lightningcss": "^1.32.0",
|
|
55
|
-
"prettier": "^3.
|
|
55
|
+
"prettier": "^3.9.1"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@floating-ui/dom": "^1.7.6",
|
package/src/base/list-item.js
CHANGED
|
@@ -41,7 +41,7 @@ export class ListItem extends FormAssociated(InternalsAttached(LitElement)) {
|
|
|
41
41
|
this.focused = false;
|
|
42
42
|
}
|
|
43
43
|
constructor(...args){
|
|
44
|
-
super(...args), this.
|
|
44
|
+
super(...args), this._role = 'option', this.selected = false, this.focused = false;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
_ts_decorate([
|
package/src/base/list.js
CHANGED
|
@@ -16,6 +16,12 @@ const Base = InternalsAttached(LitElement);
|
|
|
16
16
|
get $items() {
|
|
17
17
|
return this.listController.items || [];
|
|
18
18
|
}
|
|
19
|
+
render() {
|
|
20
|
+
return html` ${this.renderItemSlot()} `;
|
|
21
|
+
}
|
|
22
|
+
renderItemSlot() {
|
|
23
|
+
return html`<slot part="items"></slot>`;
|
|
24
|
+
}
|
|
19
25
|
constructor(){
|
|
20
26
|
super(), this._scrollPadding = 0, this.noFocusControl = false, this.listController = new ListController(this, {
|
|
21
27
|
isItem: (item)=>item.getAttribute('seele-base') === 'option' && !item.hasAttribute('disabled') && !item.hidden,
|
|
@@ -52,12 +58,6 @@ const Base = InternalsAttached(LitElement);
|
|
|
52
58
|
this.addEventListener('mouseover', (e)=>this.#handleMouseOver(e));
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
|
-
render() {
|
|
56
|
-
return html` ${this.renderItemSlot()} `;
|
|
57
|
-
}
|
|
58
|
-
renderItemSlot() {
|
|
59
|
-
return html`<slot part="items"></slot>`;
|
|
60
|
-
}
|
|
61
61
|
updated(changed) {
|
|
62
62
|
// TODO: Find somewhere to put this
|
|
63
63
|
// this.listController.clearSearch();
|
package/src/base/select.js
CHANGED
|
@@ -42,55 +42,6 @@ const Base = FormAssociated(FocusDelegated(InternalsAttached(LitElement)));
|
|
|
42
42
|
get selectedOptions() {
|
|
43
43
|
return (this.getSelectedOptions() ?? []).map(([option])=>option);
|
|
44
44
|
}
|
|
45
|
-
constructor(){
|
|
46
|
-
super(), // Form-related
|
|
47
|
-
this.required = false, // Passed to field
|
|
48
|
-
this.error = false, // Passed to menu
|
|
49
|
-
this.quick = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.open = false, /**
|
|
50
|
-
* Text to display in the field. Only set for SSR.
|
|
51
|
-
*/ this.displayText = '', this[VALUE] = '', this.lastUserSetValue = null, this.lastUserSetSelectedIndex = null, this.lastSelectedOption = null, this.lastSelectedOptionRecords = [], this.#dispatchChangeEvent = ()=>{
|
|
52
|
-
this.dispatchEvent(new Event('input', {
|
|
53
|
-
bubbles: true,
|
|
54
|
-
composed: true
|
|
55
|
-
}));
|
|
56
|
-
this.dispatchEvent(new Event('change', {
|
|
57
|
-
bubbles: true
|
|
58
|
-
}));
|
|
59
|
-
};
|
|
60
|
-
if (!isServer) {
|
|
61
|
-
this.addEventListener('focusout', this.handleFocusOut);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
async firstUpdated(changed) {
|
|
65
|
-
// If this has been handled on update already due to SSR, try again.
|
|
66
|
-
if (!this.lastSelectedOptionRecords.length) {
|
|
67
|
-
this.initUserSelection();
|
|
68
|
-
}
|
|
69
|
-
// Case for when the DOM is streaming, there are no children, and a child
|
|
70
|
-
// has [selected] set on it, we need to wait for DOM to render something.
|
|
71
|
-
if (!this.lastSelectedOptionRecords.length && !isServer && !this.$options.length) {
|
|
72
|
-
setTimeout(()=>{
|
|
73
|
-
this.updateValueAndDisplayText();
|
|
74
|
-
}, 0);
|
|
75
|
-
}
|
|
76
|
-
super.firstUpdated(changed);
|
|
77
|
-
}
|
|
78
|
-
update(changed) {
|
|
79
|
-
if (!this.hasUpdated) {
|
|
80
|
-
this.initUserSelection();
|
|
81
|
-
}
|
|
82
|
-
super.update(changed);
|
|
83
|
-
}
|
|
84
|
-
updated(changed) {
|
|
85
|
-
super.updated(changed);
|
|
86
|
-
if (changed.has('open')) {
|
|
87
|
-
if (this.open) {
|
|
88
|
-
this.#focusSelectedItemOrFirst();
|
|
89
|
-
} else {
|
|
90
|
-
this.$field.setAttribute('aria-activedescendant', '');
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
45
|
render() {
|
|
95
46
|
return html`${this.renderField()}${this.renderMenu()}`;
|
|
96
47
|
}
|
|
@@ -145,31 +96,80 @@ const Base = FormAssociated(FocusDelegated(InternalsAttached(LitElement)));
|
|
|
145
96
|
renderFieldContent() {
|
|
146
97
|
return html`<span part="value">${this.displayText || html` `}</span>`;
|
|
147
98
|
}
|
|
99
|
+
constructor(){
|
|
100
|
+
super(), // Form-related
|
|
101
|
+
this.required = false, // Passed to field
|
|
102
|
+
this.error = false, // Passed to menu
|
|
103
|
+
this.quick = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.open = false, /**
|
|
104
|
+
* Text to display in the field. Only set for SSR.
|
|
105
|
+
*/ this.displayText = '', this[VALUE] = '', this.lastUserSetValue = null, this.lastUserSetSelectedIndex = null, this.lastSelectedOption = null, this.lastSelectedOptionRecords = [], this.#dispatchChangeEvent = ()=>{
|
|
106
|
+
this.dispatchEvent(new Event('input', {
|
|
107
|
+
bubbles: true,
|
|
108
|
+
composed: true
|
|
109
|
+
}));
|
|
110
|
+
this.dispatchEvent(new Event('change', {
|
|
111
|
+
bubbles: true
|
|
112
|
+
}));
|
|
113
|
+
};
|
|
114
|
+
if (!isServer) {
|
|
115
|
+
this.addEventListener('focusout', this._handleFocusOut);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async firstUpdated(changed) {
|
|
119
|
+
// If this has been handled on update already due to SSR, try again.
|
|
120
|
+
if (!this.lastSelectedOptionRecords.length) {
|
|
121
|
+
this.initUserSelection();
|
|
122
|
+
}
|
|
123
|
+
// Case for when the DOM is streaming, there are no children, and a child
|
|
124
|
+
// has [selected] set on it, we need to wait for DOM to render something.
|
|
125
|
+
if (!this.lastSelectedOptionRecords.length && !isServer && !this.$options.length) {
|
|
126
|
+
setTimeout(()=>{
|
|
127
|
+
this.updateValueAndDisplayText();
|
|
128
|
+
}, 0);
|
|
129
|
+
}
|
|
130
|
+
super.firstUpdated(changed);
|
|
131
|
+
}
|
|
132
|
+
update(changed) {
|
|
133
|
+
if (!this.hasUpdated) {
|
|
134
|
+
this.initUserSelection();
|
|
135
|
+
}
|
|
136
|
+
super.update(changed);
|
|
137
|
+
}
|
|
138
|
+
updated(changed) {
|
|
139
|
+
super.updated(changed);
|
|
140
|
+
if (changed.has('open')) {
|
|
141
|
+
if (this.open) {
|
|
142
|
+
this.#focusSelectedItemOrFirst();
|
|
143
|
+
} else {
|
|
144
|
+
this.$field.setAttribute('aria-activedescendant', '');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
148
|
/**
|
|
149
149
|
* TODO: Handle clear action
|
|
150
|
-
*/
|
|
150
|
+
*/ _handleFieldKeydown(event) {
|
|
151
151
|
if (this.disabled) return;
|
|
152
152
|
const eventClone = new KeyboardEvent(event.type, event);
|
|
153
153
|
eventClone.preventDefault = ()=>event.preventDefault();
|
|
154
154
|
eventClone.stopPropagation = ()=>event.stopPropagation();
|
|
155
155
|
this.$menu.$menu.dispatchEvent(eventClone);
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
_handleMenuSelect(event) {
|
|
158
158
|
if (this.selectItem(event.detail.item)) {
|
|
159
159
|
this.#dispatchChangeEvent();
|
|
160
160
|
}
|
|
161
161
|
this.open = false;
|
|
162
162
|
}
|
|
163
|
-
|
|
163
|
+
_handleMenuItemFocus(event) {
|
|
164
164
|
this.$field.setAttribute('aria-activedescendant', event.detail.item.id);
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
_handleFocusOut(event) {
|
|
167
167
|
const relatedTarget = event.relatedTarget;
|
|
168
168
|
if (!this.contains(relatedTarget) && !this.$menu.contains(relatedTarget)) {
|
|
169
169
|
this.open = false;
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
|
|
172
|
+
_handleSlotChange() {
|
|
173
173
|
// When slots change, check for initially selected items if value is not set
|
|
174
174
|
if (!this.value) {
|
|
175
175
|
this.updateValueAndDisplayText();
|
package/src/base/tab-panel.js
CHANGED
|
@@ -4,17 +4,17 @@ import { property } from 'lit/decorators.js';
|
|
|
4
4
|
import { InternalsAttached, internals } from './mixins/internals-attached.js';
|
|
5
5
|
import { genUniqueId } from '../core/unique-id.js';
|
|
6
6
|
export class TabPanel extends InternalsAttached(LitElement) {
|
|
7
|
+
render() {
|
|
8
|
+
return html`<slot></slot>`;
|
|
9
|
+
}
|
|
7
10
|
connectedCallback() {
|
|
8
11
|
super.connectedCallback();
|
|
9
12
|
this.setAttribute('seele-base', 'tabpanel');
|
|
10
13
|
this[internals].role = this._role;
|
|
11
14
|
if (!this.id) this.id = genUniqueId('tabpanel');
|
|
12
15
|
}
|
|
13
|
-
render() {
|
|
14
|
-
return html`<slot></slot>`;
|
|
15
|
-
}
|
|
16
16
|
constructor(...args){
|
|
17
|
-
super(...args), this.
|
|
17
|
+
super(...args), this._role = 'tabpanel', this.value = '';
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
_ts_decorate([
|
package/src/base/tab.js
CHANGED
|
@@ -6,6 +6,9 @@ import { genUniqueId } from '../core/unique-id.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* TODO: disabled
|
|
8
8
|
*/ export class Tab extends InternalsAttached(LitElement) {
|
|
9
|
+
render() {
|
|
10
|
+
return html`<slot></slot>`;
|
|
11
|
+
}
|
|
9
12
|
connectedCallback() {
|
|
10
13
|
super.connectedCallback();
|
|
11
14
|
this.setAttribute('seele-base', 'tab');
|
|
@@ -32,11 +35,8 @@ import { genUniqueId } from '../core/unique-id.js';
|
|
|
32
35
|
this.focused = false;
|
|
33
36
|
super.blur();
|
|
34
37
|
}
|
|
35
|
-
render() {
|
|
36
|
-
return html`<slot></slot>`;
|
|
37
|
-
}
|
|
38
38
|
constructor(...args){
|
|
39
|
-
super(...args), this.
|
|
39
|
+
super(...args), this._role = 'tab', this.selected = false, this.focused = false, this.value = '';
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
_ts_decorate([
|
package/src/base/tabs.js
CHANGED
|
@@ -11,6 +11,13 @@ import { internals } from './mixins/internals-attached.js';
|
|
|
11
11
|
get $parent() {
|
|
12
12
|
return this.parentNode instanceof ShadowRoot ? this.parentNode.host : this.parentElement;
|
|
13
13
|
}
|
|
14
|
+
render() {
|
|
15
|
+
return html`
|
|
16
|
+
<div part="tablist" role="tablist">
|
|
17
|
+
<slot @slotchange=${this.#handleSlotChange}></slot>
|
|
18
|
+
</div>
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
14
21
|
connectedCallback() {
|
|
15
22
|
super.connectedCallback();
|
|
16
23
|
if (!isServer) {
|
|
@@ -26,65 +33,9 @@ import { internals } from './mixins/internals-attached.js';
|
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
|
-
#handleSlotChange
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const panel = parent.querySelector(`[seele-base="tab"][value="${tab.value}"]`);
|
|
33
|
-
if (!panel) console.error('[seele] cannot find a matching panel for tab ', tab);
|
|
34
|
-
// TODO: ariaLabelledByElements
|
|
35
|
-
tab.setAttribute('aria-controls', panel.id);
|
|
36
|
-
panel.setAttribute('aria-labelledby', tab.id);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
#handleKeyDown(event) {
|
|
40
|
-
const tabs = this.$tabs;
|
|
41
|
-
if (!tabs.length) return;
|
|
42
|
-
const activeElement = this.getRootNode().activeElement;
|
|
43
|
-
const currentIndex = tabs.findIndex((t)=>t === activeElement || t.focused);
|
|
44
|
-
let nextIndex = currentIndex !== -1 ? currentIndex : 0;
|
|
45
|
-
let handled = false;
|
|
46
|
-
switch(event.key){
|
|
47
|
-
case 'ArrowLeft':
|
|
48
|
-
nextIndex = currentIndex <= 0 ? tabs.length - 1 : currentIndex - 1;
|
|
49
|
-
handled = true;
|
|
50
|
-
break;
|
|
51
|
-
case 'ArrowRight':
|
|
52
|
-
nextIndex = currentIndex >= tabs.length - 1 ? 0 : currentIndex + 1;
|
|
53
|
-
handled = true;
|
|
54
|
-
break;
|
|
55
|
-
case 'Home':
|
|
56
|
-
nextIndex = 0;
|
|
57
|
-
handled = true;
|
|
58
|
-
break;
|
|
59
|
-
case 'End':
|
|
60
|
-
nextIndex = tabs.length - 1;
|
|
61
|
-
handled = true;
|
|
62
|
-
break;
|
|
63
|
-
case 'Enter':
|
|
64
|
-
case ' ':
|
|
65
|
-
if (currentIndex !== -1) {
|
|
66
|
-
this.selectTab(tabs[currentIndex]);
|
|
67
|
-
}
|
|
68
|
-
handled = true;
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
if (handled) {
|
|
72
|
-
event.preventDefault();
|
|
73
|
-
event.stopPropagation();
|
|
74
|
-
if (event.key !== 'Enter' && event.key !== ' ') {
|
|
75
|
-
this.focusTab(tabs[nextIndex]);
|
|
76
|
-
if (this.switch === 'auto') this.selectTab(tabs[nextIndex]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
#handleClick(event) {
|
|
81
|
-
const target = event.target;
|
|
82
|
-
const tab = target.closest('md-tab');
|
|
83
|
-
if (tab && this.$tabs.includes(tab)) {
|
|
84
|
-
this.focusTab(tab);
|
|
85
|
-
this.selectTab(tab);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
36
|
+
#handleSlotChange;
|
|
37
|
+
#handleKeyDown;
|
|
38
|
+
#handleClick;
|
|
88
39
|
focusTab(tab) {
|
|
89
40
|
this.$tabs.forEach((t)=>{
|
|
90
41
|
t.blur();
|
|
@@ -115,15 +66,64 @@ import { internals } from './mixins/internals-attached.js';
|
|
|
115
66
|
composed: true
|
|
116
67
|
}));
|
|
117
68
|
}
|
|
118
|
-
render() {
|
|
119
|
-
return html`
|
|
120
|
-
<div part="tablist" role="tablist">
|
|
121
|
-
<slot @slotchange=${this.#handleSlotChange}></slot>
|
|
122
|
-
</div>
|
|
123
|
-
`;
|
|
124
|
-
}
|
|
125
69
|
constructor(...args){
|
|
126
|
-
super(...args), this.switch = 'manual', this.selected = '', this
|
|
70
|
+
super(...args), this._role = 'tablist', this.switch = 'manual', this.selected = '', this.#handleSlotChange = (_)=>{
|
|
71
|
+
const parent = this.$parent;
|
|
72
|
+
this.$tabs.forEach((tab)=>{
|
|
73
|
+
const panel = parent.querySelector(`[seele-base="tab"][value="${tab.value}"]`);
|
|
74
|
+
if (!panel) console.error('[seele] cannot find a matching panel for tab ', tab);
|
|
75
|
+
// TODO: ariaLabelledByElements
|
|
76
|
+
tab.setAttribute('aria-controls', panel.id);
|
|
77
|
+
panel.setAttribute('aria-labelledby', tab.id);
|
|
78
|
+
});
|
|
79
|
+
}, this.#handleKeyDown = (event)=>{
|
|
80
|
+
const tabs = this.$tabs;
|
|
81
|
+
if (!tabs.length) return;
|
|
82
|
+
const activeElement = this.getRootNode().activeElement;
|
|
83
|
+
const currentIndex = tabs.findIndex((t)=>t === activeElement || t.focused);
|
|
84
|
+
let nextIndex = currentIndex !== -1 ? currentIndex : 0;
|
|
85
|
+
let handled = false;
|
|
86
|
+
switch(event.key){
|
|
87
|
+
case 'ArrowLeft':
|
|
88
|
+
nextIndex = currentIndex <= 0 ? tabs.length - 1 : currentIndex - 1;
|
|
89
|
+
handled = true;
|
|
90
|
+
break;
|
|
91
|
+
case 'ArrowRight':
|
|
92
|
+
nextIndex = currentIndex >= tabs.length - 1 ? 0 : currentIndex + 1;
|
|
93
|
+
handled = true;
|
|
94
|
+
break;
|
|
95
|
+
case 'Home':
|
|
96
|
+
nextIndex = 0;
|
|
97
|
+
handled = true;
|
|
98
|
+
break;
|
|
99
|
+
case 'End':
|
|
100
|
+
nextIndex = tabs.length - 1;
|
|
101
|
+
handled = true;
|
|
102
|
+
break;
|
|
103
|
+
case 'Enter':
|
|
104
|
+
case ' ':
|
|
105
|
+
if (currentIndex !== -1) {
|
|
106
|
+
this.selectTab(tabs[currentIndex]);
|
|
107
|
+
}
|
|
108
|
+
handled = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
if (handled) {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
event.stopPropagation();
|
|
114
|
+
if (event.key !== 'Enter' && event.key !== ' ') {
|
|
115
|
+
this.focusTab(tabs[nextIndex]);
|
|
116
|
+
if (this.switch === 'auto') this.selectTab(tabs[nextIndex]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}, this.#handleClick = (event)=>{
|
|
120
|
+
const target = event.target;
|
|
121
|
+
const tab = target.closest('md-tab');
|
|
122
|
+
if (tab && this.$tabs.includes(tab)) {
|
|
123
|
+
this.focusTab(tab);
|
|
124
|
+
this.selectTab(tab);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
_ts_decorate([
|
|
@@ -69,7 +69,7 @@ export class ToggleButton extends Base {
|
|
|
69
69
|
};
|
|
70
70
|
this[internals].role = 'button';
|
|
71
71
|
this.checked = this.hasAttribute('checked');
|
|
72
|
-
this.
|
|
72
|
+
this._updateInternals();
|
|
73
73
|
}
|
|
74
74
|
connectedCallback() {
|
|
75
75
|
super.connectedCallback();
|
|
@@ -91,10 +91,10 @@ export class ToggleButton extends Base {
|
|
|
91
91
|
}
|
|
92
92
|
updated(changed) {
|
|
93
93
|
if (changed.has('checked') || changed.has('disabled')) {
|
|
94
|
-
this.
|
|
94
|
+
this._updateInternals();
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
_updateInternals() {
|
|
98
98
|
this[internals].states.delete('unchecked');
|
|
99
99
|
this[internals].states.delete('checked');
|
|
100
100
|
this[internals].ariaPressed = this.checked ? 'true' : 'false';
|
package/src/base/tooltip.js
CHANGED
|
@@ -10,6 +10,9 @@ const Base = Attachable(InternalsAttached(LitElement));
|
|
|
10
10
|
/**
|
|
11
11
|
* TODO: Check if $control controls a menu/popover and keep hidden when it is open.
|
|
12
12
|
*/ export class Tooltip extends Base {
|
|
13
|
+
render() {
|
|
14
|
+
return html`<slot @slotchange="${this.#handleSlotChange}"></slot>`;
|
|
15
|
+
}
|
|
13
16
|
// Different from those in the popoverController, these timers are used to
|
|
14
17
|
// manage the delay before showing/hiding the tooltip.
|
|
15
18
|
#openTimer;
|
|
@@ -70,9 +73,6 @@ const Base = Attachable(InternalsAttached(LitElement));
|
|
|
70
73
|
};
|
|
71
74
|
this[internals].role = 'tooltip';
|
|
72
75
|
}
|
|
73
|
-
render() {
|
|
74
|
-
return html`<slot @slotchange="${this.#handleSlotChange}"></slot>`;
|
|
75
|
-
}
|
|
76
76
|
handleControlChange(prev = null, next = null) {
|
|
77
77
|
const eventHandlers = {
|
|
78
78
|
focusin: this.#handleFocusIn,
|
package/src/m3/field/field.js
CHANGED
|
@@ -12,12 +12,6 @@ import { fieldStyles } from './field-styles.css.js';
|
|
|
12
12
|
fieldStyles
|
|
13
13
|
];
|
|
14
14
|
}
|
|
15
|
-
update(changedProperties) {
|
|
16
|
-
if (changedProperties.has('label')) {
|
|
17
|
-
this.hasLabel = !!this.label;
|
|
18
|
-
}
|
|
19
|
-
super.update(changedProperties);
|
|
20
|
-
}
|
|
21
15
|
render() {
|
|
22
16
|
return html`
|
|
23
17
|
<div class="container">${this.renderContainerContent()}</div>
|
|
@@ -46,6 +40,12 @@ import { fieldStyles } from './field-styles.css.js';
|
|
|
46
40
|
@slotchange=${this.handleSlotChange}
|
|
47
41
|
></slot>`;
|
|
48
42
|
}
|
|
43
|
+
update(changedProperties) {
|
|
44
|
+
if (changedProperties.has('label')) {
|
|
45
|
+
this.hasLabel = !!this.label;
|
|
46
|
+
}
|
|
47
|
+
super.update(changedProperties);
|
|
48
|
+
}
|
|
49
49
|
handleSlotChange(e) {
|
|
50
50
|
const slot = e.target;
|
|
51
51
|
const hasContent = slot.assignedNodes({
|
|
@@ -7,28 +7,25 @@ import { Attachable } from '../../base/mixins/attachable.js';
|
|
|
7
7
|
import { InternalsAttached, internals } from '../../base/mixins/internals-attached.js';
|
|
8
8
|
import { focusRingStyles } from './focus-ring-styles.css.js';
|
|
9
9
|
export class M3FocusRing extends Attachable(InternalsAttached(LitElement)) {
|
|
10
|
-
constructor(){
|
|
11
|
-
super(), this.inward = false, this.#boundFocusIn = this.#handleFocusIn.bind(this), this.#boundFocusOut = this.#handleFocusOut.bind(this), this.#boundPointerDown = this.#handlePointerDown.bind(this);
|
|
12
|
-
this[internals].ariaHidden = 'true';
|
|
13
|
-
}
|
|
14
10
|
static{
|
|
15
11
|
this.styles = [
|
|
16
12
|
focusRingStyles
|
|
17
13
|
];
|
|
18
14
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#handlePointerDown() {
|
|
30
|
-
this[internals].states.delete('visible');
|
|
15
|
+
constructor(){
|
|
16
|
+
super(), this.inward = false, this.#handleFocusIn = ()=>{
|
|
17
|
+
if (focusVisible) this[internals].states.add('visible');
|
|
18
|
+
else this[internals].states.delete('visible');
|
|
19
|
+
}, this.#handleFocusOut = ()=>{
|
|
20
|
+
this[internals].states.delete('visible');
|
|
21
|
+
}, this.#handlePointerDown = ()=>{
|
|
22
|
+
this[internals].states.delete('visible');
|
|
23
|
+
};
|
|
24
|
+
this[internals].ariaHidden = 'true';
|
|
31
25
|
}
|
|
26
|
+
#handleFocusIn;
|
|
27
|
+
#handleFocusOut;
|
|
28
|
+
#handlePointerDown;
|
|
32
29
|
visualFocus() {
|
|
33
30
|
this.#handleFocusIn();
|
|
34
31
|
}
|
|
@@ -37,9 +34,9 @@ export class M3FocusRing extends Attachable(InternalsAttached(LitElement)) {
|
|
|
37
34
|
}
|
|
38
35
|
handleControlChange(prev = null, next = null) {
|
|
39
36
|
const eventHandlers = {
|
|
40
|
-
focusin: this.#
|
|
41
|
-
focusout: this.#
|
|
42
|
-
pointerdown: this.#
|
|
37
|
+
focusin: this.#handleFocusIn,
|
|
38
|
+
focusout: this.#handleFocusOut,
|
|
39
|
+
pointerdown: this.#handlePointerDown
|
|
43
40
|
};
|
|
44
41
|
Object.keys(eventHandlers).forEach((eventName)=>{
|
|
45
42
|
prev?.removeEventListener(eventName, eventHandlers[eventName]);
|
package/src/m3/list/list-item.js
CHANGED
|
@@ -5,29 +5,12 @@ import { ListItem } from '../../base/list-item.js';
|
|
|
5
5
|
import '../item/item.js';
|
|
6
6
|
import { listItemStyles } from './list-item-styles.css.js';
|
|
7
7
|
export class M3ListItem extends ListItem {
|
|
8
|
-
constructor(){
|
|
9
|
-
super();
|
|
10
|
-
this.updateComplete.then(()=>{
|
|
11
|
-
this.ripple.$control = this;
|
|
12
|
-
this.focusRing.$control = this;
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
8
|
static{
|
|
16
9
|
this.styles = [
|
|
17
10
|
...super.styles,
|
|
18
11
|
listItemStyles
|
|
19
12
|
];
|
|
20
13
|
}
|
|
21
|
-
updated(changed) {
|
|
22
|
-
super.updated(changed);
|
|
23
|
-
if (changed.has('focused')) {
|
|
24
|
-
if (this.focused) {
|
|
25
|
-
this.focusRing.visualFocus();
|
|
26
|
-
} else {
|
|
27
|
-
this.focusRing.visualBlur();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
14
|
render() {
|
|
32
15
|
return html`
|
|
33
16
|
<md-item>
|
|
@@ -48,6 +31,23 @@ export class M3ListItem extends ListItem {
|
|
|
48
31
|
</md-item>
|
|
49
32
|
`;
|
|
50
33
|
}
|
|
34
|
+
constructor(){
|
|
35
|
+
super();
|
|
36
|
+
this.updateComplete.then(()=>{
|
|
37
|
+
this.ripple.$control = this;
|
|
38
|
+
this.focusRing.$control = this;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
updated(changed) {
|
|
42
|
+
super.updated(changed);
|
|
43
|
+
if (changed.has('focused')) {
|
|
44
|
+
if (this.focused) {
|
|
45
|
+
this.focusRing.visualFocus();
|
|
46
|
+
} else {
|
|
47
|
+
this.focusRing.visualBlur();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
_ts_decorate([
|
|
53
53
|
query('md-ripple')
|
package/src/m3/list/list.js
CHANGED
|
@@ -4,14 +4,14 @@ import { List } from '../../base/list.js';
|
|
|
4
4
|
import { listStyles } from './list-styles.css.js';
|
|
5
5
|
export class M3List extends List {
|
|
6
6
|
static{
|
|
7
|
-
// FIXME: Might cause a long list to scroll more than expected
|
|
8
|
-
// override readonly _scrollPadding = 4;
|
|
9
7
|
this.styles = [
|
|
10
8
|
listStyles
|
|
11
9
|
];
|
|
12
10
|
}
|
|
13
11
|
constructor(...args){
|
|
14
|
-
super(...args),
|
|
12
|
+
super(...args), // FIXME: Might cause a long list to scroll more than expected
|
|
13
|
+
// override readonly _scrollPadding = 4;
|
|
14
|
+
this.color = 'standard';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
_ts_decorate([
|
package/src/m3/menu/menu.js
CHANGED
|
@@ -5,8 +5,6 @@ import { Menu } from '../../base/menu.js';
|
|
|
5
5
|
import { menuStyles } from './menu-styles.css.js';
|
|
6
6
|
export class M3Menu extends Menu {
|
|
7
7
|
static{
|
|
8
|
-
// FIXME: Might cause a long list to scroll more than expected
|
|
9
|
-
// override readonly _scrollPadding = 4;
|
|
10
8
|
this.styles = [
|
|
11
9
|
menuStyles
|
|
12
10
|
];
|
|
@@ -15,7 +13,9 @@ export class M3Menu extends Menu {
|
|
|
15
13
|
super(...args), this._durations = {
|
|
16
14
|
show: 300,
|
|
17
15
|
hide: 150
|
|
18
|
-
},
|
|
16
|
+
}, // FIXME: Might cause a long list to scroll more than expected
|
|
17
|
+
// override readonly _scrollPadding = 4;
|
|
18
|
+
this.color = 'standard';
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
_ts_decorate([
|
|
@@ -23,7 +23,7 @@ export class MdFilledSelect extends M3Select {
|
|
|
23
23
|
.focused=${this.open || this.focused}
|
|
24
24
|
supportingtext=${this.supportingText}
|
|
25
25
|
@click=${this.toggle}
|
|
26
|
-
@keydown=${this.
|
|
26
|
+
@keydown=${this._handleFieldKeydown}
|
|
27
27
|
@focus=${()=>this.focused = true}
|
|
28
28
|
@blur=${()=>this.focused = false}
|
|
29
29
|
tabindex=${this.disabled ? '-1' : '0'}
|
|
@@ -23,7 +23,7 @@ export class MdOutlinedSelect extends M3Select {
|
|
|
23
23
|
.focused=${this.open || this.focused}
|
|
24
24
|
supportingtext=${this.supportingText}
|
|
25
25
|
@click=${this.toggle}
|
|
26
|
-
@keydown=${this.
|
|
26
|
+
@keydown=${this._handleFieldKeydown}
|
|
27
27
|
@focus=${()=>this.focused = true}
|
|
28
28
|
@blur=${()=>this.focused = false}
|
|
29
29
|
tabindex=${this.disabled ? '-1' : '0'}
|
package/src/m3/select/select.js
CHANGED
|
@@ -23,10 +23,10 @@ import { Select } from '../../base/select.js';
|
|
|
23
23
|
?open="${this.open}"
|
|
24
24
|
@open="${()=>this.open = true}"
|
|
25
25
|
@close="${()=>this.open = false}"
|
|
26
|
-
@item-focus="${this.
|
|
27
|
-
@select="${this.
|
|
26
|
+
@item-focus="${this._handleMenuItemFocus}"
|
|
27
|
+
@select="${this._handleMenuSelect}"
|
|
28
28
|
>
|
|
29
|
-
<slot part="items" @slotchange=${this.
|
|
29
|
+
<slot part="items" @slotchange=${this._handleSlotChange}></slot>
|
|
30
30
|
</md-menu>
|
|
31
31
|
`;
|
|
32
32
|
}
|
package/src/m3/slider/slider.js
CHANGED
|
@@ -74,12 +74,12 @@ export class M3Slider extends Slider {
|
|
|
74
74
|
<div class="inactive-after"></div>
|
|
75
75
|
</div>
|
|
76
76
|
${this.ticks ? html`
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
<div class="tickmarks">
|
|
78
|
+
<div class="inactive-before"></div>
|
|
79
|
+
<div class="active"></div>
|
|
80
|
+
<div class="inactive-after"></div>
|
|
81
|
+
</div>
|
|
82
|
+
` : nothing}
|
|
83
83
|
`;
|
|
84
84
|
}
|
|
85
85
|
renderLabel(value) {
|
|
@@ -9,16 +9,6 @@ export class M3Toolbar extends InternalsAttached(LitElement) {
|
|
|
9
9
|
toolbarStyles
|
|
10
10
|
];
|
|
11
11
|
}
|
|
12
|
-
constructor(){
|
|
13
|
-
super(), this.type = 'docked', this.color = 'standard', this.orientation = 'horizontal';
|
|
14
|
-
this[internals].role = 'toolbar';
|
|
15
|
-
this[internals].ariaOrientation = this.orientation;
|
|
16
|
-
}
|
|
17
|
-
updated(changed) {
|
|
18
|
-
if (changed.has('orientation')) {
|
|
19
|
-
this[internals].ariaOrientation = this.orientation;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
12
|
render() {
|
|
23
13
|
return html`
|
|
24
14
|
<div part="container">
|
|
@@ -29,6 +19,16 @@ export class M3Toolbar extends InternalsAttached(LitElement) {
|
|
|
29
19
|
</div>
|
|
30
20
|
`;
|
|
31
21
|
}
|
|
22
|
+
constructor(){
|
|
23
|
+
super(), this.type = 'docked', this.color = 'standard', this.orientation = 'horizontal';
|
|
24
|
+
this[internals].role = 'toolbar';
|
|
25
|
+
this[internals].ariaOrientation = this.orientation;
|
|
26
|
+
}
|
|
27
|
+
updated(changed) {
|
|
28
|
+
if (changed.has('orientation')) {
|
|
29
|
+
this[internals].ariaOrientation = this.orientation;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
32
|
}
|
|
33
33
|
_ts_decorate([
|
|
34
34
|
property({
|