@agencecinq/utils 2.0.1 → 2.0.2
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/.turbo/turbo-build.log +13 -0
- package/dist/index.js +11 -11
- package/package.json +10 -13
- package/src/environment.ts +35 -0
- package/src/events.ts +9 -0
- package/src/focus-trap.ts +87 -0
- package/src/index.ts +6 -0
- package/src/keycode.ts +33 -0
- package/src/scroll.ts +76 -0
- package/src/throttle.ts +28 -0
- package/tsconfig.json +16 -0
- package/vite.config.ts +18 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @agencecinq/utils@2.0.1 build /Users/19h47/Sites/agencecinq-shopify/packages/utils
|
|
4
|
+
> vite build
|
|
5
|
+
|
|
6
|
+
[36mvite v7.3.1 [32mbuilding client environment for production...[36m[39m
|
|
7
|
+
[2K[1Gtransforming (1) [2msrc/index.ts[22m[2K[1Gtransforming (3) [2msrc/events.ts[22m[2K[1G[32m✓[39m 7 modules transformed.
|
|
8
|
+
[2K[1Grendering chunks (1)...[2K[1G[32m
|
|
9
|
+
[36m[vite:dts][32m Start generate declaration files...[39m
|
|
10
|
+
[2K[1Gcomputing gzip size (0)...[2K[1Gcomputing gzip size (1)...[2K[1G[2mdist/[22m[36mindex.js [39m[1m[2m3.28 kB[22m[1m[22m[2m │ gzip: 1.52 kB[22m
|
|
11
|
+
[32m[36m[vite:dts][32m Declaration files built in 2669ms.
|
|
12
|
+
[39m
|
|
13
|
+
[32m✓ built in 3.22s[39m
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const O = {
|
|
|
12
12
|
return (...c) => {
|
|
13
13
|
r = c, n || (n = setTimeout(s, t));
|
|
14
14
|
};
|
|
15
|
-
}, l = document.documentElement, { body: d } = document,
|
|
15
|
+
}, l = document.documentElement, { body: d } = document, W = l.hasAttribute("data-debug"), o = {
|
|
16
16
|
y: 0,
|
|
17
17
|
x: 0
|
|
18
18
|
}, a = {
|
|
@@ -26,15 +26,15 @@ window.addEventListener(
|
|
|
26
26
|
}, 100),
|
|
27
27
|
{ passive: !0 }
|
|
28
28
|
);
|
|
29
|
-
const
|
|
29
|
+
const k = {
|
|
30
30
|
lg: window.matchMedia("(width >= 64rem)"),
|
|
31
31
|
xl: window.matchMedia("(min-width: 1280px)"),
|
|
32
32
|
"2xl": window.matchMedia("(min-width: 1440px)"),
|
|
33
33
|
"3xl": window.matchMedia("(min-width: 1920px)")
|
|
34
|
-
},
|
|
34
|
+
}, C = !0, u = (e, t) => {
|
|
35
35
|
typeof e < "u" && (o.x = e), typeof t < "u" && (o.y = t), window.scrollTo(o.x, o.y);
|
|
36
36
|
};
|
|
37
|
-
function
|
|
37
|
+
function N() {
|
|
38
38
|
const e = l.scrollLeft, t = l.scrollTop, n = d.scrollLeft, r = d.scrollTop;
|
|
39
39
|
o.x = window.scrollX || e || n, o.y = window.scrollY || t || r || 0, l.style.setProperty("overflow", "hidden"), l.style.setProperty("height", "100%"), l.style.setProperty("scroll-padding-top", "0px"), u(o.x, o.y);
|
|
40
40
|
}
|
|
@@ -73,7 +73,7 @@ function G(e, t = e) {
|
|
|
73
73
|
function E(e = null) {
|
|
74
74
|
i.keydown && document.removeEventListener("keydown", i.keydown), e && e.focus();
|
|
75
75
|
}
|
|
76
|
-
const p = 8, w = 9, h = 13, b = 16, A = 27, x = 32, g = 33, R = 34, v = 35, P = 36, S = 37, T = 38,
|
|
76
|
+
const p = 8, w = 9, h = 13, b = 16, A = 27, x = 32, g = 33, R = 34, v = 35, P = 36, S = 37, T = 38, L = 39, D = 40, _ = 46, M = {
|
|
77
77
|
BACKSPACE: p,
|
|
78
78
|
TAB: w,
|
|
79
79
|
ENTER: h,
|
|
@@ -86,23 +86,23 @@ const p = 8, w = 9, h = 13, b = 16, A = 27, x = 32, g = 33, R = 34, v = 35, P =
|
|
|
86
86
|
HOME: P,
|
|
87
87
|
ARROW_LEFT: S,
|
|
88
88
|
ARROW_UP: T,
|
|
89
|
-
ARROW_RIGHT:
|
|
90
|
-
ARROW_DOWN:
|
|
89
|
+
ARROW_RIGHT: L,
|
|
90
|
+
ARROW_DOWN: D,
|
|
91
91
|
DELETE: _
|
|
92
92
|
};
|
|
93
93
|
export {
|
|
94
94
|
O as EVENTS,
|
|
95
95
|
G as addTrapFocus,
|
|
96
96
|
d as body,
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
k as breakpoints,
|
|
98
|
+
N as disableScroll,
|
|
99
99
|
H as enableScroll,
|
|
100
100
|
m as getFocusableElements,
|
|
101
101
|
l as html,
|
|
102
|
-
|
|
102
|
+
W as isDebug,
|
|
103
103
|
M as keycode,
|
|
104
104
|
a as mouse,
|
|
105
|
-
|
|
105
|
+
C as production,
|
|
106
106
|
E as removeTrapFocus,
|
|
107
107
|
o as scroll,
|
|
108
108
|
f as throttle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agencecinq/utils",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,25 +10,22 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "./dist/index.js",
|
|
12
12
|
"module": "./dist/index.js",
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
13
|
"exports": {
|
|
15
14
|
".": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
18
17
|
}
|
|
19
18
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"dev": "vite",
|
|
25
|
-
"build": "vite build"
|
|
26
|
-
},
|
|
27
19
|
"devDependencies": {
|
|
28
|
-
"
|
|
29
|
-
"vite
|
|
20
|
+
"typescript": "^5.9.3",
|
|
21
|
+
"vite": "^7.3.1",
|
|
22
|
+
"vite-plugin-dts": "^4.5.4"
|
|
30
23
|
},
|
|
31
24
|
"publishConfig": {
|
|
32
25
|
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "vite",
|
|
29
|
+
"build": "vite build"
|
|
33
30
|
}
|
|
34
31
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { throttle } from "./throttle";
|
|
2
|
+
|
|
3
|
+
const html = document.documentElement;
|
|
4
|
+
const { body } = document;
|
|
5
|
+
const isDebug = html.hasAttribute('data-debug');
|
|
6
|
+
|
|
7
|
+
const scroll = {
|
|
8
|
+
y: 0,
|
|
9
|
+
x: 0,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const mouse = {
|
|
13
|
+
x: 0,
|
|
14
|
+
y: 0,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
window.addEventListener(
|
|
18
|
+
'pointermove',
|
|
19
|
+
throttle(({ x, y }) => {
|
|
20
|
+
mouse.x = x;
|
|
21
|
+
mouse.y = y;
|
|
22
|
+
}, 100),
|
|
23
|
+
{ passive: true }
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const breakpoints = {
|
|
27
|
+
lg: window.matchMedia('(width >= 64rem)'),
|
|
28
|
+
xl: window.matchMedia('(min-width: 1280px)'),
|
|
29
|
+
'2xl': window.matchMedia('(min-width: 1440px)'),
|
|
30
|
+
'3xl': window.matchMedia('(min-width: 1920px)'),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const production = import.meta.env.PROD;
|
|
34
|
+
|
|
35
|
+
export { html, body, isDebug, scroll, mouse, breakpoints, production };
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const trapFocusHandlers: {
|
|
2
|
+
focusin?: (event: FocusEvent) => void;
|
|
3
|
+
focusout?: () => void;
|
|
4
|
+
keydown?: (event: KeyboardEvent) => void;
|
|
5
|
+
} = {};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Filtre les éléments réellement visibles et focalisables
|
|
9
|
+
*/
|
|
10
|
+
function isVisible(el: HTMLElement): boolean {
|
|
11
|
+
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getFocusableElements(container: HTMLElement): HTMLElement[] {
|
|
15
|
+
if (!container) return [];
|
|
16
|
+
|
|
17
|
+
const selector = [
|
|
18
|
+
'summary',
|
|
19
|
+
'a[href]',
|
|
20
|
+
'button:enabled',
|
|
21
|
+
'[tabindex]:not([tabindex^="-"])',
|
|
22
|
+
'input:not([type=hidden]):enabled',
|
|
23
|
+
'select:enabled',
|
|
24
|
+
'textarea:enabled',
|
|
25
|
+
'object',
|
|
26
|
+
'iframe',
|
|
27
|
+
'[contenteditable]'
|
|
28
|
+
].join(',');
|
|
29
|
+
|
|
30
|
+
return Array.from(container.querySelectorAll<HTMLElement>(selector))
|
|
31
|
+
.filter(el => isVisible(el) && el.getAttribute('tabindex') !== '-1');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function addTrapFocus(container: HTMLElement, elementToFocus: HTMLElement = container): void {
|
|
35
|
+
const elements = getFocusableElements(container);
|
|
36
|
+
if (elements.length === 0) return;
|
|
37
|
+
|
|
38
|
+
const first = elements[0];
|
|
39
|
+
const last = elements[elements.length - 1];
|
|
40
|
+
|
|
41
|
+
// Nettoyage avant d'ajouter (pour éviter les doublons)
|
|
42
|
+
removeTrapFocus();
|
|
43
|
+
|
|
44
|
+
trapFocusHandlers.keydown = (event: KeyboardEvent): void => {
|
|
45
|
+
if (event.key !== 'Tab') return;
|
|
46
|
+
|
|
47
|
+
if (event.shiftKey) {
|
|
48
|
+
// Tab arrière
|
|
49
|
+
if (document.activeElement === first || document.activeElement === container) {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
last.focus();
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
// Tab avant
|
|
55
|
+
if (document.activeElement === last) {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
first.focus();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
document.addEventListener('keydown', trapFocusHandlers.keydown);
|
|
63
|
+
|
|
64
|
+
// Focus initial
|
|
65
|
+
elementToFocus.focus();
|
|
66
|
+
|
|
67
|
+
// Support spécifique pour les inputs texte (sélection du contenu)
|
|
68
|
+
if (
|
|
69
|
+
elementToFocus instanceof HTMLInputElement &&
|
|
70
|
+
['search', 'text', 'email', 'url'].includes(elementToFocus.type) &&
|
|
71
|
+
elementToFocus.value
|
|
72
|
+
) {
|
|
73
|
+
elementToFocus.setSelectionRange(0, elementToFocus.value.length);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function removeTrapFocus(elementToFocus: HTMLElement | null = null): void {
|
|
78
|
+
if (trapFocusHandlers.keydown) {
|
|
79
|
+
document.removeEventListener('keydown', trapFocusHandlers.keydown);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (elementToFocus) {
|
|
83
|
+
elementToFocus.focus();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { addTrapFocus, removeTrapFocus, getFocusableElements };
|
package/src/index.ts
ADDED
package/src/keycode.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const BACKSPACE = 8;
|
|
2
|
+
const TAB = 9;
|
|
3
|
+
const ENTER = 13;
|
|
4
|
+
const SHIFT = 16;
|
|
5
|
+
const ESCAPE = 27;
|
|
6
|
+
const SPACE = 32;
|
|
7
|
+
const PAGE_UP = 33;
|
|
8
|
+
const PAGE_DOWN = 34;
|
|
9
|
+
const END = 35;
|
|
10
|
+
const HOME = 36;
|
|
11
|
+
const ARROW_LEFT = 37;
|
|
12
|
+
const ARROW_UP = 38;
|
|
13
|
+
const ARROW_RIGHT = 39;
|
|
14
|
+
const ARROW_DOWN = 40;
|
|
15
|
+
const DELETE = 46;
|
|
16
|
+
|
|
17
|
+
export const keycode = {
|
|
18
|
+
BACKSPACE,
|
|
19
|
+
TAB,
|
|
20
|
+
ENTER,
|
|
21
|
+
SHIFT,
|
|
22
|
+
ESCAPE,
|
|
23
|
+
SPACE,
|
|
24
|
+
PAGE_UP,
|
|
25
|
+
PAGE_DOWN,
|
|
26
|
+
END,
|
|
27
|
+
HOME,
|
|
28
|
+
ARROW_LEFT,
|
|
29
|
+
ARROW_UP,
|
|
30
|
+
ARROW_RIGHT,
|
|
31
|
+
ARROW_DOWN,
|
|
32
|
+
DELETE,
|
|
33
|
+
};
|
package/src/scroll.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { html, body, scroll } from "./environment";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resets the scroll position of the window to the specified coordinates.
|
|
6
|
+
*
|
|
7
|
+
* @param positionX - The X coordinate to scroll to, as a number. If undefined, the X coordinate will not be changed.
|
|
8
|
+
* @param positionY - The Y coordinate to scroll to, as a number. If undefined, the Y coordinate will not be changed.
|
|
9
|
+
*/
|
|
10
|
+
const reset = (positionX: number, positionY: number) => {
|
|
11
|
+
// console.log('resetScroll', positionX, positionY)
|
|
12
|
+
if ("undefined" !== typeof positionX) {
|
|
13
|
+
scroll.x = positionX;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if ("undefined" !== typeof positionY) {
|
|
17
|
+
scroll.y = positionY;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
window.scrollTo(scroll.x, scroll.y);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* disableScroll
|
|
26
|
+
*
|
|
27
|
+
* Lock scroll position, but retain settings for later
|
|
28
|
+
*
|
|
29
|
+
* @see http://stackoverflow.com/a/3656618
|
|
30
|
+
*/
|
|
31
|
+
export function disableScroll() {
|
|
32
|
+
// console.info('disableScroll');
|
|
33
|
+
|
|
34
|
+
const documentElementScrollLeft = html.scrollLeft;
|
|
35
|
+
const documentElementScrollTop = html.scrollTop;
|
|
36
|
+
|
|
37
|
+
const bodyScrollLeft = body.scrollLeft;
|
|
38
|
+
const bodyScrollTop = body.scrollTop;
|
|
39
|
+
|
|
40
|
+
scroll.x = window.scrollX || documentElementScrollLeft || bodyScrollLeft;
|
|
41
|
+
scroll.y = window.scrollY || documentElementScrollTop || bodyScrollTop || 0;
|
|
42
|
+
|
|
43
|
+
// console.log('disableScroll',scroll)
|
|
44
|
+
|
|
45
|
+
html.style.setProperty("overflow", "hidden");
|
|
46
|
+
html.style.setProperty("height", "100%");
|
|
47
|
+
html.style.setProperty("scroll-padding-top", "0px");
|
|
48
|
+
|
|
49
|
+
// eslint-disable-next-line
|
|
50
|
+
reset(scroll.x, scroll.y);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function enableScroll(position: number | boolean | undefined = 0): void {
|
|
54
|
+
// console.info('enableScroll');
|
|
55
|
+
|
|
56
|
+
let resumeScroll = true;
|
|
57
|
+
let currentPosition: number = scroll.y;
|
|
58
|
+
|
|
59
|
+
if (typeof position === "number") {
|
|
60
|
+
currentPosition = position;
|
|
61
|
+
} else if (typeof position === "boolean" && position === false) {
|
|
62
|
+
resumeScroll = false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// console.log('enableScroll', { scroll, resumeScroll, currentPosition });
|
|
66
|
+
|
|
67
|
+
// unlock scroll position
|
|
68
|
+
html.style.removeProperty("overflow");
|
|
69
|
+
html.style.removeProperty("height");
|
|
70
|
+
html.style.removeProperty("scroll-padding-top");
|
|
71
|
+
|
|
72
|
+
// resume scroll position if possible
|
|
73
|
+
if (resumeScroll) {
|
|
74
|
+
reset(scroll.x, currentPosition);
|
|
75
|
+
}
|
|
76
|
+
}
|
package/src/throttle.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface ThrottleFunction {
|
|
2
|
+
(func: (...args: any[]) => void, wait: number): (...args: any[]) => void;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.
|
|
6
|
+
*
|
|
7
|
+
* @param func - The function to throttle.
|
|
8
|
+
* @param wait - The number of milliseconds to wait before allowing `func` to be called again.
|
|
9
|
+
* @returns A new throttled function.
|
|
10
|
+
*/
|
|
11
|
+
export const throttle: ThrottleFunction = (func, wait) => {
|
|
12
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
13
|
+
let lastArgs: any[] | null = null;
|
|
14
|
+
|
|
15
|
+
const later = () => {
|
|
16
|
+
if (lastArgs) {
|
|
17
|
+
func(...lastArgs);
|
|
18
|
+
}
|
|
19
|
+
timeout = null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (...args: any[]) => {
|
|
23
|
+
lastArgs = args;
|
|
24
|
+
if (!timeout) {
|
|
25
|
+
timeout = setTimeout(later, wait);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
"baseUrl": ".",
|
|
10
|
+
"paths": {
|
|
11
|
+
"@agencecinq/utils": ["./src/index.ts"]
|
|
12
|
+
},
|
|
13
|
+
"types": ["vite/client"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*"]
|
|
16
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import dts from 'vite-plugin-dts';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
build: {
|
|
7
|
+
lib: {
|
|
8
|
+
entry: resolve(__dirname, 'src/index.ts'),
|
|
9
|
+
fileName: 'index',
|
|
10
|
+
formats: ['es']
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
plugins: [
|
|
14
|
+
dts({
|
|
15
|
+
insertTypesEntry: true,
|
|
16
|
+
})
|
|
17
|
+
]
|
|
18
|
+
});
|