@thednp/shorty 2.0.4 → 2.0.5
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/README.md +5 -3
- package/dist/shorty.cjs +17 -1
- package/dist/shorty.cjs.map +1 -1
- package/dist/shorty.d.ts +18 -6
- package/dist/shorty.js +17 -1
- package/dist/shorty.js.map +1 -1
- package/dist/shorty.mjs +418 -384
- package/dist/shorty.mjs.map +1 -1
- package/dts.config.ts +1 -7
- package/package.json +12 -14
- package/src/boolean/isMobile.ts +1 -1
- package/src/boolean/supportPassive.ts +1 -1
- package/src/get/getRectRelativeToOffsetParent.ts +1 -1
- package/src/index.ts +6 -0
- package/src/misc/createCustomEvent.ts +2 -2
- package/src/misc/data.ts +2 -5
- package/src/misc/emulateAnimationEnd.ts +4 -4
- package/src/misc/emulateTransitionEnd.ts +3 -3
- package/src/misc/focusTrap.ts +64 -0
- package/src/misc/normalizeOptions.ts +2 -2
- package/src/misc/timer.ts +3 -3
- package/src/selectors/getCustomElements.ts +1 -2
- package/src/selectors/getElementById.ts +2 -2
- package/src/selectors/getElementsByClassName.ts +2 -7
- package/src/selectors/getElementsByTagName.ts +2 -5
- package/src/selectors/querySelector.ts +6 -3
- package/src/selectors/querySelectorAll.ts +4 -1
- package/src/strings/focusableSelector.ts +4 -0
- package/test/fixtures/getExampleDom.ts +12 -8
- package/test/is.test.ts +15 -11
- package/test/misc.test.ts +65 -17
- package/{vite.config.ts → vite.config.mts} +3 -8
- /package/{vitest.config-ui.ts → vitest.config-ui.mts} +0 -0
- /package/{vitest.config.ts → vitest.config.mts} +0 -0
package/dts.config.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
const packageJson = require("./package.json");
|
|
2
|
-
|
|
3
|
-
const getPackageName = () => {
|
|
4
|
-
return packageJson.name.includes('@') ? packageJson.name.split('/')[1] : packageJson.name;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
1
|
const config = {
|
|
8
2
|
entries: [
|
|
9
3
|
{
|
|
10
4
|
filePath: "./src/index.ts",
|
|
11
|
-
outFile: `./dist
|
|
5
|
+
outFile: `./dist/shorty.d.ts`,
|
|
12
6
|
noCheck: false,
|
|
13
7
|
output: {
|
|
14
8
|
exportReferencedTypes: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thednp/shorty",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "TypeScript shorties for the web",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./dist/shorty.js",
|
|
@@ -32,27 +32,25 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/thednp/shorty",
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/node": "^20.16.
|
|
35
|
+
"@types/node": "^20.16.15",
|
|
36
36
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
37
37
|
"@typescript-eslint/parser": "^5.62.0",
|
|
38
|
-
"@vitest/browser": "^2.1.
|
|
39
|
-
"@vitest/coverage-istanbul": "^2.1.
|
|
40
|
-
"@vitest/ui": "^2.1.
|
|
38
|
+
"@vitest/browser": "^2.1.3",
|
|
39
|
+
"@vitest/coverage-istanbul": "^2.1.3",
|
|
40
|
+
"@vitest/ui": "^2.1.3",
|
|
41
41
|
"dts-bundle-generator": "^9.5.1",
|
|
42
42
|
"eslint": "^8.57.1",
|
|
43
43
|
"eslint-plugin-jsdoc": "^46.10.1",
|
|
44
44
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
45
45
|
"eslint-plugin-prettier": "^4.2.1",
|
|
46
|
-
"happy-dom": "^15.7.4",
|
|
47
46
|
"istanbul-lib-coverage": "^3.2.2",
|
|
48
47
|
"istanbul-lib-instrument": "^5.2.1",
|
|
49
48
|
"nyc": "^15.1.0",
|
|
50
|
-
"playwright": "^1.
|
|
49
|
+
"playwright": "^1.48.1",
|
|
51
50
|
"prettier": "^2.8.8",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"vitest": "^2.1.1"
|
|
51
|
+
"typescript": "^5.6.3",
|
|
52
|
+
"vite": "^5.4.10",
|
|
53
|
+
"vitest": "^2.1.3"
|
|
56
54
|
},
|
|
57
55
|
"engines": {
|
|
58
56
|
"node": ">=16",
|
|
@@ -61,15 +59,15 @@
|
|
|
61
59
|
"scripts": {
|
|
62
60
|
"pre-test": "pnpm clean-coverage",
|
|
63
61
|
"badges": "npx -p dependency-version-badge update-badge typescript prettier eslint vitest vite",
|
|
64
|
-
"test": "pnpm pre-test && vitest --config vitest.config.
|
|
65
|
-
"test-ui": "pnpm pre-test && vitest --config vitest.config-ui.
|
|
62
|
+
"test": "pnpm pre-test && vitest --config vitest.config.mts",
|
|
63
|
+
"test-ui": "pnpm pre-test && vitest --config vitest.config-ui.mts",
|
|
66
64
|
"clean-coverage": "rm -rf coverage .nyc_output",
|
|
67
65
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
68
66
|
"lint": "pnpm lint:ts && pnpm check:ts",
|
|
69
67
|
"lint:ts": "eslint -c .eslintrc.cjs --ext .ts src",
|
|
70
68
|
"fix:ts": "eslint -c .eslintrc.cjs --ext .ts src --fix",
|
|
71
69
|
"check:ts": "tsc -noEmit",
|
|
72
|
-
"build": "
|
|
70
|
+
"build": "vite build && pnpm dts",
|
|
73
71
|
"dts": "dts-bundle-generator --config ./dts.config.ts"
|
|
74
72
|
}
|
|
75
73
|
}
|
package/src/boolean/isMobile.ts
CHANGED
|
@@ -4,7 +4,7 @@ import userAgent from '../strings/userAgent';
|
|
|
4
4
|
const mobileBrands = /iPhone|iPad|iPod|Android/i;
|
|
5
5
|
let isMobileCheck = false;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// istanbul ignore else @preserve
|
|
8
8
|
if (userAgentData) {
|
|
9
9
|
isMobileCheck = userAgentData.brands.some(x => mobileBrands.test(x.brand));
|
|
10
10
|
} else {
|
|
@@ -22,7 +22,7 @@ const getRectRelativeToOffsetParent = (
|
|
|
22
22
|
const rect = getBoundingClientRect(element, isParentAnElement && isScaledElement(offsetParent));
|
|
23
23
|
const offsets = { x: 0, y: 0 };
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// istanbul ignore else @preserve
|
|
26
26
|
if (isParentAnElement) {
|
|
27
27
|
const offsetRect = getBoundingClientRect(offsetParent, true);
|
|
28
28
|
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
package/src/index.ts
CHANGED
|
@@ -77,6 +77,7 @@ import focusEvents from './strings/focusEvents';
|
|
|
77
77
|
import focusEvent from './strings/focusEvent';
|
|
78
78
|
import focusinEvent from './strings/focusinEvent';
|
|
79
79
|
import focusoutEvent from './strings/focusoutEvent';
|
|
80
|
+
import focusableSelector from './strings/focusableSelector';
|
|
80
81
|
|
|
81
82
|
import gesturechangeEvent from './strings/gesturechangeEvent';
|
|
82
83
|
import gestureendEvent from './strings/gestureendEvent';
|
|
@@ -194,6 +195,7 @@ import setElementStyle from './misc/setElementStyle';
|
|
|
194
195
|
import Timer from './misc/timer';
|
|
195
196
|
import toLowerCase from './misc/toLowerCase';
|
|
196
197
|
import toUpperCase from './misc/toUpperCase';
|
|
198
|
+
import { type FocusableElement, hasFocusTrap, toggleFocusTrap } from './misc/focusTrap';
|
|
197
199
|
|
|
198
200
|
// get
|
|
199
201
|
import getBoundingClientRect from './get/getBoundingClientRect';
|
|
@@ -397,6 +399,9 @@ export {
|
|
|
397
399
|
createCustomEvent,
|
|
398
400
|
toUpperCase,
|
|
399
401
|
toLowerCase,
|
|
402
|
+
focusableSelector,
|
|
403
|
+
hasFocusTrap,
|
|
404
|
+
toggleFocusTrap,
|
|
400
405
|
Timer,
|
|
401
406
|
emulateAnimationEnd,
|
|
402
407
|
emulateTransitionEnd,
|
|
@@ -480,6 +485,7 @@ export {
|
|
|
480
485
|
export * from './interface/navigatorUA.d';
|
|
481
486
|
export * from './interface/offsetRect.d';
|
|
482
487
|
|
|
488
|
+
export type { FocusableElement };
|
|
483
489
|
export type { OriginalEvent } from './interface/originalEvent.d';
|
|
484
490
|
|
|
485
491
|
export type { BoundingClientRect } from './interface/boundingClientRect.d';
|
|
@@ -9,7 +9,7 @@ import ObjectAssign from './ObjectAssign';
|
|
|
9
9
|
* @param config Event.options | Event.properties
|
|
10
10
|
* @returns a new namespaced event
|
|
11
11
|
*/
|
|
12
|
-
const createCustomEvent = <O extends Record<string, unknown>, T extends OriginalEvent>(
|
|
12
|
+
const createCustomEvent = <O extends unknown & Record<string, unknown>, T extends OriginalEvent>(
|
|
13
13
|
eventType: string,
|
|
14
14
|
config?: O,
|
|
15
15
|
): T => {
|
|
@@ -18,7 +18,7 @@ const createCustomEvent = <O extends Record<string, unknown>, T extends Original
|
|
|
18
18
|
bubbles: true,
|
|
19
19
|
}) as T;
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// istanbul ignore else @preserve
|
|
22
22
|
if (isObject(config)) {
|
|
23
23
|
ObjectAssign(OriginalCustomEvent, config);
|
|
24
24
|
}
|
package/src/misc/data.ts
CHANGED
|
@@ -19,7 +19,7 @@ const Data = {
|
|
|
19
19
|
set: <T>(element: HTMLElement, component: string, instance: T): void => {
|
|
20
20
|
if (!isHTMLElement(element)) return;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// istanbul ignore else @preserve
|
|
23
23
|
if (!componentData.has(component)) {
|
|
24
24
|
componentData.set(component, new Map<HTMLElement, T>());
|
|
25
25
|
}
|
|
@@ -51,11 +51,9 @@ const Data = {
|
|
|
51
51
|
get: <T>(element: HTMLElement, component: string): T | null => {
|
|
52
52
|
if (!isHTMLElement(element) || !component) return null;
|
|
53
53
|
const instanceMap = Data.getAllFor<T>(component);
|
|
54
|
-
// const instanceMap = componentData.get(component) as Map<HTMLElement, InstanceType<T>>;
|
|
55
54
|
|
|
56
55
|
const instance = element && instanceMap && instanceMap.get(element);
|
|
57
56
|
|
|
58
|
-
// return (instance as T) || null;
|
|
59
57
|
return instance || null;
|
|
60
58
|
},
|
|
61
59
|
|
|
@@ -67,13 +65,12 @@ const Data = {
|
|
|
67
65
|
*/
|
|
68
66
|
remove: <T>(element: HTMLElement, component: string): void => {
|
|
69
67
|
const instanceMap = Data.getAllFor<T>(component);
|
|
70
|
-
// const instanceMap = componentData.get(component) as Map<HTMLElement, InstanceType<T>>;
|
|
71
68
|
|
|
72
69
|
if (!instanceMap || !isHTMLElement(element)) return;
|
|
73
70
|
|
|
74
71
|
instanceMap.delete(element);
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
// istanbul ignore else @preserve
|
|
77
74
|
if (instanceMap.size === 0) {
|
|
78
75
|
componentData.delete(component);
|
|
79
76
|
}
|
|
@@ -17,9 +17,9 @@ const emulateAnimationEnd = (element: HTMLElement, handler: EventListener): void
|
|
|
17
17
|
const delay = getElementAnimationDelay(element);
|
|
18
18
|
|
|
19
19
|
if (duration) {
|
|
20
|
-
|
|
20
|
+
// Wrap the handler in on -> off callback
|
|
21
21
|
const animationEndWrapper = (e: Event): void => {
|
|
22
|
-
|
|
22
|
+
// istanbul ignore else @preserve
|
|
23
23
|
if (e.target === element) {
|
|
24
24
|
handler.apply(element, [e]);
|
|
25
25
|
element.removeEventListener(animationEndEvent, animationEndWrapper);
|
|
@@ -28,11 +28,11 @@ const emulateAnimationEnd = (element: HTMLElement, handler: EventListener): void
|
|
|
28
28
|
};
|
|
29
29
|
element.addEventListener(animationEndEvent, animationEndWrapper);
|
|
30
30
|
setTimeout(() => {
|
|
31
|
-
|
|
31
|
+
// istanbul ignore next @preserve
|
|
32
32
|
if (!called) dispatchEvent(element, endEvent);
|
|
33
33
|
}, duration + delay + 17);
|
|
34
34
|
} else {
|
|
35
|
-
|
|
35
|
+
// istanbul ignore next @preserve
|
|
36
36
|
handler.apply(element, [endEvent]);
|
|
37
37
|
}
|
|
38
38
|
};
|
|
@@ -17,9 +17,9 @@ const emulateTransitionEnd = (element: HTMLElement, handler: EventListener): voi
|
|
|
17
17
|
const delay = getElementTransitionDelay(element);
|
|
18
18
|
|
|
19
19
|
if (duration) {
|
|
20
|
-
|
|
20
|
+
// Wrap the handler in on -> off callback
|
|
21
21
|
const transitionEndWrapper = (e: Event): void => {
|
|
22
|
-
|
|
22
|
+
// istanbul ignore else @preserve
|
|
23
23
|
if (e.target === element) {
|
|
24
24
|
handler.apply(element, [e]);
|
|
25
25
|
element.removeEventListener(transitionEndEvent, transitionEndWrapper);
|
|
@@ -28,7 +28,7 @@ const emulateTransitionEnd = (element: HTMLElement, handler: EventListener): voi
|
|
|
28
28
|
};
|
|
29
29
|
element.addEventListener(transitionEndEvent, transitionEndWrapper);
|
|
30
30
|
setTimeout(() => {
|
|
31
|
-
|
|
31
|
+
// istanbul ignore next @preserve
|
|
32
32
|
if (!called) dispatchEvent(element, endEvent);
|
|
33
33
|
}, duration + delay + 17);
|
|
34
34
|
} else {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import ariaHidden from '../strings/ariaHidden';
|
|
2
|
+
import focusableSelector from '../strings/focusableSelector';
|
|
3
|
+
import querySelectorAll from '../selectors/querySelectorAll';
|
|
4
|
+
import getAttribute from '../attr/getAttribute';
|
|
5
|
+
import hasAttribute from '../attr/hasAttribute';
|
|
6
|
+
import off from '../event/off';
|
|
7
|
+
import on from '../event/on';
|
|
8
|
+
import getDocument from '../get/getDocument';
|
|
9
|
+
import { KeyboardEvent } from '../interface/event';
|
|
10
|
+
|
|
11
|
+
const focusTrapMap = new Map<HTMLElement, boolean>();
|
|
12
|
+
|
|
13
|
+
export type FocusableElement =
|
|
14
|
+
| HTMLAnchorElement
|
|
15
|
+
| HTMLButtonElement
|
|
16
|
+
| HTMLInputElement
|
|
17
|
+
| HTMLTextAreaElement
|
|
18
|
+
| HTMLDataListElement
|
|
19
|
+
| HTMLDetailsElement
|
|
20
|
+
| HTMLSelectElement;
|
|
21
|
+
|
|
22
|
+
function handleKeyboardNavigation<T extends HTMLElement & EventTarget>(
|
|
23
|
+
this: T,
|
|
24
|
+
event: KeyboardEvent<T>,
|
|
25
|
+
) {
|
|
26
|
+
const { shiftKey, code } = event;
|
|
27
|
+
const doc = getDocument(this);
|
|
28
|
+
const focusableElements = [...querySelectorAll<FocusableElement>(focusableSelector, this)].filter(
|
|
29
|
+
el => !hasAttribute(el, 'disabled') && !getAttribute(el, ariaHidden),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!focusableElements.length) return;
|
|
33
|
+
const firstFocusable = focusableElements[0];
|
|
34
|
+
const lastFocusable = focusableElements[focusableElements.length - 1];
|
|
35
|
+
|
|
36
|
+
// istanbul ignore else @preserve
|
|
37
|
+
if (code === 'Tab') {
|
|
38
|
+
if (shiftKey && doc.activeElement === firstFocusable) {
|
|
39
|
+
lastFocusable.focus();
|
|
40
|
+
event.preventDefault();
|
|
41
|
+
} else if (!shiftKey && doc.activeElement === lastFocusable) {
|
|
42
|
+
firstFocusable.focus();
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Utility to check if a designated element is affected by focus trap;
|
|
50
|
+
* @param target
|
|
51
|
+
*/
|
|
52
|
+
export const hasFocusTrap = (target: HTMLElement) => focusTrapMap.has(target) === true;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Utility to toggle focus trap inside a designated target element;
|
|
56
|
+
* @param target
|
|
57
|
+
*/
|
|
58
|
+
export const toggleFocusTrap = (target: HTMLElement) => {
|
|
59
|
+
const isCurrentlyTrapped = hasFocusTrap(target);
|
|
60
|
+
const action = !isCurrentlyTrapped ? on : off;
|
|
61
|
+
action(target, 'keydown', handleKeyboardNavigation);
|
|
62
|
+
if (isCurrentlyTrapped) focusTrapMap.delete(target);
|
|
63
|
+
else focusTrapMap.set(target, true);
|
|
64
|
+
};
|
|
@@ -29,7 +29,7 @@ const normalizeOptions = <T extends { [key: string]: any }>(
|
|
|
29
29
|
const key: keyof T =
|
|
30
30
|
ns && typeof k === 'string' && k.includes(ns)
|
|
31
31
|
? k.replace(ns, '').replace(/[A-Z]/g, (match: string) => toLowerCase(match))
|
|
32
|
-
: k;
|
|
32
|
+
: /* istanbul ignore next @preserve */ k;
|
|
33
33
|
|
|
34
34
|
dataOps[key] = normalizeValue(v) as T[keyof T];
|
|
35
35
|
});
|
|
@@ -39,7 +39,7 @@ const normalizeOptions = <T extends { [key: string]: any }>(
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
ObjectEntries(defaultOps).forEach(([k, v]) => {
|
|
42
|
-
|
|
42
|
+
// istanbul ignore else @preserve
|
|
43
43
|
if (k in INPUT) {
|
|
44
44
|
normalOps[k] = INPUT[k] as T[keyof T];
|
|
45
45
|
} else if (k in dataOps) {
|
package/src/misc/timer.ts
CHANGED
|
@@ -23,9 +23,9 @@ const Timer = {
|
|
|
23
23
|
set: (element: HTMLElement, callback: TimerHandler, delay: number, key?: string): void => {
|
|
24
24
|
if (!isHTMLElement(element)) return;
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// istanbul ignore else @preserve
|
|
27
27
|
if (key && key.length) {
|
|
28
|
-
|
|
28
|
+
// istanbul ignore else @preserve
|
|
29
29
|
if (!TimeCache.has(element)) {
|
|
30
30
|
TimeCache.set(element, new Map());
|
|
31
31
|
}
|
|
@@ -70,7 +70,7 @@ const Timer = {
|
|
|
70
70
|
if (key && key.length && isMap(keyTimers as KeyMap)) {
|
|
71
71
|
clearTimeout((keyTimers as KeyMap).get(key));
|
|
72
72
|
(keyTimers as KeyMap).delete(key);
|
|
73
|
-
|
|
73
|
+
// istanbul ignore else @preserve
|
|
74
74
|
if ((keyTimers as KeyMap).size === 0) {
|
|
75
75
|
TimeCache.delete(element);
|
|
76
76
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import isCustomElement from '../is/isCustomElement';
|
|
2
2
|
import getElementsByTagName from './getElementsByTagName';
|
|
3
|
-
import type { CustomElement } from '../interface/customElement';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Returns an `Array` of `Node` elements that are registered as
|
|
@@ -11,7 +10,7 @@ import type { CustomElement } from '../interface/customElement';
|
|
|
11
10
|
* @param parent parent to look into
|
|
12
11
|
* @returns the query result
|
|
13
12
|
*/
|
|
14
|
-
const getCustomElements = (parent?: ParentNode)
|
|
13
|
+
const getCustomElements = (parent?: ParentNode) => {
|
|
15
14
|
const collection = getElementsByTagName('*', parent);
|
|
16
15
|
|
|
17
16
|
return [...collection].filter(isCustomElement);
|
|
@@ -9,8 +9,8 @@ import getDocument from '../get/getDocument';
|
|
|
9
9
|
* @param context an element in it's document or document
|
|
10
10
|
* @returns the requested element
|
|
11
11
|
*/
|
|
12
|
-
const getElementById = (id: string, context?: Node)
|
|
13
|
-
return getDocument(context).getElementById(id) || null;
|
|
12
|
+
const getElementById = <T extends HTMLElement>(id: string, context?: Node) => {
|
|
13
|
+
return (getDocument(context).getElementById(id) as T) || null;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export default getElementById;
|
|
@@ -9,14 +9,9 @@ import isNode from '../is/isNode';
|
|
|
9
9
|
* @param parent optional Element to look into
|
|
10
10
|
* @return the 'HTMLCollection'
|
|
11
11
|
*/
|
|
12
|
-
const getElementsByClassName = (
|
|
13
|
-
selector: string,
|
|
14
|
-
parent?: ParentNode,
|
|
15
|
-
): HTMLCollectionOf<HTMLElement> => {
|
|
12
|
+
const getElementsByClassName = <T extends HTMLElement>(selector: string, parent?: ParentNode) => {
|
|
16
13
|
const lookUp = parent && isNode(parent) ? parent : getDocument();
|
|
17
|
-
return (lookUp as HTMLElement | Document).getElementsByClassName(
|
|
18
|
-
selector,
|
|
19
|
-
) as HTMLCollectionOf<HTMLElement>;
|
|
14
|
+
return (lookUp as HTMLElement | Document).getElementsByClassName(selector) as HTMLCollectionOf<T>;
|
|
20
15
|
};
|
|
21
16
|
|
|
22
17
|
export default getElementsByClassName;
|
|
@@ -9,12 +9,9 @@ import isNode from '../is/isNode';
|
|
|
9
9
|
* @param parent optional Element to look into
|
|
10
10
|
* @return the 'HTMLCollection'
|
|
11
11
|
*/
|
|
12
|
-
const getElementsByTagName = (
|
|
13
|
-
selector: string,
|
|
14
|
-
parent?: ParentNode,
|
|
15
|
-
): HTMLCollectionOf<HTMLElement> => {
|
|
12
|
+
const getElementsByTagName = <T extends HTMLElement>(selector: string, parent?: ParentNode) => {
|
|
16
13
|
const lookUp = isNode(parent) ? parent : getDocument();
|
|
17
|
-
return (lookUp as Document).getElementsByTagName(selector) as HTMLCollectionOf<
|
|
14
|
+
return (lookUp as Document).getElementsByTagName(selector) as HTMLCollectionOf<T>;
|
|
18
15
|
};
|
|
19
16
|
|
|
20
17
|
export default getElementsByTagName;
|
|
@@ -10,13 +10,16 @@ import isHTMLElement from '../is/isHTMLElement';
|
|
|
10
10
|
* @param parent optional node to look into
|
|
11
11
|
* @return the `HTMLElement` or `querySelector` result
|
|
12
12
|
*/
|
|
13
|
-
const querySelector =
|
|
13
|
+
const querySelector = <T extends HTMLElement>(
|
|
14
|
+
selector: HTMLElement | string,
|
|
15
|
+
parent?: ParentNode,
|
|
16
|
+
): T | null => {
|
|
14
17
|
if (isHTMLElement(selector)) {
|
|
15
|
-
return selector;
|
|
18
|
+
return selector as T;
|
|
16
19
|
}
|
|
17
20
|
const lookUp = isNode(parent) ? parent : getDocument();
|
|
18
21
|
|
|
19
|
-
return lookUp.querySelector(selector);
|
|
22
|
+
return lookUp.querySelector<T>(selector);
|
|
20
23
|
};
|
|
21
24
|
|
|
22
25
|
export default querySelector;
|
|
@@ -8,7 +8,10 @@ import isNode from '../is/isNode';
|
|
|
8
8
|
* @param parent optional node to look into
|
|
9
9
|
* @return the query result
|
|
10
10
|
*/
|
|
11
|
-
const querySelectorAll =
|
|
11
|
+
const querySelectorAll = <T extends HTMLElement>(
|
|
12
|
+
selector: string,
|
|
13
|
+
parent?: ParentNode,
|
|
14
|
+
): NodeListOf<T> => {
|
|
12
15
|
const lookUp = isNode(parent) ? parent : getDocument();
|
|
13
16
|
return lookUp.querySelectorAll(selector);
|
|
14
17
|
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const div = document.createElement('div');
|
|
3
|
-
div.className = 'm-4';
|
|
4
|
-
const tempDocument = new DOMParser().parseFromString(`
|
|
1
|
+
const markup = `<div class="p-5">
|
|
5
2
|
<div id="alertDemo" class="alert alert-warning alert-dismissible fade show" data-bs-op1="false" data-bs-op2="true" data-bs-op3="10" data-bs-title="" role="alert">
|
|
6
3
|
<button role="button" type="button" class="btn-close bg-none" data-bs-target="alertDemo" data-bs-dismiss="alert" aria-label="Close">
|
|
7
4
|
<svg viewBox="0 0 16 16" class="align-top">
|
|
@@ -10,6 +7,10 @@ export const getExampleDOM = () => {
|
|
|
10
7
|
</svg>
|
|
11
8
|
</button>
|
|
12
9
|
<p><b>Holy guacamole!</b> Best check yo self, you're not looking too good.</p>
|
|
10
|
+
<button class="btn btn-outline-secondary">
|
|
11
|
+
ReadMore
|
|
12
|
+
</button>
|
|
13
|
+
|
|
13
14
|
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgODAgNDMiIHdpZHRoPSI4MCIgaGVpZ2h0PSI0MyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCiAgICAgICAgICAgICAgICAgIDxyZWN0IGZpbGw9IndoaXRlIiBzdHJva2U9IiNjY2MiIHN0cm9rZS13aWR0aD0iMSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcng9IjUiPjwvcmVjdD4NCiAgICAgICAgICAgICAgICAgIDx0ZXh0IGRpcmVjdGlvbj0ibHRyIiBmaWxsPSIjMzMzIiB4PSIyNSIgeT0iMjUiIGZvbnQtc2l6ZT0iMTQiPklNRzwvdGV4dD4NCiAgICAgICAgICAgICAgICA8L3N2Zz4=" alt="Image">
|
|
14
15
|
</div>
|
|
15
16
|
<table class="table">
|
|
@@ -40,9 +41,12 @@ export const getExampleDOM = () => {
|
|
|
40
41
|
</tr>
|
|
41
42
|
</tbody>
|
|
42
43
|
</table>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
</div>
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
export const getExampleDOM = () => {
|
|
48
|
+
const tempDocument = new DOMParser().parseFromString(markup, 'text/html');
|
|
49
|
+
const container = tempDocument.body.querySelector('div')!;
|
|
46
50
|
|
|
47
|
-
return
|
|
51
|
+
return container;
|
|
48
52
|
};
|
package/test/is.test.ts
CHANGED
|
@@ -8,13 +8,20 @@ import CustomElem from './fixtures/custom-elem';
|
|
|
8
8
|
describe('Shorty Library Tests - IS', () => {
|
|
9
9
|
const wrapper = document.createElement('div');
|
|
10
10
|
document.body.append(wrapper);
|
|
11
|
+
|
|
11
12
|
afterEach(async () => {
|
|
12
13
|
wrapper.innerHTML = '';
|
|
13
14
|
});
|
|
14
15
|
|
|
15
|
-
it('Test is folder', () => {
|
|
16
|
+
it('Test is folder', async () => {
|
|
17
|
+
vi.useFakeTimers();
|
|
16
18
|
const container = getExampleDOM();
|
|
19
|
+
const CE1 = new CustomElem();
|
|
20
|
+
CE1.className = 'btn btn-outline-primary';
|
|
21
|
+
CE1.style.transform = 'scale(1.01)';
|
|
22
|
+
container.append(CE1);
|
|
17
23
|
wrapper.append(container);
|
|
24
|
+
await vi.waitFor(() => container.querySelector('table'), 200);
|
|
18
25
|
const win = container.ownerDocument.defaultView!;
|
|
19
26
|
|
|
20
27
|
const {
|
|
@@ -51,15 +58,12 @@ describe('Shorty Library Tests - IS', () => {
|
|
|
51
58
|
} = SHORTY;
|
|
52
59
|
|
|
53
60
|
// const win = getWindow($element[0]);
|
|
54
|
-
|
|
55
|
-
CE1.className = 'btn btn-outline-primary';
|
|
56
|
-
CE1.style.transform = 'scale(1.01)';
|
|
57
|
-
document.body.append(CE1);
|
|
61
|
+
|
|
58
62
|
|
|
59
63
|
const element = querySelector('.alert', container)!;
|
|
60
64
|
const CE = querySelector('custom-elem', document) as HTMLElement;
|
|
61
65
|
CE.className = 'btn btn-outline-primary';
|
|
62
|
-
|
|
66
|
+
CE.style.transform = 'scale(1.01)';
|
|
63
67
|
// win.document.body.append(CE);
|
|
64
68
|
const img = querySelector('img', element);
|
|
65
69
|
const svg = querySelector('svg', element);
|
|
@@ -154,12 +158,12 @@ describe('Shorty Library Tests - IS', () => {
|
|
|
154
158
|
|
|
155
159
|
expect(isElementInScrollRange(), 'isElementInScrollRange()').to.be.false;
|
|
156
160
|
expect(isElementInScrollRange(win as any), 'isElementInScrollRange(window)').to.be.false;
|
|
157
|
-
expect(isElementInScrollRange(CE!), 'isElementInScrollRange(CustomElement)').to.be.
|
|
161
|
+
expect(isElementInScrollRange(CE!), 'isElementInScrollRange(CustomElement)').to.be.false;
|
|
158
162
|
expect(isElementInScrollRange(element), 'isElementInScrollRange(node)').to.be.true;
|
|
159
163
|
|
|
160
164
|
expect(isElementInViewport(), 'isElementInScrollRange()').to.be.false;
|
|
161
165
|
expect(isElementInViewport(win as any), 'isElementInScrollRange(window)').to.be.false;
|
|
162
|
-
expect(isElementInViewport(CE
|
|
166
|
+
expect(isElementInViewport(CE), 'isElementInViewport(CustomElement)').to.be.false;
|
|
163
167
|
expect(isElementInViewport(element), 'isElementInScrollRange(node)').to.be.true;
|
|
164
168
|
|
|
165
169
|
expect(isNode(), 'isNode()').to.be.false;
|
|
@@ -183,7 +187,7 @@ describe('Shorty Library Tests - IS', () => {
|
|
|
183
187
|
expect(isScaledElement(element), 'isScaledElement(node)').to.be.false;
|
|
184
188
|
expect(isScaledElement(win as any), 'isScaledElement(window)').to.be.false;
|
|
185
189
|
expect(isScaledElement(win.document as any), 'isScaledElement(document)').to.be.false;
|
|
186
|
-
expect(isScaledElement(CE
|
|
190
|
+
expect(isScaledElement(CE), 'isScaledElement(expected)').to.be.true;
|
|
187
191
|
|
|
188
192
|
expect(isSVGElement(), 'isSVGElement()').to.be.false;
|
|
189
193
|
expect(isSVGElement(element), 'isSVGElement(node)').to.be.false;
|
|
@@ -230,7 +234,7 @@ describe('Shorty Library Tests - IS', () => {
|
|
|
230
234
|
expect(isShadowRoot(element), 'isShadowRoot(element)').to.be.false;
|
|
231
235
|
expect(isShadowRoot(document), 'isShadowRoot(document)').to.be.false;
|
|
232
236
|
expect(isShadowRoot(CE!.shadowRoot), 'isShadowRoot(CustomElement.shadowRoot)').to.be.true;
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
}, 350);
|
|
238
|
+
vi.advanceTimersByTime(350)
|
|
235
239
|
});
|
|
236
240
|
});
|