@everymatrix/general-input 1.22.0 → 1.22.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/dist/cjs/checkbox-group-input_10.cjs.entry.js +27763 -17684
- package/dist/components/active-mixin.js +97 -7
- package/dist/components/checkbox-group-input2.js +2863 -390
- package/dist/components/date-input2.js +6683 -2984
- package/dist/components/field-mixin.js +2423 -3723
- package/dist/components/input-field-shared-styles.js +993 -242
- package/dist/components/password-input2.js +1870 -94
- package/dist/components/vaadin-button.js +1531 -157
- package/dist/components/vaadin-combo-box.js +2655 -783
- package/dist/components/virtual-keyboard-controller.js +1163 -1742
- package/dist/esm/checkbox-group-input_10.entry.js +27763 -17684
- package/dist/general-input/general-input.esm.js +1 -1
- package/dist/general-input/p-983d18d7.entry.js +4143 -0
- package/package.json +9 -6
- package/dist/components/pattern-mixin.js +0 -85
- package/dist/general-input/p-553c91f3.entry.js +0 -3583
- /package/dist/types/Users/{catalin.poclid/Documents/work → adrian.pripon/Documents/Work}/widgets-stencil/packages/general-input/.stencil/packages/general-input/stencil.config.d.ts +0 -0
|
@@ -1,23 +1,1286 @@
|
|
|
1
1
|
import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
|
|
2
2
|
import { t as translate, a as tooltipIconSvg } from './tooltipIcon.js';
|
|
3
|
-
import { i as inputFieldShared,
|
|
4
|
-
import {
|
|
5
|
-
import { P as PatternMixin } from './pattern-mixin.js';
|
|
3
|
+
import { i as inputFieldShared, a as InputControlMixin, b as inputFieldShared$1 } from './input-field-shared-styles.js';
|
|
4
|
+
import { o, u as usageStatistics, e as InputController, f as LabelledInputController, h as html, P as PolymerElement, i } from './field-mixin.js';
|
|
6
5
|
import { b as button, B as Button } from './vaadin-button.js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @license
|
|
10
|
-
* Copyright (c) 2017 -
|
|
9
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
10
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* @polymerMixin
|
|
14
|
+
*/
|
|
15
|
+
const ThemePropertyMixin = (superClass) =>
|
|
16
|
+
class VaadinThemePropertyMixin extends superClass {
|
|
17
|
+
static get properties() {
|
|
18
|
+
return {
|
|
19
|
+
/**
|
|
20
|
+
* Helper property with theme attribute value facilitating propagation
|
|
21
|
+
* in shadow DOM.
|
|
22
|
+
*
|
|
23
|
+
* Enables the component implementation to propagate the `theme`
|
|
24
|
+
* attribute value to the sub-components in Shadow DOM by binding
|
|
25
|
+
* the sub-component's "theme" attribute to the `theme` property of
|
|
26
|
+
* the host.
|
|
27
|
+
*
|
|
28
|
+
* **NOTE:** Extending the mixin only provides the property for binding,
|
|
29
|
+
* and does not make the propagation alone.
|
|
30
|
+
*
|
|
31
|
+
* See [Styling Components: Sub-components](https://vaadin.com/docs/latest/styling/styling-components/#sub-components).
|
|
32
|
+
* page for more information.
|
|
33
|
+
*
|
|
34
|
+
* @protected
|
|
35
|
+
*/
|
|
36
|
+
_theme: {
|
|
37
|
+
type: String,
|
|
38
|
+
readOnly: true,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static get observedAttributes() {
|
|
44
|
+
return [...super.observedAttributes, 'theme'];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @protected */
|
|
48
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
49
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
50
|
+
|
|
51
|
+
if (name === 'theme') {
|
|
52
|
+
this._set_theme(newValue);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @license
|
|
59
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
60
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @typedef {Object} Theme
|
|
65
|
+
* @property {string} themeFor
|
|
66
|
+
* @property {CSSResult[]} styles
|
|
67
|
+
* @property {string | string[]} [include]
|
|
68
|
+
* @property {string} [moduleId]
|
|
69
|
+
*
|
|
70
|
+
* @typedef {CSSResult[] | CSSResult} CSSResultGroup
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @type {Theme[]}
|
|
75
|
+
*/
|
|
76
|
+
const themeRegistry = [];
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if the custom element type has themes applied.
|
|
80
|
+
* @param {Function} elementClass
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
function classHasThemes$1(elementClass) {
|
|
84
|
+
return elementClass && Object.prototype.hasOwnProperty.call(elementClass, '__themes');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if the custom element type has themes applied.
|
|
89
|
+
* @param {string} tagName
|
|
90
|
+
* @returns {boolean}
|
|
91
|
+
*/
|
|
92
|
+
function hasThemes$1(tagName) {
|
|
93
|
+
return classHasThemes$1(customElements.get(tagName));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Flattens the styles into a single array of styles.
|
|
98
|
+
* @param {CSSResultGroup} styles
|
|
99
|
+
* @param {CSSResult[]} result
|
|
100
|
+
* @returns {CSSResult[]}
|
|
101
|
+
*/
|
|
102
|
+
function flattenStyles$1(styles = []) {
|
|
103
|
+
return [styles].flat(Infinity).filter((style) => {
|
|
104
|
+
if (style instanceof o) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
console.warn('An item in styles is not of type CSSResult. Use `unsafeCSS` or `css`.');
|
|
108
|
+
return false;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Registers CSS styles for a component type. Make sure to register the styles before
|
|
114
|
+
* the first instance of a component of the type is attached to DOM.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} themeFor The local/tag name of the component type to register the styles for
|
|
117
|
+
* @param {CSSResultGroup} styles The CSS style rules to be registered for the component type
|
|
118
|
+
* matching themeFor and included in the local scope of each component instance
|
|
119
|
+
* @param {{moduleId?: string, include?: string | string[]}} options Additional options
|
|
120
|
+
* @return {void}
|
|
121
|
+
*/
|
|
122
|
+
function registerStyles$1(themeFor, styles, options = {}) {
|
|
123
|
+
if (themeFor) {
|
|
124
|
+
if (hasThemes$1(themeFor)) {
|
|
125
|
+
console.warn(`The custom element definition for "${themeFor}"
|
|
126
|
+
was finalized before a style module was registered.
|
|
127
|
+
Make sure to add component specific style modules before
|
|
128
|
+
importing the corresponding custom element.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
styles = flattenStyles$1(styles);
|
|
133
|
+
|
|
134
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
135
|
+
window.Vaadin.styleModules.registerStyles(themeFor, styles, options);
|
|
136
|
+
} else {
|
|
137
|
+
themeRegistry.push({
|
|
138
|
+
themeFor,
|
|
139
|
+
styles,
|
|
140
|
+
include: options.include,
|
|
141
|
+
moduleId: options.moduleId,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Returns all registered themes. By default the themeRegistry is returned as is.
|
|
148
|
+
* In case the style-modules adapter is imported, the themes are obtained from there instead
|
|
149
|
+
* @returns {Theme[]}
|
|
150
|
+
*/
|
|
151
|
+
function getAllThemes() {
|
|
152
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
153
|
+
return window.Vaadin.styleModules.getAllThemes();
|
|
154
|
+
}
|
|
155
|
+
return themeRegistry;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Returns true if the themeFor string matches the tag name
|
|
160
|
+
* @param {string} themeFor
|
|
161
|
+
* @param {string} tagName
|
|
162
|
+
* @returns {boolean}
|
|
163
|
+
*/
|
|
164
|
+
function matchesThemeFor(themeFor, tagName) {
|
|
165
|
+
return (themeFor || '').split(' ').some((themeForToken) => {
|
|
166
|
+
return new RegExp(`^${themeForToken.split('*').join('.*')}$`, 'u').test(tagName);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Maps the moduleName to an include priority number which is used for
|
|
172
|
+
* determining the order in which styles are applied.
|
|
173
|
+
* @param {string} moduleName
|
|
174
|
+
* @returns {number}
|
|
175
|
+
*/
|
|
176
|
+
function getIncludePriority(moduleName = '') {
|
|
177
|
+
let includePriority = 0;
|
|
178
|
+
if (moduleName.startsWith('lumo-') || moduleName.startsWith('material-')) {
|
|
179
|
+
includePriority = 1;
|
|
180
|
+
} else if (moduleName.startsWith('vaadin-')) {
|
|
181
|
+
includePriority = 2;
|
|
182
|
+
}
|
|
183
|
+
return includePriority;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Gets an array of CSSResults matching the include property of the theme.
|
|
188
|
+
* @param {Theme} theme
|
|
189
|
+
* @returns {CSSResult[]}
|
|
190
|
+
*/
|
|
191
|
+
function getIncludedStyles(theme) {
|
|
192
|
+
const includedStyles = [];
|
|
193
|
+
if (theme.include) {
|
|
194
|
+
[].concat(theme.include).forEach((includeModuleId) => {
|
|
195
|
+
const includedTheme = getAllThemes().find((s) => s.moduleId === includeModuleId);
|
|
196
|
+
if (includedTheme) {
|
|
197
|
+
includedStyles.push(...getIncludedStyles(includedTheme), ...includedTheme.styles);
|
|
198
|
+
} else {
|
|
199
|
+
console.warn(`Included moduleId ${includeModuleId} not found in style registry`);
|
|
200
|
+
}
|
|
201
|
+
}, theme.styles);
|
|
202
|
+
}
|
|
203
|
+
return includedStyles;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Includes the styles to the template.
|
|
208
|
+
* @param {CSSResult[]} styles
|
|
209
|
+
* @param {HTMLTemplateElement} template
|
|
210
|
+
*/
|
|
211
|
+
function addStylesToTemplate(styles, template) {
|
|
212
|
+
const styleEl = document.createElement('style');
|
|
213
|
+
styleEl.innerHTML = styles.map((style) => style.cssText).join('\n');
|
|
214
|
+
template.content.appendChild(styleEl);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Returns an array of themes that should be used for styling a component matching
|
|
219
|
+
* the tag name. The array is sorted by the include order.
|
|
220
|
+
* @param {string} tagName
|
|
221
|
+
* @returns {Theme[]}
|
|
222
|
+
*/
|
|
223
|
+
function getThemes(tagName) {
|
|
224
|
+
const defaultModuleName = `${tagName}-default-theme`;
|
|
225
|
+
|
|
226
|
+
const themes = getAllThemes()
|
|
227
|
+
// Filter by matching themeFor properties
|
|
228
|
+
.filter((theme) => theme.moduleId !== defaultModuleName && matchesThemeFor(theme.themeFor, tagName))
|
|
229
|
+
.map((theme) => ({
|
|
230
|
+
...theme,
|
|
231
|
+
// Prepend styles from included themes
|
|
232
|
+
styles: [...getIncludedStyles(theme), ...theme.styles],
|
|
233
|
+
// Map moduleId to includePriority
|
|
234
|
+
includePriority: getIncludePriority(theme.moduleId),
|
|
235
|
+
}))
|
|
236
|
+
// Sort by includePriority
|
|
237
|
+
.sort((themeA, themeB) => themeB.includePriority - themeA.includePriority);
|
|
238
|
+
|
|
239
|
+
if (themes.length > 0) {
|
|
240
|
+
return themes;
|
|
241
|
+
}
|
|
242
|
+
// No theme modules found, return the default module if it exists
|
|
243
|
+
return getAllThemes().filter((theme) => theme.moduleId === defaultModuleName);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @polymerMixin
|
|
248
|
+
* @mixes ThemePropertyMixin
|
|
249
|
+
*/
|
|
250
|
+
const ThemableMixin = (superClass) =>
|
|
251
|
+
class VaadinThemableMixin extends ThemePropertyMixin(superClass) {
|
|
252
|
+
/**
|
|
253
|
+
* Covers PolymerElement based component styling
|
|
254
|
+
* @protected
|
|
255
|
+
*/
|
|
256
|
+
static finalize() {
|
|
257
|
+
super.finalize();
|
|
258
|
+
|
|
259
|
+
// Make sure not to run the logic intended for PolymerElement when LitElement is used.
|
|
260
|
+
if (this.elementStyles) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const template = this.prototype._template;
|
|
265
|
+
if (!template || classHasThemes$1(this)) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
addStylesToTemplate(this.getStylesForThis(), template);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Covers LitElement based component styling
|
|
274
|
+
*
|
|
275
|
+
* @protected
|
|
276
|
+
*/
|
|
277
|
+
static finalizeStyles(styles) {
|
|
278
|
+
// The "styles" object originates from the "static get styles()" function of
|
|
279
|
+
// a LitElement based component. The theme styles are added after it
|
|
280
|
+
// so that they can override the component styles.
|
|
281
|
+
const themeStyles = this.getStylesForThis();
|
|
282
|
+
return styles ? [...super.finalizeStyles(styles), ...themeStyles] : themeStyles;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Get styles for the component type
|
|
287
|
+
*
|
|
288
|
+
* @private
|
|
289
|
+
*/
|
|
290
|
+
static getStylesForThis() {
|
|
291
|
+
const parent = Object.getPrototypeOf(this.prototype);
|
|
292
|
+
const inheritedThemes = (parent ? parent.constructor.__themes : []) || [];
|
|
293
|
+
this.__themes = [...inheritedThemes, ...getThemes(this.is)];
|
|
294
|
+
const themeStyles = this.__themes.flatMap((theme) => theme.styles);
|
|
295
|
+
// Remove duplicates
|
|
296
|
+
return themeStyles.filter((style, index) => index === themeStyles.lastIndexOf(style));
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* @license
|
|
302
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
303
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
registerStyles$1('vaadin-text-field', inputFieldShared, {
|
|
307
|
+
moduleId: 'lumo-text-field-styles',
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @license
|
|
312
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
313
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
314
|
+
*/
|
|
315
|
+
function defineCustomElement$2(CustomElement) {
|
|
316
|
+
const defined = customElements.get(CustomElement.is);
|
|
317
|
+
if (!defined) {
|
|
318
|
+
customElements.define(CustomElement.is, CustomElement);
|
|
319
|
+
} else {
|
|
320
|
+
const definedVersion = defined.version;
|
|
321
|
+
if (definedVersion && CustomElement.version && definedVersion === CustomElement.version) {
|
|
322
|
+
// Just loading the same thing again
|
|
323
|
+
console.warn(`The component ${CustomElement.is} has been loaded twice`);
|
|
324
|
+
} else {
|
|
325
|
+
console.error(
|
|
326
|
+
`Tried to define ${CustomElement.is} version ${CustomElement.version} when version ${defined.version} is already in use. Something will probably break.`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @license
|
|
334
|
+
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
335
|
+
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
336
|
+
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
337
|
+
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
338
|
+
* Code distributed by Google as part of the polymer project is also
|
|
339
|
+
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
340
|
+
*/
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Async interface wrapper around `requestIdleCallback`. Falls back to
|
|
344
|
+
* `setTimeout` on browsers that do not support `requestIdleCallback`.
|
|
345
|
+
*
|
|
346
|
+
* @namespace
|
|
347
|
+
* @summary Async interface wrapper around `requestIdleCallback`.
|
|
348
|
+
*/
|
|
349
|
+
const idlePeriod = {
|
|
350
|
+
/**
|
|
351
|
+
* Enqueues a function called at `requestIdleCallback` timing.
|
|
352
|
+
*
|
|
353
|
+
* @memberof idlePeriod
|
|
354
|
+
* @param {function(!IdleDeadline):void} fn Callback to run
|
|
355
|
+
* @return {number} Handle used for canceling task
|
|
356
|
+
*/
|
|
357
|
+
run(fn) {
|
|
358
|
+
return window.requestIdleCallback ? window.requestIdleCallback(fn) : window.setTimeout(fn, 16);
|
|
359
|
+
},
|
|
360
|
+
/**
|
|
361
|
+
* Cancels a previously enqueued `idlePeriod` callback.
|
|
362
|
+
*
|
|
363
|
+
* @memberof idlePeriod
|
|
364
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
365
|
+
* @return {void}
|
|
366
|
+
*/
|
|
367
|
+
cancel(handle) {
|
|
368
|
+
if (window.cancelIdleCallback) {
|
|
369
|
+
window.cancelIdleCallback(handle);
|
|
370
|
+
} else {
|
|
371
|
+
window.clearTimeout(handle);
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
@license
|
|
378
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
379
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
380
|
+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
381
|
+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
382
|
+
Code distributed by Google as part of the polymer project is also
|
|
383
|
+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
384
|
+
*/
|
|
385
|
+
|
|
386
|
+
const debouncerQueue = new Set();
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @summary Collapse multiple callbacks into one invocation after a timer.
|
|
390
|
+
*/
|
|
391
|
+
class Debouncer {
|
|
392
|
+
/**
|
|
393
|
+
* Creates a debouncer if no debouncer is passed as a parameter
|
|
394
|
+
* or it cancels an active debouncer otherwise. The following
|
|
395
|
+
* example shows how a debouncer can be called multiple times within a
|
|
396
|
+
* microtask and "debounced" such that the provided callback function is
|
|
397
|
+
* called once. Add this method to a custom element:
|
|
398
|
+
*
|
|
399
|
+
* ```js
|
|
400
|
+
* import {microTask} from '@vaadin/component-base/src/async.js';
|
|
401
|
+
* import {Debouncer} from '@vaadin/component-base/src/debounce.js';
|
|
402
|
+
* // ...
|
|
403
|
+
*
|
|
404
|
+
* _debounceWork() {
|
|
405
|
+
* this._debounceJob = Debouncer.debounce(this._debounceJob,
|
|
406
|
+
* microTask, () => this._doWork());
|
|
407
|
+
* }
|
|
408
|
+
* ```
|
|
409
|
+
*
|
|
410
|
+
* If the `_debounceWork` method is called multiple times within the same
|
|
411
|
+
* microtask, the `_doWork` function will be called only once at the next
|
|
412
|
+
* microtask checkpoint.
|
|
413
|
+
*
|
|
414
|
+
* Note: In testing it is often convenient to avoid asynchrony. To accomplish
|
|
415
|
+
* this with a debouncer, you can use `enqueueDebouncer` and
|
|
416
|
+
* `flush`. For example, extend the above example by adding
|
|
417
|
+
* `enqueueDebouncer(this._debounceJob)` at the end of the
|
|
418
|
+
* `_debounceWork` method. Then in a test, call `flush` to ensure
|
|
419
|
+
* the debouncer has completed.
|
|
420
|
+
*
|
|
421
|
+
* @param {Debouncer?} debouncer Debouncer object.
|
|
422
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface
|
|
423
|
+
* @param {function()} callback Callback to run.
|
|
424
|
+
* @return {!Debouncer} Returns a debouncer object.
|
|
425
|
+
*/
|
|
426
|
+
static debounce(debouncer, asyncModule, callback) {
|
|
427
|
+
if (debouncer instanceof Debouncer) {
|
|
428
|
+
// Cancel the async callback, but leave in debouncerQueue if it was
|
|
429
|
+
// enqueued, to maintain 1.x flush order
|
|
430
|
+
debouncer._cancelAsync();
|
|
431
|
+
} else {
|
|
432
|
+
debouncer = new Debouncer();
|
|
433
|
+
}
|
|
434
|
+
debouncer.setConfig(asyncModule, callback);
|
|
435
|
+
return debouncer;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
constructor() {
|
|
439
|
+
this._asyncModule = null;
|
|
440
|
+
this._callback = null;
|
|
441
|
+
this._timer = null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Sets the scheduler; that is, a module with the Async interface,
|
|
446
|
+
* a callback and optional arguments to be passed to the run function
|
|
447
|
+
* from the async module.
|
|
448
|
+
*
|
|
449
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface.
|
|
450
|
+
* @param {function()} callback Callback to run.
|
|
451
|
+
* @return {void}
|
|
452
|
+
*/
|
|
453
|
+
setConfig(asyncModule, callback) {
|
|
454
|
+
this._asyncModule = asyncModule;
|
|
455
|
+
this._callback = callback;
|
|
456
|
+
this._timer = this._asyncModule.run(() => {
|
|
457
|
+
this._timer = null;
|
|
458
|
+
debouncerQueue.delete(this);
|
|
459
|
+
this._callback();
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Cancels an active debouncer and returns a reference to itself.
|
|
465
|
+
*
|
|
466
|
+
* @return {void}
|
|
467
|
+
*/
|
|
468
|
+
cancel() {
|
|
469
|
+
if (this.isActive()) {
|
|
470
|
+
this._cancelAsync();
|
|
471
|
+
// Canceling a debouncer removes its spot from the flush queue,
|
|
472
|
+
// so if a debouncer is manually canceled and re-debounced, it
|
|
473
|
+
// will reset its flush order (this is a very minor difference from 1.x)
|
|
474
|
+
// Re-debouncing via the `debounce` API retains the 1.x FIFO flush order
|
|
475
|
+
debouncerQueue.delete(this);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Cancels a debouncer's async callback.
|
|
481
|
+
*
|
|
482
|
+
* @return {void}
|
|
483
|
+
*/
|
|
484
|
+
_cancelAsync() {
|
|
485
|
+
if (this.isActive()) {
|
|
486
|
+
this._asyncModule.cancel(/** @type {number} */ (this._timer));
|
|
487
|
+
this._timer = null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Flushes an active debouncer and returns a reference to itself.
|
|
493
|
+
*
|
|
494
|
+
* @return {void}
|
|
495
|
+
*/
|
|
496
|
+
flush() {
|
|
497
|
+
if (this.isActive()) {
|
|
498
|
+
this.cancel();
|
|
499
|
+
this._callback();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Returns true if the debouncer is active.
|
|
505
|
+
*
|
|
506
|
+
* @return {boolean} True if active.
|
|
507
|
+
*/
|
|
508
|
+
isActive() {
|
|
509
|
+
return this._timer != null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Adds a `Debouncer` to a list of globally flushable tasks.
|
|
515
|
+
*
|
|
516
|
+
* @param {!Debouncer} debouncer Debouncer to enqueue
|
|
517
|
+
* @return {void}
|
|
518
|
+
*/
|
|
519
|
+
function enqueueDebouncer(debouncer) {
|
|
520
|
+
debouncerQueue.add(debouncer);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* @license
|
|
525
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
526
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Array of Vaadin custom element classes that have been subscribed to the dir changes.
|
|
531
|
+
*/
|
|
532
|
+
const directionSubscribers = [];
|
|
533
|
+
|
|
534
|
+
function alignDirs(element, documentDir, elementDir = element.getAttribute('dir')) {
|
|
535
|
+
if (documentDir) {
|
|
536
|
+
element.setAttribute('dir', documentDir);
|
|
537
|
+
} else if (elementDir != null) {
|
|
538
|
+
element.removeAttribute('dir');
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function getDocumentDir() {
|
|
543
|
+
return document.documentElement.getAttribute('dir');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function directionUpdater() {
|
|
547
|
+
const documentDir = getDocumentDir();
|
|
548
|
+
directionSubscribers.forEach((element) => {
|
|
549
|
+
alignDirs(element, documentDir);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const directionObserver = new MutationObserver(directionUpdater);
|
|
554
|
+
directionObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] });
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* A mixin to handle `dir` attribute based on the one set on the `<html>` element.
|
|
558
|
+
*
|
|
559
|
+
* @polymerMixin
|
|
560
|
+
*/
|
|
561
|
+
const DirMixin = (superClass) =>
|
|
562
|
+
class VaadinDirMixin extends superClass {
|
|
563
|
+
static get properties() {
|
|
564
|
+
return {
|
|
565
|
+
/**
|
|
566
|
+
* @protected
|
|
567
|
+
*/
|
|
568
|
+
dir: {
|
|
569
|
+
type: String,
|
|
570
|
+
value: '',
|
|
571
|
+
reflectToAttribute: true,
|
|
572
|
+
converter: {
|
|
573
|
+
fromAttribute: (attr) => {
|
|
574
|
+
return !attr ? '' : attr;
|
|
575
|
+
},
|
|
576
|
+
toAttribute: (prop) => {
|
|
577
|
+
return prop === '' ? null : prop;
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* @return {boolean}
|
|
586
|
+
* @protected
|
|
587
|
+
*/
|
|
588
|
+
get __isRTL() {
|
|
589
|
+
return this.getAttribute('dir') === 'rtl';
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** @protected */
|
|
593
|
+
connectedCallback() {
|
|
594
|
+
super.connectedCallback();
|
|
595
|
+
|
|
596
|
+
if (!this.hasAttribute('dir') || this.__restoreSubscription) {
|
|
597
|
+
this.__subscribe();
|
|
598
|
+
alignDirs(this, getDocumentDir(), null);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/** @protected */
|
|
603
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
604
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
605
|
+
if (name !== 'dir') {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const documentDir = getDocumentDir();
|
|
610
|
+
|
|
611
|
+
// New value equals to the document direction and the element is not subscribed to the changes
|
|
612
|
+
const newValueEqlDocDir = newValue === documentDir && directionSubscribers.indexOf(this) === -1;
|
|
613
|
+
// Value was emptied and the element is not subscribed to the changes
|
|
614
|
+
const newValueEmptied = !newValue && oldValue && directionSubscribers.indexOf(this) === -1;
|
|
615
|
+
// New value is different and the old equals to document direction and the element is not subscribed to the changes
|
|
616
|
+
const newDiffValue = newValue !== documentDir && oldValue === documentDir;
|
|
617
|
+
|
|
618
|
+
if (newValueEqlDocDir || newValueEmptied) {
|
|
619
|
+
this.__subscribe();
|
|
620
|
+
alignDirs(this, documentDir, newValue);
|
|
621
|
+
} else if (newDiffValue) {
|
|
622
|
+
this.__unsubscribe();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/** @protected */
|
|
627
|
+
disconnectedCallback() {
|
|
628
|
+
super.disconnectedCallback();
|
|
629
|
+
this.__restoreSubscription = directionSubscribers.includes(this);
|
|
630
|
+
this.__unsubscribe();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** @protected */
|
|
634
|
+
_valueToNodeAttribute(node, value, attribute) {
|
|
635
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
636
|
+
// If the property contains an empty string then it should not create an empty attribute
|
|
637
|
+
if (attribute === 'dir' && value === '' && !node.hasAttribute('dir')) {
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
super._valueToNodeAttribute(node, value, attribute);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/** @protected */
|
|
644
|
+
_attributeToProperty(attribute, value, type) {
|
|
645
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
646
|
+
// If the attribute is removed, then the dir property should contain an empty string instead of null
|
|
647
|
+
if (attribute === 'dir' && !value) {
|
|
648
|
+
this.dir = '';
|
|
649
|
+
} else {
|
|
650
|
+
super._attributeToProperty(attribute, value, type);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/** @private */
|
|
655
|
+
__subscribe() {
|
|
656
|
+
if (!directionSubscribers.includes(this)) {
|
|
657
|
+
directionSubscribers.push(this);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/** @private */
|
|
662
|
+
__unsubscribe() {
|
|
663
|
+
if (directionSubscribers.includes(this)) {
|
|
664
|
+
directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* @license
|
|
671
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
672
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
673
|
+
*/
|
|
674
|
+
|
|
675
|
+
if (!window.Vaadin) {
|
|
676
|
+
window.Vaadin = {};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Array of Vaadin custom element classes that have been finalized.
|
|
681
|
+
*/
|
|
682
|
+
if (!window.Vaadin.registrations) {
|
|
683
|
+
window.Vaadin.registrations = [];
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (!window.Vaadin.developmentModeCallback) {
|
|
687
|
+
window.Vaadin.developmentModeCallback = {};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics'] = function () {
|
|
691
|
+
usageStatistics();
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
let statsJob;
|
|
695
|
+
|
|
696
|
+
const registered = new Set();
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* @polymerMixin
|
|
700
|
+
* @mixes DirMixin
|
|
701
|
+
*/
|
|
702
|
+
const ElementMixin = (superClass) =>
|
|
703
|
+
class VaadinElementMixin extends DirMixin(superClass) {
|
|
704
|
+
static get version() {
|
|
705
|
+
return '24.2.3';
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/** @protected */
|
|
709
|
+
static finalize() {
|
|
710
|
+
super.finalize();
|
|
711
|
+
|
|
712
|
+
const { is } = this;
|
|
713
|
+
|
|
714
|
+
// Registers a class prototype for telemetry purposes.
|
|
715
|
+
if (is && !registered.has(is)) {
|
|
716
|
+
window.Vaadin.registrations.push(this);
|
|
717
|
+
registered.add(is);
|
|
718
|
+
|
|
719
|
+
if (window.Vaadin.developmentModeCallback) {
|
|
720
|
+
statsJob = Debouncer.debounce(statsJob, idlePeriod, () => {
|
|
721
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics']();
|
|
722
|
+
});
|
|
723
|
+
enqueueDebouncer(statsJob);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
constructor() {
|
|
729
|
+
super();
|
|
730
|
+
|
|
731
|
+
if (document.doctype === null) {
|
|
732
|
+
console.warn(
|
|
733
|
+
'Vaadin components require the "standards mode" declaration. Please add <!DOCTYPE html> to the HTML document.',
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* @license
|
|
741
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
742
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
743
|
+
*/
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Returns true if the given node is an empty text node, false otherwise.
|
|
747
|
+
*
|
|
748
|
+
* @param {Node} node
|
|
749
|
+
* @return {boolean}
|
|
750
|
+
*/
|
|
751
|
+
function isEmptyTextNode$1(node) {
|
|
752
|
+
return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '';
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* @license
|
|
757
|
+
* Copyright (c) 2023 Vaadin Ltd.
|
|
758
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
759
|
+
*/
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* A helper for observing slot changes.
|
|
763
|
+
*/
|
|
764
|
+
class SlotObserver$1 {
|
|
765
|
+
constructor(slot, callback) {
|
|
766
|
+
/** @type HTMLSlotElement */
|
|
767
|
+
this.slot = slot;
|
|
768
|
+
|
|
769
|
+
/** @type Function */
|
|
770
|
+
this.callback = callback;
|
|
771
|
+
|
|
772
|
+
/** @type {Node[]} */
|
|
773
|
+
this._storedNodes = [];
|
|
774
|
+
|
|
775
|
+
this._connected = false;
|
|
776
|
+
this._scheduled = false;
|
|
777
|
+
|
|
778
|
+
this._boundSchedule = () => {
|
|
779
|
+
this._schedule();
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
this.connect();
|
|
783
|
+
this._schedule();
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Activates an observer. This method is automatically called when
|
|
788
|
+
* a `SlotObserver` is created. It should only be called to re-activate
|
|
789
|
+
* an observer that has been deactivated via the `disconnect` method.
|
|
790
|
+
*/
|
|
791
|
+
connect() {
|
|
792
|
+
this.slot.addEventListener('slotchange', this._boundSchedule);
|
|
793
|
+
this._connected = true;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Deactivates the observer. After calling this method the observer callback
|
|
798
|
+
* will not be called when changes to slotted nodes occur. The `connect` method
|
|
799
|
+
* may be subsequently called to reactivate the observer.
|
|
800
|
+
*/
|
|
801
|
+
disconnect() {
|
|
802
|
+
this.slot.removeEventListener('slotchange', this._boundSchedule);
|
|
803
|
+
this._connected = false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/** @private */
|
|
807
|
+
_schedule() {
|
|
808
|
+
if (!this._scheduled) {
|
|
809
|
+
this._scheduled = true;
|
|
810
|
+
|
|
811
|
+
queueMicrotask(() => {
|
|
812
|
+
this.flush();
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Run the observer callback synchronously.
|
|
819
|
+
*/
|
|
820
|
+
flush() {
|
|
821
|
+
if (!this._connected) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
this._scheduled = false;
|
|
826
|
+
|
|
827
|
+
this._processNodes();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/** @private */
|
|
831
|
+
_processNodes() {
|
|
832
|
+
const currentNodes = this.slot.assignedNodes({ flatten: true });
|
|
833
|
+
|
|
834
|
+
let addedNodes = [];
|
|
835
|
+
const removedNodes = [];
|
|
836
|
+
const movedNodes = [];
|
|
837
|
+
|
|
838
|
+
if (currentNodes.length) {
|
|
839
|
+
addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
if (this._storedNodes.length) {
|
|
843
|
+
this._storedNodes.forEach((node, index) => {
|
|
844
|
+
const idx = currentNodes.indexOf(node);
|
|
845
|
+
if (idx === -1) {
|
|
846
|
+
removedNodes.push(node);
|
|
847
|
+
} else if (idx !== index) {
|
|
848
|
+
movedNodes.push(node);
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (addedNodes.length || removedNodes.length || movedNodes.length) {
|
|
854
|
+
this.callback({ addedNodes, movedNodes, removedNodes });
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
this._storedNodes = currentNodes;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* @license
|
|
863
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
11
864
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
12
865
|
*/
|
|
13
866
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
867
|
+
let uniqueId$1 = 0;
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Returns a unique integer id.
|
|
871
|
+
*
|
|
872
|
+
* @return {number}
|
|
873
|
+
*/
|
|
874
|
+
function generateUniqueId$1() {
|
|
875
|
+
// eslint-disable-next-line no-plusplus
|
|
876
|
+
return uniqueId$1++;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* @license
|
|
881
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
882
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
883
|
+
*/
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* A controller for providing content to slot element and observing changes.
|
|
887
|
+
*/
|
|
888
|
+
class SlotController$1 extends EventTarget {
|
|
889
|
+
/**
|
|
890
|
+
* Ensure that every instance has unique ID.
|
|
891
|
+
*
|
|
892
|
+
* @param {HTMLElement} host
|
|
893
|
+
* @param {string} slotName
|
|
894
|
+
* @return {string}
|
|
895
|
+
* @protected
|
|
896
|
+
*/
|
|
897
|
+
static generateId(host, slotName) {
|
|
898
|
+
const prefix = slotName || 'default';
|
|
899
|
+
return `${prefix}-${host.localName}-${generateUniqueId$1()}`;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
constructor(host, slotName, tagName, config = {}) {
|
|
903
|
+
super();
|
|
904
|
+
|
|
905
|
+
const { initializer, multiple, observe, useUniqueId } = config;
|
|
906
|
+
|
|
907
|
+
this.host = host;
|
|
908
|
+
this.slotName = slotName;
|
|
909
|
+
this.tagName = tagName;
|
|
910
|
+
this.observe = typeof observe === 'boolean' ? observe : true;
|
|
911
|
+
this.multiple = typeof multiple === 'boolean' ? multiple : false;
|
|
912
|
+
this.slotInitializer = initializer;
|
|
913
|
+
|
|
914
|
+
if (multiple) {
|
|
915
|
+
this.nodes = [];
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// Only generate the default ID if requested by the controller.
|
|
919
|
+
if (useUniqueId) {
|
|
920
|
+
this.defaultId = this.constructor.generateId(host, slotName);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
hostConnected() {
|
|
925
|
+
if (!this.initialized) {
|
|
926
|
+
if (this.multiple) {
|
|
927
|
+
this.initMultiple();
|
|
928
|
+
} else {
|
|
929
|
+
this.initSingle();
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
if (this.observe) {
|
|
933
|
+
this.observeSlot();
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
this.initialized = true;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/** @protected */
|
|
941
|
+
initSingle() {
|
|
942
|
+
let node = this.getSlotChild();
|
|
943
|
+
|
|
944
|
+
if (!node) {
|
|
945
|
+
node = this.attachDefaultNode();
|
|
946
|
+
this.initNode(node);
|
|
947
|
+
} else {
|
|
948
|
+
this.node = node;
|
|
949
|
+
this.initAddedNode(node);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/** @protected */
|
|
954
|
+
initMultiple() {
|
|
955
|
+
const children = this.getSlotChildren();
|
|
956
|
+
|
|
957
|
+
if (children.length === 0) {
|
|
958
|
+
const defaultNode = this.attachDefaultNode();
|
|
959
|
+
if (defaultNode) {
|
|
960
|
+
this.nodes = [defaultNode];
|
|
961
|
+
this.initNode(defaultNode);
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
this.nodes = children;
|
|
965
|
+
children.forEach((node) => {
|
|
966
|
+
this.initAddedNode(node);
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Create and attach default node using the provided tag name, if any.
|
|
973
|
+
* @return {Node | undefined}
|
|
974
|
+
* @protected
|
|
975
|
+
*/
|
|
976
|
+
attachDefaultNode() {
|
|
977
|
+
const { host, slotName, tagName } = this;
|
|
978
|
+
|
|
979
|
+
// Check if the node was created previously and if so, reuse it.
|
|
980
|
+
let node = this.defaultNode;
|
|
981
|
+
|
|
982
|
+
// Tag name is optional, sometimes we don't init default content.
|
|
983
|
+
if (!node && tagName) {
|
|
984
|
+
node = document.createElement(tagName);
|
|
985
|
+
if (node instanceof Element) {
|
|
986
|
+
if (slotName !== '') {
|
|
987
|
+
node.setAttribute('slot', slotName);
|
|
988
|
+
}
|
|
989
|
+
this.node = node;
|
|
990
|
+
this.defaultNode = node;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (node) {
|
|
995
|
+
host.appendChild(node);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return node;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
1003
|
+
* @return {Node}
|
|
1004
|
+
*/
|
|
1005
|
+
getSlotChildren() {
|
|
1006
|
+
const { slotName } = this;
|
|
1007
|
+
return Array.from(this.host.childNodes).filter((node) => {
|
|
1008
|
+
// Either an element (any slot) or a text node (only un-named slot).
|
|
1009
|
+
return (
|
|
1010
|
+
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
1011
|
+
(node.nodeType === Node.TEXT_NODE && node.textContent.trim() && slotName === '')
|
|
1012
|
+
);
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* Return a reference to the node managed by the controller.
|
|
1018
|
+
* @return {Node}
|
|
1019
|
+
*/
|
|
1020
|
+
getSlotChild() {
|
|
1021
|
+
return this.getSlotChildren()[0];
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
1026
|
+
*
|
|
1027
|
+
* @param {Node} node
|
|
1028
|
+
* @protected
|
|
1029
|
+
*/
|
|
1030
|
+
initNode(node) {
|
|
1031
|
+
const { slotInitializer } = this;
|
|
1032
|
+
// Don't try to bind `this` to initializer (normally it's arrow function).
|
|
1033
|
+
// Instead, pass the host as a first argument to access component's state.
|
|
1034
|
+
if (slotInitializer) {
|
|
1035
|
+
slotInitializer(node, this.host);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Override to initialize the newly added custom node.
|
|
1041
|
+
*
|
|
1042
|
+
* @param {Node} _node
|
|
1043
|
+
* @protected
|
|
1044
|
+
*/
|
|
1045
|
+
initCustomNode(_node) {}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Override to teardown slotted node when it's removed.
|
|
1049
|
+
*
|
|
1050
|
+
* @param {Node} _node
|
|
1051
|
+
* @protected
|
|
1052
|
+
*/
|
|
1053
|
+
teardownNode(_node) {}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
1057
|
+
*
|
|
1058
|
+
* @param {Node} node
|
|
1059
|
+
* @protected
|
|
1060
|
+
*/
|
|
1061
|
+
initAddedNode(node) {
|
|
1062
|
+
if (node !== this.defaultNode) {
|
|
1063
|
+
this.initCustomNode(node);
|
|
1064
|
+
this.initNode(node);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Setup the observer to manage slot content changes.
|
|
1070
|
+
* @protected
|
|
1071
|
+
*/
|
|
1072
|
+
observeSlot() {
|
|
1073
|
+
const { slotName } = this;
|
|
1074
|
+
const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
|
|
1075
|
+
const slot = this.host.shadowRoot.querySelector(selector);
|
|
1076
|
+
|
|
1077
|
+
this.__slotObserver = new SlotObserver$1(slot, ({ addedNodes, removedNodes }) => {
|
|
1078
|
+
const current = this.multiple ? this.nodes : [this.node];
|
|
1079
|
+
|
|
1080
|
+
// Calling `slot.assignedNodes()` includes whitespace text nodes in case of default slot:
|
|
1081
|
+
// unlike comment nodes, they are not filtered out. So we need to manually ignore them.
|
|
1082
|
+
const newNodes = addedNodes.filter((node) => !isEmptyTextNode$1(node) && !current.includes(node));
|
|
1083
|
+
|
|
1084
|
+
if (removedNodes.length) {
|
|
1085
|
+
this.nodes = current.filter((node) => !removedNodes.includes(node));
|
|
1086
|
+
|
|
1087
|
+
removedNodes.forEach((node) => {
|
|
1088
|
+
this.teardownNode(node);
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (newNodes && newNodes.length > 0) {
|
|
1093
|
+
if (this.multiple) {
|
|
1094
|
+
// Remove default node if exists
|
|
1095
|
+
if (this.defaultNode) {
|
|
1096
|
+
this.defaultNode.remove();
|
|
1097
|
+
}
|
|
1098
|
+
this.nodes = [...current, ...newNodes].filter((node) => node !== this.defaultNode);
|
|
1099
|
+
newNodes.forEach((node) => {
|
|
1100
|
+
this.initAddedNode(node);
|
|
1101
|
+
});
|
|
1102
|
+
} else {
|
|
1103
|
+
// Remove previous node if exists
|
|
1104
|
+
if (this.node) {
|
|
1105
|
+
this.node.remove();
|
|
1106
|
+
}
|
|
1107
|
+
this.node = newNodes[0];
|
|
1108
|
+
this.initAddedNode(this.node);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* @license
|
|
1117
|
+
* Copyright (c) 2022 - 2023 Vaadin Ltd.
|
|
1118
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1119
|
+
*/
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* A controller that manages the slotted tooltip element.
|
|
1123
|
+
*/
|
|
1124
|
+
class TooltipController extends SlotController$1 {
|
|
1125
|
+
constructor(host) {
|
|
1126
|
+
// Do not provide slot factory to create tooltip lazily.
|
|
1127
|
+
super(host, 'tooltip');
|
|
1128
|
+
|
|
1129
|
+
this.setTarget(host);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* Override to initialize the newly added custom tooltip.
|
|
1134
|
+
*
|
|
1135
|
+
* @param {Node} tooltipNode
|
|
1136
|
+
* @protected
|
|
1137
|
+
* @override
|
|
1138
|
+
*/
|
|
1139
|
+
initCustomNode(tooltipNode) {
|
|
1140
|
+
tooltipNode.target = this.target;
|
|
1141
|
+
|
|
1142
|
+
if (this.ariaTarget !== undefined) {
|
|
1143
|
+
tooltipNode.ariaTarget = this.ariaTarget;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if (this.context !== undefined) {
|
|
1147
|
+
tooltipNode.context = this.context;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
if (this.manual !== undefined) {
|
|
1151
|
+
tooltipNode.manual = this.manual;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
if (this.opened !== undefined) {
|
|
1155
|
+
tooltipNode.opened = this.opened;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
if (this.position !== undefined) {
|
|
1159
|
+
tooltipNode._position = this.position;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
if (this.shouldShow !== undefined) {
|
|
1163
|
+
tooltipNode.shouldShow = this.shouldShow;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
this.__notifyChange();
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Override to notify the host when the tooltip is removed.
|
|
1171
|
+
*
|
|
1172
|
+
* @param {Node} tooltipNode
|
|
1173
|
+
* @protected
|
|
1174
|
+
* @override
|
|
1175
|
+
*/
|
|
1176
|
+
teardownNode() {
|
|
1177
|
+
this.__notifyChange();
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/**
|
|
1181
|
+
* Set an HTML element for linking with the tooltip overlay
|
|
1182
|
+
* via `aria-describedby` attribute used by screen readers.
|
|
1183
|
+
* @param {HTMLElement} ariaTarget
|
|
1184
|
+
*/
|
|
1185
|
+
setAriaTarget(ariaTarget) {
|
|
1186
|
+
this.ariaTarget = ariaTarget;
|
|
1187
|
+
|
|
1188
|
+
const tooltipNode = this.node;
|
|
1189
|
+
if (tooltipNode) {
|
|
1190
|
+
tooltipNode.ariaTarget = ariaTarget;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Set a context object to be used by generator.
|
|
1196
|
+
* @param {object} context
|
|
1197
|
+
*/
|
|
1198
|
+
setContext(context) {
|
|
1199
|
+
this.context = context;
|
|
1200
|
+
|
|
1201
|
+
const tooltipNode = this.node;
|
|
1202
|
+
if (tooltipNode) {
|
|
1203
|
+
tooltipNode.context = context;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Toggle manual state on the slotted tooltip.
|
|
1209
|
+
* @param {boolean} manual
|
|
1210
|
+
*/
|
|
1211
|
+
setManual(manual) {
|
|
1212
|
+
this.manual = manual;
|
|
1213
|
+
|
|
1214
|
+
const tooltipNode = this.node;
|
|
1215
|
+
if (tooltipNode) {
|
|
1216
|
+
tooltipNode.manual = manual;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Toggle opened state on the slotted tooltip.
|
|
1222
|
+
* @param {boolean} opened
|
|
1223
|
+
*/
|
|
1224
|
+
setOpened(opened) {
|
|
1225
|
+
this.opened = opened;
|
|
1226
|
+
|
|
1227
|
+
const tooltipNode = this.node;
|
|
1228
|
+
if (tooltipNode) {
|
|
1229
|
+
tooltipNode.opened = opened;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Set default position for the slotted tooltip.
|
|
1235
|
+
* This can be overridden by setting the position
|
|
1236
|
+
* using corresponding property or attribute.
|
|
1237
|
+
* @param {string} position
|
|
1238
|
+
*/
|
|
1239
|
+
setPosition(position) {
|
|
1240
|
+
this.position = position;
|
|
1241
|
+
|
|
1242
|
+
const tooltipNode = this.node;
|
|
1243
|
+
if (tooltipNode) {
|
|
1244
|
+
tooltipNode._position = position;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Set function used to detect whether to show
|
|
1250
|
+
* the tooltip based on a condition.
|
|
1251
|
+
* @param {Function} shouldShow
|
|
1252
|
+
*/
|
|
1253
|
+
setShouldShow(shouldShow) {
|
|
1254
|
+
this.shouldShow = shouldShow;
|
|
1255
|
+
|
|
1256
|
+
const tooltipNode = this.node;
|
|
1257
|
+
if (tooltipNode) {
|
|
1258
|
+
tooltipNode.shouldShow = shouldShow;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Set an HTML element to attach the tooltip to.
|
|
1264
|
+
* @param {HTMLElement} target
|
|
1265
|
+
*/
|
|
1266
|
+
setTarget(target) {
|
|
1267
|
+
this.target = target;
|
|
1268
|
+
|
|
1269
|
+
const tooltipNode = this.node;
|
|
1270
|
+
if (tooltipNode) {
|
|
1271
|
+
tooltipNode.target = target;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/** @private */
|
|
1276
|
+
__notifyChange() {
|
|
1277
|
+
this.dispatchEvent(new CustomEvent('tooltip-changed', { detail: { node: this.node } }));
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
17
1280
|
|
|
18
1281
|
/**
|
|
19
1282
|
* @license
|
|
20
|
-
* Copyright (c) 2021 -
|
|
1283
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
21
1284
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
22
1285
|
*/
|
|
23
1286
|
|
|
@@ -71,6 +1334,15 @@ const InputFieldMixin = (superclass) =>
|
|
|
71
1334
|
return [...super.delegateAttrs, 'autocapitalize', 'autocomplete', 'autocorrect'];
|
|
72
1335
|
}
|
|
73
1336
|
|
|
1337
|
+
// Workaround for https://github.com/Polymer/polymer/issues/5259
|
|
1338
|
+
get __data() {
|
|
1339
|
+
return this.__dataValue || {};
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
set __data(value) {
|
|
1343
|
+
this.__dataValue = value;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
74
1346
|
/**
|
|
75
1347
|
* @param {HTMLElement} input
|
|
76
1348
|
* @protected
|
|
@@ -92,15 +1364,6 @@ const InputFieldMixin = (superclass) =>
|
|
|
92
1364
|
}
|
|
93
1365
|
}
|
|
94
1366
|
|
|
95
|
-
// Workaround for https://github.com/Polymer/polymer/issues/5259
|
|
96
|
-
get __data() {
|
|
97
|
-
return this.__dataValue || {};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
set __data(value) {
|
|
101
|
-
this.__dataValue = value;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
1367
|
/**
|
|
105
1368
|
* Override an event listener from `FocusMixin`.
|
|
106
1369
|
* @param {boolean} focused
|
|
@@ -110,7 +1373,9 @@ const InputFieldMixin = (superclass) =>
|
|
|
110
1373
|
_setFocused(focused) {
|
|
111
1374
|
super._setFocused(focused);
|
|
112
1375
|
|
|
113
|
-
|
|
1376
|
+
// Do not validate when focusout is caused by document
|
|
1377
|
+
// losing focus, which happens on browser tab switch.
|
|
1378
|
+
if (!focused && document.hasFocus()) {
|
|
114
1379
|
this.validate();
|
|
115
1380
|
}
|
|
116
1381
|
}
|
|
@@ -130,35 +1395,109 @@ const InputFieldMixin = (superclass) =>
|
|
|
130
1395
|
}
|
|
131
1396
|
}
|
|
132
1397
|
|
|
133
|
-
/**
|
|
134
|
-
* Override an observer from `InputMixin` to validate the field
|
|
135
|
-
* when a new value is set programmatically.
|
|
136
|
-
*
|
|
137
|
-
* @param {string | undefined} newValue
|
|
138
|
-
* @param {string | undefined} oldValue
|
|
139
|
-
* @protected
|
|
140
|
-
* @override
|
|
141
|
-
*/
|
|
142
|
-
_valueChanged(newValue, oldValue) {
|
|
143
|
-
super._valueChanged(newValue, oldValue);
|
|
1398
|
+
/**
|
|
1399
|
+
* Override an observer from `InputMixin` to validate the field
|
|
1400
|
+
* when a new value is set programmatically.
|
|
1401
|
+
*
|
|
1402
|
+
* @param {string | undefined} newValue
|
|
1403
|
+
* @param {string | undefined} oldValue
|
|
1404
|
+
* @protected
|
|
1405
|
+
* @override
|
|
1406
|
+
*/
|
|
1407
|
+
_valueChanged(newValue, oldValue) {
|
|
1408
|
+
super._valueChanged(newValue, oldValue);
|
|
1409
|
+
|
|
1410
|
+
if (oldValue === undefined) {
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
if (this.invalid) {
|
|
1415
|
+
this.validate();
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* @license
|
|
1422
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1423
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1424
|
+
*/
|
|
1425
|
+
|
|
1426
|
+
/**
|
|
1427
|
+
* A mixin providing common text field functionality.
|
|
1428
|
+
*
|
|
1429
|
+
* @polymerMixin
|
|
1430
|
+
* @mixes InputFieldMixin
|
|
1431
|
+
*/
|
|
1432
|
+
const TextFieldMixin = (superClass) =>
|
|
1433
|
+
class TextFieldMixinClass extends InputFieldMixin(superClass) {
|
|
1434
|
+
static get properties() {
|
|
1435
|
+
return {
|
|
1436
|
+
/**
|
|
1437
|
+
* Maximum number of characters (in Unicode code points) that the user can enter.
|
|
1438
|
+
*/
|
|
1439
|
+
maxlength: {
|
|
1440
|
+
type: Number,
|
|
1441
|
+
},
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* Minimum number of characters (in Unicode code points) that the user can enter.
|
|
1445
|
+
*/
|
|
1446
|
+
minlength: {
|
|
1447
|
+
type: Number,
|
|
1448
|
+
},
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* A regular expression that the value is checked against.
|
|
1452
|
+
* The pattern must match the entire value, not just some subset.
|
|
1453
|
+
*/
|
|
1454
|
+
pattern: {
|
|
1455
|
+
type: String,
|
|
1456
|
+
},
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
static get delegateAttrs() {
|
|
1461
|
+
return [...super.delegateAttrs, 'maxlength', 'minlength', 'pattern'];
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
static get constraints() {
|
|
1465
|
+
return [...super.constraints, 'maxlength', 'minlength', 'pattern'];
|
|
1466
|
+
}
|
|
144
1467
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
1468
|
+
constructor() {
|
|
1469
|
+
super();
|
|
1470
|
+
this._setType('text');
|
|
1471
|
+
}
|
|
148
1472
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
1473
|
+
/** @protected */
|
|
1474
|
+
get clearElement() {
|
|
1475
|
+
return this.$.clearButton;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/** @protected */
|
|
1479
|
+
ready() {
|
|
1480
|
+
super.ready();
|
|
1481
|
+
|
|
1482
|
+
this.addController(
|
|
1483
|
+
new InputController(this, (input) => {
|
|
1484
|
+
this._setInputElement(input);
|
|
1485
|
+
this._setFocusElement(input);
|
|
1486
|
+
this.stateTarget = input;
|
|
1487
|
+
this.ariaTarget = input;
|
|
1488
|
+
}),
|
|
1489
|
+
);
|
|
1490
|
+
this.addController(new LabelledInputController(this.inputElement, this._labelController));
|
|
152
1491
|
}
|
|
153
1492
|
};
|
|
154
1493
|
|
|
155
1494
|
/**
|
|
156
1495
|
* @license
|
|
157
|
-
* Copyright (c) 2017 -
|
|
1496
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
158
1497
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
159
1498
|
*/
|
|
160
1499
|
|
|
161
|
-
registerStyles('vaadin-text-field', inputFieldShared$1, { moduleId: 'vaadin-text-field-styles' });
|
|
1500
|
+
registerStyles$1('vaadin-text-field', inputFieldShared$1, { moduleId: 'vaadin-text-field-styles' });
|
|
162
1501
|
|
|
163
1502
|
/**
|
|
164
1503
|
* `<vaadin-text-field>` is a web component that allows the user to input and edit text.
|
|
@@ -215,7 +1554,7 @@ registerStyles('vaadin-text-field', inputFieldShared$1, { moduleId: 'vaadin-text
|
|
|
215
1554
|
* `focus-ring` | Set when the element is keyboard focused | :host
|
|
216
1555
|
* `readonly` | Set to a readonly text field | :host
|
|
217
1556
|
*
|
|
218
|
-
* See [Styling Components](https://vaadin.com/docs/latest/styling/
|
|
1557
|
+
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
|
|
219
1558
|
*
|
|
220
1559
|
* @fires {Event} input - Fired when the value is changed by the user: on every typing keystroke, and the value is cleared using the clear button.
|
|
221
1560
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
@@ -223,13 +1562,13 @@ registerStyles('vaadin-text-field', inputFieldShared$1, { moduleId: 'vaadin-text
|
|
|
223
1562
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
224
1563
|
* @fires {CustomEvent} validated - Fired whenever the field is validated.
|
|
225
1564
|
*
|
|
1565
|
+
* @customElement
|
|
226
1566
|
* @extends HTMLElement
|
|
227
1567
|
* @mixes ElementMixin
|
|
228
1568
|
* @mixes ThemableMixin
|
|
229
|
-
* @mixes
|
|
230
|
-
* @mixes InputFieldMixin
|
|
1569
|
+
* @mixes TextFieldMixin
|
|
231
1570
|
*/
|
|
232
|
-
class TextField extends
|
|
1571
|
+
class TextField extends TextFieldMixin(ThemableMixin(ElementMixin(PolymerElement))) {
|
|
233
1572
|
static get is() {
|
|
234
1573
|
return 'vaadin-text-field';
|
|
235
1574
|
}
|
|
@@ -291,49 +1630,89 @@ class TextField extends PatternMixin(InputFieldMixin(ThemableMixin(ElementMixin(
|
|
|
291
1630
|
};
|
|
292
1631
|
}
|
|
293
1632
|
|
|
294
|
-
static get delegateAttrs() {
|
|
295
|
-
return [...super.delegateAttrs, 'maxlength', 'minlength'];
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
static get constraints() {
|
|
299
|
-
return [...super.constraints, 'maxlength', 'minlength'];
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
constructor() {
|
|
303
|
-
super();
|
|
304
|
-
this._setType('text');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/** @protected */
|
|
308
|
-
get clearElement() {
|
|
309
|
-
return this.$.clearButton;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
1633
|
/** @protected */
|
|
313
1634
|
ready() {
|
|
314
1635
|
super.ready();
|
|
315
1636
|
|
|
316
|
-
this.addController(
|
|
317
|
-
new InputController(this, (input) => {
|
|
318
|
-
this._setInputElement(input);
|
|
319
|
-
this._setFocusElement(input);
|
|
320
|
-
this.stateTarget = input;
|
|
321
|
-
this.ariaTarget = input;
|
|
322
|
-
}),
|
|
323
|
-
);
|
|
324
|
-
this.addController(new LabelledInputController(this.inputElement, this._labelController));
|
|
325
|
-
|
|
326
1637
|
this._tooltipController = new TooltipController(this);
|
|
327
1638
|
this._tooltipController.setPosition('top');
|
|
1639
|
+
this._tooltipController.setAriaTarget(this.inputElement);
|
|
328
1640
|
this.addController(this._tooltipController);
|
|
329
1641
|
}
|
|
330
1642
|
}
|
|
331
1643
|
|
|
332
|
-
|
|
1644
|
+
defineCustomElement$2(TextField);
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* @license
|
|
1648
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
1649
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1650
|
+
*/
|
|
1651
|
+
|
|
1652
|
+
/**
|
|
1653
|
+
* Check if the custom element type has themes applied.
|
|
1654
|
+
* @param {Function} elementClass
|
|
1655
|
+
* @returns {boolean}
|
|
1656
|
+
*/
|
|
1657
|
+
function classHasThemes(elementClass) {
|
|
1658
|
+
return elementClass && Object.prototype.hasOwnProperty.call(elementClass, '__themes');
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
/**
|
|
1662
|
+
* Check if the custom element type has themes applied.
|
|
1663
|
+
* @param {string} tagName
|
|
1664
|
+
* @returns {boolean}
|
|
1665
|
+
*/
|
|
1666
|
+
function hasThemes(tagName) {
|
|
1667
|
+
return classHasThemes(customElements.get(tagName));
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
/**
|
|
1671
|
+
* Flattens the styles into a single array of styles.
|
|
1672
|
+
* @param {CSSResultGroup} styles
|
|
1673
|
+
* @param {CSSResult[]} result
|
|
1674
|
+
* @returns {CSSResult[]}
|
|
1675
|
+
*/
|
|
1676
|
+
function flattenStyles(styles = []) {
|
|
1677
|
+
return [styles].flat(Infinity).filter((style) => {
|
|
1678
|
+
if (style instanceof o) {
|
|
1679
|
+
return true;
|
|
1680
|
+
}
|
|
1681
|
+
console.warn('An item in styles is not of type CSSResult. Use `unsafeCSS` or `css`.');
|
|
1682
|
+
return false;
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
/**
|
|
1687
|
+
* Registers CSS styles for a component type. Make sure to register the styles before
|
|
1688
|
+
* the first instance of a component of the type is attached to DOM.
|
|
1689
|
+
*
|
|
1690
|
+
* @param {string} themeFor The local/tag name of the component type to register the styles for
|
|
1691
|
+
* @param {CSSResultGroup} styles The CSS style rules to be registered for the component type
|
|
1692
|
+
* matching themeFor and included in the local scope of each component instance
|
|
1693
|
+
* @param {{moduleId?: string, include?: string | string[]}} options Additional options
|
|
1694
|
+
* @return {void}
|
|
1695
|
+
*/
|
|
1696
|
+
function registerStyles(themeFor, styles, options = {}) {
|
|
1697
|
+
if (themeFor) {
|
|
1698
|
+
if (hasThemes(themeFor)) {
|
|
1699
|
+
console.warn(`The custom element definition for "${themeFor}"
|
|
1700
|
+
was finalized before a style module was registered.
|
|
1701
|
+
Make sure to add component specific style modules before
|
|
1702
|
+
importing the corresponding custom element.`);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
styles = flattenStyles(styles);
|
|
1707
|
+
|
|
1708
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
1709
|
+
window.Vaadin.styleModules.registerStyles(themeFor, styles, options);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
333
1712
|
|
|
334
1713
|
/**
|
|
335
1714
|
* @license
|
|
336
|
-
* Copyright (c) 2021 -
|
|
1715
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
337
1716
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
338
1717
|
*/
|
|
339
1718
|
|
|
@@ -358,7 +1737,7 @@ registerStyles('vaadin-password-field-button', [button, passwordFieldButton], {
|
|
|
358
1737
|
|
|
359
1738
|
/**
|
|
360
1739
|
* @license
|
|
361
|
-
* Copyright (c) 2021 -
|
|
1740
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
362
1741
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
363
1742
|
*/
|
|
364
1743
|
|
|
@@ -386,13 +1765,36 @@ registerStyles('vaadin-password-field', [inputFieldShared, passwordField], { mod
|
|
|
386
1765
|
|
|
387
1766
|
/**
|
|
388
1767
|
* @license
|
|
389
|
-
* Copyright (c) 2021 -
|
|
1768
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1769
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1770
|
+
*/
|
|
1771
|
+
function defineCustomElement$1(CustomElement) {
|
|
1772
|
+
const defined = customElements.get(CustomElement.is);
|
|
1773
|
+
if (!defined) {
|
|
1774
|
+
customElements.define(CustomElement.is, CustomElement);
|
|
1775
|
+
} else {
|
|
1776
|
+
const definedVersion = defined.version;
|
|
1777
|
+
if (definedVersion && CustomElement.version && definedVersion === CustomElement.version) {
|
|
1778
|
+
// Just loading the same thing again
|
|
1779
|
+
console.warn(`The component ${CustomElement.is} has been loaded twice`);
|
|
1780
|
+
} else {
|
|
1781
|
+
console.error(
|
|
1782
|
+
`Tried to define ${CustomElement.is} version ${CustomElement.version} when version ${defined.version} is already in use. Something will probably break.`,
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* @license
|
|
1790
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
390
1791
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
391
1792
|
*/
|
|
392
1793
|
|
|
393
1794
|
/**
|
|
394
1795
|
* An element used internally by `<vaadin-password-field>`. Not intended to be used separately.
|
|
395
1796
|
*
|
|
1797
|
+
* @customElement
|
|
396
1798
|
* @extends Button
|
|
397
1799
|
* @private
|
|
398
1800
|
*/
|
|
@@ -417,11 +1819,387 @@ class PasswordFieldButton extends Button {
|
|
|
417
1819
|
}
|
|
418
1820
|
}
|
|
419
1821
|
|
|
420
|
-
|
|
1822
|
+
defineCustomElement$1(PasswordFieldButton);
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* @license
|
|
1826
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1827
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1828
|
+
*/
|
|
1829
|
+
|
|
1830
|
+
/**
|
|
1831
|
+
* Returns true if the given node is an empty text node, false otherwise.
|
|
1832
|
+
*
|
|
1833
|
+
* @param {Node} node
|
|
1834
|
+
* @return {boolean}
|
|
1835
|
+
*/
|
|
1836
|
+
function isEmptyTextNode(node) {
|
|
1837
|
+
return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '';
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/**
|
|
1841
|
+
* @license
|
|
1842
|
+
* Copyright (c) 2023 Vaadin Ltd.
|
|
1843
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1844
|
+
*/
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* A helper for observing slot changes.
|
|
1848
|
+
*/
|
|
1849
|
+
class SlotObserver {
|
|
1850
|
+
constructor(slot, callback) {
|
|
1851
|
+
/** @type HTMLSlotElement */
|
|
1852
|
+
this.slot = slot;
|
|
1853
|
+
|
|
1854
|
+
/** @type Function */
|
|
1855
|
+
this.callback = callback;
|
|
1856
|
+
|
|
1857
|
+
/** @type {Node[]} */
|
|
1858
|
+
this._storedNodes = [];
|
|
1859
|
+
|
|
1860
|
+
this._connected = false;
|
|
1861
|
+
this._scheduled = false;
|
|
1862
|
+
|
|
1863
|
+
this._boundSchedule = () => {
|
|
1864
|
+
this._schedule();
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
this.connect();
|
|
1868
|
+
this._schedule();
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
/**
|
|
1872
|
+
* Activates an observer. This method is automatically called when
|
|
1873
|
+
* a `SlotObserver` is created. It should only be called to re-activate
|
|
1874
|
+
* an observer that has been deactivated via the `disconnect` method.
|
|
1875
|
+
*/
|
|
1876
|
+
connect() {
|
|
1877
|
+
this.slot.addEventListener('slotchange', this._boundSchedule);
|
|
1878
|
+
this._connected = true;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
/**
|
|
1882
|
+
* Deactivates the observer. After calling this method the observer callback
|
|
1883
|
+
* will not be called when changes to slotted nodes occur. The `connect` method
|
|
1884
|
+
* may be subsequently called to reactivate the observer.
|
|
1885
|
+
*/
|
|
1886
|
+
disconnect() {
|
|
1887
|
+
this.slot.removeEventListener('slotchange', this._boundSchedule);
|
|
1888
|
+
this._connected = false;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/** @private */
|
|
1892
|
+
_schedule() {
|
|
1893
|
+
if (!this._scheduled) {
|
|
1894
|
+
this._scheduled = true;
|
|
1895
|
+
|
|
1896
|
+
queueMicrotask(() => {
|
|
1897
|
+
this.flush();
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* Run the observer callback synchronously.
|
|
1904
|
+
*/
|
|
1905
|
+
flush() {
|
|
1906
|
+
if (!this._connected) {
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
this._scheduled = false;
|
|
1911
|
+
|
|
1912
|
+
this._processNodes();
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
/** @private */
|
|
1916
|
+
_processNodes() {
|
|
1917
|
+
const currentNodes = this.slot.assignedNodes({ flatten: true });
|
|
1918
|
+
|
|
1919
|
+
let addedNodes = [];
|
|
1920
|
+
const removedNodes = [];
|
|
1921
|
+
const movedNodes = [];
|
|
1922
|
+
|
|
1923
|
+
if (currentNodes.length) {
|
|
1924
|
+
addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
if (this._storedNodes.length) {
|
|
1928
|
+
this._storedNodes.forEach((node, index) => {
|
|
1929
|
+
const idx = currentNodes.indexOf(node);
|
|
1930
|
+
if (idx === -1) {
|
|
1931
|
+
removedNodes.push(node);
|
|
1932
|
+
} else if (idx !== index) {
|
|
1933
|
+
movedNodes.push(node);
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
if (addedNodes.length || removedNodes.length || movedNodes.length) {
|
|
1939
|
+
this.callback({ addedNodes, movedNodes, removedNodes });
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
this._storedNodes = currentNodes;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
/**
|
|
1947
|
+
* @license
|
|
1948
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1949
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1950
|
+
*/
|
|
1951
|
+
|
|
1952
|
+
let uniqueId = 0;
|
|
1953
|
+
|
|
1954
|
+
/**
|
|
1955
|
+
* Returns a unique integer id.
|
|
1956
|
+
*
|
|
1957
|
+
* @return {number}
|
|
1958
|
+
*/
|
|
1959
|
+
function generateUniqueId() {
|
|
1960
|
+
// eslint-disable-next-line no-plusplus
|
|
1961
|
+
return uniqueId++;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* @license
|
|
1966
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1967
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1968
|
+
*/
|
|
1969
|
+
|
|
1970
|
+
/**
|
|
1971
|
+
* A controller for providing content to slot element and observing changes.
|
|
1972
|
+
*/
|
|
1973
|
+
class SlotController extends EventTarget {
|
|
1974
|
+
/**
|
|
1975
|
+
* Ensure that every instance has unique ID.
|
|
1976
|
+
*
|
|
1977
|
+
* @param {HTMLElement} host
|
|
1978
|
+
* @param {string} slotName
|
|
1979
|
+
* @return {string}
|
|
1980
|
+
* @protected
|
|
1981
|
+
*/
|
|
1982
|
+
static generateId(host, slotName) {
|
|
1983
|
+
const prefix = slotName || 'default';
|
|
1984
|
+
return `${prefix}-${host.localName}-${generateUniqueId()}`;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
constructor(host, slotName, tagName, config = {}) {
|
|
1988
|
+
super();
|
|
1989
|
+
|
|
1990
|
+
const { initializer, multiple, observe, useUniqueId } = config;
|
|
1991
|
+
|
|
1992
|
+
this.host = host;
|
|
1993
|
+
this.slotName = slotName;
|
|
1994
|
+
this.tagName = tagName;
|
|
1995
|
+
this.observe = typeof observe === 'boolean' ? observe : true;
|
|
1996
|
+
this.multiple = typeof multiple === 'boolean' ? multiple : false;
|
|
1997
|
+
this.slotInitializer = initializer;
|
|
1998
|
+
|
|
1999
|
+
if (multiple) {
|
|
2000
|
+
this.nodes = [];
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// Only generate the default ID if requested by the controller.
|
|
2004
|
+
if (useUniqueId) {
|
|
2005
|
+
this.defaultId = this.constructor.generateId(host, slotName);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
hostConnected() {
|
|
2010
|
+
if (!this.initialized) {
|
|
2011
|
+
if (this.multiple) {
|
|
2012
|
+
this.initMultiple();
|
|
2013
|
+
} else {
|
|
2014
|
+
this.initSingle();
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
if (this.observe) {
|
|
2018
|
+
this.observeSlot();
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
this.initialized = true;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/** @protected */
|
|
2026
|
+
initSingle() {
|
|
2027
|
+
let node = this.getSlotChild();
|
|
2028
|
+
|
|
2029
|
+
if (!node) {
|
|
2030
|
+
node = this.attachDefaultNode();
|
|
2031
|
+
this.initNode(node);
|
|
2032
|
+
} else {
|
|
2033
|
+
this.node = node;
|
|
2034
|
+
this.initAddedNode(node);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
/** @protected */
|
|
2039
|
+
initMultiple() {
|
|
2040
|
+
const children = this.getSlotChildren();
|
|
2041
|
+
|
|
2042
|
+
if (children.length === 0) {
|
|
2043
|
+
const defaultNode = this.attachDefaultNode();
|
|
2044
|
+
if (defaultNode) {
|
|
2045
|
+
this.nodes = [defaultNode];
|
|
2046
|
+
this.initNode(defaultNode);
|
|
2047
|
+
}
|
|
2048
|
+
} else {
|
|
2049
|
+
this.nodes = children;
|
|
2050
|
+
children.forEach((node) => {
|
|
2051
|
+
this.initAddedNode(node);
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
/**
|
|
2057
|
+
* Create and attach default node using the provided tag name, if any.
|
|
2058
|
+
* @return {Node | undefined}
|
|
2059
|
+
* @protected
|
|
2060
|
+
*/
|
|
2061
|
+
attachDefaultNode() {
|
|
2062
|
+
const { host, slotName, tagName } = this;
|
|
2063
|
+
|
|
2064
|
+
// Check if the node was created previously and if so, reuse it.
|
|
2065
|
+
let node = this.defaultNode;
|
|
2066
|
+
|
|
2067
|
+
// Tag name is optional, sometimes we don't init default content.
|
|
2068
|
+
if (!node && tagName) {
|
|
2069
|
+
node = document.createElement(tagName);
|
|
2070
|
+
if (node instanceof Element) {
|
|
2071
|
+
if (slotName !== '') {
|
|
2072
|
+
node.setAttribute('slot', slotName);
|
|
2073
|
+
}
|
|
2074
|
+
this.node = node;
|
|
2075
|
+
this.defaultNode = node;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
if (node) {
|
|
2080
|
+
host.appendChild(node);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
return node;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
2088
|
+
* @return {Node}
|
|
2089
|
+
*/
|
|
2090
|
+
getSlotChildren() {
|
|
2091
|
+
const { slotName } = this;
|
|
2092
|
+
return Array.from(this.host.childNodes).filter((node) => {
|
|
2093
|
+
// Either an element (any slot) or a text node (only un-named slot).
|
|
2094
|
+
return (
|
|
2095
|
+
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
2096
|
+
(node.nodeType === Node.TEXT_NODE && node.textContent.trim() && slotName === '')
|
|
2097
|
+
);
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
/**
|
|
2102
|
+
* Return a reference to the node managed by the controller.
|
|
2103
|
+
* @return {Node}
|
|
2104
|
+
*/
|
|
2105
|
+
getSlotChild() {
|
|
2106
|
+
return this.getSlotChildren()[0];
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
/**
|
|
2110
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
2111
|
+
*
|
|
2112
|
+
* @param {Node} node
|
|
2113
|
+
* @protected
|
|
2114
|
+
*/
|
|
2115
|
+
initNode(node) {
|
|
2116
|
+
const { slotInitializer } = this;
|
|
2117
|
+
// Don't try to bind `this` to initializer (normally it's arrow function).
|
|
2118
|
+
// Instead, pass the host as a first argument to access component's state.
|
|
2119
|
+
if (slotInitializer) {
|
|
2120
|
+
slotInitializer(node, this.host);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
/**
|
|
2125
|
+
* Override to initialize the newly added custom node.
|
|
2126
|
+
*
|
|
2127
|
+
* @param {Node} _node
|
|
2128
|
+
* @protected
|
|
2129
|
+
*/
|
|
2130
|
+
initCustomNode(_node) {}
|
|
2131
|
+
|
|
2132
|
+
/**
|
|
2133
|
+
* Override to teardown slotted node when it's removed.
|
|
2134
|
+
*
|
|
2135
|
+
* @param {Node} _node
|
|
2136
|
+
* @protected
|
|
2137
|
+
*/
|
|
2138
|
+
teardownNode(_node) {}
|
|
2139
|
+
|
|
2140
|
+
/**
|
|
2141
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
2142
|
+
*
|
|
2143
|
+
* @param {Node} node
|
|
2144
|
+
* @protected
|
|
2145
|
+
*/
|
|
2146
|
+
initAddedNode(node) {
|
|
2147
|
+
if (node !== this.defaultNode) {
|
|
2148
|
+
this.initCustomNode(node);
|
|
2149
|
+
this.initNode(node);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* Setup the observer to manage slot content changes.
|
|
2155
|
+
* @protected
|
|
2156
|
+
*/
|
|
2157
|
+
observeSlot() {
|
|
2158
|
+
const { slotName } = this;
|
|
2159
|
+
const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
|
|
2160
|
+
const slot = this.host.shadowRoot.querySelector(selector);
|
|
2161
|
+
|
|
2162
|
+
this.__slotObserver = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
|
|
2163
|
+
const current = this.multiple ? this.nodes : [this.node];
|
|
2164
|
+
|
|
2165
|
+
// Calling `slot.assignedNodes()` includes whitespace text nodes in case of default slot:
|
|
2166
|
+
// unlike comment nodes, they are not filtered out. So we need to manually ignore them.
|
|
2167
|
+
const newNodes = addedNodes.filter((node) => !isEmptyTextNode(node) && !current.includes(node));
|
|
2168
|
+
|
|
2169
|
+
if (removedNodes.length) {
|
|
2170
|
+
this.nodes = current.filter((node) => !removedNodes.includes(node));
|
|
2171
|
+
|
|
2172
|
+
removedNodes.forEach((node) => {
|
|
2173
|
+
this.teardownNode(node);
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
if (newNodes && newNodes.length > 0) {
|
|
2178
|
+
if (this.multiple) {
|
|
2179
|
+
// Remove default node if exists
|
|
2180
|
+
if (this.defaultNode) {
|
|
2181
|
+
this.defaultNode.remove();
|
|
2182
|
+
}
|
|
2183
|
+
this.nodes = [...current, ...newNodes].filter((node) => node !== this.defaultNode);
|
|
2184
|
+
newNodes.forEach((node) => {
|
|
2185
|
+
this.initAddedNode(node);
|
|
2186
|
+
});
|
|
2187
|
+
} else {
|
|
2188
|
+
// Remove previous node if exists
|
|
2189
|
+
if (this.node) {
|
|
2190
|
+
this.node.remove();
|
|
2191
|
+
}
|
|
2192
|
+
this.node = newNodes[0];
|
|
2193
|
+
this.initAddedNode(this.node);
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
421
2199
|
|
|
422
2200
|
/**
|
|
423
2201
|
* @license
|
|
424
|
-
* Copyright (c) 2021 -
|
|
2202
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
425
2203
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
426
2204
|
*/
|
|
427
2205
|
|
|
@@ -457,7 +2235,7 @@ let memoizedTemplate;
|
|
|
457
2235
|
* -------------------|---------------------------------
|
|
458
2236
|
* `password-visible` | Set when the password is visible
|
|
459
2237
|
*
|
|
460
|
-
* See [Styling Components](https://vaadin.com/docs/latest/styling/
|
|
2238
|
+
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
|
|
461
2239
|
*
|
|
462
2240
|
* @fires {Event} input - Fired when the value is changed by the user: on every typing keystroke, and the value is cleared using the clear button.
|
|
463
2241
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
@@ -465,6 +2243,7 @@ let memoizedTemplate;
|
|
|
465
2243
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
466
2244
|
* @fires {CustomEvent} validated - Fired whenever the field is validated.
|
|
467
2245
|
*
|
|
2246
|
+
* @customElement
|
|
468
2247
|
* @extends TextField
|
|
469
2248
|
*/
|
|
470
2249
|
class PasswordField extends TextField {
|
|
@@ -538,6 +2317,14 @@ class PasswordField extends TextField {
|
|
|
538
2317
|
return ['__i18nChanged(i18n.*)'];
|
|
539
2318
|
}
|
|
540
2319
|
|
|
2320
|
+
constructor() {
|
|
2321
|
+
super();
|
|
2322
|
+
this._setType('password');
|
|
2323
|
+
this.__boundRevealButtonClick = this._onRevealButtonClick.bind(this);
|
|
2324
|
+
this.__boundRevealButtonMouseDown = this._onRevealButtonMouseDown.bind(this);
|
|
2325
|
+
this.__lastChange = '';
|
|
2326
|
+
}
|
|
2327
|
+
|
|
541
2328
|
/** @protected */
|
|
542
2329
|
get slotStyles() {
|
|
543
2330
|
const tag = this.localName;
|
|
@@ -556,31 +2343,20 @@ class PasswordField extends TextField {
|
|
|
556
2343
|
return this._revealButtonController && this._revealButtonController.node;
|
|
557
2344
|
}
|
|
558
2345
|
|
|
559
|
-
constructor() {
|
|
560
|
-
super();
|
|
561
|
-
this._setType('password');
|
|
562
|
-
this.__boundRevealButtonClick = this._onRevealButtonClick.bind(this);
|
|
563
|
-
this.__boundRevealButtonMouseDown = this._onRevealButtonMouseDown.bind(this);
|
|
564
|
-
this.__lastChange = '';
|
|
565
|
-
}
|
|
566
|
-
|
|
567
2346
|
/** @protected */
|
|
568
2347
|
ready() {
|
|
569
2348
|
super.ready();
|
|
570
2349
|
|
|
571
2350
|
this._revealPart = this.shadowRoot.querySelector('[part="reveal-button"]');
|
|
572
2351
|
|
|
573
|
-
this._revealButtonController = new SlotController(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
() => document.createElement('vaadin-password-field-button'),
|
|
577
|
-
(host, btn) => {
|
|
578
|
-
btn.disabled = host.disabled;
|
|
2352
|
+
this._revealButtonController = new SlotController(this, 'reveal', 'vaadin-password-field-button', {
|
|
2353
|
+
initializer: (btn) => {
|
|
2354
|
+
btn.disabled = this.disabled;
|
|
579
2355
|
|
|
580
|
-
btn.addEventListener('click',
|
|
581
|
-
btn.addEventListener('mousedown',
|
|
2356
|
+
btn.addEventListener('click', this.__boundRevealButtonClick);
|
|
2357
|
+
btn.addEventListener('mousedown', this.__boundRevealButtonMouseDown);
|
|
582
2358
|
},
|
|
583
|
-
);
|
|
2359
|
+
});
|
|
584
2360
|
this.addController(this._revealButtonController);
|
|
585
2361
|
|
|
586
2362
|
this.__updateAriaLabel(this.i18n);
|
|
@@ -737,7 +2513,7 @@ class PasswordField extends TextField {
|
|
|
737
2513
|
}
|
|
738
2514
|
}
|
|
739
2515
|
|
|
740
|
-
|
|
2516
|
+
defineCustomElement$1(PasswordField);
|
|
741
2517
|
|
|
742
2518
|
const passwordInputCss = "*,*::before,*::after{padding:0;margin:0;box-sizing:border-box}.password{font-family:\"Roboto\";font-style:normal}.password__wrapper{position:relative;width:100%}.password__wrapper--autofilled{pointer-events:none}.password__wrapper--autofilled .password__label{color:#979797}.password__wrapper--autofilled .password__input::part(input-field){color:#979797}.password__wrapper--flex{display:flex;gap:5px}.password__wrapper--relative{position:relative}.password__label{font-family:inherit;font-style:normal;font-weight:500;font-size:16px;line-height:20px;color:#2A3841}.password__label--required::after{content:\"*\";font-family:inherit;color:#2A3841;margin-left:2px}.password__input{width:inherit;border:none;margin-bottom:5px}.password__input[focused]::part(input-field){border-color:#3E3E3E}.password__input[invalid]::part(input-field){border-color:#cc0000b3}.password__input::part(input-field){border-radius:4px;background-color:transparent;font-family:inherit;font-style:normal;font-weight:300;font-size:16px;line-height:19px;color:#2A2E3F;width:100%;position:relative;border:2px solid #DEE1EE}.password__input>input:placeholder-shown{color:#979797}.password__error-message{position:absolute;top:calc(100% + 5px);left:0;color:#cc0000b3}.password__complexity{position:relative;padding:10px;display:flex;flex-direction:column;gap:20px;justify-content:center;margin-top:20px;font-weight:300;background:#FFFFFF;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;height:150px;border:1px solid #B0B0B0}.password__complexity--strength{display:flex;justify-content:space-evenly}.password__complexity--strength meter::-webkit-meter-optimum-value{background:#1F1F1F}.password__complexity--strength meter::-moz-meter-bar{background:#B0B0B0}.password__complexity--hidden{display:none}.password__complexity--text-bold{font-weight:500}.password__complexity--checkbox{margin-right:5px}.password__complexity:after{content:\"\";position:absolute;width:25px;height:25px;border-top:1px solid #B0B0B0;border-right:0 solid #B0B0B0;border-left:1px solid #B0B0B0;border-bottom:0 solid #B0B0B0;bottom:92%;left:50%;margin-left:-25px;transform:rotate(45deg);margin-top:-25px;background-color:#FFFFFF}.password__tooltip-icon{width:16px;height:auto}.password__tooltip{position:absolute;top:0;left:20px;background-color:#FFFFFF;border:1px solid #B0B0B0;color:#2B2D3F;padding:10px;border-radius:5px;opacity:0;transition:opacity 0.3s ease-in-out;z-index:10}.password__tooltip.visible{opacity:1}";
|
|
743
2519
|
|