@vaadin/component-base 23.0.0-alpha1 → 23.0.0-alpha5

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.
Files changed (42) hide show
  1. package/index.d.ts +2 -0
  2. package/index.js +2 -0
  3. package/package.json +3 -2
  4. package/src/a11y-announcer.d.ts +10 -0
  5. package/src/a11y-announcer.js +32 -0
  6. package/src/active-mixin.d.ts +1 -1
  7. package/src/active-mixin.js +5 -5
  8. package/src/async.js +8 -5
  9. package/src/browser-utils.js +1 -1
  10. package/src/controller-mixin.d.ts +1 -1
  11. package/src/controller-mixin.js +1 -1
  12. package/src/debounce.js +10 -4
  13. package/src/dir-helper.d.ts +1 -1
  14. package/src/dir-helper.js +3 -2
  15. package/src/dir-mixin.d.ts +1 -1
  16. package/src/dir-mixin.js +7 -7
  17. package/src/disabled-mixin.d.ts +1 -1
  18. package/src/disabled-mixin.js +1 -1
  19. package/src/element-mixin.d.ts +1 -1
  20. package/src/element-mixin.js +2 -2
  21. package/src/focus-mixin.d.ts +1 -1
  22. package/src/focus-mixin.js +1 -1
  23. package/src/focus-trap-controller.d.ts +39 -0
  24. package/src/focus-trap-controller.js +139 -0
  25. package/src/focus-utils.d.ts +45 -0
  26. package/src/focus-utils.js +228 -0
  27. package/src/gestures.d.ts +76 -0
  28. package/src/gestures.js +932 -0
  29. package/src/iron-list-core.js +40 -38
  30. package/src/keyboard-mixin.d.ts +1 -1
  31. package/src/keyboard-mixin.js +1 -1
  32. package/src/resize-mixin.d.ts +19 -0
  33. package/src/resize-mixin.js +56 -0
  34. package/src/slot-controller.d.ts +57 -0
  35. package/src/slot-controller.js +169 -0
  36. package/src/slot-mixin.d.ts +1 -1
  37. package/src/slot-mixin.js +11 -3
  38. package/src/tabindex-mixin.d.ts +1 -1
  39. package/src/tabindex-mixin.js +1 -1
  40. package/src/templates.js +1 -1
  41. package/src/virtualizer-iron-list-adapter.js +5 -6
  42. package/src/virtualizer.js +6 -6
