@vaadin/component-base 23.0.4 → 23.1.0-alpha2
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 +2 -2
- package/src/element-mixin.js +1 -1
- package/src/polylit-mixin.d.ts +23 -0
- package/src/polylit-mixin.js +266 -0
- package/src/tabindex-mixin.d.ts +5 -2
- package/src/tabindex-mixin.js +7 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/component-base",
|
|
3
|
-
"version": "23.0
|
|
3
|
+
"version": "23.1.0-alpha2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
43
43
|
"sinon": "^9.2.4"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "6842dcb8b163d4512fae8d3d12a6559077a4aee6"
|
|
46
46
|
}
|
package/src/element-mixin.js
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
+
import { LitElement } from 'lit';
|
|
8
|
+
|
|
9
|
+
export declare function PolylitMixin<T extends Constructor<LitElement>>(base: T): T & Constructor<PolylitMixinClass>;
|
|
10
|
+
|
|
11
|
+
export declare class PolylitMixinClass {
|
|
12
|
+
ready(): void;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reads a value from a path.
|
|
16
|
+
*/
|
|
17
|
+
protected _get(root: Object, path: String): any;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sets a value to a path.
|
|
21
|
+
*/
|
|
22
|
+
protected _set(root: Object, path: String, value: any): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { dedupeMixin } from '@open-wc/dedupe-mixin';
|
|
7
|
+
|
|
8
|
+
const caseMap = {};
|
|
9
|
+
|
|
10
|
+
const CAMEL_TO_DASH = /([A-Z])/g;
|
|
11
|
+
|
|
12
|
+
function camelToDash(camel) {
|
|
13
|
+
return caseMap[camel] || (caseMap[camel] = camel.replace(CAMEL_TO_DASH, '-$1').toLowerCase());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function upper(name) {
|
|
17
|
+
return name[0].toUpperCase() + name.substring(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseObserver(observerString) {
|
|
21
|
+
const [method, rest] = observerString.split('(');
|
|
22
|
+
const observerProps = rest
|
|
23
|
+
.replace(')', '')
|
|
24
|
+
.split(',')
|
|
25
|
+
.map((prop) => prop.trim());
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
method,
|
|
29
|
+
observerProps
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getOrCreateMap(obj, name) {
|
|
34
|
+
if (!Object.prototype.hasOwnProperty.call(obj, name)) {
|
|
35
|
+
// clone any existing entries (superclasses)
|
|
36
|
+
obj[name] = new Map(obj[name]);
|
|
37
|
+
}
|
|
38
|
+
return obj[name];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const PolylitMixinImplementation = (superclass) => {
|
|
42
|
+
class PolylitMixinClass extends superclass {
|
|
43
|
+
static createProperty(name, options) {
|
|
44
|
+
if ([String, Boolean, Number, Array].includes(options)) {
|
|
45
|
+
options = {
|
|
46
|
+
type: options
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (options.reflectToAttribute) {
|
|
51
|
+
options.reflect = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
super.createProperty(name, options);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static getOrCreateMap(name) {
|
|
58
|
+
return getOrCreateMap(this, name);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @protected
|
|
63
|
+
* @override
|
|
64
|
+
*/
|
|
65
|
+
static finalize() {
|
|
66
|
+
super.finalize();
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(this.observers)) {
|
|
69
|
+
const complexObservers = this.getOrCreateMap('__complexObservers');
|
|
70
|
+
|
|
71
|
+
this.observers.forEach((observer) => {
|
|
72
|
+
const { method, observerProps } = parseObserver(observer);
|
|
73
|
+
complexObservers.set(method, observerProps);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static addCheckedInitializer(initializer) {
|
|
79
|
+
super.addInitializer((instance) => {
|
|
80
|
+
// Prevent initializer from affecting superclass
|
|
81
|
+
if (instance instanceof this) {
|
|
82
|
+
initializer(instance);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static getPropertyDescriptor(name, key, options) {
|
|
88
|
+
const defaultDescriptor = super.getPropertyDescriptor(name, key, options);
|
|
89
|
+
|
|
90
|
+
let result = defaultDescriptor;
|
|
91
|
+
|
|
92
|
+
if ('value' in options) {
|
|
93
|
+
// Set the default value
|
|
94
|
+
this.addCheckedInitializer((instance) => {
|
|
95
|
+
if (typeof options.value === 'function') {
|
|
96
|
+
instance[name] = options.value.call(instance);
|
|
97
|
+
} else {
|
|
98
|
+
instance[name] = options.value;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (options.readOnly) {
|
|
104
|
+
const setter = defaultDescriptor.set;
|
|
105
|
+
|
|
106
|
+
this.addCheckedInitializer((instance) => {
|
|
107
|
+
// This is run during construction of the element
|
|
108
|
+
instance['_set' + upper(name)] = function (value) {
|
|
109
|
+
setter.call(instance, value);
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
result = {
|
|
114
|
+
get: defaultDescriptor.get,
|
|
115
|
+
set() {
|
|
116
|
+
// Do nothing, property is read-only.
|
|
117
|
+
},
|
|
118
|
+
configurable: true,
|
|
119
|
+
enumerable: true
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (options.observer) {
|
|
124
|
+
const method = options.observer;
|
|
125
|
+
|
|
126
|
+
// set this method
|
|
127
|
+
this.getOrCreateMap('__observers').set(name, method);
|
|
128
|
+
|
|
129
|
+
this.addCheckedInitializer((instance) => {
|
|
130
|
+
if (!instance[method]) {
|
|
131
|
+
console.warn(`observer method ${method} not defined`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (options.notify) {
|
|
137
|
+
if (!this.__notifyProps) {
|
|
138
|
+
this.__notifyProps = new Set();
|
|
139
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
140
|
+
} else if (!this.hasOwnProperty('__notifyProps')) {
|
|
141
|
+
// clone any existing observers (superclasses)
|
|
142
|
+
const notifyProps = this.__notifyProps;
|
|
143
|
+
this.__notifyProps = new Set(notifyProps);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// set this method
|
|
147
|
+
this.__notifyProps.add(name);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.computed) {
|
|
151
|
+
const assignComputedMethod = `__assignComputed${name}`;
|
|
152
|
+
const observer = parseObserver(options.computed);
|
|
153
|
+
this.prototype[assignComputedMethod] = function (...props) {
|
|
154
|
+
this[name] = this[observer.method](...props);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
this.getOrCreateMap('__complexObservers').set(assignComputedMethod, observer.observerProps);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!options.attribute) {
|
|
161
|
+
options.attribute = camelToDash(name);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** @protected */
|
|
168
|
+
ready() {
|
|
169
|
+
if (super.ready) {
|
|
170
|
+
super.ready();
|
|
171
|
+
}
|
|
172
|
+
this.$ = this.$ || {};
|
|
173
|
+
this.shadowRoot.querySelectorAll('[id]').forEach((node) => {
|
|
174
|
+
this.$[node.id] = node;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** @protected */
|
|
179
|
+
firstUpdated() {
|
|
180
|
+
super.firstUpdated();
|
|
181
|
+
|
|
182
|
+
this.ready();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** @protected */
|
|
186
|
+
updated(props) {
|
|
187
|
+
if (this.constructor.__observers) {
|
|
188
|
+
this.__runObservers(props, this.constructor.__observers);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.constructor.__complexObservers) {
|
|
192
|
+
this.__runComplexObservers(props, this.constructor.__complexObservers);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (this.__dynamicObservers) {
|
|
196
|
+
this.__runComplexObservers(props, this.__dynamicObservers);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (this.constructor.__notifyProps) {
|
|
200
|
+
this.__runNotifyProps(props, this.constructor.__notifyProps);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @protected */
|
|
205
|
+
_createMethodObserver(observer) {
|
|
206
|
+
const dynamicObservers = getOrCreateMap(this, '__dynamicObservers');
|
|
207
|
+
const { method, observerProps } = parseObserver(observer);
|
|
208
|
+
dynamicObservers.set(method, observerProps);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** @private */
|
|
212
|
+
__runComplexObservers(props, observers) {
|
|
213
|
+
observers.forEach((observerProps, method) => {
|
|
214
|
+
if (observerProps.some((prop) => props.has(prop))) {
|
|
215
|
+
if (!this[method]) {
|
|
216
|
+
console.warn(`observer method ${method} not defined`);
|
|
217
|
+
} else {
|
|
218
|
+
this[method](...observerProps.map((prop) => this[prop]));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** @private */
|
|
225
|
+
__runObservers(props, observers) {
|
|
226
|
+
props.forEach((v, k) => {
|
|
227
|
+
const observer = observers.get(k);
|
|
228
|
+
if (observer !== undefined && this[observer]) {
|
|
229
|
+
this[observer](this[k], v);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** @private */
|
|
235
|
+
__runNotifyProps(props, notifyProps) {
|
|
236
|
+
props.forEach((_, k) => {
|
|
237
|
+
if (notifyProps.has(k)) {
|
|
238
|
+
this.dispatchEvent(
|
|
239
|
+
new CustomEvent(`${camelToDash(k)}-changed`, {
|
|
240
|
+
detail: {
|
|
241
|
+
value: this[k]
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** @protected */
|
|
250
|
+
_get(path, object) {
|
|
251
|
+
return path.split('.').reduce((obj, property) => (obj ? obj[property] : undefined), object);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** @protected */
|
|
255
|
+
_set(path, value, object) {
|
|
256
|
+
const pathParts = path.split('.');
|
|
257
|
+
const lastPart = pathParts.pop();
|
|
258
|
+
const target = pathParts.reduce((target, part) => target[part], object);
|
|
259
|
+
target[lastPart] = value;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return PolylitMixinClass;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export const PolylitMixin = dedupeMixin(PolylitMixinImplementation);
|
package/src/tabindex-mixin.d.ts
CHANGED
|
@@ -9,8 +9,6 @@ import { DisabledMixinClass } from './disabled-mixin.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* A mixin to toggle the `tabindex` attribute.
|
|
11
11
|
*
|
|
12
|
-
* By default, the attribute is set to 0 that makes the element focusable.
|
|
13
|
-
*
|
|
14
12
|
* The attribute is set to -1 whenever the user disables the element
|
|
15
13
|
* and restored with the last known value once the element is enabled.
|
|
16
14
|
*/
|
|
@@ -24,6 +22,11 @@ export declare class TabindexMixinClass {
|
|
|
24
22
|
*/
|
|
25
23
|
tabindex: number | undefined | null;
|
|
26
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Stores the last known tabindex since the element has been disabled.
|
|
27
|
+
*/
|
|
28
|
+
protected _lastTabIndex: number | undefined | null;
|
|
29
|
+
|
|
27
30
|
/**
|
|
28
31
|
* When the user has changed tabindex while the element is disabled,
|
|
29
32
|
* the observer reverts tabindex to -1 and rather saves the new tabindex value to apply it later.
|
package/src/tabindex-mixin.js
CHANGED
|
@@ -8,8 +8,6 @@ import { DisabledMixin } from './disabled-mixin.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* A mixin to toggle the `tabindex` attribute.
|
|
10
10
|
*
|
|
11
|
-
* By default, the attribute is set to 0 that makes the element focusable.
|
|
12
|
-
*
|
|
13
11
|
* The attribute is set to -1 whenever the user disables the element
|
|
14
12
|
* and restored with the last known value once the element is enabled.
|
|
15
13
|
*
|
|
@@ -22,11 +20,11 @@ export const TabindexMixin = (superclass) =>
|
|
|
22
20
|
return {
|
|
23
21
|
/**
|
|
24
22
|
* Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
|
|
23
|
+
*
|
|
25
24
|
* @protected
|
|
26
25
|
*/
|
|
27
26
|
tabindex: {
|
|
28
27
|
type: Number,
|
|
29
|
-
value: 0,
|
|
30
28
|
reflectToAttribute: true,
|
|
31
29
|
observer: '_tabindexChanged'
|
|
32
30
|
},
|
|
@@ -34,11 +32,10 @@ export const TabindexMixin = (superclass) =>
|
|
|
34
32
|
/**
|
|
35
33
|
* Stores the last known tabindex since the element has been disabled.
|
|
36
34
|
*
|
|
37
|
-
* @
|
|
35
|
+
* @protected
|
|
38
36
|
*/
|
|
39
|
-
|
|
40
|
-
type: Number
|
|
41
|
-
value: 0
|
|
37
|
+
_lastTabIndex: {
|
|
38
|
+
type: Number
|
|
42
39
|
}
|
|
43
40
|
};
|
|
44
41
|
}
|
|
@@ -57,11 +54,11 @@ export const TabindexMixin = (superclass) =>
|
|
|
57
54
|
|
|
58
55
|
if (disabled) {
|
|
59
56
|
if (this.tabindex !== undefined) {
|
|
60
|
-
this.
|
|
57
|
+
this._lastTabIndex = this.tabindex;
|
|
61
58
|
}
|
|
62
59
|
this.tabindex = -1;
|
|
63
60
|
} else if (oldDisabled) {
|
|
64
|
-
this.tabindex = this.
|
|
61
|
+
this.tabindex = this._lastTabIndex;
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
64
|
|
|
@@ -74,7 +71,7 @@ export const TabindexMixin = (superclass) =>
|
|
|
74
71
|
*/
|
|
75
72
|
_tabindexChanged(tabindex) {
|
|
76
73
|
if (this.disabled && tabindex !== -1) {
|
|
77
|
-
this.
|
|
74
|
+
this._lastTabIndex = tabindex;
|
|
78
75
|
this.tabindex = -1;
|
|
79
76
|
}
|
|
80
77
|
}
|