@arcgis/toolkit 4.34.0-next.61
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/LICENSE.md +13 -0
- package/README.md +21 -0
- package/dist/array/index.cjs +12 -0
- package/dist/array/index.d.cts +12 -0
- package/dist/array/index.d.ts +12 -0
- package/dist/array/index.js +12 -0
- package/dist/dom/index.cjs +161 -0
- package/dist/dom/index.d.cts +115 -0
- package/dist/dom/index.d.ts +115 -0
- package/dist/dom/index.js +161 -0
- package/dist/error/index.cjs +36 -0
- package/dist/error/index.d.cts +32 -0
- package/dist/error/index.d.ts +32 -0
- package/dist/error/index.js +36 -0
- package/dist/function/index.cjs +16 -0
- package/dist/function/index.d.cts +19 -0
- package/dist/function/index.d.ts +19 -0
- package/dist/function/index.js +16 -0
- package/dist/intl/index.cjs +103 -0
- package/dist/intl/index.d.cts +121 -0
- package/dist/intl/index.d.ts +121 -0
- package/dist/intl/index.js +103 -0
- package/dist/predicate/index.cjs +8 -0
- package/dist/predicate/index.d.cts +24 -0
- package/dist/predicate/index.d.ts +24 -0
- package/dist/predicate/index.js +8 -0
- package/dist/promise/index.cjs +30 -0
- package/dist/promise/index.d.cts +46 -0
- package/dist/promise/index.d.ts +46 -0
- package/dist/promise/index.js +30 -0
- package/dist/string/index.cjs +91 -0
- package/dist/string/index.d.cts +102 -0
- package/dist/string/index.d.ts +102 -0
- package/dist/string/index.js +91 -0
- package/dist/tests/utils.d.cts +1 -0
- package/dist/tests/utils.d.ts +1 -0
- package/dist/type/index.d.cts +15 -0
- package/dist/type/index.d.ts +15 -0
- package/dist/url/index.cjs +26 -0
- package/dist/url/index.d.cts +18 -0
- package/dist/url/index.d.ts +18 -0
- package/dist/url/index.js +26 -0
- package/package.json +66 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Licensing
|
|
2
|
+
|
|
3
|
+
COPYRIGHT © 2025 Esri
|
|
4
|
+
|
|
5
|
+
All rights reserved under the copyright laws of the United States and applicable international laws, treaties, and conventions.
|
|
6
|
+
|
|
7
|
+
This material is licensed for use under the Esri Master License Agreement (MLA), and is bound by the terms of that agreement. You may redistribute and use this code without modification, provided you adhere to the terms of the MLA and include this copyright notice.
|
|
8
|
+
|
|
9
|
+
See use restrictions at http://www.esri.com/legal/pdfs/mla_e204_e300/english
|
|
10
|
+
|
|
11
|
+
For additional information, contact: Environmental Systems Research Institute, Inc. Attn: Contracts and Legal Services Department 380 New York Street Redlands, California, USA 92373 USA
|
|
12
|
+
|
|
13
|
+
email: contracts@esri.com
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# ArcGIS Maps SDK for JavaScript - Internal Toolkit
|
|
2
|
+
|
|
3
|
+
**No Esri Technical Support included.**
|
|
4
|
+
|
|
5
|
+
Package that is part of the [ArcGIS Maps SDK for JavaScript](https://developers.arcgis.com/javascript).
|
|
6
|
+
|
|
7
|
+
It is not intended to be used directly, but rather used as a dependency by other packages in the SDK.
|
|
8
|
+
|
|
9
|
+
## License
|
|
10
|
+
|
|
11
|
+
COPYRIGHT © 2025 Esri
|
|
12
|
+
|
|
13
|
+
All rights reserved under the copyright laws of the United States and applicable international laws, treaties, and conventions.
|
|
14
|
+
|
|
15
|
+
This material is licensed for use under the Esri Master License Agreement (MLA), and is bound by the terms of that agreement. You may redistribute and use this code without modification, provided you adhere to the terms of the MLA and include this copyright notice.
|
|
16
|
+
|
|
17
|
+
See use restrictions at <http://www.esri.com/legal/pdfs/mla_e204_e300/english>
|
|
18
|
+
|
|
19
|
+
For additional information, contact: Environmental Systems Research Institute, Inc. Attn: Contracts and Legal Services Department 380 New York Street Redlands, California, USA 92373 USA
|
|
20
|
+
|
|
21
|
+
email: contracts@esri.com
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mappedFind = (array, callback) => {
|
|
4
|
+
for (let i = 0; i < array.length; i++) {
|
|
5
|
+
const value = callback(array[i], i);
|
|
6
|
+
if (value != null) {
|
|
7
|
+
return value ?? void 0;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return;
|
|
11
|
+
};
|
|
12
|
+
exports.mappedFind = mappedFind;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { nil } from '../type';
|
|
2
|
+
/**
|
|
3
|
+
* A combination of map and find.
|
|
4
|
+
* Find a value in an array, and return its mapped variant.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // Given array of url strings, return the first valid URL object.
|
|
9
|
+
* const url = mappedFind(urlsStrings, (url) => URL.parse(url));
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const mappedFind: <Item, ReturnType>(array: readonly Item[], callback: (item: Item, index: number) => nil | ReturnType) => ReturnType | undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { nil } from '../type';
|
|
2
|
+
/**
|
|
3
|
+
* A combination of map and find.
|
|
4
|
+
* Find a value in an array, and return its mapped variant.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // Given array of url strings, return the first valid URL object.
|
|
9
|
+
* const url = mappedFind(urlsStrings, (url) => URL.parse(url));
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const mappedFind: <Item, ReturnType>(array: readonly Item[], callback: (item: Item, index: number) => nil | ReturnType) => ReturnType | undefined;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const classes = (...classes2) => {
|
|
4
|
+
const effectiveClasses = [];
|
|
5
|
+
for (let i = 0; i < classes2.length; i++) {
|
|
6
|
+
const arg = classes2[i];
|
|
7
|
+
if (typeof arg === "string") {
|
|
8
|
+
effectiveClasses.push(arg);
|
|
9
|
+
} else if (Array.isArray(arg)) {
|
|
10
|
+
effectiveClasses.push.apply(effectiveClasses, arg);
|
|
11
|
+
} else if (typeof arg === "object") {
|
|
12
|
+
for (const prop in arg) {
|
|
13
|
+
if (arg[prop]) {
|
|
14
|
+
effectiveClasses.push(prop);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const className = effectiveClasses.join(" ");
|
|
20
|
+
effectiveClasses.length = 0;
|
|
21
|
+
return className;
|
|
22
|
+
};
|
|
23
|
+
const inTargetElement = (element, targetElement) => {
|
|
24
|
+
let currentElement = element;
|
|
25
|
+
while (currentElement) {
|
|
26
|
+
if (currentElement === targetElement) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (!currentElement.parentNode) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (currentElement.parentNode instanceof ShadowRoot) {
|
|
33
|
+
currentElement = currentElement.parentNode.host;
|
|
34
|
+
} else {
|
|
35
|
+
currentElement = currentElement.parentNode;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
};
|
|
40
|
+
const observeAncestorsMutation = (element, attributeFilter, callback) => {
|
|
41
|
+
const subscribe = observe(attributeFilter).subscribe;
|
|
42
|
+
return subscribe((mutations) => {
|
|
43
|
+
const matched = mutations.some((mutation) => inTargetElement(element, mutation.target));
|
|
44
|
+
if (matched) {
|
|
45
|
+
callback();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const observers = {};
|
|
50
|
+
const observe = (attributeFilter) => {
|
|
51
|
+
const attributes = attributeFilter.join(",");
|
|
52
|
+
const previousObserver = observers[attributes];
|
|
53
|
+
if (previousObserver !== void 0) {
|
|
54
|
+
return previousObserver;
|
|
55
|
+
}
|
|
56
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
57
|
+
const mutationObserver = new MutationObserver((mutations) => subscribers.forEach((callback) => callback(mutations)));
|
|
58
|
+
if (globalThis.document) {
|
|
59
|
+
mutationObserver.observe(document.documentElement, {
|
|
60
|
+
attributes: true,
|
|
61
|
+
attributeFilter,
|
|
62
|
+
subtree: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const observer = {
|
|
66
|
+
subscribe: (callback) => {
|
|
67
|
+
subscribers.add(callback);
|
|
68
|
+
return () => {
|
|
69
|
+
subscribers.delete(callback);
|
|
70
|
+
if (subscribers.size === 0) {
|
|
71
|
+
mutationObserver.disconnect();
|
|
72
|
+
observers[attributes] = void 0;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
observers[attributes] = observer;
|
|
78
|
+
return observer;
|
|
79
|
+
};
|
|
80
|
+
const getClosestElement = (base, selector) => {
|
|
81
|
+
let currentElement = base;
|
|
82
|
+
while (currentElement) {
|
|
83
|
+
const element = currentElement.closest?.(selector);
|
|
84
|
+
if (element) {
|
|
85
|
+
return element;
|
|
86
|
+
}
|
|
87
|
+
const rootElement = currentElement.getRootNode?.();
|
|
88
|
+
if (rootElement === globalThis.document) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
currentElement = rootElement.host;
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
};
|
|
95
|
+
function unsafeGetCalciteModeName(el) {
|
|
96
|
+
const closestElWithMode = getClosestElement(el, `.calcite-mode-dark, .calcite-mode-light, .calcite-mode-auto`);
|
|
97
|
+
return closestElWithMode?.classList.contains("calcite-mode-dark") || closestElWithMode?.classList.contains("calcite-mode-auto") && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
98
|
+
}
|
|
99
|
+
const unsafeGetElementDirection = (el) => (
|
|
100
|
+
//#endregion unsafeGetElementDirection
|
|
101
|
+
getElementAttribute(el, "dir", "ltr")
|
|
102
|
+
);
|
|
103
|
+
const getElementAttribute = (el, attributeName, fallbackValue) => {
|
|
104
|
+
const closest = getClosestElement(el, `[${attributeName}]`);
|
|
105
|
+
return closest?.getAttribute(attributeName) ?? fallbackValue;
|
|
106
|
+
};
|
|
107
|
+
const focusElement = async (el) => {
|
|
108
|
+
if (el == null) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (hasSetFocus(el)) {
|
|
112
|
+
await el.setFocus();
|
|
113
|
+
} else {
|
|
114
|
+
el.focus();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const hasSetFocus = (ref) => typeof ref.setFocus === "function";
|
|
118
|
+
const setFocusOnElement = (ref, selector) => {
|
|
119
|
+
if (!ref?.shadowRoot) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (ref.hasAttribute("hydrated") || ref.hasAttribute("calcite-hydrated")) {
|
|
123
|
+
setFocus(ref, selector);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
void Promise.resolve(ref.componentOnReady?.()).then(() => setFocus(ref, selector));
|
|
127
|
+
};
|
|
128
|
+
const isElement = (ref) => ref.nodeType === Node.ELEMENT_NODE;
|
|
129
|
+
const setFocus = (ref, selector = "") => {
|
|
130
|
+
if (!isElement(ref)) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
if (ref.matches(selector)) {
|
|
134
|
+
if (hasSetFocus(ref)) {
|
|
135
|
+
setTimeout(() => void ref.setFocus(), 0);
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
for (const child of ref.children) {
|
|
140
|
+
if (setFocus(child, selector)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const shadowRoot = ref.shadowRoot;
|
|
145
|
+
if (shadowRoot) {
|
|
146
|
+
for (const child of shadowRoot.children) {
|
|
147
|
+
if (setFocus(child, selector)) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
};
|
|
154
|
+
exports.classes = classes;
|
|
155
|
+
exports.focusElement = focusElement;
|
|
156
|
+
exports.getClosestElement = getClosestElement;
|
|
157
|
+
exports.getElementAttribute = getElementAttribute;
|
|
158
|
+
exports.observeAncestorsMutation = observeAncestorsMutation;
|
|
159
|
+
exports.setFocusOnElement = setFocusOnElement;
|
|
160
|
+
exports.unsafeGetCalciteModeName = unsafeGetCalciteModeName;
|
|
161
|
+
exports.unsafeGetElementDirection = unsafeGetElementDirection;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { nil } from '../type';
|
|
2
|
+
/**
|
|
3
|
+
* Combine multiple class names into a single string.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This function is less necessary in Lumina packages as the `class` JSX prop
|
|
7
|
+
* accepts `Record<string, boolean>` objects.
|
|
8
|
+
*/
|
|
9
|
+
export declare const classes: (...classes: (nil | Record<string, boolean> | string[] | string | false)[]) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Observe the element and its ancestors for attribute mutations.
|
|
12
|
+
* If the attributes have been changed in the ancestor tree then the callback
|
|
13
|
+
* will be invoked.
|
|
14
|
+
*
|
|
15
|
+
* @param element The element on which to observe the attribute mutations.
|
|
16
|
+
* @param attributeFilter The list of attributes to observe.
|
|
17
|
+
* @param callback The callback to invoke when the attributes have been changed.
|
|
18
|
+
* @returns A callback to unsubscribe from the observer.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* observeAncestorsMutation(
|
|
23
|
+
* element,
|
|
24
|
+
* ["dir", "lang"],
|
|
25
|
+
* () => console.log(getElementAttribute(element, "dir", "ltr"))
|
|
26
|
+
* );
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const observeAncestorsMutation: (element: Node, attributeFilter: string[], callback: () => void) => (() => void);
|
|
30
|
+
/**
|
|
31
|
+
* Find the closest element that matches the selector.
|
|
32
|
+
* It will traverse the element's ancestors to find the target element.
|
|
33
|
+
* Shadow DOM boundaries are also taken into account.
|
|
34
|
+
* @param base The element to start the search from.
|
|
35
|
+
* @param selector The selector to match.
|
|
36
|
+
* @returns The closest element that matches the selector or null if not found.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This is similar to [Element.closest()](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest),
|
|
40
|
+
* but the DOM's utility only looks up until the first shadow boundary.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const hostElement = getClosestElement(element, "arcgis-map, arcgis-scene");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare const getClosestElement: <T = Element>(base: Element, selector: string) => T | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Use the closest Calcite mode class name to determine the
|
|
50
|
+
* theme of the element. It will traverse the element's
|
|
51
|
+
* ancestors to find the theme. Shadow DOM boundaries are also
|
|
52
|
+
* taken into account.
|
|
53
|
+
*
|
|
54
|
+
* @param base The element to start the search from.
|
|
55
|
+
* @returns The theme of the element ("light" or "dark"). "light" is the default.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* It is advised to consider alternative solutions before using this utility:
|
|
59
|
+
* - Calcite CSS variables. Benefits: makes styles more consistent,
|
|
60
|
+
* and variables are updated automatically to match dark/light theme.
|
|
61
|
+
* - Detect dark mode using CSS selectors and apply styles in CSS.
|
|
62
|
+
* Benefit: styles update automatically when the theme changes.
|
|
63
|
+
*/
|
|
64
|
+
export declare function unsafeGetCalciteModeName(el: HTMLElement): "dark" | "light";
|
|
65
|
+
/**
|
|
66
|
+
* Get direction property of the closest element.
|
|
67
|
+
*
|
|
68
|
+
* @param el The element to start the search from.
|
|
69
|
+
* @returns The direction of the element ("ltr" | "rtl"). "ltr" is the default.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* Do not set the `dir` property on the element itself. Do not set the `dir`
|
|
73
|
+
* attribute on the components you are rendering. The `dir` attribute is only
|
|
74
|
+
* meant to be set by the consumers of your component. Your component is
|
|
75
|
+
* expected to respect what was set by the consumer.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* Prefer [useDirection()](http://localhost:5173/components/lumina/controllers/useDirection)
|
|
79
|
+
* to ensure your component is responsive to direction changes.
|
|
80
|
+
*/
|
|
81
|
+
export declare const unsafeGetElementDirection: (el: HTMLElement) => "ltr" | "rtl";
|
|
82
|
+
/**
|
|
83
|
+
* Get the attribute value from the element or closest ancestor.
|
|
84
|
+
* Shadow DOM boundaries are also taken into account.
|
|
85
|
+
* If the attribute is not found then the fallback value is returned.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const dir = getElementAttribute(element, "dir", "ltr");
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare const getElementAttribute: (el: Element, attributeName: string, fallbackValue: string) => string;
|
|
93
|
+
/**
|
|
94
|
+
* Focus the element if it is focusable.
|
|
95
|
+
* @returns A promise that resolves once the focus is set.
|
|
96
|
+
*/
|
|
97
|
+
export declare const focusElement: (el: FocusableElement | undefined) => Promise<void>;
|
|
98
|
+
export interface FocusableElement extends HTMLElement {
|
|
99
|
+
setFocus?: () => Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Set the focus on the element that matches the selector.
|
|
103
|
+
* It will traverse the element's ancestors to find the target element.
|
|
104
|
+
* Shadow DOM boundaries are also taken into account.
|
|
105
|
+
* If the element is not found then the focus is not set.
|
|
106
|
+
* Example: `setFocusOnElement(element, "[role='menuitem']");`
|
|
107
|
+
* @param ref The element to start the search from.
|
|
108
|
+
* @param selector The selector to match.
|
|
109
|
+
* @returns Returns true if the focus is set on the element.
|
|
110
|
+
*
|
|
111
|
+
* @deprecated This function is doing too much. Import from `focusElement(getClosestElement())` from `@arcgis/toolkit/dom` instead.
|
|
112
|
+
*/
|
|
113
|
+
export declare const setFocusOnElement: (ref: (Element & {
|
|
114
|
+
componentOnReady?: () => Promise<void>;
|
|
115
|
+
}) | null | undefined, selector: string) => void;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { nil } from '../type';
|
|
2
|
+
/**
|
|
3
|
+
* Combine multiple class names into a single string.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This function is less necessary in Lumina packages as the `class` JSX prop
|
|
7
|
+
* accepts `Record<string, boolean>` objects.
|
|
8
|
+
*/
|
|
9
|
+
export declare const classes: (...classes: (nil | Record<string, boolean> | string[] | string | false)[]) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Observe the element and its ancestors for attribute mutations.
|
|
12
|
+
* If the attributes have been changed in the ancestor tree then the callback
|
|
13
|
+
* will be invoked.
|
|
14
|
+
*
|
|
15
|
+
* @param element The element on which to observe the attribute mutations.
|
|
16
|
+
* @param attributeFilter The list of attributes to observe.
|
|
17
|
+
* @param callback The callback to invoke when the attributes have been changed.
|
|
18
|
+
* @returns A callback to unsubscribe from the observer.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* observeAncestorsMutation(
|
|
23
|
+
* element,
|
|
24
|
+
* ["dir", "lang"],
|
|
25
|
+
* () => console.log(getElementAttribute(element, "dir", "ltr"))
|
|
26
|
+
* );
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const observeAncestorsMutation: (element: Node, attributeFilter: string[], callback: () => void) => (() => void);
|
|
30
|
+
/**
|
|
31
|
+
* Find the closest element that matches the selector.
|
|
32
|
+
* It will traverse the element's ancestors to find the target element.
|
|
33
|
+
* Shadow DOM boundaries are also taken into account.
|
|
34
|
+
* @param base The element to start the search from.
|
|
35
|
+
* @param selector The selector to match.
|
|
36
|
+
* @returns The closest element that matches the selector or null if not found.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This is similar to [Element.closest()](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest),
|
|
40
|
+
* but the DOM's utility only looks up until the first shadow boundary.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const hostElement = getClosestElement(element, "arcgis-map, arcgis-scene");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare const getClosestElement: <T = Element>(base: Element, selector: string) => T | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Use the closest Calcite mode class name to determine the
|
|
50
|
+
* theme of the element. It will traverse the element's
|
|
51
|
+
* ancestors to find the theme. Shadow DOM boundaries are also
|
|
52
|
+
* taken into account.
|
|
53
|
+
*
|
|
54
|
+
* @param base The element to start the search from.
|
|
55
|
+
* @returns The theme of the element ("light" or "dark"). "light" is the default.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* It is advised to consider alternative solutions before using this utility:
|
|
59
|
+
* - Calcite CSS variables. Benefits: makes styles more consistent,
|
|
60
|
+
* and variables are updated automatically to match dark/light theme.
|
|
61
|
+
* - Detect dark mode using CSS selectors and apply styles in CSS.
|
|
62
|
+
* Benefit: styles update automatically when the theme changes.
|
|
63
|
+
*/
|
|
64
|
+
export declare function unsafeGetCalciteModeName(el: HTMLElement): "dark" | "light";
|
|
65
|
+
/**
|
|
66
|
+
* Get direction property of the closest element.
|
|
67
|
+
*
|
|
68
|
+
* @param el The element to start the search from.
|
|
69
|
+
* @returns The direction of the element ("ltr" | "rtl"). "ltr" is the default.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* Do not set the `dir` property on the element itself. Do not set the `dir`
|
|
73
|
+
* attribute on the components you are rendering. The `dir` attribute is only
|
|
74
|
+
* meant to be set by the consumers of your component. Your component is
|
|
75
|
+
* expected to respect what was set by the consumer.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* Prefer [useDirection()](http://localhost:5173/components/lumina/controllers/useDirection)
|
|
79
|
+
* to ensure your component is responsive to direction changes.
|
|
80
|
+
*/
|
|
81
|
+
export declare const unsafeGetElementDirection: (el: HTMLElement) => "ltr" | "rtl";
|
|
82
|
+
/**
|
|
83
|
+
* Get the attribute value from the element or closest ancestor.
|
|
84
|
+
* Shadow DOM boundaries are also taken into account.
|
|
85
|
+
* If the attribute is not found then the fallback value is returned.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const dir = getElementAttribute(element, "dir", "ltr");
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare const getElementAttribute: (el: Element, attributeName: string, fallbackValue: string) => string;
|
|
93
|
+
/**
|
|
94
|
+
* Focus the element if it is focusable.
|
|
95
|
+
* @returns A promise that resolves once the focus is set.
|
|
96
|
+
*/
|
|
97
|
+
export declare const focusElement: (el: FocusableElement | undefined) => Promise<void>;
|
|
98
|
+
export interface FocusableElement extends HTMLElement {
|
|
99
|
+
setFocus?: () => Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Set the focus on the element that matches the selector.
|
|
103
|
+
* It will traverse the element's ancestors to find the target element.
|
|
104
|
+
* Shadow DOM boundaries are also taken into account.
|
|
105
|
+
* If the element is not found then the focus is not set.
|
|
106
|
+
* Example: `setFocusOnElement(element, "[role='menuitem']");`
|
|
107
|
+
* @param ref The element to start the search from.
|
|
108
|
+
* @param selector The selector to match.
|
|
109
|
+
* @returns Returns true if the focus is set on the element.
|
|
110
|
+
*
|
|
111
|
+
* @deprecated This function is doing too much. Import from `focusElement(getClosestElement())` from `@arcgis/toolkit/dom` instead.
|
|
112
|
+
*/
|
|
113
|
+
export declare const setFocusOnElement: (ref: (Element & {
|
|
114
|
+
componentOnReady?: () => Promise<void>;
|
|
115
|
+
}) | null | undefined, selector: string) => void;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const classes = (...classes2) => {
|
|
2
|
+
const effectiveClasses = [];
|
|
3
|
+
for (let i = 0; i < classes2.length; i++) {
|
|
4
|
+
const arg = classes2[i];
|
|
5
|
+
if (typeof arg === "string") {
|
|
6
|
+
effectiveClasses.push(arg);
|
|
7
|
+
} else if (Array.isArray(arg)) {
|
|
8
|
+
effectiveClasses.push.apply(effectiveClasses, arg);
|
|
9
|
+
} else if (typeof arg === "object") {
|
|
10
|
+
for (const prop in arg) {
|
|
11
|
+
if (arg[prop]) {
|
|
12
|
+
effectiveClasses.push(prop);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const className = effectiveClasses.join(" ");
|
|
18
|
+
effectiveClasses.length = 0;
|
|
19
|
+
return className;
|
|
20
|
+
};
|
|
21
|
+
const inTargetElement = (element, targetElement) => {
|
|
22
|
+
let currentElement = element;
|
|
23
|
+
while (currentElement) {
|
|
24
|
+
if (currentElement === targetElement) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (!currentElement.parentNode) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (currentElement.parentNode instanceof ShadowRoot) {
|
|
31
|
+
currentElement = currentElement.parentNode.host;
|
|
32
|
+
} else {
|
|
33
|
+
currentElement = currentElement.parentNode;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
const observeAncestorsMutation = (element, attributeFilter, callback) => {
|
|
39
|
+
const subscribe = observe(attributeFilter).subscribe;
|
|
40
|
+
return subscribe((mutations) => {
|
|
41
|
+
const matched = mutations.some((mutation) => inTargetElement(element, mutation.target));
|
|
42
|
+
if (matched) {
|
|
43
|
+
callback();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const observers = {};
|
|
48
|
+
const observe = (attributeFilter) => {
|
|
49
|
+
const attributes = attributeFilter.join(",");
|
|
50
|
+
const previousObserver = observers[attributes];
|
|
51
|
+
if (previousObserver !== void 0) {
|
|
52
|
+
return previousObserver;
|
|
53
|
+
}
|
|
54
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
55
|
+
const mutationObserver = new MutationObserver((mutations) => subscribers.forEach((callback) => callback(mutations)));
|
|
56
|
+
if (globalThis.document) {
|
|
57
|
+
mutationObserver.observe(document.documentElement, {
|
|
58
|
+
attributes: true,
|
|
59
|
+
attributeFilter,
|
|
60
|
+
subtree: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const observer = {
|
|
64
|
+
subscribe: (callback) => {
|
|
65
|
+
subscribers.add(callback);
|
|
66
|
+
return () => {
|
|
67
|
+
subscribers.delete(callback);
|
|
68
|
+
if (subscribers.size === 0) {
|
|
69
|
+
mutationObserver.disconnect();
|
|
70
|
+
observers[attributes] = void 0;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
observers[attributes] = observer;
|
|
76
|
+
return observer;
|
|
77
|
+
};
|
|
78
|
+
const getClosestElement = (base, selector) => {
|
|
79
|
+
let currentElement = base;
|
|
80
|
+
while (currentElement) {
|
|
81
|
+
const element = currentElement.closest?.(selector);
|
|
82
|
+
if (element) {
|
|
83
|
+
return element;
|
|
84
|
+
}
|
|
85
|
+
const rootElement = currentElement.getRootNode?.();
|
|
86
|
+
if (rootElement === globalThis.document) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
currentElement = rootElement.host;
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
};
|
|
93
|
+
function unsafeGetCalciteModeName(el) {
|
|
94
|
+
const closestElWithMode = getClosestElement(el, `.calcite-mode-dark, .calcite-mode-light, .calcite-mode-auto`);
|
|
95
|
+
return closestElWithMode?.classList.contains("calcite-mode-dark") || closestElWithMode?.classList.contains("calcite-mode-auto") && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
96
|
+
}
|
|
97
|
+
const unsafeGetElementDirection = (el) => (
|
|
98
|
+
//#endregion unsafeGetElementDirection
|
|
99
|
+
getElementAttribute(el, "dir", "ltr")
|
|
100
|
+
);
|
|
101
|
+
const getElementAttribute = (el, attributeName, fallbackValue) => {
|
|
102
|
+
const closest = getClosestElement(el, `[${attributeName}]`);
|
|
103
|
+
return closest?.getAttribute(attributeName) ?? fallbackValue;
|
|
104
|
+
};
|
|
105
|
+
const focusElement = async (el) => {
|
|
106
|
+
if (el == null) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (hasSetFocus(el)) {
|
|
110
|
+
await el.setFocus();
|
|
111
|
+
} else {
|
|
112
|
+
el.focus();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const hasSetFocus = (ref) => typeof ref.setFocus === "function";
|
|
116
|
+
const setFocusOnElement = (ref, selector) => {
|
|
117
|
+
if (!ref?.shadowRoot) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (ref.hasAttribute("hydrated") || ref.hasAttribute("calcite-hydrated")) {
|
|
121
|
+
setFocus(ref, selector);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
void Promise.resolve(ref.componentOnReady?.()).then(() => setFocus(ref, selector));
|
|
125
|
+
};
|
|
126
|
+
const isElement = (ref) => ref.nodeType === Node.ELEMENT_NODE;
|
|
127
|
+
const setFocus = (ref, selector = "") => {
|
|
128
|
+
if (!isElement(ref)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (ref.matches(selector)) {
|
|
132
|
+
if (hasSetFocus(ref)) {
|
|
133
|
+
setTimeout(() => void ref.setFocus(), 0);
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
for (const child of ref.children) {
|
|
138
|
+
if (setFocus(child, selector)) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const shadowRoot = ref.shadowRoot;
|
|
143
|
+
if (shadowRoot) {
|
|
144
|
+
for (const child of shadowRoot.children) {
|
|
145
|
+
if (setFocus(child, selector)) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
};
|
|
152
|
+
export {
|
|
153
|
+
classes,
|
|
154
|
+
focusElement,
|
|
155
|
+
getClosestElement,
|
|
156
|
+
getElementAttribute,
|
|
157
|
+
observeAncestorsMutation,
|
|
158
|
+
setFocusOnElement,
|
|
159
|
+
unsafeGetCalciteModeName,
|
|
160
|
+
unsafeGetElementDirection
|
|
161
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const isEsriInternalEnv = () => (
|
|
4
|
+
//#endregion isEsriInternalEnv
|
|
5
|
+
/*
|
|
6
|
+
* `globalThis.` is important here. Some bundlers remove the `typeof process`
|
|
7
|
+
* checks, but don't remove the usages of undefined variables - this can cause
|
|
8
|
+
* runtime error. By adding `globalThis.`, we avoid having `typeof process`
|
|
9
|
+
* check removed by the bundler.
|
|
10
|
+
* This does meant tree-shaking won't happen for the isEsriInternalEnv()
|
|
11
|
+
* check, but this is ok since this check is meant to always be behind the
|
|
12
|
+
* development/test guard.
|
|
13
|
+
* See https://devtopia.esri.com/WebGIS/arcgis-web-components/pull/2087#issuecomment-5152454
|
|
14
|
+
*/
|
|
15
|
+
typeof globalThis.process === "object" && !!process.env.ESRI_INTERNAL
|
|
16
|
+
);
|
|
17
|
+
const safeCall = (callback, thisContext, ...rest) => {
|
|
18
|
+
try {
|
|
19
|
+
return callback?.call(thisContext, ...rest);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(error, callback);
|
|
22
|
+
}
|
|
23
|
+
return void 0;
|
|
24
|
+
};
|
|
25
|
+
const safeAsyncCall = async (callback, thisContext, ...rest) => {
|
|
26
|
+
try {
|
|
27
|
+
const result = callback?.call(thisContext, ...rest);
|
|
28
|
+
return await result;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(error, callback);
|
|
31
|
+
}
|
|
32
|
+
return void 0;
|
|
33
|
+
};
|
|
34
|
+
exports.isEsriInternalEnv = isEsriInternalEnv;
|
|
35
|
+
exports.safeAsyncCall = safeAsyncCall;
|
|
36
|
+
exports.safeCall = safeCall;
|