@everymatrix/general-input 1.21.7 → 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 +27621 -18042
- package/dist/components/active-mixin.js +92 -2
- package/dist/components/checkbox-group-input2.js +2810 -282
- package/dist/components/date-input2.js +2666 -210
- package/dist/components/field-mixin.js +1299 -2313
- package/dist/components/input-field-shared-styles.js +679 -25
- package/dist/components/password-input2.js +1736 -7
- package/dist/components/vaadin-button.js +1346 -1
- package/dist/components/vaadin-combo-box.js +1762 -51
- package/dist/components/virtual-keyboard-controller.js +161 -83
- package/dist/esm/checkbox-group-input_10.entry.js +27621 -18042
- package/dist/general-input/general-input.esm.js +1 -1
- package/dist/general-input/p-983d18d7.entry.js +4143 -0
- package/package.json +11 -1
- package/dist/general-input/p-bcde6ed8.entry.js +0 -3646
|
@@ -1,10 +1,302 @@
|
|
|
1
1
|
import { proxyCustomElement, HTMLElement as HTMLElement$1, createEvent, h } from '@stencil/core/internal/client';
|
|
2
2
|
import { t as translate$1, a as tooltipIconSvg } from './tooltipIcon.js';
|
|
3
|
-
import { i as inputFieldShared,
|
|
4
|
-
import {
|
|
5
|
-
import { m as menuOverlay, P as PositionMixin, O as OverlayMixin, o as overlayStyles, a as afterNextRender,
|
|
3
|
+
import { i as inputFieldShared, I as InputConstraintsMixin, a as InputControlMixin, b as inputFieldShared$1 } from './input-field-shared-styles.js';
|
|
4
|
+
import { o, i, h as html, P as PolymerElement, d as dedupingMixin, k as PropertyEffects, w as wrap$1, s as strictTemplatePolicy, l as legacyWarnings, m as legacyOptimizations, n as useShadow, p as suppressTemplateNotifications, t as timeOut$1, q as microTask$1, v as matches, x as translate, j as FocusMixin, u as usageStatistics, c as DelegateFocusMixin, K as KeyboardMixin, e as InputController, f as LabelledInputController } from './field-mixin.js';
|
|
5
|
+
import { m as menuOverlay, P as PositionMixin, O as OverlayMixin, o as overlayStyles, a as afterNextRender, V as VirtualKeyboardController, h as hideOthers } from './virtual-keyboard-controller.js';
|
|
6
6
|
import './vaadin-button.js';
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @license
|
|
10
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
11
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @polymerMixin
|
|
15
|
+
*/
|
|
16
|
+
const ThemePropertyMixin = (superClass) =>
|
|
17
|
+
class VaadinThemePropertyMixin extends superClass {
|
|
18
|
+
static get properties() {
|
|
19
|
+
return {
|
|
20
|
+
/**
|
|
21
|
+
* Helper property with theme attribute value facilitating propagation
|
|
22
|
+
* in shadow DOM.
|
|
23
|
+
*
|
|
24
|
+
* Enables the component implementation to propagate the `theme`
|
|
25
|
+
* attribute value to the sub-components in Shadow DOM by binding
|
|
26
|
+
* the sub-component's "theme" attribute to the `theme` property of
|
|
27
|
+
* the host.
|
|
28
|
+
*
|
|
29
|
+
* **NOTE:** Extending the mixin only provides the property for binding,
|
|
30
|
+
* and does not make the propagation alone.
|
|
31
|
+
*
|
|
32
|
+
* See [Styling Components: Sub-components](https://vaadin.com/docs/latest/styling/styling-components/#sub-components).
|
|
33
|
+
* page for more information.
|
|
34
|
+
*
|
|
35
|
+
* @protected
|
|
36
|
+
*/
|
|
37
|
+
_theme: {
|
|
38
|
+
type: String,
|
|
39
|
+
readOnly: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static get observedAttributes() {
|
|
45
|
+
return [...super.observedAttributes, 'theme'];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @protected */
|
|
49
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
50
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
51
|
+
|
|
52
|
+
if (name === 'theme') {
|
|
53
|
+
this._set_theme(newValue);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @license
|
|
60
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
61
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @typedef {Object} Theme
|
|
66
|
+
* @property {string} themeFor
|
|
67
|
+
* @property {CSSResult[]} styles
|
|
68
|
+
* @property {string | string[]} [include]
|
|
69
|
+
* @property {string} [moduleId]
|
|
70
|
+
*
|
|
71
|
+
* @typedef {CSSResult[] | CSSResult} CSSResultGroup
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @type {Theme[]}
|
|
76
|
+
*/
|
|
77
|
+
const themeRegistry = [];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if the custom element type has themes applied.
|
|
81
|
+
* @param {Function} elementClass
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
function classHasThemes(elementClass) {
|
|
85
|
+
return elementClass && Object.prototype.hasOwnProperty.call(elementClass, '__themes');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if the custom element type has themes applied.
|
|
90
|
+
* @param {string} tagName
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
function hasThemes(tagName) {
|
|
94
|
+
return classHasThemes(customElements.get(tagName));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Flattens the styles into a single array of styles.
|
|
99
|
+
* @param {CSSResultGroup} styles
|
|
100
|
+
* @param {CSSResult[]} result
|
|
101
|
+
* @returns {CSSResult[]}
|
|
102
|
+
*/
|
|
103
|
+
function flattenStyles(styles = []) {
|
|
104
|
+
return [styles].flat(Infinity).filter((style) => {
|
|
105
|
+
if (style instanceof o) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
console.warn('An item in styles is not of type CSSResult. Use `unsafeCSS` or `css`.');
|
|
109
|
+
return false;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Registers CSS styles for a component type. Make sure to register the styles before
|
|
115
|
+
* the first instance of a component of the type is attached to DOM.
|
|
116
|
+
*
|
|
117
|
+
* @param {string} themeFor The local/tag name of the component type to register the styles for
|
|
118
|
+
* @param {CSSResultGroup} styles The CSS style rules to be registered for the component type
|
|
119
|
+
* matching themeFor and included in the local scope of each component instance
|
|
120
|
+
* @param {{moduleId?: string, include?: string | string[]}} options Additional options
|
|
121
|
+
* @return {void}
|
|
122
|
+
*/
|
|
123
|
+
function registerStyles(themeFor, styles, options = {}) {
|
|
124
|
+
if (themeFor) {
|
|
125
|
+
if (hasThemes(themeFor)) {
|
|
126
|
+
console.warn(`The custom element definition for "${themeFor}"
|
|
127
|
+
was finalized before a style module was registered.
|
|
128
|
+
Make sure to add component specific style modules before
|
|
129
|
+
importing the corresponding custom element.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
styles = flattenStyles(styles);
|
|
134
|
+
|
|
135
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
136
|
+
window.Vaadin.styleModules.registerStyles(themeFor, styles, options);
|
|
137
|
+
} else {
|
|
138
|
+
themeRegistry.push({
|
|
139
|
+
themeFor,
|
|
140
|
+
styles,
|
|
141
|
+
include: options.include,
|
|
142
|
+
moduleId: options.moduleId,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns all registered themes. By default the themeRegistry is returned as is.
|
|
149
|
+
* In case the style-modules adapter is imported, the themes are obtained from there instead
|
|
150
|
+
* @returns {Theme[]}
|
|
151
|
+
*/
|
|
152
|
+
function getAllThemes() {
|
|
153
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
154
|
+
return window.Vaadin.styleModules.getAllThemes();
|
|
155
|
+
}
|
|
156
|
+
return themeRegistry;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns true if the themeFor string matches the tag name
|
|
161
|
+
* @param {string} themeFor
|
|
162
|
+
* @param {string} tagName
|
|
163
|
+
* @returns {boolean}
|
|
164
|
+
*/
|
|
165
|
+
function matchesThemeFor(themeFor, tagName) {
|
|
166
|
+
return (themeFor || '').split(' ').some((themeForToken) => {
|
|
167
|
+
return new RegExp(`^${themeForToken.split('*').join('.*')}$`, 'u').test(tagName);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Maps the moduleName to an include priority number which is used for
|
|
173
|
+
* determining the order in which styles are applied.
|
|
174
|
+
* @param {string} moduleName
|
|
175
|
+
* @returns {number}
|
|
176
|
+
*/
|
|
177
|
+
function getIncludePriority(moduleName = '') {
|
|
178
|
+
let includePriority = 0;
|
|
179
|
+
if (moduleName.startsWith('lumo-') || moduleName.startsWith('material-')) {
|
|
180
|
+
includePriority = 1;
|
|
181
|
+
} else if (moduleName.startsWith('vaadin-')) {
|
|
182
|
+
includePriority = 2;
|
|
183
|
+
}
|
|
184
|
+
return includePriority;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Gets an array of CSSResults matching the include property of the theme.
|
|
189
|
+
* @param {Theme} theme
|
|
190
|
+
* @returns {CSSResult[]}
|
|
191
|
+
*/
|
|
192
|
+
function getIncludedStyles(theme) {
|
|
193
|
+
const includedStyles = [];
|
|
194
|
+
if (theme.include) {
|
|
195
|
+
[].concat(theme.include).forEach((includeModuleId) => {
|
|
196
|
+
const includedTheme = getAllThemes().find((s) => s.moduleId === includeModuleId);
|
|
197
|
+
if (includedTheme) {
|
|
198
|
+
includedStyles.push(...getIncludedStyles(includedTheme), ...includedTheme.styles);
|
|
199
|
+
} else {
|
|
200
|
+
console.warn(`Included moduleId ${includeModuleId} not found in style registry`);
|
|
201
|
+
}
|
|
202
|
+
}, theme.styles);
|
|
203
|
+
}
|
|
204
|
+
return includedStyles;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Includes the styles to the template.
|
|
209
|
+
* @param {CSSResult[]} styles
|
|
210
|
+
* @param {HTMLTemplateElement} template
|
|
211
|
+
*/
|
|
212
|
+
function addStylesToTemplate(styles, template) {
|
|
213
|
+
const styleEl = document.createElement('style');
|
|
214
|
+
styleEl.innerHTML = styles.map((style) => style.cssText).join('\n');
|
|
215
|
+
template.content.appendChild(styleEl);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Returns an array of themes that should be used for styling a component matching
|
|
220
|
+
* the tag name. The array is sorted by the include order.
|
|
221
|
+
* @param {string} tagName
|
|
222
|
+
* @returns {Theme[]}
|
|
223
|
+
*/
|
|
224
|
+
function getThemes(tagName) {
|
|
225
|
+
const defaultModuleName = `${tagName}-default-theme`;
|
|
226
|
+
|
|
227
|
+
const themes = getAllThemes()
|
|
228
|
+
// Filter by matching themeFor properties
|
|
229
|
+
.filter((theme) => theme.moduleId !== defaultModuleName && matchesThemeFor(theme.themeFor, tagName))
|
|
230
|
+
.map((theme) => ({
|
|
231
|
+
...theme,
|
|
232
|
+
// Prepend styles from included themes
|
|
233
|
+
styles: [...getIncludedStyles(theme), ...theme.styles],
|
|
234
|
+
// Map moduleId to includePriority
|
|
235
|
+
includePriority: getIncludePriority(theme.moduleId),
|
|
236
|
+
}))
|
|
237
|
+
// Sort by includePriority
|
|
238
|
+
.sort((themeA, themeB) => themeB.includePriority - themeA.includePriority);
|
|
239
|
+
|
|
240
|
+
if (themes.length > 0) {
|
|
241
|
+
return themes;
|
|
242
|
+
}
|
|
243
|
+
// No theme modules found, return the default module if it exists
|
|
244
|
+
return getAllThemes().filter((theme) => theme.moduleId === defaultModuleName);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @polymerMixin
|
|
249
|
+
* @mixes ThemePropertyMixin
|
|
250
|
+
*/
|
|
251
|
+
const ThemableMixin = (superClass) =>
|
|
252
|
+
class VaadinThemableMixin extends ThemePropertyMixin(superClass) {
|
|
253
|
+
/**
|
|
254
|
+
* Covers PolymerElement based component styling
|
|
255
|
+
* @protected
|
|
256
|
+
*/
|
|
257
|
+
static finalize() {
|
|
258
|
+
super.finalize();
|
|
259
|
+
|
|
260
|
+
// Make sure not to run the logic intended for PolymerElement when LitElement is used.
|
|
261
|
+
if (this.elementStyles) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const template = this.prototype._template;
|
|
266
|
+
if (!template || classHasThemes(this)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
addStylesToTemplate(this.getStylesForThis(), template);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Covers LitElement based component styling
|
|
275
|
+
*
|
|
276
|
+
* @protected
|
|
277
|
+
*/
|
|
278
|
+
static finalizeStyles(styles) {
|
|
279
|
+
// The "styles" object originates from the "static get styles()" function of
|
|
280
|
+
// a LitElement based component. The theme styles are added after it
|
|
281
|
+
// so that they can override the component styles.
|
|
282
|
+
const themeStyles = this.getStylesForThis();
|
|
283
|
+
return styles ? [...super.finalizeStyles(styles), ...themeStyles] : themeStyles;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get styles for the component type
|
|
288
|
+
*
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
static getStylesForThis() {
|
|
292
|
+
const parent = Object.getPrototypeOf(this.prototype);
|
|
293
|
+
const inheritedThemes = (parent ? parent.constructor.__themes : []) || [];
|
|
294
|
+
this.__themes = [...inheritedThemes, ...getThemes(this.is)];
|
|
295
|
+
const themeStyles = this.__themes.flatMap((theme) => theme.styles);
|
|
296
|
+
// Remove duplicates
|
|
297
|
+
return themeStyles.filter((style, index) => index === themeStyles.lastIndexOf(style));
|
|
298
|
+
}
|
|
299
|
+
};
|
|
8
300
|
|
|
9
301
|
const datePickerOverlay = i`
|
|
10
302
|
[part='overlay'] {
|
|
@@ -436,6 +728,174 @@ const datePicker = i`
|
|
|
436
728
|
|
|
437
729
|
registerStyles('vaadin-date-picker', [inputFieldShared, datePicker], { moduleId: 'lumo-date-picker' });
|
|
438
730
|
|
|
731
|
+
/**
|
|
732
|
+
* @license
|
|
733
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
734
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
735
|
+
*/
|
|
736
|
+
function defineCustomElement$1(CustomElement) {
|
|
737
|
+
const defined = customElements.get(CustomElement.is);
|
|
738
|
+
if (!defined) {
|
|
739
|
+
customElements.define(CustomElement.is, CustomElement);
|
|
740
|
+
} else {
|
|
741
|
+
const definedVersion = defined.version;
|
|
742
|
+
if (definedVersion && CustomElement.version && definedVersion === CustomElement.version) {
|
|
743
|
+
// Just loading the same thing again
|
|
744
|
+
console.warn(`The component ${CustomElement.is} has been loaded twice`);
|
|
745
|
+
} else {
|
|
746
|
+
console.error(
|
|
747
|
+
`Tried to define ${CustomElement.is} version ${CustomElement.version} when version ${defined.version} is already in use. Something will probably break.`,
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* @license
|
|
755
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
756
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
757
|
+
*/
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Array of Vaadin custom element classes that have been subscribed to the dir changes.
|
|
761
|
+
*/
|
|
762
|
+
const directionSubscribers = [];
|
|
763
|
+
|
|
764
|
+
function alignDirs(element, documentDir, elementDir = element.getAttribute('dir')) {
|
|
765
|
+
if (documentDir) {
|
|
766
|
+
element.setAttribute('dir', documentDir);
|
|
767
|
+
} else if (elementDir != null) {
|
|
768
|
+
element.removeAttribute('dir');
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function getDocumentDir() {
|
|
773
|
+
return document.documentElement.getAttribute('dir');
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function directionUpdater() {
|
|
777
|
+
const documentDir = getDocumentDir();
|
|
778
|
+
directionSubscribers.forEach((element) => {
|
|
779
|
+
alignDirs(element, documentDir);
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const directionObserver = new MutationObserver(directionUpdater);
|
|
784
|
+
directionObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] });
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* A mixin to handle `dir` attribute based on the one set on the `<html>` element.
|
|
788
|
+
*
|
|
789
|
+
* @polymerMixin
|
|
790
|
+
*/
|
|
791
|
+
const DirMixin = (superClass) =>
|
|
792
|
+
class VaadinDirMixin extends superClass {
|
|
793
|
+
static get properties() {
|
|
794
|
+
return {
|
|
795
|
+
/**
|
|
796
|
+
* @protected
|
|
797
|
+
*/
|
|
798
|
+
dir: {
|
|
799
|
+
type: String,
|
|
800
|
+
value: '',
|
|
801
|
+
reflectToAttribute: true,
|
|
802
|
+
converter: {
|
|
803
|
+
fromAttribute: (attr) => {
|
|
804
|
+
return !attr ? '' : attr;
|
|
805
|
+
},
|
|
806
|
+
toAttribute: (prop) => {
|
|
807
|
+
return prop === '' ? null : prop;
|
|
808
|
+
},
|
|
809
|
+
},
|
|
810
|
+
},
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* @return {boolean}
|
|
816
|
+
* @protected
|
|
817
|
+
*/
|
|
818
|
+
get __isRTL() {
|
|
819
|
+
return this.getAttribute('dir') === 'rtl';
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/** @protected */
|
|
823
|
+
connectedCallback() {
|
|
824
|
+
super.connectedCallback();
|
|
825
|
+
|
|
826
|
+
if (!this.hasAttribute('dir') || this.__restoreSubscription) {
|
|
827
|
+
this.__subscribe();
|
|
828
|
+
alignDirs(this, getDocumentDir(), null);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/** @protected */
|
|
833
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
834
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
835
|
+
if (name !== 'dir') {
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const documentDir = getDocumentDir();
|
|
840
|
+
|
|
841
|
+
// New value equals to the document direction and the element is not subscribed to the changes
|
|
842
|
+
const newValueEqlDocDir = newValue === documentDir && directionSubscribers.indexOf(this) === -1;
|
|
843
|
+
// Value was emptied and the element is not subscribed to the changes
|
|
844
|
+
const newValueEmptied = !newValue && oldValue && directionSubscribers.indexOf(this) === -1;
|
|
845
|
+
// New value is different and the old equals to document direction and the element is not subscribed to the changes
|
|
846
|
+
const newDiffValue = newValue !== documentDir && oldValue === documentDir;
|
|
847
|
+
|
|
848
|
+
if (newValueEqlDocDir || newValueEmptied) {
|
|
849
|
+
this.__subscribe();
|
|
850
|
+
alignDirs(this, documentDir, newValue);
|
|
851
|
+
} else if (newDiffValue) {
|
|
852
|
+
this.__unsubscribe();
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/** @protected */
|
|
857
|
+
disconnectedCallback() {
|
|
858
|
+
super.disconnectedCallback();
|
|
859
|
+
this.__restoreSubscription = directionSubscribers.includes(this);
|
|
860
|
+
this.__unsubscribe();
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/** @protected */
|
|
864
|
+
_valueToNodeAttribute(node, value, attribute) {
|
|
865
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
866
|
+
// If the property contains an empty string then it should not create an empty attribute
|
|
867
|
+
if (attribute === 'dir' && value === '' && !node.hasAttribute('dir')) {
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
super._valueToNodeAttribute(node, value, attribute);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/** @protected */
|
|
874
|
+
_attributeToProperty(attribute, value, type) {
|
|
875
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
876
|
+
// If the attribute is removed, then the dir property should contain an empty string instead of null
|
|
877
|
+
if (attribute === 'dir' && !value) {
|
|
878
|
+
this.dir = '';
|
|
879
|
+
} else {
|
|
880
|
+
super._attributeToProperty(attribute, value, type);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/** @private */
|
|
885
|
+
__subscribe() {
|
|
886
|
+
if (!directionSubscribers.includes(this)) {
|
|
887
|
+
directionSubscribers.push(this);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/** @private */
|
|
892
|
+
__unsubscribe() {
|
|
893
|
+
if (directionSubscribers.includes(this)) {
|
|
894
|
+
directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
|
|
439
899
|
/**
|
|
440
900
|
* @license
|
|
441
901
|
* Copyright (c) 2016 - 2023 Vaadin Ltd.
|
|
@@ -668,177 +1128,550 @@ function parseDate(str) {
|
|
|
668
1128
|
|
|
669
1129
|
/**
|
|
670
1130
|
* @license
|
|
671
|
-
* Copyright (c)
|
|
672
|
-
* This
|
|
1131
|
+
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
1132
|
+
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
1133
|
+
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
1134
|
+
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
1135
|
+
* Code distributed by Google as part of the polymer project is also
|
|
1136
|
+
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
673
1137
|
*/
|
|
674
1138
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
height: 100%;
|
|
687
|
-
overflow: auto;
|
|
688
|
-
outline: none;
|
|
689
|
-
margin-right: -40px;
|
|
690
|
-
-webkit-overflow-scrolling: touch;
|
|
691
|
-
overflow-x: hidden;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
#scroller.notouchscroll {
|
|
695
|
-
-webkit-overflow-scrolling: auto;
|
|
696
|
-
}
|
|
1139
|
+
/**
|
|
1140
|
+
* @fileoverview
|
|
1141
|
+
*
|
|
1142
|
+
* This module provides a number of strategies for enqueuing asynchronous
|
|
1143
|
+
* tasks. Each sub-module provides a standard `run(fn)` interface that returns a
|
|
1144
|
+
* handle, and a `cancel(handle)` interface for canceling async tasks before
|
|
1145
|
+
* they run.
|
|
1146
|
+
*
|
|
1147
|
+
* @summary Module that provides a number of strategies for enqueuing
|
|
1148
|
+
* asynchronous tasks.
|
|
1149
|
+
*/
|
|
697
1150
|
|
|
698
|
-
|
|
699
|
-
|
|
1151
|
+
let microtaskCurrHandle = 0;
|
|
1152
|
+
let microtaskLastHandle = 0;
|
|
1153
|
+
const microtaskCallbacks = [];
|
|
1154
|
+
let microtaskScheduled = false;
|
|
1155
|
+
|
|
1156
|
+
function microtaskFlush() {
|
|
1157
|
+
microtaskScheduled = false;
|
|
1158
|
+
const len = microtaskCallbacks.length;
|
|
1159
|
+
for (let i = 0; i < len; i++) {
|
|
1160
|
+
const cb = microtaskCallbacks[i];
|
|
1161
|
+
if (cb) {
|
|
1162
|
+
try {
|
|
1163
|
+
cb();
|
|
1164
|
+
} catch (e) {
|
|
1165
|
+
setTimeout(() => {
|
|
1166
|
+
throw e;
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
700
1169
|
}
|
|
1170
|
+
}
|
|
1171
|
+
microtaskCallbacks.splice(0, len);
|
|
1172
|
+
microtaskLastHandle += len;
|
|
1173
|
+
}
|
|
701
1174
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1175
|
+
/**
|
|
1176
|
+
* Async interface wrapper around `setTimeout`.
|
|
1177
|
+
*
|
|
1178
|
+
* @namespace
|
|
1179
|
+
* @summary Async interface wrapper around `setTimeout`.
|
|
1180
|
+
*/
|
|
1181
|
+
const timeOut = {
|
|
1182
|
+
/**
|
|
1183
|
+
* Returns a sub-module with the async interface providing the provided
|
|
1184
|
+
* delay.
|
|
1185
|
+
*
|
|
1186
|
+
* @memberof timeOut
|
|
1187
|
+
* @param {number=} delay Time to wait before calling callbacks in ms
|
|
1188
|
+
* @return {!AsyncInterface} An async timeout interface
|
|
1189
|
+
*/
|
|
1190
|
+
after(delay) {
|
|
1191
|
+
return {
|
|
1192
|
+
run(fn) {
|
|
1193
|
+
return window.setTimeout(fn, delay);
|
|
1194
|
+
},
|
|
1195
|
+
cancel(handle) {
|
|
1196
|
+
window.clearTimeout(handle);
|
|
1197
|
+
},
|
|
1198
|
+
};
|
|
1199
|
+
},
|
|
1200
|
+
/**
|
|
1201
|
+
* Enqueues a function called in the next task.
|
|
1202
|
+
*
|
|
1203
|
+
* @memberof timeOut
|
|
1204
|
+
* @param {!Function} fn Callback to run
|
|
1205
|
+
* @param {number=} delay Delay in milliseconds
|
|
1206
|
+
* @return {number} Handle used for canceling task
|
|
1207
|
+
*/
|
|
1208
|
+
run(fn, delay) {
|
|
1209
|
+
return window.setTimeout(fn, delay);
|
|
1210
|
+
},
|
|
1211
|
+
/**
|
|
1212
|
+
* Cancels a previously enqueued `timeOut` callback.
|
|
1213
|
+
*
|
|
1214
|
+
* @memberof timeOut
|
|
1215
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
1216
|
+
* @return {void}
|
|
1217
|
+
*/
|
|
1218
|
+
cancel(handle) {
|
|
1219
|
+
window.clearTimeout(handle);
|
|
1220
|
+
},
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
/**
|
|
1224
|
+
* Async interface wrapper around `requestIdleCallback`. Falls back to
|
|
1225
|
+
* `setTimeout` on browsers that do not support `requestIdleCallback`.
|
|
1226
|
+
*
|
|
1227
|
+
* @namespace
|
|
1228
|
+
* @summary Async interface wrapper around `requestIdleCallback`.
|
|
1229
|
+
*/
|
|
1230
|
+
const idlePeriod = {
|
|
1231
|
+
/**
|
|
1232
|
+
* Enqueues a function called at `requestIdleCallback` timing.
|
|
1233
|
+
*
|
|
1234
|
+
* @memberof idlePeriod
|
|
1235
|
+
* @param {function(!IdleDeadline):void} fn Callback to run
|
|
1236
|
+
* @return {number} Handle used for canceling task
|
|
1237
|
+
*/
|
|
1238
|
+
run(fn) {
|
|
1239
|
+
return window.requestIdleCallback ? window.requestIdleCallback(fn) : window.setTimeout(fn, 16);
|
|
1240
|
+
},
|
|
1241
|
+
/**
|
|
1242
|
+
* Cancels a previously enqueued `idlePeriod` callback.
|
|
1243
|
+
*
|
|
1244
|
+
* @memberof idlePeriod
|
|
1245
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
1246
|
+
* @return {void}
|
|
1247
|
+
*/
|
|
1248
|
+
cancel(handle) {
|
|
1249
|
+
if (window.cancelIdleCallback) {
|
|
1250
|
+
window.cancelIdleCallback(handle);
|
|
1251
|
+
} else {
|
|
1252
|
+
window.clearTimeout(handle);
|
|
709
1253
|
}
|
|
1254
|
+
},
|
|
1255
|
+
};
|
|
710
1256
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
1257
|
+
/**
|
|
1258
|
+
* Async interface for enqueuing callbacks that run at microtask timing.
|
|
1259
|
+
*
|
|
1260
|
+
* @namespace
|
|
1261
|
+
* @summary Async interface for enqueuing callbacks that run at microtask
|
|
1262
|
+
* timing.
|
|
1263
|
+
*/
|
|
1264
|
+
const microTask = {
|
|
1265
|
+
/**
|
|
1266
|
+
* Enqueues a function called at microtask timing.
|
|
1267
|
+
*
|
|
1268
|
+
* @memberof microTask
|
|
1269
|
+
* @param {!Function=} callback Callback to run
|
|
1270
|
+
* @return {number} Handle used for canceling task
|
|
1271
|
+
*/
|
|
1272
|
+
run(callback) {
|
|
1273
|
+
if (!microtaskScheduled) {
|
|
1274
|
+
microtaskScheduled = true;
|
|
1275
|
+
queueMicrotask(() => microtaskFlush());
|
|
1276
|
+
}
|
|
1277
|
+
microtaskCallbacks.push(callback);
|
|
1278
|
+
const result = microtaskCurrHandle;
|
|
1279
|
+
microtaskCurrHandle += 1;
|
|
1280
|
+
return result;
|
|
1281
|
+
},
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Cancels a previously enqueued `microTask` callback.
|
|
1285
|
+
*
|
|
1286
|
+
* @memberof microTask
|
|
1287
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
1288
|
+
* @return {void}
|
|
1289
|
+
*/
|
|
1290
|
+
cancel(handle) {
|
|
1291
|
+
const idx = handle - microtaskLastHandle;
|
|
1292
|
+
if (idx >= 0) {
|
|
1293
|
+
if (!microtaskCallbacks[idx]) {
|
|
1294
|
+
throw new Error(`invalid async handle: ${handle}`);
|
|
717
1295
|
}
|
|
1296
|
+
microtaskCallbacks[idx] = null;
|
|
718
1297
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
<div id="scroller">
|
|
722
|
-
<div class="buffer"></div>
|
|
723
|
-
<div class="buffer"></div>
|
|
724
|
-
<div id="fullHeight"></div>
|
|
725
|
-
</div>
|
|
726
|
-
`;
|
|
1298
|
+
},
|
|
1299
|
+
};
|
|
727
1300
|
|
|
728
1301
|
/**
|
|
729
|
-
* @
|
|
730
|
-
*
|
|
1302
|
+
* @license
|
|
1303
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1304
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
731
1305
|
*/
|
|
732
|
-
class InfiniteScroller extends HTMLElement {
|
|
733
|
-
constructor() {
|
|
734
|
-
super();
|
|
735
1306
|
|
|
736
|
-
|
|
737
|
-
root.appendChild(template.content.cloneNode(true));
|
|
1307
|
+
const testUserAgent = (regexp) => regexp.test(navigator.userAgent);
|
|
738
1308
|
|
|
739
|
-
|
|
740
|
-
* Count of individual items in each buffer.
|
|
741
|
-
* The scroller has 2 buffers altogether so bufferSize of 20
|
|
742
|
-
* will result in 40 buffered DOM items in total.
|
|
743
|
-
* Changing after initialization not supported.
|
|
744
|
-
* @type {number}
|
|
745
|
-
*/
|
|
746
|
-
this.bufferSize = 20;
|
|
1309
|
+
const testPlatform = (regexp) => regexp.test(navigator.platform);
|
|
747
1310
|
|
|
748
|
-
|
|
749
|
-
* The amount of initial scroll top. Needed in order for the
|
|
750
|
-
* user to be able to scroll backwards.
|
|
751
|
-
* @type {number}
|
|
752
|
-
* @private
|
|
753
|
-
*/
|
|
754
|
-
this._initialScroll = 500000;
|
|
1311
|
+
const testVendor = (regexp) => regexp.test(navigator.vendor);
|
|
755
1312
|
|
|
756
|
-
|
|
757
|
-
* The index/position mapped at _initialScroll point.
|
|
758
|
-
* @type {number}
|
|
759
|
-
* @private
|
|
760
|
-
*/
|
|
761
|
-
this._initialIndex = 0;
|
|
1313
|
+
testUserAgent(/Android/u);
|
|
762
1314
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1315
|
+
testUserAgent(/Chrome/u) && testVendor(/Google Inc/u);
|
|
1316
|
+
|
|
1317
|
+
const isFirefox = testUserAgent(/Firefox/u);
|
|
1318
|
+
|
|
1319
|
+
// IPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
|
|
1320
|
+
const isIPad = testPlatform(/^iPad/u) || (testPlatform(/^Mac/u) && navigator.maxTouchPoints > 1);
|
|
1321
|
+
|
|
1322
|
+
const isIPhone = testPlatform(/^iPhone/u);
|
|
1323
|
+
|
|
1324
|
+
const isIOS = isIPhone || isIPad;
|
|
1325
|
+
|
|
1326
|
+
testUserAgent(/^((?!chrome|android).)*safari/iu);
|
|
1327
|
+
|
|
1328
|
+
(() => {
|
|
1329
|
+
try {
|
|
1330
|
+
document.createEvent('TouchEvent');
|
|
1331
|
+
return true;
|
|
1332
|
+
} catch (e) {
|
|
1333
|
+
return false;
|
|
768
1334
|
}
|
|
1335
|
+
})();
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
@license
|
|
1339
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
1340
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
1341
|
+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
1342
|
+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
1343
|
+
Code distributed by Google as part of the polymer project is also
|
|
1344
|
+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
1345
|
+
*/
|
|
769
1346
|
|
|
1347
|
+
const debouncerQueue$1 = new Set();
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* @summary Collapse multiple callbacks into one invocation after a timer.
|
|
1351
|
+
*/
|
|
1352
|
+
class Debouncer$1 {
|
|
770
1353
|
/**
|
|
771
|
-
*
|
|
1354
|
+
* Creates a debouncer if no debouncer is passed as a parameter
|
|
1355
|
+
* or it cancels an active debouncer otherwise. The following
|
|
1356
|
+
* example shows how a debouncer can be called multiple times within a
|
|
1357
|
+
* microtask and "debounced" such that the provided callback function is
|
|
1358
|
+
* called once. Add this method to a custom element:
|
|
1359
|
+
*
|
|
1360
|
+
* ```js
|
|
1361
|
+
* import {microTask} from '@vaadin/component-base/src/async.js';
|
|
1362
|
+
* import {Debouncer} from '@vaadin/component-base/src/debounce.js';
|
|
1363
|
+
* // ...
|
|
1364
|
+
*
|
|
1365
|
+
* _debounceWork() {
|
|
1366
|
+
* this._debounceJob = Debouncer.debounce(this._debounceJob,
|
|
1367
|
+
* microTask, () => this._doWork());
|
|
1368
|
+
* }
|
|
1369
|
+
* ```
|
|
1370
|
+
*
|
|
1371
|
+
* If the `_debounceWork` method is called multiple times within the same
|
|
1372
|
+
* microtask, the `_doWork` function will be called only once at the next
|
|
1373
|
+
* microtask checkpoint.
|
|
1374
|
+
*
|
|
1375
|
+
* Note: In testing it is often convenient to avoid asynchrony. To accomplish
|
|
1376
|
+
* this with a debouncer, you can use `enqueueDebouncer` and
|
|
1377
|
+
* `flush`. For example, extend the above example by adding
|
|
1378
|
+
* `enqueueDebouncer(this._debounceJob)` at the end of the
|
|
1379
|
+
* `_debounceWork` method. Then in a test, call `flush` to ensure
|
|
1380
|
+
* the debouncer has completed.
|
|
1381
|
+
*
|
|
1382
|
+
* @param {Debouncer?} debouncer Debouncer object.
|
|
1383
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface
|
|
1384
|
+
* @param {function()} callback Callback to run.
|
|
1385
|
+
* @return {!Debouncer} Returns a debouncer object.
|
|
772
1386
|
*/
|
|
773
|
-
|
|
774
|
-
|
|
1387
|
+
static debounce(debouncer, asyncModule, callback) {
|
|
1388
|
+
if (debouncer instanceof Debouncer$1) {
|
|
1389
|
+
// Cancel the async callback, but leave in debouncerQueue if it was
|
|
1390
|
+
// enqueued, to maintain 1.x flush order
|
|
1391
|
+
debouncer._cancelAsync();
|
|
1392
|
+
} else {
|
|
1393
|
+
debouncer = new Debouncer$1();
|
|
1394
|
+
}
|
|
1395
|
+
debouncer.setConfig(asyncModule, callback);
|
|
1396
|
+
return debouncer;
|
|
775
1397
|
}
|
|
776
1398
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
1399
|
+
constructor() {
|
|
1400
|
+
this._asyncModule = null;
|
|
1401
|
+
this._callback = null;
|
|
1402
|
+
this._timer = null;
|
|
782
1403
|
}
|
|
783
1404
|
|
|
784
1405
|
/**
|
|
785
|
-
*
|
|
1406
|
+
* Sets the scheduler; that is, a module with the Async interface,
|
|
1407
|
+
* a callback and optional arguments to be passed to the run function
|
|
1408
|
+
* from the async module.
|
|
1409
|
+
*
|
|
1410
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface.
|
|
1411
|
+
* @param {function()} callback Callback to run.
|
|
1412
|
+
* @return {void}
|
|
786
1413
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
1414
|
+
setConfig(asyncModule, callback) {
|
|
1415
|
+
this._asyncModule = asyncModule;
|
|
1416
|
+
this._callback = callback;
|
|
1417
|
+
this._timer = this._asyncModule.run(() => {
|
|
1418
|
+
this._timer = null;
|
|
1419
|
+
debouncerQueue$1.delete(this);
|
|
1420
|
+
this._callback();
|
|
1421
|
+
});
|
|
789
1422
|
}
|
|
790
1423
|
|
|
791
1424
|
/**
|
|
792
|
-
*
|
|
1425
|
+
* Cancels an active debouncer and returns a reference to itself.
|
|
1426
|
+
*
|
|
1427
|
+
* @return {void}
|
|
793
1428
|
*/
|
|
794
|
-
|
|
795
|
-
if (
|
|
796
|
-
|
|
797
|
-
//
|
|
798
|
-
|
|
799
|
-
this
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
this._itemHeightVal = parseFloat(itemHeightPx);
|
|
1429
|
+
cancel() {
|
|
1430
|
+
if (this.isActive()) {
|
|
1431
|
+
this._cancelAsync();
|
|
1432
|
+
// Canceling a debouncer removes its spot from the flush queue,
|
|
1433
|
+
// so if a debouncer is manually canceled and re-debounced, it
|
|
1434
|
+
// will reset its flush order (this is a very minor difference from 1.x)
|
|
1435
|
+
// Re-debouncing via the `debounce` API retains the 1.x FIFO flush order
|
|
1436
|
+
debouncerQueue$1.delete(this);
|
|
803
1437
|
}
|
|
804
|
-
|
|
805
|
-
return this._itemHeightVal;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
/** @private */
|
|
809
|
-
get _bufferHeight() {
|
|
810
|
-
return this.itemHeight * this.bufferSize;
|
|
811
1438
|
}
|
|
812
1439
|
|
|
813
1440
|
/**
|
|
814
|
-
*
|
|
1441
|
+
* Cancels a debouncer's async callback.
|
|
1442
|
+
*
|
|
1443
|
+
* @return {void}
|
|
815
1444
|
*/
|
|
816
|
-
|
|
817
|
-
|
|
1445
|
+
_cancelAsync() {
|
|
1446
|
+
if (this.isActive()) {
|
|
1447
|
+
this._asyncModule.cancel(/** @type {number} */ (this._timer));
|
|
1448
|
+
this._timer = null;
|
|
1449
|
+
}
|
|
818
1450
|
}
|
|
819
1451
|
|
|
820
1452
|
/**
|
|
821
|
-
*
|
|
1453
|
+
* Flushes an active debouncer and returns a reference to itself.
|
|
822
1454
|
*
|
|
823
|
-
* @
|
|
1455
|
+
* @return {void}
|
|
824
1456
|
*/
|
|
825
|
-
|
|
826
|
-
this.
|
|
827
|
-
|
|
828
|
-
this
|
|
829
|
-
} else {
|
|
830
|
-
this._initialIndex = ~~index;
|
|
831
|
-
this._reset();
|
|
832
|
-
this._scrollDisabled = true;
|
|
833
|
-
this.$.scroller.scrollTop += (index % 1) * this.itemHeight;
|
|
834
|
-
this._scrollDisabled = false;
|
|
1457
|
+
flush() {
|
|
1458
|
+
if (this.isActive()) {
|
|
1459
|
+
this.cancel();
|
|
1460
|
+
this._callback();
|
|
835
1461
|
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* Returns true if the debouncer is active.
|
|
1466
|
+
*
|
|
1467
|
+
* @return {boolean} True if active.
|
|
1468
|
+
*/
|
|
1469
|
+
isActive() {
|
|
1470
|
+
return this._timer != null;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
* Adds a `Debouncer` to a list of globally flushable tasks.
|
|
1476
|
+
*
|
|
1477
|
+
* @param {!Debouncer} debouncer Debouncer to enqueue
|
|
1478
|
+
* @return {void}
|
|
1479
|
+
*/
|
|
1480
|
+
function enqueueDebouncer$1(debouncer) {
|
|
1481
|
+
debouncerQueue$1.add(debouncer);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* @license
|
|
1486
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1487
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1488
|
+
*/
|
|
1489
|
+
|
|
1490
|
+
let uniqueId = 0;
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* Returns a unique integer id.
|
|
1494
|
+
*
|
|
1495
|
+
* @return {number}
|
|
1496
|
+
*/
|
|
1497
|
+
function generateUniqueId() {
|
|
1498
|
+
// eslint-disable-next-line no-plusplus
|
|
1499
|
+
return uniqueId++;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
/**
|
|
1503
|
+
* @license
|
|
1504
|
+
* Copyright (c) 2016 - 2023 Vaadin Ltd.
|
|
1505
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1506
|
+
*/
|
|
1507
|
+
|
|
1508
|
+
const template = document.createElement('template');
|
|
1509
|
+
template.innerHTML = `
|
|
1510
|
+
<style>
|
|
1511
|
+
:host {
|
|
1512
|
+
display: block;
|
|
1513
|
+
overflow: hidden;
|
|
1514
|
+
height: 500px;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
#scroller {
|
|
1518
|
+
position: relative;
|
|
1519
|
+
height: 100%;
|
|
1520
|
+
overflow: auto;
|
|
1521
|
+
outline: none;
|
|
1522
|
+
margin-right: -40px;
|
|
1523
|
+
-webkit-overflow-scrolling: touch;
|
|
1524
|
+
overflow-x: hidden;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
#scroller.notouchscroll {
|
|
1528
|
+
-webkit-overflow-scrolling: auto;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
#scroller::-webkit-scrollbar {
|
|
1532
|
+
display: none;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
.buffer {
|
|
1536
|
+
position: absolute;
|
|
1537
|
+
width: var(--vaadin-infinite-scroller-buffer-width, 100%);
|
|
1538
|
+
box-sizing: border-box;
|
|
1539
|
+
padding-right: 40px;
|
|
1540
|
+
top: var(--vaadin-infinite-scroller-buffer-offset, 0);
|
|
1541
|
+
animation: fadein 0.2s;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
@keyframes fadein {
|
|
1545
|
+
from {
|
|
1546
|
+
opacity: 0;
|
|
1547
|
+
}
|
|
1548
|
+
to {
|
|
1549
|
+
opacity: 1;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
</style>
|
|
1553
|
+
|
|
1554
|
+
<div id="scroller">
|
|
1555
|
+
<div class="buffer"></div>
|
|
1556
|
+
<div class="buffer"></div>
|
|
1557
|
+
<div id="fullHeight"></div>
|
|
1558
|
+
</div>
|
|
1559
|
+
`;
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* @extends HTMLElement
|
|
1563
|
+
* @private
|
|
1564
|
+
*/
|
|
1565
|
+
class InfiniteScroller extends HTMLElement {
|
|
1566
|
+
constructor() {
|
|
1567
|
+
super();
|
|
1568
|
+
|
|
1569
|
+
const root = this.attachShadow({ mode: 'open' });
|
|
1570
|
+
root.appendChild(template.content.cloneNode(true));
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* Count of individual items in each buffer.
|
|
1574
|
+
* The scroller has 2 buffers altogether so bufferSize of 20
|
|
1575
|
+
* will result in 40 buffered DOM items in total.
|
|
1576
|
+
* Changing after initialization not supported.
|
|
1577
|
+
* @type {number}
|
|
1578
|
+
*/
|
|
1579
|
+
this.bufferSize = 20;
|
|
1580
|
+
|
|
1581
|
+
/**
|
|
1582
|
+
* The amount of initial scroll top. Needed in order for the
|
|
1583
|
+
* user to be able to scroll backwards.
|
|
1584
|
+
* @type {number}
|
|
1585
|
+
* @private
|
|
1586
|
+
*/
|
|
1587
|
+
this._initialScroll = 500000;
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* The index/position mapped at _initialScroll point.
|
|
1591
|
+
* @type {number}
|
|
1592
|
+
* @private
|
|
1593
|
+
*/
|
|
1594
|
+
this._initialIndex = 0;
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* @type {boolean}
|
|
1598
|
+
* @private
|
|
1599
|
+
*/
|
|
1600
|
+
this._activated = false;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* @return {boolean}
|
|
1605
|
+
*/
|
|
1606
|
+
get active() {
|
|
1607
|
+
return this._activated;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
set active(active) {
|
|
1611
|
+
if (active && !this._activated) {
|
|
1612
|
+
this._createPool();
|
|
1613
|
+
this._activated = true;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
/**
|
|
1618
|
+
* @return {number}
|
|
1619
|
+
*/
|
|
1620
|
+
get bufferOffset() {
|
|
1621
|
+
return this._buffers[0].offsetTop;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
/**
|
|
1625
|
+
* @return {number}
|
|
1626
|
+
*/
|
|
1627
|
+
get itemHeight() {
|
|
1628
|
+
if (!this._itemHeightVal) {
|
|
1629
|
+
const itemHeight = getComputedStyle(this).getPropertyValue('--vaadin-infinite-scroller-item-height');
|
|
1630
|
+
// Use background-position temp inline style for unit conversion
|
|
1631
|
+
const tmpStyleProp = 'background-position';
|
|
1632
|
+
this.$.fullHeight.style.setProperty(tmpStyleProp, itemHeight);
|
|
1633
|
+
const itemHeightPx = getComputedStyle(this.$.fullHeight).getPropertyValue(tmpStyleProp);
|
|
1634
|
+
this.$.fullHeight.style.removeProperty(tmpStyleProp);
|
|
1635
|
+
this._itemHeightVal = parseFloat(itemHeightPx);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
return this._itemHeightVal;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
/** @private */
|
|
1642
|
+
get _bufferHeight() {
|
|
1643
|
+
return this.itemHeight * this.bufferSize;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* @return {number}
|
|
1648
|
+
*/
|
|
1649
|
+
get position() {
|
|
1650
|
+
return (this.$.scroller.scrollTop - this._buffers[0].translateY) / this.itemHeight + this._firstIndex;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Current scroller position as index. Can be a fractional number.
|
|
1655
|
+
*
|
|
1656
|
+
* @type {number}
|
|
1657
|
+
*/
|
|
1658
|
+
set position(index) {
|
|
1659
|
+
this._preventScrollEvent = true;
|
|
1660
|
+
if (index > this._firstIndex && index < this._firstIndex + this.bufferSize * 2) {
|
|
1661
|
+
this.$.scroller.scrollTop = this.itemHeight * (index - this._firstIndex) + this._buffers[0].translateY;
|
|
1662
|
+
} else {
|
|
1663
|
+
this._initialIndex = ~~index;
|
|
1664
|
+
this._reset();
|
|
1665
|
+
this._scrollDisabled = true;
|
|
1666
|
+
this.$.scroller.scrollTop += (index % 1) * this.itemHeight;
|
|
1667
|
+
this._scrollDisabled = false;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
if (this._mayHaveMomentum) {
|
|
1671
|
+
// Stop the possible iOS Safari momentum with -webkit-overflow-scrolling: auto;
|
|
1672
|
+
this.$.scroller.classList.add('notouchscroll');
|
|
1673
|
+
this._mayHaveMomentum = false;
|
|
836
1674
|
|
|
837
|
-
if (this._mayHaveMomentum) {
|
|
838
|
-
// Stop the possible iOS Safari momentum with -webkit-overflow-scrolling: auto;
|
|
839
|
-
this.$.scroller.classList.add('notouchscroll');
|
|
840
|
-
this._mayHaveMomentum = false;
|
|
841
|
-
|
|
842
1675
|
setTimeout(() => {
|
|
843
1676
|
// Restore -webkit-overflow-scrolling: touch; after a small delay.
|
|
844
1677
|
this.$.scroller.classList.remove('notouchscroll');
|
|
@@ -1546,11 +2379,11 @@ function showHideChildren(hide, children) {
|
|
|
1546
2379
|
} else if (n.localName === 'slot') {
|
|
1547
2380
|
if (hide) {
|
|
1548
2381
|
n.__polymerReplaced__ = document.createComment('hidden-slot');
|
|
1549
|
-
wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);
|
|
2382
|
+
wrap$1(wrap$1(n).parentNode).replaceChild(n.__polymerReplaced__, n);
|
|
1550
2383
|
} else {
|
|
1551
2384
|
const replace = n.__polymerReplaced__;
|
|
1552
2385
|
if (replace) {
|
|
1553
|
-
wrap(wrap(replace).parentNode).replaceChild(n, replace);
|
|
2386
|
+
wrap$1(wrap$1(replace).parentNode).replaceChild(n, replace);
|
|
1554
2387
|
}
|
|
1555
2388
|
}
|
|
1556
2389
|
}
|
|
@@ -2106,7 +2939,7 @@ function modelForElement(template, node) {
|
|
|
2106
2939
|
} else {
|
|
2107
2940
|
// Still in a template scope, keep going up until
|
|
2108
2941
|
// a __templatizeInstance is found
|
|
2109
|
-
node = wrap(node).parentNode;
|
|
2942
|
+
node = wrap$1(node).parentNode;
|
|
2110
2943
|
}
|
|
2111
2944
|
}
|
|
2112
2945
|
return null;
|
|
@@ -2683,7 +3516,7 @@ class DomRepeat extends domRepeatBase {
|
|
|
2683
3516
|
// only perform attachment if the element was previously detached.
|
|
2684
3517
|
if (this.__isDetached) {
|
|
2685
3518
|
this.__isDetached = false;
|
|
2686
|
-
let wrappedParent = wrap(wrap(this).parentNode);
|
|
3519
|
+
let wrappedParent = wrap$1(wrap$1(this).parentNode);
|
|
2687
3520
|
for (let i=0; i<this.__instances.length; i++) {
|
|
2688
3521
|
this.__attachInstance(i, wrappedParent);
|
|
2689
3522
|
}
|
|
@@ -2840,7 +3673,7 @@ class DomRepeat extends domRepeatBase {
|
|
|
2840
3673
|
__debounceRender(fn, delay = 0) {
|
|
2841
3674
|
this.__renderDebouncer = Debouncer.debounce(
|
|
2842
3675
|
this.__renderDebouncer
|
|
2843
|
-
, delay > 0 ? timeOut$1.after(delay) : microTask
|
|
3676
|
+
, delay > 0 ? timeOut$1.after(delay) : microTask$1
|
|
2844
3677
|
, fn.bind(this));
|
|
2845
3678
|
enqueueDebouncer(this.__renderDebouncer);
|
|
2846
3679
|
}
|
|
@@ -2994,7 +3827,7 @@ class DomRepeat extends domRepeatBase {
|
|
|
2994
3827
|
|
|
2995
3828
|
__detachInstance(idx) {
|
|
2996
3829
|
let inst = this.__instances[idx];
|
|
2997
|
-
const wrappedRoot = wrap(inst.root);
|
|
3830
|
+
const wrappedRoot = wrap$1(inst.root);
|
|
2998
3831
|
for (let i=0; i<inst.children.length; i++) {
|
|
2999
3832
|
let el = inst.children[i];
|
|
3000
3833
|
wrappedRoot.appendChild(el);
|
|
@@ -3025,7 +3858,7 @@ class DomRepeat extends domRepeatBase {
|
|
|
3025
3858
|
const inst = this.__stampInstance(item, instIdx, itemIdx);
|
|
3026
3859
|
let beforeRow = this.__instances[instIdx + 1];
|
|
3027
3860
|
let beforeNode = beforeRow ? beforeRow.children[0] : this;
|
|
3028
|
-
wrap(wrap(this).parentNode).insertBefore(inst.root, beforeNode);
|
|
3861
|
+
wrap$1(wrap$1(this).parentNode).insertBefore(inst.root, beforeNode);
|
|
3029
3862
|
this.__instances[instIdx] = inst;
|
|
3030
3863
|
return inst;
|
|
3031
3864
|
}
|
|
@@ -3085,50 +3918,918 @@ class DomRepeat extends domRepeatBase {
|
|
|
3085
3918
|
* @param {!HTMLElement} el Element for which to return the item.
|
|
3086
3919
|
* @return {*} Item associated with the element.
|
|
3087
3920
|
*/
|
|
3088
|
-
itemForElement(el) {
|
|
3089
|
-
let instance = this.modelForElement(el);
|
|
3090
|
-
return instance && instance[this.as];
|
|
3091
|
-
}
|
|
3921
|
+
itemForElement(el) {
|
|
3922
|
+
let instance = this.modelForElement(el);
|
|
3923
|
+
return instance && instance[this.as];
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
/**
|
|
3927
|
+
* Returns the inst index for a given element stamped by this `dom-repeat`.
|
|
3928
|
+
* If `sort` is provided, the index will reflect the sorted order (rather
|
|
3929
|
+
* than the original array order).
|
|
3930
|
+
*
|
|
3931
|
+
* @param {!HTMLElement} el Element for which to return the index.
|
|
3932
|
+
* @return {?number} Row index associated with the element (note this may
|
|
3933
|
+
* not correspond to the array index if a user `sort` is applied).
|
|
3934
|
+
*/
|
|
3935
|
+
indexForElement(el) {
|
|
3936
|
+
let instance = this.modelForElement(el);
|
|
3937
|
+
return instance && instance[this.indexAs];
|
|
3938
|
+
}
|
|
3939
|
+
|
|
3940
|
+
/**
|
|
3941
|
+
* Returns the template "model" associated with a given element, which
|
|
3942
|
+
* serves as the binding scope for the template instance the element is
|
|
3943
|
+
* contained in. A template model
|
|
3944
|
+
* should be used to manipulate data associated with this template instance.
|
|
3945
|
+
*
|
|
3946
|
+
* Example:
|
|
3947
|
+
*
|
|
3948
|
+
* let model = modelForElement(el);
|
|
3949
|
+
* if (model.index < 10) {
|
|
3950
|
+
* model.set('item.checked', true);
|
|
3951
|
+
* }
|
|
3952
|
+
*
|
|
3953
|
+
* @param {!HTMLElement} el Element for which to return a template model.
|
|
3954
|
+
* @return {TemplateInstanceBase} Model representing the binding scope for
|
|
3955
|
+
* the element.
|
|
3956
|
+
*/
|
|
3957
|
+
modelForElement(el) {
|
|
3958
|
+
return modelForElement(this.template, el);
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
}
|
|
3962
|
+
|
|
3963
|
+
customElements.define(DomRepeat.is, DomRepeat);
|
|
3964
|
+
|
|
3965
|
+
/**
|
|
3966
|
+
@license
|
|
3967
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
3968
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
3969
|
+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
3970
|
+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
3971
|
+
Code distributed by Google as part of the polymer project is also
|
|
3972
|
+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
3973
|
+
*/
|
|
3974
|
+
|
|
3975
|
+
const passiveTouchGestures = false;
|
|
3976
|
+
const wrap = (node) => node;
|
|
3977
|
+
|
|
3978
|
+
// Detect native touch action support
|
|
3979
|
+
const HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
|
|
3980
|
+
const GESTURE_KEY = '__polymerGestures';
|
|
3981
|
+
const HANDLED_OBJ = '__polymerGesturesHandled';
|
|
3982
|
+
const TOUCH_ACTION = '__polymerGesturesTouchAction';
|
|
3983
|
+
// Radius for tap and track
|
|
3984
|
+
const TAP_DISTANCE = 25;
|
|
3985
|
+
const TRACK_DISTANCE = 5;
|
|
3986
|
+
// Number of last N track positions to keep
|
|
3987
|
+
const TRACK_LENGTH = 2;
|
|
3988
|
+
|
|
3989
|
+
const MOUSE_EVENTS = ['mousedown', 'mousemove', 'mouseup', 'click'];
|
|
3990
|
+
// An array of bitmask values for mapping MouseEvent.which to MouseEvent.buttons
|
|
3991
|
+
const MOUSE_WHICH_TO_BUTTONS = [0, 1, 4, 2];
|
|
3992
|
+
const MOUSE_HAS_BUTTONS = (function () {
|
|
3993
|
+
try {
|
|
3994
|
+
return new MouseEvent('test', { buttons: 1 }).buttons === 1;
|
|
3995
|
+
} catch (e) {
|
|
3996
|
+
return false;
|
|
3997
|
+
}
|
|
3998
|
+
})();
|
|
3999
|
+
|
|
4000
|
+
/**
|
|
4001
|
+
* @param {string} name Possible mouse event name
|
|
4002
|
+
* @return {boolean} true if mouse event, false if not
|
|
4003
|
+
*/
|
|
4004
|
+
function isMouseEvent(name) {
|
|
4005
|
+
return MOUSE_EVENTS.indexOf(name) > -1;
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
/* eslint no-empty: ["error", { "allowEmptyCatch": true }] */
|
|
4009
|
+
// check for passive event listeners
|
|
4010
|
+
let supportsPassive = false;
|
|
4011
|
+
(function () {
|
|
4012
|
+
try {
|
|
4013
|
+
const opts = Object.defineProperty({}, 'passive', {
|
|
4014
|
+
// eslint-disable-next-line getter-return
|
|
4015
|
+
get() {
|
|
4016
|
+
supportsPassive = true;
|
|
4017
|
+
},
|
|
4018
|
+
});
|
|
4019
|
+
window.addEventListener('test', null, opts);
|
|
4020
|
+
window.removeEventListener('test', null, opts);
|
|
4021
|
+
} catch (e) {}
|
|
4022
|
+
})();
|
|
4023
|
+
|
|
4024
|
+
/**
|
|
4025
|
+
* Generate settings for event listeners, dependant on `passiveTouchGestures`
|
|
4026
|
+
*
|
|
4027
|
+
* @param {string} eventName Event name to determine if `{passive}` option is
|
|
4028
|
+
* needed
|
|
4029
|
+
* @return {{passive: boolean} | undefined} Options to use for addEventListener
|
|
4030
|
+
* and removeEventListener
|
|
4031
|
+
*/
|
|
4032
|
+
function PASSIVE_TOUCH(eventName) {
|
|
4033
|
+
if (isMouseEvent(eventName) || eventName === 'touchend') {
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
if (HAS_NATIVE_TA && supportsPassive && passiveTouchGestures) {
|
|
4037
|
+
return { passive: true };
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
// Check for touch-only devices
|
|
4042
|
+
const IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/u);
|
|
4043
|
+
|
|
4044
|
+
// Defined at https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute
|
|
4045
|
+
/** @type {!Object<boolean>} */
|
|
4046
|
+
const canBeDisabled = {
|
|
4047
|
+
button: true,
|
|
4048
|
+
command: true,
|
|
4049
|
+
fieldset: true,
|
|
4050
|
+
input: true,
|
|
4051
|
+
keygen: true,
|
|
4052
|
+
optgroup: true,
|
|
4053
|
+
option: true,
|
|
4054
|
+
select: true,
|
|
4055
|
+
textarea: true,
|
|
4056
|
+
};
|
|
4057
|
+
|
|
4058
|
+
/**
|
|
4059
|
+
* @param {MouseEvent} ev event to test for left mouse button down
|
|
4060
|
+
* @return {boolean} has left mouse button down
|
|
4061
|
+
*/
|
|
4062
|
+
function hasLeftMouseButton(ev) {
|
|
4063
|
+
const type = ev.type;
|
|
4064
|
+
// Exit early if the event is not a mouse event
|
|
4065
|
+
if (!isMouseEvent(type)) {
|
|
4066
|
+
return false;
|
|
4067
|
+
}
|
|
4068
|
+
// Ev.button is not reliable for mousemove (0 is overloaded as both left button and no buttons)
|
|
4069
|
+
// instead we use ev.buttons (bitmask of buttons) or fall back to ev.which (deprecated, 0 for no buttons, 1 for left button)
|
|
4070
|
+
if (type === 'mousemove') {
|
|
4071
|
+
// Allow undefined for testing events
|
|
4072
|
+
let buttons = ev.buttons === undefined ? 1 : ev.buttons;
|
|
4073
|
+
if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
|
|
4074
|
+
buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
|
|
4075
|
+
}
|
|
4076
|
+
// Buttons is a bitmask, check that the left button bit is set (1)
|
|
4077
|
+
return Boolean(buttons & 1);
|
|
4078
|
+
}
|
|
4079
|
+
// Allow undefined for testing events
|
|
4080
|
+
const button = ev.button === undefined ? 0 : ev.button;
|
|
4081
|
+
// Ev.button is 0 in mousedown/mouseup/click for left button activation
|
|
4082
|
+
return button === 0;
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
function isSyntheticClick(ev) {
|
|
4086
|
+
if (ev.type === 'click') {
|
|
4087
|
+
// Ev.detail is 0 for HTMLElement.click in most browsers
|
|
4088
|
+
if (ev.detail === 0) {
|
|
4089
|
+
return true;
|
|
4090
|
+
}
|
|
4091
|
+
// In the worst case, check that the x/y position of the click is within
|
|
4092
|
+
// the bounding box of the target of the event
|
|
4093
|
+
// Thanks IE 10 >:(
|
|
4094
|
+
const t = _findOriginalTarget(ev);
|
|
4095
|
+
// Make sure the target of the event is an element so we can use getBoundingClientRect,
|
|
4096
|
+
// if not, just assume it is a synthetic click
|
|
4097
|
+
if (!t.nodeType || /** @type {Element} */ (t).nodeType !== Node.ELEMENT_NODE) {
|
|
4098
|
+
return true;
|
|
4099
|
+
}
|
|
4100
|
+
const bcr = /** @type {Element} */ (t).getBoundingClientRect();
|
|
4101
|
+
// Use page x/y to account for scrolling
|
|
4102
|
+
const x = ev.pageX,
|
|
4103
|
+
y = ev.pageY;
|
|
4104
|
+
// Ev is a synthetic click if the position is outside the bounding box of the target
|
|
4105
|
+
return !(x >= bcr.left && x <= bcr.right && y >= bcr.top && y <= bcr.bottom);
|
|
4106
|
+
}
|
|
4107
|
+
return false;
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
const POINTERSTATE = {
|
|
4111
|
+
mouse: {
|
|
4112
|
+
target: null,
|
|
4113
|
+
mouseIgnoreJob: null,
|
|
4114
|
+
},
|
|
4115
|
+
touch: {
|
|
4116
|
+
x: 0,
|
|
4117
|
+
y: 0,
|
|
4118
|
+
id: -1,
|
|
4119
|
+
scrollDecided: false,
|
|
4120
|
+
},
|
|
4121
|
+
};
|
|
4122
|
+
|
|
4123
|
+
function firstTouchAction(ev) {
|
|
4124
|
+
let ta = 'auto';
|
|
4125
|
+
const path = getComposedPath(ev);
|
|
4126
|
+
for (let i = 0, n; i < path.length; i++) {
|
|
4127
|
+
n = path[i];
|
|
4128
|
+
if (n[TOUCH_ACTION]) {
|
|
4129
|
+
ta = n[TOUCH_ACTION];
|
|
4130
|
+
break;
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
return ta;
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
function trackDocument(stateObj, movefn, upfn) {
|
|
4137
|
+
stateObj.movefn = movefn;
|
|
4138
|
+
stateObj.upfn = upfn;
|
|
4139
|
+
document.addEventListener('mousemove', movefn);
|
|
4140
|
+
document.addEventListener('mouseup', upfn);
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
function untrackDocument(stateObj) {
|
|
4144
|
+
document.removeEventListener('mousemove', stateObj.movefn);
|
|
4145
|
+
document.removeEventListener('mouseup', stateObj.upfn);
|
|
4146
|
+
stateObj.movefn = null;
|
|
4147
|
+
stateObj.upfn = null;
|
|
4148
|
+
}
|
|
4149
|
+
|
|
4150
|
+
/**
|
|
4151
|
+
* Returns the composedPath for the given event.
|
|
4152
|
+
* @param {Event} event to process
|
|
4153
|
+
* @return {!Array<!EventTarget>} Path of the event
|
|
4154
|
+
*/
|
|
4155
|
+
const getComposedPath =
|
|
4156
|
+
window.ShadyDOM && window.ShadyDOM.noPatch
|
|
4157
|
+
? window.ShadyDOM.composedPath
|
|
4158
|
+
: (event) => (event.composedPath && event.composedPath()) || [];
|
|
4159
|
+
|
|
4160
|
+
/** @type {!Object<string, !GestureRecognizer>} */
|
|
4161
|
+
const gestures = {};
|
|
4162
|
+
|
|
4163
|
+
/** @type {!Array<!GestureRecognizer>} */
|
|
4164
|
+
const recognizers = [];
|
|
4165
|
+
|
|
4166
|
+
/**
|
|
4167
|
+
* Finds the element rendered on the screen at the provided coordinates.
|
|
4168
|
+
*
|
|
4169
|
+
* Similar to `document.elementFromPoint`, but pierces through
|
|
4170
|
+
* shadow roots.
|
|
4171
|
+
*
|
|
4172
|
+
* @param {number} x Horizontal pixel coordinate
|
|
4173
|
+
* @param {number} y Vertical pixel coordinate
|
|
4174
|
+
* @return {Element} Returns the deepest shadowRoot inclusive element
|
|
4175
|
+
* found at the screen position given.
|
|
4176
|
+
*/
|
|
4177
|
+
function deepTargetFind(x, y) {
|
|
4178
|
+
let node = document.elementFromPoint(x, y);
|
|
4179
|
+
let next = node;
|
|
4180
|
+
// This code path is only taken when native ShadowDOM is used
|
|
4181
|
+
// if there is a shadowroot, it may have a node at x/y
|
|
4182
|
+
// if there is not a shadowroot, exit the loop
|
|
4183
|
+
while (next && next.shadowRoot && !window.ShadyDOM) {
|
|
4184
|
+
// If there is a node at x/y in the shadowroot, look deeper
|
|
4185
|
+
const oldNext = next;
|
|
4186
|
+
next = next.shadowRoot.elementFromPoint(x, y);
|
|
4187
|
+
// On Safari, elementFromPoint may return the shadowRoot host
|
|
4188
|
+
if (oldNext === next) {
|
|
4189
|
+
break;
|
|
4190
|
+
}
|
|
4191
|
+
if (next) {
|
|
4192
|
+
node = next;
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
return node;
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
/**
|
|
4199
|
+
* A cheaper check than ev.composedPath()[0];
|
|
4200
|
+
*
|
|
4201
|
+
* @private
|
|
4202
|
+
* @param {Event|Touch} ev Event.
|
|
4203
|
+
* @return {EventTarget} Returns the event target.
|
|
4204
|
+
*/
|
|
4205
|
+
function _findOriginalTarget(ev) {
|
|
4206
|
+
const path = getComposedPath(/** @type {?Event} */ (ev));
|
|
4207
|
+
// It shouldn't be, but sometimes path is empty (window on Safari).
|
|
4208
|
+
return path.length > 0 ? path[0] : ev.target;
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
/**
|
|
4212
|
+
* @private
|
|
4213
|
+
* @param {Event} ev Event.
|
|
4214
|
+
* @return {void}
|
|
4215
|
+
*/
|
|
4216
|
+
function _handleNative(ev) {
|
|
4217
|
+
const type = ev.type;
|
|
4218
|
+
const node = ev.currentTarget;
|
|
4219
|
+
const gobj = node[GESTURE_KEY];
|
|
4220
|
+
if (!gobj) {
|
|
4221
|
+
return;
|
|
4222
|
+
}
|
|
4223
|
+
const gs = gobj[type];
|
|
4224
|
+
if (!gs) {
|
|
4225
|
+
return;
|
|
4226
|
+
}
|
|
4227
|
+
if (!ev[HANDLED_OBJ]) {
|
|
4228
|
+
ev[HANDLED_OBJ] = {};
|
|
4229
|
+
if (type.startsWith('touch')) {
|
|
4230
|
+
const t = ev.changedTouches[0];
|
|
4231
|
+
if (type === 'touchstart') {
|
|
4232
|
+
// Only handle the first finger
|
|
4233
|
+
if (ev.touches.length === 1) {
|
|
4234
|
+
POINTERSTATE.touch.id = t.identifier;
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
if (POINTERSTATE.touch.id !== t.identifier) {
|
|
4238
|
+
return;
|
|
4239
|
+
}
|
|
4240
|
+
if (!HAS_NATIVE_TA) {
|
|
4241
|
+
if (type === 'touchstart' || type === 'touchmove') {
|
|
4242
|
+
_handleTouchAction(ev);
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
const handled = ev[HANDLED_OBJ];
|
|
4248
|
+
// Used to ignore synthetic mouse events
|
|
4249
|
+
if (handled.skip) {
|
|
4250
|
+
return;
|
|
4251
|
+
}
|
|
4252
|
+
// Reset recognizer state
|
|
4253
|
+
for (let i = 0, r; i < recognizers.length; i++) {
|
|
4254
|
+
r = recognizers[i];
|
|
4255
|
+
if (gs[r.name] && !handled[r.name]) {
|
|
4256
|
+
if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
|
|
4257
|
+
r.reset();
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
// Enforce gesture recognizer order
|
|
4262
|
+
for (let i = 0, r; i < recognizers.length; i++) {
|
|
4263
|
+
r = recognizers[i];
|
|
4264
|
+
if (gs[r.name] && !handled[r.name]) {
|
|
4265
|
+
handled[r.name] = true;
|
|
4266
|
+
r[type](ev);
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
/**
|
|
4272
|
+
* @private
|
|
4273
|
+
* @param {TouchEvent} ev Event.
|
|
4274
|
+
* @return {void}
|
|
4275
|
+
*/
|
|
4276
|
+
function _handleTouchAction(ev) {
|
|
4277
|
+
const t = ev.changedTouches[0];
|
|
4278
|
+
const type = ev.type;
|
|
4279
|
+
if (type === 'touchstart') {
|
|
4280
|
+
POINTERSTATE.touch.x = t.clientX;
|
|
4281
|
+
POINTERSTATE.touch.y = t.clientY;
|
|
4282
|
+
POINTERSTATE.touch.scrollDecided = false;
|
|
4283
|
+
} else if (type === 'touchmove') {
|
|
4284
|
+
if (POINTERSTATE.touch.scrollDecided) {
|
|
4285
|
+
return;
|
|
4286
|
+
}
|
|
4287
|
+
POINTERSTATE.touch.scrollDecided = true;
|
|
4288
|
+
const ta = firstTouchAction(ev);
|
|
4289
|
+
let shouldPrevent = false;
|
|
4290
|
+
const dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
|
|
4291
|
+
const dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
|
|
4292
|
+
if (!ev.cancelable) ; else if (ta === 'none') {
|
|
4293
|
+
shouldPrevent = true;
|
|
4294
|
+
} else if (ta === 'pan-x') {
|
|
4295
|
+
shouldPrevent = dy > dx;
|
|
4296
|
+
} else if (ta === 'pan-y') {
|
|
4297
|
+
shouldPrevent = dx > dy;
|
|
4298
|
+
}
|
|
4299
|
+
if (shouldPrevent) {
|
|
4300
|
+
ev.preventDefault();
|
|
4301
|
+
} else {
|
|
4302
|
+
prevent('track');
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
|
|
4307
|
+
/**
|
|
4308
|
+
* Adds an event listener to a node for the given gesture type.
|
|
4309
|
+
*
|
|
4310
|
+
* @param {!EventTarget} node Node to add listener on
|
|
4311
|
+
* @param {string} evType Gesture type: `down`, `up`, `track`, or `tap`
|
|
4312
|
+
* @param {!function(!Event):void} handler Event listener function to call
|
|
4313
|
+
* @return {boolean} Returns true if a gesture event listener was added.
|
|
4314
|
+
*/
|
|
4315
|
+
function addListener(node, evType, handler) {
|
|
4316
|
+
if (gestures[evType]) {
|
|
4317
|
+
_add(node, evType, handler);
|
|
4318
|
+
return true;
|
|
4319
|
+
}
|
|
4320
|
+
return false;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
/**
|
|
4324
|
+
* Automate the event listeners for the native events
|
|
4325
|
+
*
|
|
4326
|
+
* @private
|
|
4327
|
+
* @param {!EventTarget} node Node on which to add the event.
|
|
4328
|
+
* @param {string} evType Event type to add.
|
|
4329
|
+
* @param {function(!Event)} handler Event handler function.
|
|
4330
|
+
* @return {void}
|
|
4331
|
+
*/
|
|
4332
|
+
function _add(node, evType, handler) {
|
|
4333
|
+
const recognizer = gestures[evType];
|
|
4334
|
+
const deps = recognizer.deps;
|
|
4335
|
+
const name = recognizer.name;
|
|
4336
|
+
let gobj = node[GESTURE_KEY];
|
|
4337
|
+
if (!gobj) {
|
|
4338
|
+
node[GESTURE_KEY] = gobj = {};
|
|
4339
|
+
}
|
|
4340
|
+
for (let i = 0, dep, gd; i < deps.length; i++) {
|
|
4341
|
+
dep = deps[i];
|
|
4342
|
+
// Don't add mouse handlers on iOS because they cause gray selection overlays
|
|
4343
|
+
if (IS_TOUCH_ONLY && isMouseEvent(dep) && dep !== 'click') {
|
|
4344
|
+
continue;
|
|
4345
|
+
}
|
|
4346
|
+
gd = gobj[dep];
|
|
4347
|
+
if (!gd) {
|
|
4348
|
+
gobj[dep] = gd = { _count: 0 };
|
|
4349
|
+
}
|
|
4350
|
+
if (gd._count === 0) {
|
|
4351
|
+
node.addEventListener(dep, _handleNative, PASSIVE_TOUCH(dep));
|
|
4352
|
+
}
|
|
4353
|
+
gd[name] = (gd[name] || 0) + 1;
|
|
4354
|
+
gd._count = (gd._count || 0) + 1;
|
|
4355
|
+
}
|
|
4356
|
+
node.addEventListener(evType, handler);
|
|
4357
|
+
if (recognizer.touchAction) {
|
|
4358
|
+
setTouchAction(node, recognizer.touchAction);
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
/**
|
|
4363
|
+
* Registers a new gesture event recognizer for adding new custom
|
|
4364
|
+
* gesture event types.
|
|
4365
|
+
*
|
|
4366
|
+
* @param {!GestureRecognizer} recog Gesture recognizer descriptor
|
|
4367
|
+
* @return {void}
|
|
4368
|
+
*/
|
|
4369
|
+
function register(recog) {
|
|
4370
|
+
recognizers.push(recog);
|
|
4371
|
+
recog.emits.forEach((emit) => {
|
|
4372
|
+
gestures[emit] = recog;
|
|
4373
|
+
});
|
|
4374
|
+
}
|
|
4375
|
+
|
|
4376
|
+
/**
|
|
4377
|
+
* @private
|
|
4378
|
+
* @param {string} evName Event name.
|
|
4379
|
+
* @return {Object} Returns the gesture for the given event name.
|
|
4380
|
+
*/
|
|
4381
|
+
function _findRecognizerByEvent(evName) {
|
|
4382
|
+
for (let i = 0, r; i < recognizers.length; i++) {
|
|
4383
|
+
r = recognizers[i];
|
|
4384
|
+
for (let j = 0, n; j < r.emits.length; j++) {
|
|
4385
|
+
n = r.emits[j];
|
|
4386
|
+
if (n === evName) {
|
|
4387
|
+
return r;
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
return null;
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
/**
|
|
4395
|
+
* Sets scrolling direction on node.
|
|
4396
|
+
*
|
|
4397
|
+
* This value is checked on first move, thus it should be called prior to
|
|
4398
|
+
* adding event listeners.
|
|
4399
|
+
*
|
|
4400
|
+
* @param {!EventTarget} node Node to set touch action setting on
|
|
4401
|
+
* @param {string} value Touch action value
|
|
4402
|
+
* @return {void}
|
|
4403
|
+
*/
|
|
4404
|
+
function setTouchAction(node, value) {
|
|
4405
|
+
if (HAS_NATIVE_TA && node instanceof HTMLElement) {
|
|
4406
|
+
// NOTE: add touchAction async so that events can be added in
|
|
4407
|
+
// custom element constructors. Otherwise we run afoul of custom
|
|
4408
|
+
// elements restriction against settings attributes (style) in the
|
|
4409
|
+
// constructor.
|
|
4410
|
+
microTask.run(() => {
|
|
4411
|
+
node.style.touchAction = value;
|
|
4412
|
+
});
|
|
4413
|
+
}
|
|
4414
|
+
node[TOUCH_ACTION] = value;
|
|
4415
|
+
}
|
|
4416
|
+
|
|
4417
|
+
/**
|
|
4418
|
+
* Dispatches an event on the `target` element of `type` with the given
|
|
4419
|
+
* `detail`.
|
|
4420
|
+
* @private
|
|
4421
|
+
* @param {!EventTarget} target The element on which to fire an event.
|
|
4422
|
+
* @param {string} type The type of event to fire.
|
|
4423
|
+
* @param {!Object=} detail The detail object to populate on the event.
|
|
4424
|
+
* @return {void}
|
|
4425
|
+
*/
|
|
4426
|
+
function _fire(target, type, detail) {
|
|
4427
|
+
const ev = new Event(type, { bubbles: true, cancelable: true, composed: true });
|
|
4428
|
+
ev.detail = detail;
|
|
4429
|
+
wrap(/** @type {!Node} */ (target)).dispatchEvent(ev);
|
|
4430
|
+
// Forward `preventDefault` in a clean way
|
|
4431
|
+
if (ev.defaultPrevented) {
|
|
4432
|
+
const preventer = detail.preventer || detail.sourceEvent;
|
|
4433
|
+
if (preventer && preventer.preventDefault) {
|
|
4434
|
+
preventer.preventDefault();
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
/**
|
|
4440
|
+
* Prevents the dispatch and default action of the given event name.
|
|
4441
|
+
*
|
|
4442
|
+
* @param {string} evName Event name.
|
|
4443
|
+
* @return {void}
|
|
4444
|
+
*/
|
|
4445
|
+
function prevent(evName) {
|
|
4446
|
+
const recognizer = _findRecognizerByEvent(evName);
|
|
4447
|
+
if (recognizer.info) {
|
|
4448
|
+
recognizer.info.prevent = true;
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
register({
|
|
4453
|
+
name: 'downup',
|
|
4454
|
+
deps: ['mousedown', 'touchstart', 'touchend'],
|
|
4455
|
+
flow: {
|
|
4456
|
+
start: ['mousedown', 'touchstart'],
|
|
4457
|
+
end: ['mouseup', 'touchend'],
|
|
4458
|
+
},
|
|
4459
|
+
emits: ['down', 'up'],
|
|
4460
|
+
|
|
4461
|
+
info: {
|
|
4462
|
+
movefn: null,
|
|
4463
|
+
upfn: null,
|
|
4464
|
+
},
|
|
4465
|
+
|
|
4466
|
+
/**
|
|
4467
|
+
* @this {GestureRecognizer}
|
|
4468
|
+
* @return {void}
|
|
4469
|
+
*/
|
|
4470
|
+
reset() {
|
|
4471
|
+
untrackDocument(this.info);
|
|
4472
|
+
},
|
|
4473
|
+
|
|
4474
|
+
/**
|
|
4475
|
+
* @this {GestureRecognizer}
|
|
4476
|
+
* @param {MouseEvent} e
|
|
4477
|
+
* @return {void}
|
|
4478
|
+
*/
|
|
4479
|
+
mousedown(e) {
|
|
4480
|
+
if (!hasLeftMouseButton(e)) {
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
const t = _findOriginalTarget(e);
|
|
4484
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
4485
|
+
const self = this;
|
|
4486
|
+
const movefn = (e) => {
|
|
4487
|
+
if (!hasLeftMouseButton(e)) {
|
|
4488
|
+
downupFire('up', t, e);
|
|
4489
|
+
untrackDocument(self.info);
|
|
4490
|
+
}
|
|
4491
|
+
};
|
|
4492
|
+
const upfn = (e) => {
|
|
4493
|
+
if (hasLeftMouseButton(e)) {
|
|
4494
|
+
downupFire('up', t, e);
|
|
4495
|
+
}
|
|
4496
|
+
untrackDocument(self.info);
|
|
4497
|
+
};
|
|
4498
|
+
trackDocument(this.info, movefn, upfn);
|
|
4499
|
+
downupFire('down', t, e);
|
|
4500
|
+
},
|
|
4501
|
+
|
|
4502
|
+
/**
|
|
4503
|
+
* @this {GestureRecognizer}
|
|
4504
|
+
* @param {TouchEvent} e
|
|
4505
|
+
* @return {void}
|
|
4506
|
+
*/
|
|
4507
|
+
touchstart(e) {
|
|
4508
|
+
downupFire('down', _findOriginalTarget(e), e.changedTouches[0], e);
|
|
4509
|
+
},
|
|
4510
|
+
|
|
4511
|
+
/**
|
|
4512
|
+
* @this {GestureRecognizer}
|
|
4513
|
+
* @param {TouchEvent} e
|
|
4514
|
+
* @return {void}
|
|
4515
|
+
*/
|
|
4516
|
+
touchend(e) {
|
|
4517
|
+
downupFire('up', _findOriginalTarget(e), e.changedTouches[0], e);
|
|
4518
|
+
},
|
|
4519
|
+
});
|
|
4520
|
+
|
|
4521
|
+
/**
|
|
4522
|
+
* @param {string} type
|
|
4523
|
+
* @param {EventTarget} target
|
|
4524
|
+
* @param {Event|Touch} event
|
|
4525
|
+
* @param {Event=} preventer
|
|
4526
|
+
* @return {void}
|
|
4527
|
+
*/
|
|
4528
|
+
function downupFire(type, target, event, preventer) {
|
|
4529
|
+
if (!target) {
|
|
4530
|
+
return;
|
|
4531
|
+
}
|
|
4532
|
+
_fire(target, type, {
|
|
4533
|
+
x: event.clientX,
|
|
4534
|
+
y: event.clientY,
|
|
4535
|
+
sourceEvent: event,
|
|
4536
|
+
preventer,
|
|
4537
|
+
prevent(e) {
|
|
4538
|
+
return prevent(e);
|
|
4539
|
+
},
|
|
4540
|
+
});
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
register({
|
|
4544
|
+
name: 'track',
|
|
4545
|
+
touchAction: 'none',
|
|
4546
|
+
deps: ['mousedown', 'touchstart', 'touchmove', 'touchend'],
|
|
4547
|
+
flow: {
|
|
4548
|
+
start: ['mousedown', 'touchstart'],
|
|
4549
|
+
end: ['mouseup', 'touchend'],
|
|
4550
|
+
},
|
|
4551
|
+
emits: ['track'],
|
|
4552
|
+
|
|
4553
|
+
info: {
|
|
4554
|
+
x: 0,
|
|
4555
|
+
y: 0,
|
|
4556
|
+
state: 'start',
|
|
4557
|
+
started: false,
|
|
4558
|
+
moves: [],
|
|
4559
|
+
/** @this {GestureInfo} */
|
|
4560
|
+
addMove(move) {
|
|
4561
|
+
if (this.moves.length > TRACK_LENGTH) {
|
|
4562
|
+
this.moves.shift();
|
|
4563
|
+
}
|
|
4564
|
+
this.moves.push(move);
|
|
4565
|
+
},
|
|
4566
|
+
movefn: null,
|
|
4567
|
+
upfn: null,
|
|
4568
|
+
prevent: false,
|
|
4569
|
+
},
|
|
4570
|
+
|
|
4571
|
+
/**
|
|
4572
|
+
* @this {GestureRecognizer}
|
|
4573
|
+
* @return {void}
|
|
4574
|
+
*/
|
|
4575
|
+
reset() {
|
|
4576
|
+
this.info.state = 'start';
|
|
4577
|
+
this.info.started = false;
|
|
4578
|
+
this.info.moves = [];
|
|
4579
|
+
this.info.x = 0;
|
|
4580
|
+
this.info.y = 0;
|
|
4581
|
+
this.info.prevent = false;
|
|
4582
|
+
untrackDocument(this.info);
|
|
4583
|
+
},
|
|
4584
|
+
|
|
4585
|
+
/**
|
|
4586
|
+
* @this {GestureRecognizer}
|
|
4587
|
+
* @param {MouseEvent} e
|
|
4588
|
+
* @return {void}
|
|
4589
|
+
*/
|
|
4590
|
+
mousedown(e) {
|
|
4591
|
+
if (!hasLeftMouseButton(e)) {
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
const t = _findOriginalTarget(e);
|
|
4595
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
4596
|
+
const self = this;
|
|
4597
|
+
const movefn = (e) => {
|
|
4598
|
+
const x = e.clientX,
|
|
4599
|
+
y = e.clientY;
|
|
4600
|
+
if (trackHasMovedEnough(self.info, x, y)) {
|
|
4601
|
+
// First move is 'start', subsequent moves are 'move', mouseup is 'end'
|
|
4602
|
+
self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start';
|
|
4603
|
+
if (self.info.state === 'start') {
|
|
4604
|
+
// If and only if tracking, always prevent tap
|
|
4605
|
+
prevent('tap');
|
|
4606
|
+
}
|
|
4607
|
+
self.info.addMove({ x, y });
|
|
4608
|
+
if (!hasLeftMouseButton(e)) {
|
|
4609
|
+
// Always fire "end"
|
|
4610
|
+
self.info.state = 'end';
|
|
4611
|
+
untrackDocument(self.info);
|
|
4612
|
+
}
|
|
4613
|
+
if (t) {
|
|
4614
|
+
trackFire(self.info, t, e);
|
|
4615
|
+
}
|
|
4616
|
+
self.info.started = true;
|
|
4617
|
+
}
|
|
4618
|
+
};
|
|
4619
|
+
const upfn = (e) => {
|
|
4620
|
+
if (self.info.started) {
|
|
4621
|
+
movefn(e);
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
// Remove the temporary listeners
|
|
4625
|
+
untrackDocument(self.info);
|
|
4626
|
+
};
|
|
4627
|
+
// Add temporary document listeners as mouse retargets
|
|
4628
|
+
trackDocument(this.info, movefn, upfn);
|
|
4629
|
+
this.info.x = e.clientX;
|
|
4630
|
+
this.info.y = e.clientY;
|
|
4631
|
+
},
|
|
4632
|
+
|
|
4633
|
+
/**
|
|
4634
|
+
* @this {GestureRecognizer}
|
|
4635
|
+
* @param {TouchEvent} e
|
|
4636
|
+
* @return {void}
|
|
4637
|
+
*/
|
|
4638
|
+
touchstart(e) {
|
|
4639
|
+
const ct = e.changedTouches[0];
|
|
4640
|
+
this.info.x = ct.clientX;
|
|
4641
|
+
this.info.y = ct.clientY;
|
|
4642
|
+
},
|
|
4643
|
+
|
|
4644
|
+
/**
|
|
4645
|
+
* @this {GestureRecognizer}
|
|
4646
|
+
* @param {TouchEvent} e
|
|
4647
|
+
* @return {void}
|
|
4648
|
+
*/
|
|
4649
|
+
touchmove(e) {
|
|
4650
|
+
const t = _findOriginalTarget(e);
|
|
4651
|
+
const ct = e.changedTouches[0];
|
|
4652
|
+
const x = ct.clientX,
|
|
4653
|
+
y = ct.clientY;
|
|
4654
|
+
if (trackHasMovedEnough(this.info, x, y)) {
|
|
4655
|
+
if (this.info.state === 'start') {
|
|
4656
|
+
// If and only if tracking, always prevent tap
|
|
4657
|
+
prevent('tap');
|
|
4658
|
+
}
|
|
4659
|
+
this.info.addMove({ x, y });
|
|
4660
|
+
trackFire(this.info, t, ct);
|
|
4661
|
+
this.info.state = 'track';
|
|
4662
|
+
this.info.started = true;
|
|
4663
|
+
}
|
|
4664
|
+
},
|
|
4665
|
+
|
|
4666
|
+
/**
|
|
4667
|
+
* @this {GestureRecognizer}
|
|
4668
|
+
* @param {TouchEvent} e
|
|
4669
|
+
* @return {void}
|
|
4670
|
+
*/
|
|
4671
|
+
touchend(e) {
|
|
4672
|
+
const t = _findOriginalTarget(e);
|
|
4673
|
+
const ct = e.changedTouches[0];
|
|
4674
|
+
// Only trackend if track was started and not aborted
|
|
4675
|
+
if (this.info.started) {
|
|
4676
|
+
// Reset started state on up
|
|
4677
|
+
this.info.state = 'end';
|
|
4678
|
+
this.info.addMove({ x: ct.clientX, y: ct.clientY });
|
|
4679
|
+
trackFire(this.info, t, ct);
|
|
4680
|
+
}
|
|
4681
|
+
},
|
|
4682
|
+
});
|
|
4683
|
+
|
|
4684
|
+
/**
|
|
4685
|
+
* @param {!GestureInfo} info
|
|
4686
|
+
* @param {number} x
|
|
4687
|
+
* @param {number} y
|
|
4688
|
+
* @return {boolean}
|
|
4689
|
+
*/
|
|
4690
|
+
function trackHasMovedEnough(info, x, y) {
|
|
4691
|
+
if (info.prevent) {
|
|
4692
|
+
return false;
|
|
4693
|
+
}
|
|
4694
|
+
if (info.started) {
|
|
4695
|
+
return true;
|
|
4696
|
+
}
|
|
4697
|
+
const dx = Math.abs(info.x - x);
|
|
4698
|
+
const dy = Math.abs(info.y - y);
|
|
4699
|
+
return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4702
|
+
/**
|
|
4703
|
+
* @param {!GestureInfo} info
|
|
4704
|
+
* @param {?EventTarget} target
|
|
4705
|
+
* @param {Touch} touch
|
|
4706
|
+
* @return {void}
|
|
4707
|
+
*/
|
|
4708
|
+
function trackFire(info, target, touch) {
|
|
4709
|
+
if (!target) {
|
|
4710
|
+
return;
|
|
4711
|
+
}
|
|
4712
|
+
const secondlast = info.moves[info.moves.length - 2];
|
|
4713
|
+
const lastmove = info.moves[info.moves.length - 1];
|
|
4714
|
+
const dx = lastmove.x - info.x;
|
|
4715
|
+
const dy = lastmove.y - info.y;
|
|
4716
|
+
let ddx,
|
|
4717
|
+
ddy = 0;
|
|
4718
|
+
if (secondlast) {
|
|
4719
|
+
ddx = lastmove.x - secondlast.x;
|
|
4720
|
+
ddy = lastmove.y - secondlast.y;
|
|
4721
|
+
}
|
|
4722
|
+
_fire(target, 'track', {
|
|
4723
|
+
state: info.state,
|
|
4724
|
+
x: touch.clientX,
|
|
4725
|
+
y: touch.clientY,
|
|
4726
|
+
dx,
|
|
4727
|
+
dy,
|
|
4728
|
+
ddx,
|
|
4729
|
+
ddy,
|
|
4730
|
+
sourceEvent: touch,
|
|
4731
|
+
hover() {
|
|
4732
|
+
return deepTargetFind(touch.clientX, touch.clientY);
|
|
4733
|
+
},
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
register({
|
|
4738
|
+
name: 'tap',
|
|
4739
|
+
deps: ['mousedown', 'click', 'touchstart', 'touchend'],
|
|
4740
|
+
flow: {
|
|
4741
|
+
start: ['mousedown', 'touchstart'],
|
|
4742
|
+
end: ['click', 'touchend'],
|
|
4743
|
+
},
|
|
4744
|
+
emits: ['tap'],
|
|
4745
|
+
info: {
|
|
4746
|
+
x: NaN,
|
|
4747
|
+
y: NaN,
|
|
4748
|
+
prevent: false,
|
|
4749
|
+
},
|
|
4750
|
+
|
|
4751
|
+
/**
|
|
4752
|
+
* @this {GestureRecognizer}
|
|
4753
|
+
* @return {void}
|
|
4754
|
+
*/
|
|
4755
|
+
reset() {
|
|
4756
|
+
this.info.x = NaN;
|
|
4757
|
+
this.info.y = NaN;
|
|
4758
|
+
this.info.prevent = false;
|
|
4759
|
+
},
|
|
4760
|
+
|
|
4761
|
+
/**
|
|
4762
|
+
* @this {GestureRecognizer}
|
|
4763
|
+
* @param {MouseEvent} e
|
|
4764
|
+
* @return {void}
|
|
4765
|
+
*/
|
|
4766
|
+
mousedown(e) {
|
|
4767
|
+
if (hasLeftMouseButton(e)) {
|
|
4768
|
+
this.info.x = e.clientX;
|
|
4769
|
+
this.info.y = e.clientY;
|
|
4770
|
+
}
|
|
4771
|
+
},
|
|
4772
|
+
|
|
4773
|
+
/**
|
|
4774
|
+
* @this {GestureRecognizer}
|
|
4775
|
+
* @param {MouseEvent} e
|
|
4776
|
+
* @return {void}
|
|
4777
|
+
*/
|
|
4778
|
+
click(e) {
|
|
4779
|
+
if (hasLeftMouseButton(e)) {
|
|
4780
|
+
trackForward(this.info, e);
|
|
4781
|
+
}
|
|
4782
|
+
},
|
|
3092
4783
|
|
|
3093
4784
|
/**
|
|
3094
|
-
*
|
|
3095
|
-
*
|
|
3096
|
-
*
|
|
3097
|
-
*
|
|
3098
|
-
* @param {!HTMLElement} el Element for which to return the index.
|
|
3099
|
-
* @return {?number} Row index associated with the element (note this may
|
|
3100
|
-
* not correspond to the array index if a user `sort` is applied).
|
|
4785
|
+
* @this {GestureRecognizer}
|
|
4786
|
+
* @param {TouchEvent} e
|
|
4787
|
+
* @return {void}
|
|
3101
4788
|
*/
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
4789
|
+
touchstart(e) {
|
|
4790
|
+
const touch = e.changedTouches[0];
|
|
4791
|
+
this.info.x = touch.clientX;
|
|
4792
|
+
this.info.y = touch.clientY;
|
|
4793
|
+
},
|
|
3106
4794
|
|
|
3107
4795
|
/**
|
|
3108
|
-
*
|
|
3109
|
-
*
|
|
3110
|
-
*
|
|
3111
|
-
* should be used to manipulate data associated with this template instance.
|
|
3112
|
-
*
|
|
3113
|
-
* Example:
|
|
3114
|
-
*
|
|
3115
|
-
* let model = modelForElement(el);
|
|
3116
|
-
* if (model.index < 10) {
|
|
3117
|
-
* model.set('item.checked', true);
|
|
3118
|
-
* }
|
|
3119
|
-
*
|
|
3120
|
-
* @param {!HTMLElement} el Element for which to return a template model.
|
|
3121
|
-
* @return {TemplateInstanceBase} Model representing the binding scope for
|
|
3122
|
-
* the element.
|
|
4796
|
+
* @this {GestureRecognizer}
|
|
4797
|
+
* @param {TouchEvent} e
|
|
4798
|
+
* @return {void}
|
|
3123
4799
|
*/
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
}
|
|
4800
|
+
touchend(e) {
|
|
4801
|
+
trackForward(this.info, e.changedTouches[0], e);
|
|
4802
|
+
},
|
|
4803
|
+
});
|
|
3127
4804
|
|
|
4805
|
+
/**
|
|
4806
|
+
* @param {!GestureInfo} info
|
|
4807
|
+
* @param {Event | Touch} e
|
|
4808
|
+
* @param {Event=} preventer
|
|
4809
|
+
* @return {void}
|
|
4810
|
+
*/
|
|
4811
|
+
function trackForward(info, e, preventer) {
|
|
4812
|
+
const dx = Math.abs(e.clientX - info.x);
|
|
4813
|
+
const dy = Math.abs(e.clientY - info.y);
|
|
4814
|
+
// Find original target from `preventer` for TouchEvents, or `e` for MouseEvents
|
|
4815
|
+
const t = _findOriginalTarget(preventer || e);
|
|
4816
|
+
if (!t || (canBeDisabled[/** @type {!HTMLElement} */ (t).localName] && t.hasAttribute('disabled'))) {
|
|
4817
|
+
return;
|
|
4818
|
+
}
|
|
4819
|
+
// Dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`
|
|
4820
|
+
if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) || isSyntheticClick(e)) {
|
|
4821
|
+
// Prevent taps from being generated if an event has canceled them
|
|
4822
|
+
if (!info.prevent) {
|
|
4823
|
+
_fire(t, 'tap', {
|
|
4824
|
+
x: e.clientX,
|
|
4825
|
+
y: e.clientY,
|
|
4826
|
+
sourceEvent: e,
|
|
4827
|
+
preventer,
|
|
4828
|
+
});
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
3128
4831
|
}
|
|
3129
4832
|
|
|
3130
|
-
customElements.define(DomRepeat.is, DomRepeat);
|
|
3131
|
-
|
|
3132
4833
|
/**
|
|
3133
4834
|
* @license
|
|
3134
4835
|
* Copyright (c) 2016 - 2023 Vaadin Ltd.
|
|
@@ -3663,6 +5364,87 @@ class MonthCalendar extends MonthCalendarMixin(ThemableMixin(PolymerElement)) {
|
|
|
3663
5364
|
|
|
3664
5365
|
defineCustomElement$1(MonthCalendar);
|
|
3665
5366
|
|
|
5367
|
+
/**
|
|
5368
|
+
* @license
|
|
5369
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
5370
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5371
|
+
*/
|
|
5372
|
+
|
|
5373
|
+
/**
|
|
5374
|
+
* @typedef ReactiveController
|
|
5375
|
+
* @type {import('lit').ReactiveController}
|
|
5376
|
+
*/
|
|
5377
|
+
|
|
5378
|
+
/**
|
|
5379
|
+
* A mixin for connecting controllers to the element.
|
|
5380
|
+
*
|
|
5381
|
+
* @polymerMixin
|
|
5382
|
+
*/
|
|
5383
|
+
const ControllerMixin = dedupingMixin((superClass) => {
|
|
5384
|
+
// If the superclass extends from LitElement,
|
|
5385
|
+
// use its own controllers implementation.
|
|
5386
|
+
if (typeof superClass.prototype.addController === 'function') {
|
|
5387
|
+
return superClass;
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5390
|
+
return class ControllerMixinClass extends superClass {
|
|
5391
|
+
constructor() {
|
|
5392
|
+
super();
|
|
5393
|
+
|
|
5394
|
+
/**
|
|
5395
|
+
* @type {Set<ReactiveController>}
|
|
5396
|
+
*/
|
|
5397
|
+
this.__controllers = new Set();
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
/** @protected */
|
|
5401
|
+
connectedCallback() {
|
|
5402
|
+
super.connectedCallback();
|
|
5403
|
+
|
|
5404
|
+
this.__controllers.forEach((c) => {
|
|
5405
|
+
if (c.hostConnected) {
|
|
5406
|
+
c.hostConnected();
|
|
5407
|
+
}
|
|
5408
|
+
});
|
|
5409
|
+
}
|
|
5410
|
+
|
|
5411
|
+
/** @protected */
|
|
5412
|
+
disconnectedCallback() {
|
|
5413
|
+
super.disconnectedCallback();
|
|
5414
|
+
|
|
5415
|
+
this.__controllers.forEach((c) => {
|
|
5416
|
+
if (c.hostDisconnected) {
|
|
5417
|
+
c.hostDisconnected();
|
|
5418
|
+
}
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
|
|
5422
|
+
/**
|
|
5423
|
+
* Registers a controller to participate in the element update cycle.
|
|
5424
|
+
*
|
|
5425
|
+
* @param {ReactiveController} controller
|
|
5426
|
+
* @protected
|
|
5427
|
+
*/
|
|
5428
|
+
addController(controller) {
|
|
5429
|
+
this.__controllers.add(controller);
|
|
5430
|
+
// Call hostConnected if a controller is added after the element is attached.
|
|
5431
|
+
if (this.$ !== undefined && this.isConnected && controller.hostConnected) {
|
|
5432
|
+
controller.hostConnected();
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
|
|
5436
|
+
/**
|
|
5437
|
+
* Removes a controller from the element.
|
|
5438
|
+
*
|
|
5439
|
+
* @param {ReactiveController} controller
|
|
5440
|
+
* @protected
|
|
5441
|
+
*/
|
|
5442
|
+
removeController(controller) {
|
|
5443
|
+
this.__controllers.delete(controller);
|
|
5444
|
+
}
|
|
5445
|
+
};
|
|
5446
|
+
});
|
|
5447
|
+
|
|
3666
5448
|
/**
|
|
3667
5449
|
* @license
|
|
3668
5450
|
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
@@ -3682,53 +5464,411 @@ class MediaQueryController {
|
|
|
3682
5464
|
*/
|
|
3683
5465
|
this.query = query;
|
|
3684
5466
|
|
|
3685
|
-
/**
|
|
3686
|
-
* Function to call when media query changes.
|
|
3687
|
-
*
|
|
3688
|
-
* @type {Function}
|
|
3689
|
-
* @protected
|
|
3690
|
-
*/
|
|
3691
|
-
this.callback = callback;
|
|
5467
|
+
/**
|
|
5468
|
+
* Function to call when media query changes.
|
|
5469
|
+
*
|
|
5470
|
+
* @type {Function}
|
|
5471
|
+
* @protected
|
|
5472
|
+
*/
|
|
5473
|
+
this.callback = callback;
|
|
5474
|
+
|
|
5475
|
+
this._boundQueryHandler = this._queryHandler.bind(this);
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5478
|
+
hostConnected() {
|
|
5479
|
+
this._removeListener();
|
|
5480
|
+
|
|
5481
|
+
this._mediaQuery = window.matchMedia(this.query);
|
|
5482
|
+
|
|
5483
|
+
this._addListener();
|
|
5484
|
+
|
|
5485
|
+
this._queryHandler(this._mediaQuery);
|
|
5486
|
+
}
|
|
5487
|
+
|
|
5488
|
+
hostDisconnected() {
|
|
5489
|
+
this._removeListener();
|
|
5490
|
+
}
|
|
5491
|
+
|
|
5492
|
+
/** @private */
|
|
5493
|
+
_addListener() {
|
|
5494
|
+
if (this._mediaQuery) {
|
|
5495
|
+
this._mediaQuery.addListener(this._boundQueryHandler);
|
|
5496
|
+
}
|
|
5497
|
+
}
|
|
5498
|
+
|
|
5499
|
+
/** @private */
|
|
5500
|
+
_removeListener() {
|
|
5501
|
+
if (this._mediaQuery) {
|
|
5502
|
+
this._mediaQuery.removeListener(this._boundQueryHandler);
|
|
5503
|
+
}
|
|
5504
|
+
|
|
5505
|
+
this._mediaQuery = null;
|
|
5506
|
+
}
|
|
5507
|
+
|
|
5508
|
+
/** @private */
|
|
5509
|
+
_queryHandler(mediaQuery) {
|
|
5510
|
+
if (typeof this.callback === 'function') {
|
|
5511
|
+
this.callback(mediaQuery.matches);
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
|
|
5516
|
+
/**
|
|
5517
|
+
* @license
|
|
5518
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
5519
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5520
|
+
*/
|
|
5521
|
+
|
|
5522
|
+
/**
|
|
5523
|
+
* Returns true if the given node is an empty text node, false otherwise.
|
|
5524
|
+
*
|
|
5525
|
+
* @param {Node} node
|
|
5526
|
+
* @return {boolean}
|
|
5527
|
+
*/
|
|
5528
|
+
function isEmptyTextNode(node) {
|
|
5529
|
+
return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '';
|
|
5530
|
+
}
|
|
5531
|
+
|
|
5532
|
+
/**
|
|
5533
|
+
* @license
|
|
5534
|
+
* Copyright (c) 2023 Vaadin Ltd.
|
|
5535
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5536
|
+
*/
|
|
5537
|
+
|
|
5538
|
+
/**
|
|
5539
|
+
* A helper for observing slot changes.
|
|
5540
|
+
*/
|
|
5541
|
+
class SlotObserver {
|
|
5542
|
+
constructor(slot, callback) {
|
|
5543
|
+
/** @type HTMLSlotElement */
|
|
5544
|
+
this.slot = slot;
|
|
5545
|
+
|
|
5546
|
+
/** @type Function */
|
|
5547
|
+
this.callback = callback;
|
|
5548
|
+
|
|
5549
|
+
/** @type {Node[]} */
|
|
5550
|
+
this._storedNodes = [];
|
|
5551
|
+
|
|
5552
|
+
this._connected = false;
|
|
5553
|
+
this._scheduled = false;
|
|
5554
|
+
|
|
5555
|
+
this._boundSchedule = () => {
|
|
5556
|
+
this._schedule();
|
|
5557
|
+
};
|
|
5558
|
+
|
|
5559
|
+
this.connect();
|
|
5560
|
+
this._schedule();
|
|
5561
|
+
}
|
|
5562
|
+
|
|
5563
|
+
/**
|
|
5564
|
+
* Activates an observer. This method is automatically called when
|
|
5565
|
+
* a `SlotObserver` is created. It should only be called to re-activate
|
|
5566
|
+
* an observer that has been deactivated via the `disconnect` method.
|
|
5567
|
+
*/
|
|
5568
|
+
connect() {
|
|
5569
|
+
this.slot.addEventListener('slotchange', this._boundSchedule);
|
|
5570
|
+
this._connected = true;
|
|
5571
|
+
}
|
|
5572
|
+
|
|
5573
|
+
/**
|
|
5574
|
+
* Deactivates the observer. After calling this method the observer callback
|
|
5575
|
+
* will not be called when changes to slotted nodes occur. The `connect` method
|
|
5576
|
+
* may be subsequently called to reactivate the observer.
|
|
5577
|
+
*/
|
|
5578
|
+
disconnect() {
|
|
5579
|
+
this.slot.removeEventListener('slotchange', this._boundSchedule);
|
|
5580
|
+
this._connected = false;
|
|
5581
|
+
}
|
|
5582
|
+
|
|
5583
|
+
/** @private */
|
|
5584
|
+
_schedule() {
|
|
5585
|
+
if (!this._scheduled) {
|
|
5586
|
+
this._scheduled = true;
|
|
5587
|
+
|
|
5588
|
+
queueMicrotask(() => {
|
|
5589
|
+
this.flush();
|
|
5590
|
+
});
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5593
|
+
|
|
5594
|
+
/**
|
|
5595
|
+
* Run the observer callback synchronously.
|
|
5596
|
+
*/
|
|
5597
|
+
flush() {
|
|
5598
|
+
if (!this._connected) {
|
|
5599
|
+
return;
|
|
5600
|
+
}
|
|
5601
|
+
|
|
5602
|
+
this._scheduled = false;
|
|
5603
|
+
|
|
5604
|
+
this._processNodes();
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5607
|
+
/** @private */
|
|
5608
|
+
_processNodes() {
|
|
5609
|
+
const currentNodes = this.slot.assignedNodes({ flatten: true });
|
|
5610
|
+
|
|
5611
|
+
let addedNodes = [];
|
|
5612
|
+
const removedNodes = [];
|
|
5613
|
+
const movedNodes = [];
|
|
5614
|
+
|
|
5615
|
+
if (currentNodes.length) {
|
|
5616
|
+
addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
|
|
5617
|
+
}
|
|
5618
|
+
|
|
5619
|
+
if (this._storedNodes.length) {
|
|
5620
|
+
this._storedNodes.forEach((node, index) => {
|
|
5621
|
+
const idx = currentNodes.indexOf(node);
|
|
5622
|
+
if (idx === -1) {
|
|
5623
|
+
removedNodes.push(node);
|
|
5624
|
+
} else if (idx !== index) {
|
|
5625
|
+
movedNodes.push(node);
|
|
5626
|
+
}
|
|
5627
|
+
});
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5630
|
+
if (addedNodes.length || removedNodes.length || movedNodes.length) {
|
|
5631
|
+
this.callback({ addedNodes, movedNodes, removedNodes });
|
|
5632
|
+
}
|
|
5633
|
+
|
|
5634
|
+
this._storedNodes = currentNodes;
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5637
|
+
|
|
5638
|
+
/**
|
|
5639
|
+
* @license
|
|
5640
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
5641
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5642
|
+
*/
|
|
5643
|
+
|
|
5644
|
+
/**
|
|
5645
|
+
* A controller for providing content to slot element and observing changes.
|
|
5646
|
+
*/
|
|
5647
|
+
class SlotController extends EventTarget {
|
|
5648
|
+
/**
|
|
5649
|
+
* Ensure that every instance has unique ID.
|
|
5650
|
+
*
|
|
5651
|
+
* @param {HTMLElement} host
|
|
5652
|
+
* @param {string} slotName
|
|
5653
|
+
* @return {string}
|
|
5654
|
+
* @protected
|
|
5655
|
+
*/
|
|
5656
|
+
static generateId(host, slotName) {
|
|
5657
|
+
const prefix = slotName || 'default';
|
|
5658
|
+
return `${prefix}-${host.localName}-${generateUniqueId()}`;
|
|
5659
|
+
}
|
|
5660
|
+
|
|
5661
|
+
constructor(host, slotName, tagName, config = {}) {
|
|
5662
|
+
super();
|
|
5663
|
+
|
|
5664
|
+
const { initializer, multiple, observe, useUniqueId } = config;
|
|
5665
|
+
|
|
5666
|
+
this.host = host;
|
|
5667
|
+
this.slotName = slotName;
|
|
5668
|
+
this.tagName = tagName;
|
|
5669
|
+
this.observe = typeof observe === 'boolean' ? observe : true;
|
|
5670
|
+
this.multiple = typeof multiple === 'boolean' ? multiple : false;
|
|
5671
|
+
this.slotInitializer = initializer;
|
|
5672
|
+
|
|
5673
|
+
if (multiple) {
|
|
5674
|
+
this.nodes = [];
|
|
5675
|
+
}
|
|
5676
|
+
|
|
5677
|
+
// Only generate the default ID if requested by the controller.
|
|
5678
|
+
if (useUniqueId) {
|
|
5679
|
+
this.defaultId = this.constructor.generateId(host, slotName);
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
|
|
5683
|
+
hostConnected() {
|
|
5684
|
+
if (!this.initialized) {
|
|
5685
|
+
if (this.multiple) {
|
|
5686
|
+
this.initMultiple();
|
|
5687
|
+
} else {
|
|
5688
|
+
this.initSingle();
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
if (this.observe) {
|
|
5692
|
+
this.observeSlot();
|
|
5693
|
+
}
|
|
5694
|
+
|
|
5695
|
+
this.initialized = true;
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
|
|
5699
|
+
/** @protected */
|
|
5700
|
+
initSingle() {
|
|
5701
|
+
let node = this.getSlotChild();
|
|
5702
|
+
|
|
5703
|
+
if (!node) {
|
|
5704
|
+
node = this.attachDefaultNode();
|
|
5705
|
+
this.initNode(node);
|
|
5706
|
+
} else {
|
|
5707
|
+
this.node = node;
|
|
5708
|
+
this.initAddedNode(node);
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
|
|
5712
|
+
/** @protected */
|
|
5713
|
+
initMultiple() {
|
|
5714
|
+
const children = this.getSlotChildren();
|
|
3692
5715
|
|
|
3693
|
-
|
|
5716
|
+
if (children.length === 0) {
|
|
5717
|
+
const defaultNode = this.attachDefaultNode();
|
|
5718
|
+
if (defaultNode) {
|
|
5719
|
+
this.nodes = [defaultNode];
|
|
5720
|
+
this.initNode(defaultNode);
|
|
5721
|
+
}
|
|
5722
|
+
} else {
|
|
5723
|
+
this.nodes = children;
|
|
5724
|
+
children.forEach((node) => {
|
|
5725
|
+
this.initAddedNode(node);
|
|
5726
|
+
});
|
|
5727
|
+
}
|
|
3694
5728
|
}
|
|
3695
5729
|
|
|
3696
|
-
|
|
3697
|
-
|
|
5730
|
+
/**
|
|
5731
|
+
* Create and attach default node using the provided tag name, if any.
|
|
5732
|
+
* @return {Node | undefined}
|
|
5733
|
+
* @protected
|
|
5734
|
+
*/
|
|
5735
|
+
attachDefaultNode() {
|
|
5736
|
+
const { host, slotName, tagName } = this;
|
|
5737
|
+
|
|
5738
|
+
// Check if the node was created previously and if so, reuse it.
|
|
5739
|
+
let node = this.defaultNode;
|
|
5740
|
+
|
|
5741
|
+
// Tag name is optional, sometimes we don't init default content.
|
|
5742
|
+
if (!node && tagName) {
|
|
5743
|
+
node = document.createElement(tagName);
|
|
5744
|
+
if (node instanceof Element) {
|
|
5745
|
+
if (slotName !== '') {
|
|
5746
|
+
node.setAttribute('slot', slotName);
|
|
5747
|
+
}
|
|
5748
|
+
this.node = node;
|
|
5749
|
+
this.defaultNode = node;
|
|
5750
|
+
}
|
|
5751
|
+
}
|
|
3698
5752
|
|
|
3699
|
-
|
|
5753
|
+
if (node) {
|
|
5754
|
+
host.appendChild(node);
|
|
5755
|
+
}
|
|
3700
5756
|
|
|
3701
|
-
|
|
5757
|
+
return node;
|
|
5758
|
+
}
|
|
3702
5759
|
|
|
3703
|
-
|
|
5760
|
+
/**
|
|
5761
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
5762
|
+
* @return {Node}
|
|
5763
|
+
*/
|
|
5764
|
+
getSlotChildren() {
|
|
5765
|
+
const { slotName } = this;
|
|
5766
|
+
return Array.from(this.host.childNodes).filter((node) => {
|
|
5767
|
+
// Either an element (any slot) or a text node (only un-named slot).
|
|
5768
|
+
return (
|
|
5769
|
+
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
5770
|
+
(node.nodeType === Node.TEXT_NODE && node.textContent.trim() && slotName === '')
|
|
5771
|
+
);
|
|
5772
|
+
});
|
|
3704
5773
|
}
|
|
3705
5774
|
|
|
3706
|
-
|
|
3707
|
-
|
|
5775
|
+
/**
|
|
5776
|
+
* Return a reference to the node managed by the controller.
|
|
5777
|
+
* @return {Node}
|
|
5778
|
+
*/
|
|
5779
|
+
getSlotChild() {
|
|
5780
|
+
return this.getSlotChildren()[0];
|
|
3708
5781
|
}
|
|
3709
5782
|
|
|
3710
|
-
/**
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
5783
|
+
/**
|
|
5784
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
5785
|
+
*
|
|
5786
|
+
* @param {Node} node
|
|
5787
|
+
* @protected
|
|
5788
|
+
*/
|
|
5789
|
+
initNode(node) {
|
|
5790
|
+
const { slotInitializer } = this;
|
|
5791
|
+
// Don't try to bind `this` to initializer (normally it's arrow function).
|
|
5792
|
+
// Instead, pass the host as a first argument to access component's state.
|
|
5793
|
+
if (slotInitializer) {
|
|
5794
|
+
slotInitializer(node, this.host);
|
|
3714
5795
|
}
|
|
3715
5796
|
}
|
|
3716
5797
|
|
|
3717
|
-
/**
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
5798
|
+
/**
|
|
5799
|
+
* Override to initialize the newly added custom node.
|
|
5800
|
+
*
|
|
5801
|
+
* @param {Node} _node
|
|
5802
|
+
* @protected
|
|
5803
|
+
*/
|
|
5804
|
+
initCustomNode(_node) {}
|
|
3722
5805
|
|
|
3723
|
-
|
|
3724
|
-
|
|
5806
|
+
/**
|
|
5807
|
+
* Override to teardown slotted node when it's removed.
|
|
5808
|
+
*
|
|
5809
|
+
* @param {Node} _node
|
|
5810
|
+
* @protected
|
|
5811
|
+
*/
|
|
5812
|
+
teardownNode(_node) {}
|
|
3725
5813
|
|
|
3726
|
-
/**
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
5814
|
+
/**
|
|
5815
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
5816
|
+
*
|
|
5817
|
+
* @param {Node} node
|
|
5818
|
+
* @protected
|
|
5819
|
+
*/
|
|
5820
|
+
initAddedNode(node) {
|
|
5821
|
+
if (node !== this.defaultNode) {
|
|
5822
|
+
this.initCustomNode(node);
|
|
5823
|
+
this.initNode(node);
|
|
3730
5824
|
}
|
|
3731
5825
|
}
|
|
5826
|
+
|
|
5827
|
+
/**
|
|
5828
|
+
* Setup the observer to manage slot content changes.
|
|
5829
|
+
* @protected
|
|
5830
|
+
*/
|
|
5831
|
+
observeSlot() {
|
|
5832
|
+
const { slotName } = this;
|
|
5833
|
+
const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
|
|
5834
|
+
const slot = this.host.shadowRoot.querySelector(selector);
|
|
5835
|
+
|
|
5836
|
+
this.__slotObserver = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
|
|
5837
|
+
const current = this.multiple ? this.nodes : [this.node];
|
|
5838
|
+
|
|
5839
|
+
// Calling `slot.assignedNodes()` includes whitespace text nodes in case of default slot:
|
|
5840
|
+
// unlike comment nodes, they are not filtered out. So we need to manually ignore them.
|
|
5841
|
+
const newNodes = addedNodes.filter((node) => !isEmptyTextNode(node) && !current.includes(node));
|
|
5842
|
+
|
|
5843
|
+
if (removedNodes.length) {
|
|
5844
|
+
this.nodes = current.filter((node) => !removedNodes.includes(node));
|
|
5845
|
+
|
|
5846
|
+
removedNodes.forEach((node) => {
|
|
5847
|
+
this.teardownNode(node);
|
|
5848
|
+
});
|
|
5849
|
+
}
|
|
5850
|
+
|
|
5851
|
+
if (newNodes && newNodes.length > 0) {
|
|
5852
|
+
if (this.multiple) {
|
|
5853
|
+
// Remove default node if exists
|
|
5854
|
+
if (this.defaultNode) {
|
|
5855
|
+
this.defaultNode.remove();
|
|
5856
|
+
}
|
|
5857
|
+
this.nodes = [...current, ...newNodes].filter((node) => node !== this.defaultNode);
|
|
5858
|
+
newNodes.forEach((node) => {
|
|
5859
|
+
this.initAddedNode(node);
|
|
5860
|
+
});
|
|
5861
|
+
} else {
|
|
5862
|
+
// Remove previous node if exists
|
|
5863
|
+
if (this.node) {
|
|
5864
|
+
this.node.remove();
|
|
5865
|
+
}
|
|
5866
|
+
this.node = newNodes[0];
|
|
5867
|
+
this.initAddedNode(this.node);
|
|
5868
|
+
}
|
|
5869
|
+
}
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
3732
5872
|
}
|
|
3733
5873
|
|
|
3734
5874
|
/**
|
|
@@ -4877,6 +7017,322 @@ class DatePickerOverlayContent extends DatePickerOverlayContentMixin(
|
|
|
4877
7017
|
|
|
4878
7018
|
defineCustomElement$1(DatePickerOverlayContent);
|
|
4879
7019
|
|
|
7020
|
+
/**
|
|
7021
|
+
* @license
|
|
7022
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
7023
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
7024
|
+
*/
|
|
7025
|
+
|
|
7026
|
+
if (!window.Vaadin) {
|
|
7027
|
+
window.Vaadin = {};
|
|
7028
|
+
}
|
|
7029
|
+
|
|
7030
|
+
/**
|
|
7031
|
+
* Array of Vaadin custom element classes that have been finalized.
|
|
7032
|
+
*/
|
|
7033
|
+
if (!window.Vaadin.registrations) {
|
|
7034
|
+
window.Vaadin.registrations = [];
|
|
7035
|
+
}
|
|
7036
|
+
|
|
7037
|
+
if (!window.Vaadin.developmentModeCallback) {
|
|
7038
|
+
window.Vaadin.developmentModeCallback = {};
|
|
7039
|
+
}
|
|
7040
|
+
|
|
7041
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics'] = function () {
|
|
7042
|
+
usageStatistics();
|
|
7043
|
+
};
|
|
7044
|
+
|
|
7045
|
+
let statsJob;
|
|
7046
|
+
|
|
7047
|
+
const registered = new Set();
|
|
7048
|
+
|
|
7049
|
+
/**
|
|
7050
|
+
* @polymerMixin
|
|
7051
|
+
* @mixes DirMixin
|
|
7052
|
+
*/
|
|
7053
|
+
const ElementMixin = (superClass) =>
|
|
7054
|
+
class VaadinElementMixin extends DirMixin(superClass) {
|
|
7055
|
+
static get version() {
|
|
7056
|
+
return '24.2.3';
|
|
7057
|
+
}
|
|
7058
|
+
|
|
7059
|
+
/** @protected */
|
|
7060
|
+
static finalize() {
|
|
7061
|
+
super.finalize();
|
|
7062
|
+
|
|
7063
|
+
const { is } = this;
|
|
7064
|
+
|
|
7065
|
+
// Registers a class prototype for telemetry purposes.
|
|
7066
|
+
if (is && !registered.has(is)) {
|
|
7067
|
+
window.Vaadin.registrations.push(this);
|
|
7068
|
+
registered.add(is);
|
|
7069
|
+
|
|
7070
|
+
if (window.Vaadin.developmentModeCallback) {
|
|
7071
|
+
statsJob = Debouncer$1.debounce(statsJob, idlePeriod, () => {
|
|
7072
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics']();
|
|
7073
|
+
});
|
|
7074
|
+
enqueueDebouncer$1(statsJob);
|
|
7075
|
+
}
|
|
7076
|
+
}
|
|
7077
|
+
}
|
|
7078
|
+
|
|
7079
|
+
constructor() {
|
|
7080
|
+
super();
|
|
7081
|
+
|
|
7082
|
+
if (document.doctype === null) {
|
|
7083
|
+
console.warn(
|
|
7084
|
+
'Vaadin components require the "standards mode" declaration. Please add <!DOCTYPE html> to the HTML document.',
|
|
7085
|
+
);
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
};
|
|
7089
|
+
|
|
7090
|
+
/**
|
|
7091
|
+
* @license
|
|
7092
|
+
* Copyright (c) 2022 - 2023 Vaadin Ltd.
|
|
7093
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
7094
|
+
*/
|
|
7095
|
+
|
|
7096
|
+
/**
|
|
7097
|
+
* A controller that manages the slotted tooltip element.
|
|
7098
|
+
*/
|
|
7099
|
+
class TooltipController extends SlotController {
|
|
7100
|
+
constructor(host) {
|
|
7101
|
+
// Do not provide slot factory to create tooltip lazily.
|
|
7102
|
+
super(host, 'tooltip');
|
|
7103
|
+
|
|
7104
|
+
this.setTarget(host);
|
|
7105
|
+
}
|
|
7106
|
+
|
|
7107
|
+
/**
|
|
7108
|
+
* Override to initialize the newly added custom tooltip.
|
|
7109
|
+
*
|
|
7110
|
+
* @param {Node} tooltipNode
|
|
7111
|
+
* @protected
|
|
7112
|
+
* @override
|
|
7113
|
+
*/
|
|
7114
|
+
initCustomNode(tooltipNode) {
|
|
7115
|
+
tooltipNode.target = this.target;
|
|
7116
|
+
|
|
7117
|
+
if (this.ariaTarget !== undefined) {
|
|
7118
|
+
tooltipNode.ariaTarget = this.ariaTarget;
|
|
7119
|
+
}
|
|
7120
|
+
|
|
7121
|
+
if (this.context !== undefined) {
|
|
7122
|
+
tooltipNode.context = this.context;
|
|
7123
|
+
}
|
|
7124
|
+
|
|
7125
|
+
if (this.manual !== undefined) {
|
|
7126
|
+
tooltipNode.manual = this.manual;
|
|
7127
|
+
}
|
|
7128
|
+
|
|
7129
|
+
if (this.opened !== undefined) {
|
|
7130
|
+
tooltipNode.opened = this.opened;
|
|
7131
|
+
}
|
|
7132
|
+
|
|
7133
|
+
if (this.position !== undefined) {
|
|
7134
|
+
tooltipNode._position = this.position;
|
|
7135
|
+
}
|
|
7136
|
+
|
|
7137
|
+
if (this.shouldShow !== undefined) {
|
|
7138
|
+
tooltipNode.shouldShow = this.shouldShow;
|
|
7139
|
+
}
|
|
7140
|
+
|
|
7141
|
+
this.__notifyChange();
|
|
7142
|
+
}
|
|
7143
|
+
|
|
7144
|
+
/**
|
|
7145
|
+
* Override to notify the host when the tooltip is removed.
|
|
7146
|
+
*
|
|
7147
|
+
* @param {Node} tooltipNode
|
|
7148
|
+
* @protected
|
|
7149
|
+
* @override
|
|
7150
|
+
*/
|
|
7151
|
+
teardownNode() {
|
|
7152
|
+
this.__notifyChange();
|
|
7153
|
+
}
|
|
7154
|
+
|
|
7155
|
+
/**
|
|
7156
|
+
* Set an HTML element for linking with the tooltip overlay
|
|
7157
|
+
* via `aria-describedby` attribute used by screen readers.
|
|
7158
|
+
* @param {HTMLElement} ariaTarget
|
|
7159
|
+
*/
|
|
7160
|
+
setAriaTarget(ariaTarget) {
|
|
7161
|
+
this.ariaTarget = ariaTarget;
|
|
7162
|
+
|
|
7163
|
+
const tooltipNode = this.node;
|
|
7164
|
+
if (tooltipNode) {
|
|
7165
|
+
tooltipNode.ariaTarget = ariaTarget;
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
|
|
7169
|
+
/**
|
|
7170
|
+
* Set a context object to be used by generator.
|
|
7171
|
+
* @param {object} context
|
|
7172
|
+
*/
|
|
7173
|
+
setContext(context) {
|
|
7174
|
+
this.context = context;
|
|
7175
|
+
|
|
7176
|
+
const tooltipNode = this.node;
|
|
7177
|
+
if (tooltipNode) {
|
|
7178
|
+
tooltipNode.context = context;
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
|
|
7182
|
+
/**
|
|
7183
|
+
* Toggle manual state on the slotted tooltip.
|
|
7184
|
+
* @param {boolean} manual
|
|
7185
|
+
*/
|
|
7186
|
+
setManual(manual) {
|
|
7187
|
+
this.manual = manual;
|
|
7188
|
+
|
|
7189
|
+
const tooltipNode = this.node;
|
|
7190
|
+
if (tooltipNode) {
|
|
7191
|
+
tooltipNode.manual = manual;
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
|
|
7195
|
+
/**
|
|
7196
|
+
* Toggle opened state on the slotted tooltip.
|
|
7197
|
+
* @param {boolean} opened
|
|
7198
|
+
*/
|
|
7199
|
+
setOpened(opened) {
|
|
7200
|
+
this.opened = opened;
|
|
7201
|
+
|
|
7202
|
+
const tooltipNode = this.node;
|
|
7203
|
+
if (tooltipNode) {
|
|
7204
|
+
tooltipNode.opened = opened;
|
|
7205
|
+
}
|
|
7206
|
+
}
|
|
7207
|
+
|
|
7208
|
+
/**
|
|
7209
|
+
* Set default position for the slotted tooltip.
|
|
7210
|
+
* This can be overridden by setting the position
|
|
7211
|
+
* using corresponding property or attribute.
|
|
7212
|
+
* @param {string} position
|
|
7213
|
+
*/
|
|
7214
|
+
setPosition(position) {
|
|
7215
|
+
this.position = position;
|
|
7216
|
+
|
|
7217
|
+
const tooltipNode = this.node;
|
|
7218
|
+
if (tooltipNode) {
|
|
7219
|
+
tooltipNode._position = position;
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
|
|
7223
|
+
/**
|
|
7224
|
+
* Set function used to detect whether to show
|
|
7225
|
+
* the tooltip based on a condition.
|
|
7226
|
+
* @param {Function} shouldShow
|
|
7227
|
+
*/
|
|
7228
|
+
setShouldShow(shouldShow) {
|
|
7229
|
+
this.shouldShow = shouldShow;
|
|
7230
|
+
|
|
7231
|
+
const tooltipNode = this.node;
|
|
7232
|
+
if (tooltipNode) {
|
|
7233
|
+
tooltipNode.shouldShow = shouldShow;
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
|
|
7237
|
+
/**
|
|
7238
|
+
* Set an HTML element to attach the tooltip to.
|
|
7239
|
+
* @param {HTMLElement} target
|
|
7240
|
+
*/
|
|
7241
|
+
setTarget(target) {
|
|
7242
|
+
this.target = target;
|
|
7243
|
+
|
|
7244
|
+
const tooltipNode = this.node;
|
|
7245
|
+
if (tooltipNode) {
|
|
7246
|
+
tooltipNode.target = target;
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
|
|
7250
|
+
/** @private */
|
|
7251
|
+
__notifyChange() {
|
|
7252
|
+
this.dispatchEvent(new CustomEvent('tooltip-changed', { detail: { node: this.node } }));
|
|
7253
|
+
}
|
|
7254
|
+
}
|
|
7255
|
+
|
|
7256
|
+
/**
|
|
7257
|
+
* @license
|
|
7258
|
+
* Copyright (c) 2023 Vaadin Ltd.
|
|
7259
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
7260
|
+
*/
|
|
7261
|
+
|
|
7262
|
+
/**
|
|
7263
|
+
* A mixin that forwards CSS class names to the internal overlay element
|
|
7264
|
+
* by setting the `overlayClass` property or `overlay-class` attribute.
|
|
7265
|
+
*
|
|
7266
|
+
* @polymerMixin
|
|
7267
|
+
*/
|
|
7268
|
+
const OverlayClassMixin = (superclass) =>
|
|
7269
|
+
class OverlayClassMixinClass extends superclass {
|
|
7270
|
+
static get properties() {
|
|
7271
|
+
return {
|
|
7272
|
+
/**
|
|
7273
|
+
* A space-delimited list of CSS class names to set on the overlay element.
|
|
7274
|
+
* This property does not affect other CSS class names set manually via JS.
|
|
7275
|
+
*
|
|
7276
|
+
* Note, if the CSS class name was set with this property, clearing it will
|
|
7277
|
+
* remove it from the overlay, even if the same class name was also added
|
|
7278
|
+
* manually, e.g. by using `classList.add()` in the `renderer` function.
|
|
7279
|
+
*
|
|
7280
|
+
* @attr {string} overlay-class
|
|
7281
|
+
*/
|
|
7282
|
+
overlayClass: {
|
|
7283
|
+
type: String,
|
|
7284
|
+
},
|
|
7285
|
+
|
|
7286
|
+
/**
|
|
7287
|
+
* An overlay element on which CSS class names are set.
|
|
7288
|
+
*
|
|
7289
|
+
* @protected
|
|
7290
|
+
*/
|
|
7291
|
+
_overlayElement: {
|
|
7292
|
+
type: Object,
|
|
7293
|
+
},
|
|
7294
|
+
};
|
|
7295
|
+
}
|
|
7296
|
+
|
|
7297
|
+
static get observers() {
|
|
7298
|
+
return ['__updateOverlayClassNames(overlayClass, _overlayElement)'];
|
|
7299
|
+
}
|
|
7300
|
+
|
|
7301
|
+
/** @private */
|
|
7302
|
+
__updateOverlayClassNames(overlayClass, overlayElement) {
|
|
7303
|
+
if (!overlayElement) {
|
|
7304
|
+
return;
|
|
7305
|
+
}
|
|
7306
|
+
|
|
7307
|
+
// Overlay is set but overlayClass is not set
|
|
7308
|
+
if (overlayClass === undefined) {
|
|
7309
|
+
return;
|
|
7310
|
+
}
|
|
7311
|
+
|
|
7312
|
+
const { classList } = overlayElement;
|
|
7313
|
+
|
|
7314
|
+
if (!this.__initialClasses) {
|
|
7315
|
+
this.__initialClasses = new Set(classList);
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7318
|
+
if (Array.isArray(this.__previousClasses)) {
|
|
7319
|
+
// Remove old classes that no longer apply
|
|
7320
|
+
const classesToRemove = this.__previousClasses.filter((name) => !this.__initialClasses.has(name));
|
|
7321
|
+
if (classesToRemove.length > 0) {
|
|
7322
|
+
classList.remove(...classesToRemove);
|
|
7323
|
+
}
|
|
7324
|
+
}
|
|
7325
|
+
|
|
7326
|
+
// Add new classes based on the overlayClass
|
|
7327
|
+
const classesToAdd = typeof overlayClass === 'string' ? overlayClass.split(' ') : [];
|
|
7328
|
+
if (classesToAdd.length > 0) {
|
|
7329
|
+
classList.add(...classesToAdd);
|
|
7330
|
+
}
|
|
7331
|
+
|
|
7332
|
+
this.__previousClasses = classesToAdd;
|
|
7333
|
+
}
|
|
7334
|
+
};
|
|
7335
|
+
|
|
4880
7336
|
/**
|
|
4881
7337
|
* @license
|
|
4882
7338
|
* Copyright (c) 2016 - 2023 Vaadin Ltd.
|
|
@@ -6297,14 +8753,14 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
|
|
|
6297
8753
|
|
|
6298
8754
|
defineCustomElement$1(DatePicker);
|
|
6299
8755
|
|
|
6300
|
-
function _typeof(
|
|
8756
|
+
function _typeof(obj) {
|
|
6301
8757
|
"@babel/helpers - typeof";
|
|
6302
8758
|
|
|
6303
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (
|
|
6304
|
-
return typeof
|
|
6305
|
-
} : function (
|
|
6306
|
-
return
|
|
6307
|
-
}, _typeof(
|
|
8759
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
8760
|
+
return typeof obj;
|
|
8761
|
+
} : function (obj) {
|
|
8762
|
+
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
8763
|
+
}, _typeof(obj);
|
|
6308
8764
|
}
|
|
6309
8765
|
|
|
6310
8766
|
function requiredArgs(required, args) {
|