@@ -0,0 +1,228 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Returns true if the element is hidden directly with `display: none` or `visibility: hidden`,
9
+ * false otherwise.
10
+ *
11
+ * The method doesn't traverse the element's ancestors, it only checks for the CSS properties
12
+ * set directly to or inherited by the element.
13
+ *
14
+ * @param {HTMLElement} element
15
+ * @return {boolean}
16
+ */
17
+ function isElementHiddenDirectly(element) {
18
+ // Check inline style first to save a re-flow.
19
+ const style = element.style;
20
+ if (style.visibility === 'hidden' || style.display === 'none') {
21
+ return true;
22
+ }
23
+
24
+ const computedStyle = window.getComputedStyle(element);
25
+ if (computedStyle.visibility === 'hidden' || computedStyle.display === 'none') {
26
+ return true;
27
+ }
28
+
29
+ return false;
30
+ }
31
+
32
+ /**
33
+ * Returns the normalized element tabindex. If not focusable, returns -1.
34
+ * It checks for the attribute "tabindex" instead of the element property
35
+ * `tabIndex` since browsers assign different values to it.
36
+ * e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
37
+ *
38
+ * @param {HTMLElement} element
39
+ * @return {number}
40
+ */
41
+ function normalizeTabIndex(element) {
42
+ if (!isElementFocusable(element) || isElementHiddenDirectly(element)) {
43
+ return -1;
44
+ }
45
+
46
+ const tabIndex = element.getAttribute('tabindex') || 0;
47
+ return Number(tabIndex);
48
+ }
49
+
50
+ /**
51
+ * Returns if element `a` has lower tab order compared to element `b`
52
+ * (both elements are assumed to be focusable and tabbable).
53
+ * Elements with tabindex = 0 have lower tab order compared to elements
54
+ * with tabindex > 0.
55
+ * If both have same tabindex, it returns false.
56
+ *
57
+ * @param {HTMLElement} a
58
+ * @param {HTMLElement} b
59
+ * @return {boolean}
60
+ */
61
+ function hasLowerTabOrder(a, b) {
62
+ // Normalize tabIndexes
63
+ // e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
64
+ const ati = Math.max(a.tabIndex, 0);
65
+ const bti = Math.max(b.tabIndex, 0);
66
+ return ati === 0 || bti === 0 ? bti > ati : ati > bti;
67
+ }
68
+
69
+ /**
70
+ * Merge sort iterator, merges the two arrays into one, sorted by tabindex.
71
+ *
72
+ * @param {HTMLElement[]} left
73
+ * @param {HTMLElement[]} right
74
+ * @return {HTMLElement[]}
75
+ */
76
+ function mergeSortByTabIndex(left, right) {
77
+ const result = [];
78
+ while (left.length > 0 && right.length > 0) {
79
+ if (hasLowerTabOrder(left[0], right[0])) {
80
+ result.push(right.shift());
81
+ } else {
82
+ result.push(left.shift());
83
+ }
84
+ }
85
+
86
+ return result.concat(left, right);
87
+ }
88
+
89
+ /**
90
+ * Sorts an array of elements by tabindex. Returns a new array.
91
+ *
92
+ * @param {HTMLElement[]} elements
93
+ * @return {HTMLElement[]}
94
+ */
95
+ function sortElementsByTabIndex(elements) {
96
+ // Implement a merge sort as Array.prototype.sort does a non-stable sort
97
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
98
+ const len = elements.length;
99
+ if (len < 2) {
100
+ return elements;
101
+ }
102
+ const pivot = Math.ceil(len / 2);
103
+ const left = sortElementsByTabIndex(elements.slice(0, pivot));
104
+ const right = sortElementsByTabIndex(elements.slice(pivot));
105
+
106
+ return mergeSortByTabIndex(left, right);
107
+ }
108
+
109
+ /**
110
+ * Searches for nodes that are tabbable and adds them to the `result` array.
111
+ * Returns if the `result` array needs to be sorted by tabindex.
112
+ *
113
+ * @param {Node} node The starting point for the search; added to `result` if tabbable.
114
+ * @param {HTMLElement[]} result
115
+ * @return {boolean}
116
+ * @private
117
+ */
118
+ function collectFocusableNodes(node, result) {
119
+ if (node.nodeType !== Node.ELEMENT_NODE) {
120
+ // Don't traverse children if the node is not an HTML element.
121
+ return false;
122
+ }
123
+
124
+ const element = /** @type {HTMLElement} */ (node);
125
+ const tabIndex = normalizeTabIndex(element);
126
+ let needsSort = tabIndex > 0;
127
+ if (tabIndex >= 0) {
128
+ result.push(element);
129
+ }
130
+
131
+ let children = [];
132
+ if (element.localName === 'slot') {
133
+ children = element.assignedNodes({ flatten: true });
134
+ } else {
135
+ // Use shadow root if possible, will check for distributed nodes.
136
+ children = (element.shadowRoot || element).children;
137
+ }
138
+ [...children].forEach((child) => {
139
+ // Ensure method is always invoked to collect focusable children.
140
+ needsSort = collectFocusableNodes(child, result) || needsSort;
141
+ });
142
+ return needsSort;
143
+ }
144
+
145
+ /**
146
+ * Returns true if the element is hidden, false otherwise.
147
+ *
148
+ * An element is treated as hidden when any of the following conditions are met:
149
+ * - the element itself or one of its ancestors has `display: none`.
150
+ * - the element has or inherits `visibility: hidden`.
151
+ *
152
+ * @param {HTMLElement} element
153
+ * @return {boolean}
154
+ */
155
+ export function isElementHidden(element) {
156
+ // `offsetParent` is `null` when the element itself
157
+ // or one of its ancestors is hidden with `display: none`.
158
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
159
+ if (element.offsetParent === null) {
160
+ return true;
161
+ }
162
+
163
+ return isElementHiddenDirectly(element);
164
+ }
165
+
166
+ /**
167
+ * Returns true if the element is focusable, otherwise false.
168
+ *
169
+ * The list of focusable elements is taken from http://stackoverflow.com/a/1600194/4228703.
170
+ * However, there isn't a definite list, it's up to the browser.
171
+ * The only standard we have is DOM Level 2 HTML https://www.w3.org/TR/DOM-Level-2-HTML/html.html,
172
+ * according to which the only elements that have a `focus()` method are:
173
+ * - HTMLInputElement
174
+ * - HTMLSelectElement
175
+ * - HTMLTextAreaElement
176
+ * - HTMLAnchorElement
177
+ *
178
+ * This notably omits HTMLButtonElement and HTMLAreaElement.
179
+ * Referring to these tests with tabbables in different browsers
180
+ * http://allyjs.io/data-tables/focusable.html
181
+ *
182
+ * @param {HTMLElement} element
183
+ * @return {boolean}
184
+ */
185
+ export function isElementFocusable(element) {
186
+ // The element cannot be focused if its `tabindex` attribute is set to `-1`.
187
+ if (element.matches('[tabindex="-1"]')) {
188
+ return false;
189
+ }
190
+
191
+ // Elements that cannot be focused if they have a `disabled` attribute.
192
+ if (element.matches('input, select, textarea, button, object')) {
193
+ return element.matches(':not([disabled])');
194
+ }
195
+
196
+ // Elements that can be focused even if they have a `disabled` attribute.
197
+ return element.matches('a[href], area[href], iframe, [tabindex], [contentEditable]');
198
+ }
199
+
200
+ /**
201
+ * Returns true if the element is focused, false otherwise.
202
+ *
203
+ * @param {HTMLElement} element
204
+ * @return {boolean}
205
+ */
206
+ export function isElementFocused(element) {
207
+ return element.getRootNode().activeElement === element;
208
+ }
209
+
210
+ /**
211
+ * Returns a tab-ordered array of focusable elements for a root element.
212
+ * The resulting array will include the root element if it is focusable.
213
+ *
214
+ * The method traverses nodes in shadow DOM trees too if any.
215
+ *
216
+ * @param {HTMLElement} element
217
+ * @return {HTMLElement[]}
218
+ */
219
+ export function getFocusableElements(element) {
220
+ const focusableElements = [];
221
+ const needsSortByTabIndex = collectFocusableNodes(element, focusableElements);
222
+ // If there is at least one element with tabindex > 0, we need to sort
223
+ // the final array by tabindex.≈
224
+ if (needsSortByTabIndex) {
225
+ return sortElementsByTabIndex(focusableElements);
226
+ }
227
+ return focusableElements;
228
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ @license
3
+ Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ Code distributed by Google as part of the polymer project is also
8
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+
11
+ export { deepTargetFind };
12
+
13
+ /**
14
+ * Finds the element rendered on the screen at the provided coordinates.
15
+ *
16
+ * Similar to `document.elementFromPoint`, but pierces through
17
+ * shadow roots.
18
+ *
19
+ * @returns Returns the deepest shadowRoot inclusive element
20
+ * found at the screen position given.
21
+ */
22
+ declare function deepTargetFind(x: number, y: number): Element | null;
23
+
24
+ export { addListener };
25
+
26
+ /**
27
+ * Adds an event listener to a node for the given gesture type.
28
+ *
29
+ * @returns Returns true if a gesture event listener was added.
30
+ */
31
+ declare function addListener(node: EventTarget, evType: string, handler: (p0: Event) => void): boolean;
32
+
33
+ export { removeListener };
34
+
35
+ /**
36
+ * Removes an event listener from a node for the given gesture type.
37
+ *
38
+ * @returns Returns true if a gesture event listener was removed.
39
+ */
40
+ declare function removeListener(node: EventTarget, evType: string, handler: (p0: Event) => void): boolean;
41
+
42
+ export { register };
43
+
44
+ /**
45
+ * Registers a new gesture event recognizer for adding new custom
46
+ * gesture event types.
47
+ */
48
+ declare function register(recog: GestureRecognizer): void;
49
+
50
+ export { setTouchAction };
51
+
52
+ /**
53
+ * Sets scrolling direction on node.
54
+ *
55
+ * This value is checked on first move, thus it should be called prior to
56
+ * adding event listeners.
57
+ */
58
+ declare function setTouchAction(node: EventTarget, value: string): void;
59
+
60
+ export { prevent };
61
+
62
+ /**
63
+ * Prevents the dispatch and default action of the given event name.
64
+ */
65
+ declare function prevent(evName: string): void;
66
+
67
+ export interface GestureRecognizer {
68
+ reset: () => void;
69
+ mousedown?: (e: MouseEvent) => void;
70
+ mousemove?: (e: MouseEvent) => void;
71
+ mouseup?: (e: MouseEvent) => void;
72
+ touchstart?: (e: TouchEvent) => void;
73
+ touchmove?: (e: TouchEvent) => void;
74
+ touchend?: (e: TouchEvent) => void;
75
+ click?: (e: MouseEvent) => void;
76
+ }