@ryuzaki13/react-foundation-lib 2.6.0 → 2.8.0
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/chunks/{dom-RMvZy-Sx.js → dom-BnO03IyB.js} +160 -21
- package/dist/chunks/dom-BnO03IyB.js.map +1 -0
- package/dist/dom/document-scroll/acquireDocumentScrollLock.d.ts +3 -0
- package/dist/dom/document-scroll/acquireDocumentScrollLock.d.ts.map +1 -0
- package/dist/dom/document-scroll/documentScrollLockTypes.d.ts +8 -0
- package/dist/dom/document-scroll/documentScrollLockTypes.d.ts.map +1 -0
- package/dist/dom/index.d.ts +5 -0
- package/dist/dom/index.d.ts.map +1 -1
- package/dist/dom/index.js +2 -2
- package/dist/dom/observeElementResize.d.ts +7 -0
- package/dist/dom/observeElementResize.d.ts.map +1 -0
- package/dist/dom/useDocumentScrollLock.d.ts +4 -0
- package/dist/dom/useDocumentScrollLock.d.ts.map +1 -0
- package/dist/dom/useVisualViewportFrame.d.ts +4 -0
- package/dist/dom/useVisualViewportFrame.d.ts.map +1 -0
- package/dist/dom/visual-viewport/attachVisualViewportFrame.d.ts +3 -0
- package/dist/dom/visual-viewport/attachVisualViewportFrame.d.ts.map +1 -0
- package/dist/dom/visual-viewport/visualViewportFrameTypes.d.ts +7 -0
- package/dist/dom/visual-viewport/visualViewportFrameTypes.d.ts.map +1 -0
- package/dist/excel/index.js +1 -1
- package/package.json +2 -2
- package/src/dom/README.mdx +79 -1
- package/dist/chunks/dom-RMvZy-Sx.js.map +0 -1
|
@@ -22,16 +22,27 @@ function c(e) {
|
|
|
22
22
|
return n.id = e, document.body.append(n), n;
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
+
//#region src/dom/observeElementResize.ts
|
|
26
|
+
function l(e, t) {
|
|
27
|
+
if (typeof ResizeObserver > "u") return () => void 0;
|
|
28
|
+
let n = !0, r = new ResizeObserver((r) => {
|
|
29
|
+
n && r.some((t) => t.target === e) && t();
|
|
30
|
+
});
|
|
31
|
+
return r.observe(e), () => {
|
|
32
|
+
n && (n = !1, r.disconnect());
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
25
36
|
//#region src/dom/scroll-anchor/captureScrollAnchor.ts
|
|
26
|
-
var
|
|
27
|
-
function
|
|
37
|
+
var u = /* @__PURE__ */ new WeakMap();
|
|
38
|
+
function d(e, t) {
|
|
28
39
|
if (!e?.isConnected || !t?.isConnected || e === t || !e.contains(t)) return null;
|
|
29
|
-
|
|
40
|
+
u.get(e)?.release();
|
|
30
41
|
let n = t.getBoundingClientRect().top - e.getBoundingClientRect().top - e.clientTop + e.scrollTop, r = e.style.getPropertyValue("overflow-anchor"), i = e.style.getPropertyPriority("overflow-anchor"), a = !0;
|
|
31
42
|
e.style.setProperty("overflow-anchor", "none", "important");
|
|
32
|
-
let o = e.style.getPropertyValue("overflow-anchor"), s = e.style.getPropertyPriority("overflow-anchor"), c = () => e.style.getPropertyValue("overflow-anchor") === o && e.style.getPropertyPriority("overflow-anchor") === s,
|
|
43
|
+
let o = e.style.getPropertyValue("overflow-anchor"), s = e.style.getPropertyPriority("overflow-anchor"), c = () => e.style.getPropertyValue("overflow-anchor") === o && e.style.getPropertyPriority("overflow-anchor") === s, l = {
|
|
33
44
|
release() {
|
|
34
|
-
a && (a = !1,
|
|
45
|
+
a && (a = !1, u.delete(e), c() && (r ? e.style.setProperty("overflow-anchor", r, i) : e.style.removeProperty("overflow-anchor")));
|
|
35
46
|
},
|
|
36
47
|
restore() {
|
|
37
48
|
if (!a) return !1;
|
|
@@ -43,15 +54,15 @@ function u(e, t) {
|
|
|
43
54
|
behavior: "instant"
|
|
44
55
|
}), !0;
|
|
45
56
|
} finally {
|
|
46
|
-
|
|
57
|
+
l.release();
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
};
|
|
50
|
-
return
|
|
61
|
+
return u.set(e, l), l;
|
|
51
62
|
}
|
|
52
63
|
//#endregion
|
|
53
64
|
//#region src/dom/useClickOutside.ts
|
|
54
|
-
function
|
|
65
|
+
function f(t, n) {
|
|
55
66
|
e(() => {
|
|
56
67
|
let e = (e) => {
|
|
57
68
|
if (Array.isArray(t)) {
|
|
@@ -65,7 +76,7 @@ function d(t, n) {
|
|
|
65
76
|
}
|
|
66
77
|
//#endregion
|
|
67
78
|
//#region src/dom/useElementHeightObserver.ts
|
|
68
|
-
function
|
|
79
|
+
function p(e) {
|
|
69
80
|
let [t, r] = i(0);
|
|
70
81
|
return n(() => {
|
|
71
82
|
let t = e.current;
|
|
@@ -79,7 +90,7 @@ function f(e) {
|
|
|
79
90
|
}
|
|
80
91
|
//#endregion
|
|
81
92
|
//#region src/dom/useEscapeDismiss.ts
|
|
82
|
-
function
|
|
93
|
+
function m({ active: n, onDismiss: r, enabled: i = !0, documentTarget: a, containerRef: o }) {
|
|
83
94
|
let s = t(() => r());
|
|
84
95
|
e(() => {
|
|
85
96
|
if (!n || !i) return;
|
|
@@ -100,14 +111,14 @@ function p({ active: n, onDismiss: r, enabled: i = !0, documentTarget: a, contai
|
|
|
100
111
|
}
|
|
101
112
|
//#endregion
|
|
102
113
|
//#region src/dom/useOverlayFocus.ts
|
|
103
|
-
var
|
|
104
|
-
function
|
|
105
|
-
let l = r(null), u = c ?? l, d = r(null), f = t((e) => Array.from(e.querySelectorAll(
|
|
114
|
+
var h = "button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable=\"true\"]:not([tabindex=\"-1\"]), [contenteditable=\"\"]:not([tabindex=\"-1\"]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])";
|
|
115
|
+
function g({ active: n, trapFocus: i = !1, restoreFocus: a = !0, initialFocus: o = "auto", restoreFocusTarget: s, containerRef: c }) {
|
|
116
|
+
let l = r(null), u = c ?? l, d = r(null), f = t((e) => Array.from(e.querySelectorAll(h)).filter((e) => !e.hasAttribute("aria-hidden"))), p = t((e) => {
|
|
106
117
|
if (o === "container") return e;
|
|
107
118
|
if (typeof o == "function") return o(e) ?? e;
|
|
108
119
|
let t = f(e);
|
|
109
120
|
return t.find((e) => e.hasAttribute("autofocus") || e.hasAttribute("autoFocus")) ?? t[0] ?? e;
|
|
110
|
-
}),
|
|
121
|
+
}), m = t(() => s?.() ?? d.current);
|
|
111
122
|
return e(() => {
|
|
112
123
|
if (!n) return;
|
|
113
124
|
d.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
@@ -134,7 +145,7 @@ function h({ active: n, trapFocus: i = !1, restoreFocus: a = !0, initialFocus: o
|
|
|
134
145
|
};
|
|
135
146
|
return r(), () => {
|
|
136
147
|
if (window.cancelAnimationFrame(t), i && e && e.removeEventListener("keydown", o), !a) return;
|
|
137
|
-
let n =
|
|
148
|
+
let n = m();
|
|
138
149
|
n?.isConnected && n.focus({ preventScroll: !0 });
|
|
139
150
|
};
|
|
140
151
|
}, [
|
|
@@ -146,7 +157,7 @@ function h({ active: n, trapFocus: i = !1, restoreFocus: a = !0, initialFocus: o
|
|
|
146
157
|
}
|
|
147
158
|
//#endregion
|
|
148
159
|
//#region src/dom/useFocusTrap.ts
|
|
149
|
-
var
|
|
160
|
+
var _ = (e) => g({
|
|
150
161
|
active: e,
|
|
151
162
|
trapFocus: !0,
|
|
152
163
|
restoreFocus: !0,
|
|
@@ -154,7 +165,7 @@ var g = (e) => h({
|
|
|
154
165
|
});
|
|
155
166
|
//#endregion
|
|
156
167
|
//#region src/dom/useIntersectionObserver.ts
|
|
157
|
-
function
|
|
168
|
+
function v(t, n) {
|
|
158
169
|
let [r, a] = i(!1);
|
|
159
170
|
return e(() => {
|
|
160
171
|
let e = t.current;
|
|
@@ -169,7 +180,7 @@ function _(t, n) {
|
|
|
169
180
|
}
|
|
170
181
|
//#endregion
|
|
171
182
|
//#region src/dom/useIsTouchDevice.ts
|
|
172
|
-
var
|
|
183
|
+
var y = () => {
|
|
173
184
|
let [t, n] = i(!1);
|
|
174
185
|
return e(() => {
|
|
175
186
|
let e = () => {
|
|
@@ -180,8 +191,136 @@ var v = () => {
|
|
|
180
191
|
window.removeEventListener("resize", e);
|
|
181
192
|
};
|
|
182
193
|
}, []), t;
|
|
183
|
-
};
|
|
194
|
+
}, b = /* @__PURE__ */ new WeakMap();
|
|
195
|
+
function x(e, t) {
|
|
196
|
+
return t.map((t) => ({
|
|
197
|
+
name: t,
|
|
198
|
+
value: e.getPropertyValue(t),
|
|
199
|
+
priority: e.getPropertyPriority(t)
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
function S(e, t) {
|
|
203
|
+
for (let { name: n } of t) e.removeProperty(n);
|
|
204
|
+
for (let { name: n, value: r, priority: i } of t) r && e.setProperty(n, r, i);
|
|
205
|
+
}
|
|
206
|
+
function C(e, t) {
|
|
207
|
+
let n = e.defaultView, r = e.body;
|
|
208
|
+
if (!n || !r) return () => void 0;
|
|
209
|
+
let i = b.get(e);
|
|
210
|
+
if (!i) {
|
|
211
|
+
let t = e.documentElement.style, a = r.style, o = x(t, [
|
|
212
|
+
"overflow",
|
|
213
|
+
"overflow-x",
|
|
214
|
+
"overflow-y"
|
|
215
|
+
]), s = x(a, [
|
|
216
|
+
"position",
|
|
217
|
+
"top",
|
|
218
|
+
"left",
|
|
219
|
+
"width",
|
|
220
|
+
"overflow",
|
|
221
|
+
"overflow-x",
|
|
222
|
+
"overflow-y",
|
|
223
|
+
"box-sizing",
|
|
224
|
+
"padding-right"
|
|
225
|
+
]), c = x(a, ["padding-right"]), l = n.scrollX, u = n.scrollY, d = Math.max(0, n.innerWidth - e.documentElement.clientWidth), f = Number.parseFloat(n.getComputedStyle(r).paddingRight) || 0, p = /* @__PURE__ */ new Map();
|
|
226
|
+
t.setProperty("overflow", "hidden"), a.setProperty("position", "fixed"), a.setProperty("top", `${-u}px`), a.setProperty("left", `${-l}px`), a.setProperty("width", "100%"), a.setProperty("overflow", "hidden"), a.setProperty("box-sizing", "border-box"), i = {
|
|
227
|
+
leases: p,
|
|
228
|
+
updateCompensation: () => {
|
|
229
|
+
d > 0 && [...p.values()].some(Boolean) ? a.setProperty("padding-right", `${f + d}px`) : S(a, c);
|
|
230
|
+
},
|
|
231
|
+
restore: () => {
|
|
232
|
+
S(t, o), S(a, s), n.scrollTo({
|
|
233
|
+
left: l,
|
|
234
|
+
top: u,
|
|
235
|
+
behavior: "instant"
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}, b.set(e, i);
|
|
239
|
+
}
|
|
240
|
+
let a = Symbol();
|
|
241
|
+
return i.leases.set(a, t), i.updateCompensation(), () => {
|
|
242
|
+
i.leases.delete(a) && (i.leases.size > 0 ? i.updateCompensation() : (b.delete(e), i.restore()));
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/dom/useDocumentScrollLock.ts
|
|
247
|
+
function w({ active: t, documentTarget: n, compensateScrollbar: r = !1 }) {
|
|
248
|
+
e(() => {
|
|
249
|
+
if (!t) return;
|
|
250
|
+
let e = n === void 0 ? typeof document > "u" ? null : document : n;
|
|
251
|
+
if (e) return C(e, r);
|
|
252
|
+
}, [
|
|
253
|
+
t,
|
|
254
|
+
n,
|
|
255
|
+
r
|
|
256
|
+
]);
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/dom/visual-viewport/attachVisualViewportFrame.ts
|
|
260
|
+
var T = [
|
|
261
|
+
"--visual-viewport-top",
|
|
262
|
+
"--visual-viewport-left",
|
|
263
|
+
"--visual-viewport-width",
|
|
264
|
+
"--visual-viewport-height"
|
|
265
|
+
], E = /* @__PURE__ */ new WeakMap();
|
|
266
|
+
function D(e) {
|
|
267
|
+
let t = e.ownerDocument.defaultView;
|
|
268
|
+
if (!t) return () => void 0;
|
|
269
|
+
let n = t.visualViewport, r = e.style, i = T.map((e) => ({
|
|
270
|
+
name: e,
|
|
271
|
+
value: r.getPropertyValue(e),
|
|
272
|
+
priority: r.getPropertyPriority(e)
|
|
273
|
+
})), a = /* @__PURE__ */ new Map(), o = 0, s = () => {
|
|
274
|
+
o = 0;
|
|
275
|
+
let e = [
|
|
276
|
+
n?.offsetTop ?? 0,
|
|
277
|
+
n?.offsetLeft ?? 0,
|
|
278
|
+
n?.width ?? t.innerWidth,
|
|
279
|
+
n?.height ?? t.innerHeight
|
|
280
|
+
], i = [
|
|
281
|
+
0,
|
|
282
|
+
0,
|
|
283
|
+
t.innerWidth,
|
|
284
|
+
t.innerHeight
|
|
285
|
+
];
|
|
286
|
+
T.forEach((t, n) => {
|
|
287
|
+
let o = `${Number.isFinite(e[n]) ? e[n] : i[n]}px`;
|
|
288
|
+
a.get(t) !== o && (r.setProperty(t, o), a.set(t, o));
|
|
289
|
+
});
|
|
290
|
+
}, c = () => {
|
|
291
|
+
o ||= t.requestAnimationFrame(s);
|
|
292
|
+
};
|
|
293
|
+
return s(), n?.addEventListener("resize", c), n?.addEventListener("scroll", c), t.addEventListener("resize", c), () => {
|
|
294
|
+
t.cancelAnimationFrame(o), n?.removeEventListener("resize", c), n?.removeEventListener("scroll", c), t.removeEventListener("resize", c);
|
|
295
|
+
for (let { name: e, value: t, priority: n } of i) r.getPropertyValue(e) !== a.get(e) || r.getPropertyPriority(e) || (t ? r.setProperty(e, t, n) : r.removeProperty(e));
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function O(e) {
|
|
299
|
+
let t = E.get(e);
|
|
300
|
+
t || (t = {
|
|
301
|
+
leases: /* @__PURE__ */ new Set(),
|
|
302
|
+
detach: D(e)
|
|
303
|
+
}, E.set(e, t));
|
|
304
|
+
let n = Symbol();
|
|
305
|
+
return t.leases.add(n), () => {
|
|
306
|
+
!t.leases.delete(n) || t.leases.size > 0 || (E.delete(e), t.detach());
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/dom/useVisualViewportFrame.ts
|
|
311
|
+
function k({ active: t, containerRef: n }) {
|
|
312
|
+
e(() => {
|
|
313
|
+
if (!t || typeof window > "u") return;
|
|
314
|
+
let e = 0, r, i = () => {
|
|
315
|
+
let t = n.current;
|
|
316
|
+
t ? r = O(t) : e = window.requestAnimationFrame(i);
|
|
317
|
+
};
|
|
318
|
+
return i(), () => {
|
|
319
|
+
window.cancelAnimationFrame(e), r?.();
|
|
320
|
+
};
|
|
321
|
+
}, [t, n]);
|
|
322
|
+
}
|
|
184
323
|
//#endregion
|
|
185
|
-
export {
|
|
324
|
+
export { _ as a, p as c, l as d, c as f, a as h, v as i, f as l, s as m, w as n, g as o, o as p, y as r, m as s, k as t, d as u };
|
|
186
325
|
|
|
187
|
-
//# sourceMappingURL=dom-
|
|
326
|
+
//# sourceMappingURL=dom-BnO03IyB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-BnO03IyB.js","names":[],"sources":["../../src/dom/downloadFile.ts","../../src/dom/getOrCreatePortalRoot.ts","../../src/dom/observeElementResize.ts","../../src/dom/scroll-anchor/captureScrollAnchor.ts","../../src/dom/useClickOutside.ts","../../src/dom/useElementHeightObserver.ts","../../src/dom/useEscapeDismiss.ts","../../src/dom/useOverlayFocus.ts","../../src/dom/useFocusTrap.ts","../../src/dom/useIntersectionObserver.ts","../../src/dom/useIsTouchDevice.ts","../../src/dom/document-scroll/acquireDocumentScrollLock.ts","../../src/dom/useDocumentScrollLock.ts","../../src/dom/visual-viewport/attachVisualViewportFrame.ts","../../src/dom/useVisualViewportFrame.ts"],"sourcesContent":["export function downloadFileFromObjectURL(filename: string, objectUrl: string) {\n\tconst link = document.createElement(\"a\");\n\n\tlink.href = objectUrl;\n\tlink.download = filename;\n\tlink.click();\n\n\twindow.setTimeout(() => {\n\t\twindow.URL.revokeObjectURL(objectUrl);\n\t}, 0);\n}\n\nexport function downloadFileFromBlob(filename: string, blob: Blob) {\n\tconst objectUrl = window.URL.createObjectURL(blob);\n\tdownloadFileFromObjectURL(filename, objectUrl);\n}\n\nexport function downloadFileFromJson(filename: string, payload: unknown) {\n\tconst blob = new Blob([JSON.stringify(payload, null, 2)], { type: \"application/json;charset=utf-8\" });\n\tdownloadFileFromBlob(filename, blob);\n}\n","export function getOrCreatePortalRoot(id: string): HTMLElement | null {\n\tif (typeof document === \"undefined\") {\n\t\treturn null;\n\t}\n\n\tconst existingElement = document.getElementById(id);\n\tif (existingElement instanceof HTMLElement) {\n\t\treturn existingElement;\n\t}\n\n\tconst portalRoot = document.createElement(\"div\");\n\tportalRoot.id = id;\n\tdocument.body.append(portalRoot);\n\n\treturn portalRoot;\n}\n","/**\n * Наблюдает изменение одного DOM-контейнера без React state. Callback вызывается\n * в batched delivery ResizeObserver, поэтому дополнительный animation frame не нужен.\n * Возвращённый cleanup отключает observer и игнорирует уже поставленную delivery.\n */\nexport function observeElementResize(element: HTMLElement, onResize: () => void): () => void {\n\tif (typeof ResizeObserver === \"undefined\") return () => undefined;\n\tlet active = true;\n\tconst observer = new ResizeObserver((entries) => {\n\t\tif (active && entries.some((entry) => entry.target === element)) onResize();\n\t});\n\tobserver.observe(element);\n\treturn () => {\n\t\tif (!active) return;\n\t\tactive = false;\n\t\tobserver.disconnect();\n\t};\n}\n","import { type CapturedScrollAnchor } from \"./scrollAnchorTypes\";\n\n// Один scroll host не может одновременно компенсировать один и тот же prepend дважды.\nconst activeAnchors = new WeakMap<HTMLElement, CapturedScrollAnchor>();\n\n/**\n * Захватывает позицию сохраняемого элемента перед изменением обычного вертикального списка.\n * Вызывать только на browser event/effect boundary; restore — после DOM commit, release — при отмене.\n * Новый захват того же viewport завершает предыдущий без прокрутки.\n */\nexport function captureScrollAnchor(viewport: HTMLElement | null, anchor: HTMLElement | null): CapturedScrollAnchor | null {\n\tif (!viewport?.isConnected || !anchor?.isConnected || viewport === anchor || !viewport.contains(anchor)) return null;\n\n\tactiveAnchors.get(viewport)?.release();\n\tconst initialOffset =\n\t\tanchor.getBoundingClientRect().top - viewport.getBoundingClientRect().top - viewport.clientTop + viewport.scrollTop;\n\tconst initialStyle = viewport.style.getPropertyValue(\"overflow-anchor\");\n\tconst initialPriority = viewport.style.getPropertyPriority(\"overflow-anchor\");\n\tlet active = true;\n\n\t// Native anchoring иначе успеет компенсировать prepend до restore и приведёт к двойному сдвигу.\n\tviewport.style.setProperty(\"overflow-anchor\", \"none\", \"important\");\n\t// В браузере без этого CSS-свойства native anchoring тоже отсутствует: сравниваем фактически принятый стиль.\n\tconst ownedStyle = viewport.style.getPropertyValue(\"overflow-anchor\");\n\tconst ownedPriority = viewport.style.getPropertyPriority(\"overflow-anchor\");\n\tconst ownsStyle = () =>\n\t\tviewport.style.getPropertyValue(\"overflow-anchor\") === ownedStyle &&\n\t\tviewport.style.getPropertyPriority(\"overflow-anchor\") === ownedPriority;\n\n\tconst operation: CapturedScrollAnchor = {\n\t\trelease() {\n\t\t\tif (!active) return;\n\t\t\tactive = false;\n\t\t\tactiveAnchors.delete(viewport);\n\t\t\t// Не затираем новое решение host, если он сам изменил свойство во время ожидания.\n\t\t\tif (!ownsStyle()) return;\n\t\t\tif (initialStyle) viewport.style.setProperty(\"overflow-anchor\", initialStyle, initialPriority);\n\t\t\telse viewport.style.removeProperty(\"overflow-anchor\");\n\t\t},\n\t\trestore() {\n\t\t\tif (!active) return false;\n\t\t\ttry {\n\t\t\t\tif (!viewport.isConnected || !anchor.isConnected || !viewport.contains(anchor) || !ownsStyle()) return false;\n\t\t\t\tconst currentOffset =\n\t\t\t\t\tanchor.getBoundingClientRect().top - viewport.getBoundingClientRect().top - viewport.clientTop + viewport.scrollTop;\n\t\t\t\tconst delta = currentOffset - initialOffset;\n\t\t\t\t// Content-space delta не отменяет ручную прокрутку между запросом и commit.\n\t\t\t\t// Instant не наследует CSS smooth; горизонтальная позиция остаётся неизменной.\n\t\t\t\tif (delta !== 0) viewport.scrollBy({ top: delta, behavior: \"instant\" });\n\t\t\t\treturn true;\n\t\t\t} finally {\n\t\t\t\toperation.release();\n\t\t\t}\n\t\t}\n\t};\n\tactiveAnchors.set(viewport, operation);\n\treturn operation;\n}\n","import { RefObject, useEffect } from \"react\";\n\nexport function useClickOutside(ref: RefObject<HTMLElement | null> | RefObject<HTMLElement | null>[], handler: () => void) {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (event: MouseEvent) => {\n\t\t\tif (Array.isArray(ref)) {\n\t\t\t\tlet isOutside = true;\n\t\t\t\tfor (const r of ref) {\n\t\t\t\t\tif (r.current && r.current.contains(event.target as Node)) {\n\t\t\t\t\t\tisOutside = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isOutside) {\n\t\t\t\t\thandler();\n\t\t\t\t}\n\t\t\t} else if (ref.current && !ref.current.contains(event.target as Node)) {\n\t\t\t\thandler();\n\t\t\t}\n\t\t};\n\n\t\tdocument.addEventListener(\"mousedown\", handleClickOutside);\n\t\treturn () => document.removeEventListener(\"mousedown\", handleClickOutside);\n\t}, [ref, handler]);\n}\n","import { type RefObject, useLayoutEffect, useState } from \"react\";\n\nexport function useElementHeightObserver<TElement extends HTMLElement>(elementRef: RefObject<TElement | null>) {\n\tconst [height, setHeight] = useState(0);\n\n\tuseLayoutEffect(() => {\n\t\tconst element = elementRef.current;\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tconst nextHeight = entries[0]?.contentRect.height ?? element.getBoundingClientRect().height;\n\t\t\tsetHeight(nextHeight);\n\t\t});\n\t\tobserver.observe(element);\n\n\t\treturn () => observer.disconnect();\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps, react-hooks/refs\n\t}, [elementRef.current]);\n\n\treturn height;\n}\n","import { RefObject, useEffect, useEffectEvent } from \"react\";\n\ninterface UseEscapeDismissOptions {\n\tactive: boolean;\n\tonDismiss: () => void;\n\tenabled?: boolean;\n\tdocumentTarget?: Document | null;\n\tcontainerRef?: RefObject<HTMLElement | null>;\n}\n\n/**\n * Подписывает overlay на закрытие по клавише Escape.\n */\nexport function useEscapeDismiss({ active, onDismiss, enabled = true, documentTarget, containerRef }: UseEscapeDismissOptions) {\n\tconst dismiss = useEffectEvent(() => onDismiss());\n\n\tuseEffect(() => {\n\t\tif (!active || !enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetDocument = documentTarget ?? (typeof document === \"undefined\" ? null : document);\n\t\tif (!targetDocument) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst handleKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key !== \"Escape\" /*|| event.defaultPrevented*/) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst activeElement = targetDocument.activeElement;\n\t\t\tconst container = containerRef?.current;\n\t\t\tif (container && activeElement instanceof Node && activeElement !== container && !container.contains(activeElement)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevent.preventDefault();\n\t\t\tdismiss();\n\t\t};\n\n\t\ttargetDocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t\treturn () => targetDocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\t}, [active, enabled, documentTarget, containerRef]);\n}\n","import { RefObject, useEffect, useEffectEvent, useRef } from \"react\";\n\nconst focusableElementsSelector =\n\t'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable=\"true\"]:not([tabindex=\"-1\"]), [contenteditable=\"\"]:not([tabindex=\"-1\"]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])';\n\nexport interface UseOverlayFocusOptions<T extends HTMLElement> {\n\tactive: boolean;\n\ttrapFocus?: boolean;\n\trestoreFocus?: boolean;\n\tinitialFocus?: \"auto\" | \"container\" | ((container: T) => HTMLElement | null | undefined);\n\trestoreFocusTarget?: () => HTMLElement | null | undefined;\n\tcontainerRef?: RefObject<T | null>;\n}\n\n/**\n * Возвращает ref overlay-контейнера и управляет начальными/возвратными переходами фокуса.\n * Открытие и закрытие не прокручивают документ: портал может получить фокус\n * до завершения позиционирования. Пользовательский Tab по-прежнему раскрывает\n * выбранный элемент в прокручиваемом содержимом overlay.\n */\nexport function useOverlayFocus<T extends HTMLElement>({\n\tactive,\n\ttrapFocus = false,\n\trestoreFocus = true,\n\tinitialFocus = \"auto\",\n\trestoreFocusTarget,\n\tcontainerRef\n}: UseOverlayFocusOptions<T>) {\n\tconst internalOverlayRef = useRef<T | null>(null);\n\tconst overlayRef = containerRef ?? internalOverlayRef;\n\tconst previousActiveElementRef = useRef<HTMLElement | null>(null);\n\n\t/**\n\t * Собирает фокусируемые элементы overlay в актуальном DOM-порядке.\n\t */\n\tconst getFocusableElements = useEffectEvent((container: T) =>\n\t\tArray.from(container.querySelectorAll<HTMLElement>(focusableElementsSelector)).filter(\n\t\t\t(element) => !element.hasAttribute(\"aria-hidden\")\n\t\t)\n\t);\n\n\t/**\n\t * Вычисляет стартовый фокус при открытии overlay.\n\t */\n\tconst resolveInitialFocus = useEffectEvent((container: T) => {\n\t\tif (initialFocus === \"container\") {\n\t\t\treturn container;\n\t\t}\n\n\t\tif (typeof initialFocus === \"function\") {\n\t\t\treturn initialFocus(container) ?? container;\n\t\t}\n\n\t\tconst focusableElements = getFocusableElements(container);\n\t\treturn (\n\t\t\tfocusableElements.find((element) => element.hasAttribute(\"autofocus\") || element.hasAttribute(\"autoFocus\")) ??\n\t\t\tfocusableElements[0] ??\n\t\t\tcontainer\n\t\t);\n\t});\n\n\t/**\n\t * Вычисляет элемент, которому нужно вернуть фокус после закрытия overlay.\n\t */\n\tconst resolveRestoreFocusTarget = useEffectEvent(() => restoreFocusTarget?.() ?? previousActiveElementRef.current);\n\n\tuseEffect(() => {\n\t\tif (!active) {\n\t\t\treturn;\n\t\t}\n\n\t\tpreviousActiveElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\tlet overlayElement: T | null = null;\n\t\tlet rafId = 0;\n\n\t\t/**\n\t\t * Цикл откладывает инициализацию, пока ref контейнера не будет привязан к DOM.\n\t\t */\n\t\tconst attachOverlay = () => {\n\t\t\toverlayElement = overlayRef.current;\n\t\t\tif (!overlayElement) {\n\t\t\t\trafId = window.requestAnimationFrame(attachOverlay);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst focusTarget = resolveInitialFocus(overlayElement);\n\t\t\tif (focusTarget instanceof HTMLElement && focusTarget.isConnected) {\n\t\t\t\tfocusTarget.focus({ preventScroll: true });\n\t\t\t}\n\n\t\t\tif (trapFocus) {\n\t\t\t\toverlayElement.addEventListener(\"keydown\", handleTabKey);\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Зацикливает Tab внутри overlay, пока он открыт как модальный слой.\n\t\t */\n\t\tconst handleTabKey = (event: KeyboardEvent) => {\n\t\t\tif (!trapFocus || event.key !== \"Tab\" || !overlayElement) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst focusableElements = getFocusableElements(overlayElement);\n\t\t\tif (focusableElements.length === 0) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\toverlayElement.focus();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstElement = focusableElements[0];\n\t\t\tconst lastElement = focusableElements[focusableElements.length - 1];\n\t\t\tconst activeElement = document.activeElement;\n\n\t\t\tif (event.shiftKey) {\n\t\t\t\tif (activeElement === firstElement || activeElement === overlayElement) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tlastElement.focus();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (activeElement === lastElement) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tfirstElement.focus();\n\t\t\t}\n\t\t};\n\n\t\tattachOverlay();\n\n\t\treturn () => {\n\t\t\twindow.cancelAnimationFrame(rafId);\n\t\t\tif (trapFocus && overlayElement) {\n\t\t\t\toverlayElement.removeEventListener(\"keydown\", handleTabKey);\n\t\t\t}\n\n\t\t\tif (!restoreFocus) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst restoreTarget = resolveRestoreFocusTarget();\n\t\t\tif (restoreTarget?.isConnected) {\n\t\t\t\trestoreTarget.focus({ preventScroll: true });\n\t\t\t}\n\t\t};\n\t}, [active, trapFocus, restoreFocus, overlayRef]);\n\n\treturn overlayRef;\n}\n","import { useOverlayFocus } from \"./useOverlayFocus\";\n\n/**\n * Совместимый wrapper для overlay с фокус-ловушкой.\n */\nexport const useFocusTrap = (isOpen: boolean) => {\n\treturn useOverlayFocus<HTMLDivElement>({ active: isOpen, trapFocus: true, restoreFocus: true, initialFocus: \"auto\" });\n};\n","import { useEffect, useState } from \"react\";\n\nexport function useIntersectionObserver(ref: React.RefObject<Element | null>, options?: IntersectionObserverInit) {\n\tconst [isIntersecting, setIsIntersecting] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst el = ref.current;\n\t\tif (!el) return;\n\n\t\tconst observer = new IntersectionObserver(([entry]) => {\n\t\t\tsetIsIntersecting(entry.isIntersecting);\n\t\t}, options);\n\n\t\tobserver.observe(el);\n\n\t\treturn () => {\n\t\t\tif (el) {\n\t\t\t\tobserver.unobserve(el);\n\t\t\t}\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [options, ref]); // не забыть, что ref.current может меняться\n\n\treturn { isIntersecting };\n}\n","import { useEffect, useState } from \"react\";\n\nexport const useIsTouchDevice = () => {\n\tconst [isTouchDevice, setIsTouchDevice] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst checkTouchDevice = () => {\n\t\t\tconst isTouch = window.matchMedia(\"(pointer: coarse)\").matches || \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\n\t\t\tsetIsTouchDevice(isTouch);\n\t\t};\n\n\t\tcheckTouchDevice();\n\n\t\t// Обработчик для изменений в типе устройства\n\t\twindow.addEventListener(\"resize\", checkTouchDevice);\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"resize\", checkTouchDevice);\n\t\t};\n\t}, []);\n\n\treturn isTouchDevice;\n};\n","type InlineProperty = Readonly<{ name: string; value: string; priority: string }>;\n\ntype DocumentScrollLock = Readonly<{\n\tleases: Map<symbol, boolean>;\n\tupdateCompensation: () => void;\n\trestore: () => void;\n}>;\n\nconst locks = new WeakMap<Document, DocumentScrollLock>();\n\n/** Снимок ограничен принадлежащими lock свойствами, остальные inline-правки не затрагиваются. */\nfunction captureProperties(style: CSSStyleDeclaration, names: readonly string[]): readonly InlineProperty[] {\n\treturn names.map((name) => ({ name, value: style.getPropertyValue(name), priority: style.getPropertyPriority(name) }));\n}\n\nfunction restoreProperties(style: CSSStyleDeclaration, properties: readonly InlineProperty[]): void {\n\t// Сначала снимаем весь принадлежащий нам shorthand/longhand набор: иначе позднее\n\t// удаление пустого longhand может отменить только что восстановленный shorthand.\n\tfor (const { name } of properties) style.removeProperty(name);\n\tfor (const { name, value, priority } of properties) {\n\t\tif (value) style.setProperty(name, value, priority);\n\t}\n}\n\n/** Один владелец body/html на документ предотвращает преждевременный unlock вложенных overlays. */\nexport function acquireDocumentScrollLock(documentTarget: Document, compensateScrollbar: boolean): () => void {\n\tconst view = documentTarget.defaultView;\n\tconst body = documentTarget.body;\n\tif (!view || !body) return () => undefined;\n\n\tlet lock = locks.get(documentTarget);\n\tif (!lock) {\n\t\tconst rootStyle = documentTarget.documentElement.style;\n\t\tconst bodyStyle = body.style;\n\t\tconst rootProperties = captureProperties(rootStyle, [\"overflow\", \"overflow-x\", \"overflow-y\"]);\n\t\tconst bodyProperties = captureProperties(bodyStyle, [\n\t\t\t\"position\",\n\t\t\t\"top\",\n\t\t\t\"left\",\n\t\t\t\"width\",\n\t\t\t\"overflow\",\n\t\t\t\"overflow-x\",\n\t\t\t\"overflow-y\",\n\t\t\t\"box-sizing\",\n\t\t\t\"padding-right\"\n\t\t]);\n\t\tconst originalPadding = captureProperties(bodyStyle, [\"padding-right\"]);\n\t\tconst scrollX = view.scrollX;\n\t\tconst scrollY = view.scrollY;\n\t\tconst scrollbarWidth = Math.max(0, view.innerWidth - documentTarget.documentElement.clientWidth);\n\t\tconst computedPadding = Number.parseFloat(view.getComputedStyle(body).paddingRight) || 0;\n\t\tconst leases = new Map<symbol, boolean>();\n\n\t\t// Fixed body нужен и при iOS visual-viewport pan: одного overflow hidden недостаточно.\n\t\trootStyle.setProperty(\"overflow\", \"hidden\");\n\t\tbodyStyle.setProperty(\"position\", \"fixed\");\n\t\tbodyStyle.setProperty(\"top\", `${-scrollY}px`);\n\t\tbodyStyle.setProperty(\"left\", `${-scrollX}px`);\n\t\tbodyStyle.setProperty(\"width\", \"100%\");\n\t\tbodyStyle.setProperty(\"overflow\", \"hidden\");\n\t\tbodyStyle.setProperty(\"box-sizing\", \"border-box\");\n\n\t\tlock = {\n\t\t\tleases,\n\t\t\tupdateCompensation: () => {\n\t\t\t\tif (scrollbarWidth > 0 && [...leases.values()].some(Boolean)) {\n\t\t\t\t\tbodyStyle.setProperty(\"padding-right\", `${computedPadding + scrollbarWidth}px`);\n\t\t\t\t} else restoreProperties(bodyStyle, originalPadding);\n\t\t\t},\n\t\t\trestore: () => {\n\t\t\t\trestoreProperties(rootStyle, rootProperties);\n\t\t\t\trestoreProperties(bodyStyle, bodyProperties);\n\t\t\t\tview.scrollTo({ left: scrollX, top: scrollY, behavior: \"instant\" });\n\t\t\t}\n\t\t};\n\t\tlocks.set(documentTarget, lock);\n\t}\n\n\tconst lease = Symbol();\n\tlock.leases.set(lease, compensateScrollbar);\n\tlock.updateCompensation();\n\treturn () => {\n\t\tif (!lock.leases.delete(lease)) return;\n\t\tif (lock.leases.size > 0) lock.updateCompensation();\n\t\telse {\n\t\t\tlocks.delete(documentTarget);\n\t\t\tlock.restore();\n\t\t}\n\t};\n}\n","import { useEffect } from \"react\";\n\nimport { acquireDocumentScrollLock } from \"./document-scroll/acquireDocumentScrollLock\";\nimport { type UseDocumentScrollLockOptions } from \"./document-scroll/documentScrollLockTypes\";\n\n/** Блокирует фоновую прокрутку до освобождения последнего потребителя; не управляет focus/inert. */\nexport function useDocumentScrollLock({ active, documentTarget, compensateScrollbar = false }: UseDocumentScrollLockOptions): void {\n\tuseEffect(() => {\n\t\tif (!active) return;\n\t\tconst target = documentTarget === undefined ? (typeof document === \"undefined\" ? null : document) : documentTarget;\n\t\tif (!target) return;\n\t\treturn acquireDocumentScrollLock(target, compensateScrollbar);\n\t}, [active, documentTarget, compensateScrollbar]);\n}\n","const properties = [\"--visual-viewport-top\", \"--visual-viewport-left\", \"--visual-viewport-width\", \"--visual-viewport-height\"] as const;\n\nconst attachments = new WeakMap<HTMLElement, { leases: Set<symbol>; detach: () => void }>();\n\n/** Подписка меняет CSS-переменные конкретной поверхности, не вызывает React render на каждом pan. */\nfunction createVisualViewportFrame(container: HTMLElement): () => void {\n\tconst view = container.ownerDocument.defaultView;\n\tif (!view) return () => undefined;\n\tconst viewport = view.visualViewport;\n\tconst style = container.style;\n\tconst previous = properties.map((name) => ({ name, value: style.getPropertyValue(name), priority: style.getPropertyPriority(name) }));\n\tconst ownedValues = new Map<string, string>();\n\tlet frame = 0;\n\n\tconst update = (): void => {\n\t\tframe = 0;\n\t\tconst bounds = [\n\t\t\tviewport?.offsetTop ?? 0,\n\t\t\tviewport?.offsetLeft ?? 0,\n\t\t\tviewport?.width ?? view.innerWidth,\n\t\t\tviewport?.height ?? view.innerHeight\n\t\t];\n\t\tconst fallback = [0, 0, view.innerWidth, view.innerHeight];\n\t\tproperties.forEach((name, index) => {\n\t\t\tconst value = `${Number.isFinite(bounds[index]) ? bounds[index] : fallback[index]}px`;\n\t\t\tif (ownedValues.get(name) === value) return;\n\t\t\tstyle.setProperty(name, value);\n\t\t\townedValues.set(name, value);\n\t\t});\n\t};\n\n\tconst schedule = (): void => {\n\t\tif (!frame) frame = view.requestAnimationFrame(update);\n\t};\n\n\tupdate();\n\tviewport?.addEventListener(\"resize\", schedule);\n\tviewport?.addEventListener(\"scroll\", schedule);\n\tview.addEventListener(\"resize\", schedule);\n\treturn () => {\n\t\tview.cancelAnimationFrame(frame);\n\t\tviewport?.removeEventListener(\"resize\", schedule);\n\t\tviewport?.removeEventListener(\"scroll\", schedule);\n\t\tview.removeEventListener(\"resize\", schedule);\n\t\tfor (const { name, value, priority } of previous) {\n\t\t\t// Не затираем новое значение, если внешний owner уже забрал это CSS-свойство.\n\t\t\tif (style.getPropertyValue(name) !== ownedValues.get(name) || style.getPropertyPriority(name)) continue;\n\t\t\tif (value) style.setProperty(name, value, priority);\n\t\t\telse style.removeProperty(name);\n\t\t}\n\t};\n}\n\n/** Несколько модалок могут разделять portal-root; его frame снимается только последним owner. */\nexport function attachVisualViewportFrame(container: HTMLElement): () => void {\n\tlet attachment = attachments.get(container);\n\tif (!attachment) {\n\t\tattachment = { leases: new Set(), detach: createVisualViewportFrame(container) };\n\t\tattachments.set(container, attachment);\n\t}\n\tconst lease = Symbol();\n\tattachment.leases.add(lease);\n\treturn () => {\n\t\tif (!attachment.leases.delete(lease) || attachment.leases.size > 0) return;\n\t\tattachments.delete(container);\n\t\tattachment.detach();\n\t};\n}\n","import { useEffect } from \"react\";\n\nimport { attachVisualViewportFrame } from \"./visual-viewport/attachVisualViewportFrame\";\nimport { type UseVisualViewportFrameOptions } from \"./visual-viewport/visualViewportFrameTypes\";\n\n/** CSS frame использует реальные visualViewport размеры без отмены pinch zoom; SSR оставляет CSS fallback. */\nexport function useVisualViewportFrame({ active, containerRef }: UseVisualViewportFrameOptions): void {\n\tuseEffect(() => {\n\t\tif (!active || typeof window === \"undefined\") return;\n\t\tlet frame = 0;\n\t\tlet detach: (() => void) | undefined;\n\t\t// Portal может установить ref позже родительского effect; ожидание завершается при cleanup.\n\t\tconst attach = () => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (container) detach = attachVisualViewportFrame(container);\n\t\t\telse frame = window.requestAnimationFrame(attach);\n\t\t};\n\t\tattach();\n\t\treturn () => {\n\t\t\twindow.cancelAnimationFrame(frame);\n\t\t\tdetach?.();\n\t\t};\n\t}, [active, containerRef]);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Один владелец body/html на документ предотвращает преждевременный unlock вложенных overlays. */
|
|
2
|
+
export declare function acquireDocumentScrollLock(documentTarget: Document, compensateScrollbar: boolean): () => void;
|
|
3
|
+
//# sourceMappingURL=acquireDocumentScrollLock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acquireDocumentScrollLock.d.ts","sourceRoot":"","sources":["../../../src/dom/document-scroll/acquireDocumentScrollLock.ts"],"names":[],"mappings":"AAwBA,mGAAmG;AACnG,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,QAAQ,EAAE,mBAAmB,EAAE,OAAO,GAAG,MAAM,IAAI,CAgE5G"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Общая аренда блокировки документа; вложенные потребители освобождают только свою долю. */
|
|
2
|
+
export type UseDocumentScrollLockOptions = Readonly<{
|
|
3
|
+
active: boolean;
|
|
4
|
+
/** undefined выбирает глобальный document, null явно отключает DOM-операцию. */
|
|
5
|
+
documentTarget?: Document | null;
|
|
6
|
+
compensateScrollbar?: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=documentScrollLockTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentScrollLockTypes.d.ts","sourceRoot":"","sources":["../../../src/dom/document-scroll/documentScrollLockTypes.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,gFAAgF;IAChF,cAAc,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC,CAAC"}
|
package/dist/dom/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./downloadFile";
|
|
2
2
|
export * from "./getOrCreatePortalRoot";
|
|
3
|
+
export { observeElementResize } from "./observeElementResize";
|
|
3
4
|
export { captureScrollAnchor } from "./scroll-anchor/captureScrollAnchor";
|
|
4
5
|
export { type CapturedScrollAnchor } from "./scroll-anchor/scrollAnchorTypes";
|
|
5
6
|
export * from "./useClickOutside";
|
|
@@ -9,4 +10,8 @@ export * from "./useFocusTrap";
|
|
|
9
10
|
export * from "./useIntersectionObserver";
|
|
10
11
|
export * from "./useIsTouchDevice";
|
|
11
12
|
export * from "./useOverlayFocus";
|
|
13
|
+
export { useDocumentScrollLock } from "./useDocumentScrollLock";
|
|
14
|
+
export { type UseDocumentScrollLockOptions } from "./document-scroll/documentScrollLockTypes";
|
|
15
|
+
export { useVisualViewportFrame } from "./useVisualViewportFrame";
|
|
16
|
+
export { type UseVisualViewportFrameOptions } from "./visual-viewport/visualViewportFrameTypes";
|
|
12
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/dom/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2CAA2C,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,4CAA4C,CAAC"}
|
package/dist/dom/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e, c as t, d as n, f as r, i,
|
|
2
|
-
export {
|
|
1
|
+
import { a as e, c as t, d as n, f as r, h as i, i as a, l as o, m as s, n as c, o as l, p as u, r as d, s as f, t as p, u as m } from "../chunks/dom-BnO03IyB.js";
|
|
2
|
+
export { m as captureScrollAnchor, u as downloadFileFromBlob, s as downloadFileFromJson, i as downloadFileFromObjectURL, r as getOrCreatePortalRoot, n as observeElementResize, o as useClickOutside, c as useDocumentScrollLock, t as useElementHeightObserver, f as useEscapeDismiss, e as useFocusTrap, a as useIntersectionObserver, d as useIsTouchDevice, l as useOverlayFocus, p as useVisualViewportFrame };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Наблюдает изменение одного DOM-контейнера без React state. Callback вызывается
|
|
3
|
+
* в batched delivery ResizeObserver, поэтому дополнительный animation frame не нужен.
|
|
4
|
+
* Возвращённый cleanup отключает observer и игнорирует уже поставленную delivery.
|
|
5
|
+
*/
|
|
6
|
+
export declare function observeElementResize(element: HTMLElement, onResize: () => void): () => void;
|
|
7
|
+
//# sourceMappingURL=observeElementResize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observeElementResize.d.ts","sourceRoot":"","sources":["../../src/dom/observeElementResize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAY3F"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type UseDocumentScrollLockOptions } from "./document-scroll/documentScrollLockTypes";
|
|
2
|
+
/** Блокирует фоновую прокрутку до освобождения последнего потребителя; не управляет focus/inert. */
|
|
3
|
+
export declare function useDocumentScrollLock({ active, documentTarget, compensateScrollbar }: UseDocumentScrollLockOptions): void;
|
|
4
|
+
//# sourceMappingURL=useDocumentScrollLock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDocumentScrollLock.d.ts","sourceRoot":"","sources":["../../src/dom/useDocumentScrollLock.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2CAA2C,CAAC;AAE9F,oGAAoG;AACpG,wBAAgB,qBAAqB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,mBAA2B,EAAE,EAAE,4BAA4B,GAAG,IAAI,CAOjI"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type UseVisualViewportFrameOptions } from "./visual-viewport/visualViewportFrameTypes";
|
|
2
|
+
/** CSS frame использует реальные visualViewport размеры без отмены pinch zoom; SSR оставляет CSS fallback. */
|
|
3
|
+
export declare function useVisualViewportFrame({ active, containerRef }: UseVisualViewportFrameOptions): void;
|
|
4
|
+
//# sourceMappingURL=useVisualViewportFrame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVisualViewportFrame.d.ts","sourceRoot":"","sources":["../../src/dom/useVisualViewportFrame.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,4CAA4C,CAAC;AAEhG,8GAA8G;AAC9G,wBAAgB,sBAAsB,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,6BAA6B,GAAG,IAAI,CAiBpG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachVisualViewportFrame.d.ts","sourceRoot":"","sources":["../../../src/dom/visual-viewport/attachVisualViewportFrame.ts"],"names":[],"mappings":"AAqDA,iGAAiG;AACjG,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,IAAI,CAa5E"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/** Визуальная область браузера для CSS fixed-поверхности, включая экранную клавиатуру. */
|
|
3
|
+
export type UseVisualViewportFrameOptions = Readonly<{
|
|
4
|
+
active: boolean;
|
|
5
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=visualViewportFrameTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualViewportFrameTypes.d.ts","sourceRoot":"","sources":["../../../src/dom/visual-viewport/visualViewportFrameTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,0FAA0F;AAC1F,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC5C,CAAC,CAAC"}
|
package/dist/excel/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { p as e } from "../chunks/dom-BnO03IyB.js";
|
|
2
2
|
import { Sn as t, c as n, l as r, pn as i, s as a, u as o, xn as s } from "../chunks/odata-service-CWkHASdw.js";
|
|
3
3
|
import { d as c, t as l } from "../chunks/validate-DyzojM0w.js";
|
|
4
4
|
import { escapeXmlValue as u } from "../xml/index.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuzaki13/react-foundation-lib",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Reusable React and TypeScript foundation utilities, hooks, and primitives.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ryuzaki13",
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
},
|
|
202
202
|
"scripts": {
|
|
203
203
|
"build": "vite build && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
204
|
-
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
204
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit && tsc -p tsconfig.type-tests.json --noEmit",
|
|
205
205
|
"test": "vitest run",
|
|
206
206
|
"lint": "eslint .",
|
|
207
207
|
"lint:fix": "eslint . --fix",
|
package/src/dom/README.mdx
CHANGED
|
@@ -14,6 +14,8 @@ import { Meta } from "@storybook/addon-docs/blocks";
|
|
|
14
14
|
- узнать высоту элемента через `ResizeObserver`;
|
|
15
15
|
- узнать, пересекается ли элемент с viewport или другим root;
|
|
16
16
|
- сохранить позицию чтения при вставке элементов выше текущего;
|
|
17
|
+
- согласованно блокировать прокрутку документа для вложенных overlays;
|
|
18
|
+
- привязать fixed-поверхность к visual viewport при экранной клавиатуре;
|
|
17
19
|
- определить наличие touch/coarse-pointer возможностей.
|
|
18
20
|
|
|
19
21
|
Модуль является низкоуровневым browser foundation-слоем. Он не создаёт готовые кнопки, dialog, modal, popover, tooltip или download UI. Визуальный компонент по-прежнему отвечает за семантический HTML, ARIA, стили, анимацию, стек overlay, сообщения об ошибках и пользовательский сценарий.
|
|
@@ -29,6 +31,7 @@ import { Meta } from "@storybook/addon-docs/blocks";
|
|
|
29
31
|
- [Скачивание файлов](#скачивание-файлов)
|
|
30
32
|
- [`getOrCreatePortalRoot`](#getorcreateportalroot)
|
|
31
33
|
- [`captureScrollAnchor`](#capturescrollanchor)
|
|
34
|
+
- [Блокировка документа и visual viewport](#блокировка-документа-и-visual-viewport)
|
|
32
35
|
- [`useClickOutside`](#useclickoutside)
|
|
33
36
|
- [`useEscapeDismiss`](#useescapedismiss)
|
|
34
37
|
- [`useElementHeightObserver`](#useelementheightobserver)
|
|
@@ -69,7 +72,7 @@ import { Meta } from "@storybook/addon-docs/blocks";
|
|
|
69
72
|
- не удаляет portal root после использования;
|
|
70
73
|
- не реализует полноценный dialog/modal/popover;
|
|
71
74
|
- не назначает `role`, `aria-modal`, `aria-labelledby` или `aria-describedby`;
|
|
72
|
-
- не
|
|
75
|
+
- не выбирает автоматически, какие поверхности должны блокировать прокрутку страницы;
|
|
73
76
|
- не делает фон `inert`;
|
|
74
77
|
- не управляет стеком вложенных overlay;
|
|
75
78
|
- не блокирует программный уход фокуса;
|
|
@@ -2128,6 +2131,81 @@ Touch-capable laptop не обязательно mobile. Не связывайт
|
|
|
2128
2131
|
|
|
2129
2132
|
## Краткий справочник API
|
|
2130
2133
|
|
|
2134
|
+
### `observeElementResize`
|
|
2135
|
+
|
|
2136
|
+
`observeElementResize(element: HTMLElement, onResize: () => void): () => void`
|
|
2137
|
+
наблюдает один контейнер без React state и возвращает idempotent cleanup.
|
|
2138
|
+
Используйте API в browser effect/imperative lifecycle, если размер нужен для
|
|
2139
|
+
DOM-операции, а не для JSX. Начальная и последующие native deliveries вызывают
|
|
2140
|
+
callback один раз; нулевой размер не скрывается. После cleanup поздняя delivery
|
|
2141
|
+
игнорируется. Ошибка callback не поглощается.
|
|
2142
|
+
|
|
2143
|
+
API не вычисляет scroll policy и не меняет CSS. Чтение геометрии и решение,
|
|
2144
|
+
нужно ли прокручивать контейнер, остаются у consumer. Не изменяйте размеры
|
|
2145
|
+
наблюдаемого элемента без проверки возможного resize loop. Дополнительный rAF
|
|
2146
|
+
не добавляется: ResizeObserver уже группирует изменения перед paint.
|
|
2147
|
+
При отсутствии API наблюдение не начинается и cleanup остаётся безопасным;
|
|
2148
|
+
polyfill и имитация resize через window.resize не создаются. Импорт SSR-safe,
|
|
2149
|
+
но сам DOM-элемент передают только после browser commit.
|
|
2150
|
+
|
|
2151
|
+
### Блокировка документа и visual viewport
|
|
2152
|
+
|
|
2153
|
+
```tsx
|
|
2154
|
+
import { useRef } from "react";
|
|
2155
|
+
import { useDocumentScrollLock, useVisualViewportFrame } from "@ryuzaki13/react-foundation-lib/dom";
|
|
2156
|
+
|
|
2157
|
+
function Surface({ open }: { open: boolean }) {
|
|
2158
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
2159
|
+
useDocumentScrollLock({ active: open });
|
|
2160
|
+
useVisualViewportFrame({ active: open, containerRef });
|
|
2161
|
+
return open ? <div ref={containerRef} className="viewportSurface" /> : null;
|
|
2162
|
+
}
|
|
2163
|
+
```
|
|
2164
|
+
|
|
2165
|
+
```css
|
|
2166
|
+
.viewportSurface {
|
|
2167
|
+
position: fixed;
|
|
2168
|
+
top: var(--visual-viewport-top, 0px);
|
|
2169
|
+
left: var(--visual-viewport-left, 0px);
|
|
2170
|
+
width: var(--visual-viewport-width, 100%);
|
|
2171
|
+
height: var(--visual-viewport-height, 100dvh);
|
|
2172
|
+
overflow: hidden;
|
|
2173
|
+
}
|
|
2174
|
+
```
|
|
2175
|
+
|
|
2176
|
+
`UseDocumentScrollLockOptions` содержит `active`, необязательные `documentTarget`
|
|
2177
|
+
и `compensateScrollbar` (по умолчанию `false`). `undefined` выбирает глобальный
|
|
2178
|
+
document, `null` явно отключает операцию. Потребители одного документа разделяют
|
|
2179
|
+
аренды: закрытие вложенного dialog не разблокирует открытый fullscreen. После
|
|
2180
|
+
последнего cleanup восстанавливаются исходные inline properties с priority и
|
|
2181
|
+
scroll X/Y; посторонние CSS-свойства не затрагиваются. Пока lock активен, другой
|
|
2182
|
+
код не должен параллельно изменять принадлежащие ему position/top/left/width,
|
|
2183
|
+
overflow, box-sizing и padding-right body или overflow html.
|
|
2184
|
+
|
|
2185
|
+
`UseVisualViewportFrameOptions` содержит `active` и `containerRef`. Hook пишет
|
|
2186
|
+
четыре показанные CSS-переменные только на переданный контейнер; готовый layout,
|
|
2187
|
+
scroll host, safe-area padding и z-index задаёт UI-владелец. `resize` и `scroll`
|
|
2188
|
+
visual viewport объединяются одним animation frame. Несколько потребителей
|
|
2189
|
+
одного portal root разделяют подписку. Отложенное появление portal ref
|
|
2190
|
+
поддерживается; после установки DOM-узел должен оставаться тем же до деактивации.
|
|
2191
|
+
При замене узла деактивируйте прежний lifecycle либо перемонтируйте его owner.
|
|
2192
|
+
|
|
2193
|
+
При отсутствии VisualViewport используются innerWidth/innerHeight окна и его
|
|
2194
|
+
resize. Нулевая размерность сохраняется как действительное состояние, NaN
|
|
2195
|
+
заменяется fallback. Pinch zoom не отключается: hook использует CSS-pixel bounds
|
|
2196
|
+
браузера и не добавляет обратный scale. Эти hooks не определяют «телефон» по UA,
|
|
2197
|
+
не перехватывают touchmove и не заставляют окно постоянно возвращаться в (0, 0).
|
|
2198
|
+
|
|
2199
|
+
Оба hook SSR-safe: browser работа начинается только после commit, первый HTML
|
|
2200
|
+
использует CSS fallback. Они не предоставляют focus trap, inert, Escape или
|
|
2201
|
+
порядок overlays — используйте UI primitive и `useOverlayFocus` по назначению.
|
|
2202
|
+
Прежние независимые body locks нужно заменить во всех совместно открываемых
|
|
2203
|
+
потребителях: общий ref-count не может координировать чужую реализацию.
|
|
2204
|
+
|
|
2205
|
+
JSDOM покрывает leases, lifecycle и события, но не поведение виртуальной
|
|
2206
|
+
клавиатуры. Мобильные fixed-поверхности дополнительно проверяйте на физическом
|
|
2207
|
+
устройстве: keyboard open/close, pan, orientation, pinch zoom и вложенный overlay.
|
|
2208
|
+
|
|
2131
2209
|
| API | Вход | Результат | Default/событие | Главное ограничение |
|
|
2132
2210
|
| --------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------- | -------------------------------------------------------- |
|
|
2133
2211
|
| `downloadFileFromObjectURL` | filename, object URL | `void` | revoke через `setTimeout(0)` | Принимает ownership URL; нет подтверждения download. |
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dom-RMvZy-Sx.js","names":[],"sources":["../../src/dom/downloadFile.ts","../../src/dom/getOrCreatePortalRoot.ts","../../src/dom/scroll-anchor/captureScrollAnchor.ts","../../src/dom/useClickOutside.ts","../../src/dom/useElementHeightObserver.ts","../../src/dom/useEscapeDismiss.ts","../../src/dom/useOverlayFocus.ts","../../src/dom/useFocusTrap.ts","../../src/dom/useIntersectionObserver.ts","../../src/dom/useIsTouchDevice.ts"],"sourcesContent":["export function downloadFileFromObjectURL(filename: string, objectUrl: string) {\n\tconst link = document.createElement(\"a\");\n\n\tlink.href = objectUrl;\n\tlink.download = filename;\n\tlink.click();\n\n\twindow.setTimeout(() => {\n\t\twindow.URL.revokeObjectURL(objectUrl);\n\t}, 0);\n}\n\nexport function downloadFileFromBlob(filename: string, blob: Blob) {\n\tconst objectUrl = window.URL.createObjectURL(blob);\n\tdownloadFileFromObjectURL(filename, objectUrl);\n}\n\nexport function downloadFileFromJson(filename: string, payload: unknown) {\n\tconst blob = new Blob([JSON.stringify(payload, null, 2)], { type: \"application/json;charset=utf-8\" });\n\tdownloadFileFromBlob(filename, blob);\n}\n","export function getOrCreatePortalRoot(id: string): HTMLElement | null {\n\tif (typeof document === \"undefined\") {\n\t\treturn null;\n\t}\n\n\tconst existingElement = document.getElementById(id);\n\tif (existingElement instanceof HTMLElement) {\n\t\treturn existingElement;\n\t}\n\n\tconst portalRoot = document.createElement(\"div\");\n\tportalRoot.id = id;\n\tdocument.body.append(portalRoot);\n\n\treturn portalRoot;\n}\n","import { type CapturedScrollAnchor } from \"./scrollAnchorTypes\";\n\n// Один scroll host не может одновременно компенсировать один и тот же prepend дважды.\nconst activeAnchors = new WeakMap<HTMLElement, CapturedScrollAnchor>();\n\n/**\n * Захватывает позицию сохраняемого элемента перед изменением обычного вертикального списка.\n * Вызывать только на browser event/effect boundary; restore — после DOM commit, release — при отмене.\n * Новый захват того же viewport завершает предыдущий без прокрутки.\n */\nexport function captureScrollAnchor(viewport: HTMLElement | null, anchor: HTMLElement | null): CapturedScrollAnchor | null {\n\tif (!viewport?.isConnected || !anchor?.isConnected || viewport === anchor || !viewport.contains(anchor)) return null;\n\n\tactiveAnchors.get(viewport)?.release();\n\tconst initialOffset =\n\t\tanchor.getBoundingClientRect().top - viewport.getBoundingClientRect().top - viewport.clientTop + viewport.scrollTop;\n\tconst initialStyle = viewport.style.getPropertyValue(\"overflow-anchor\");\n\tconst initialPriority = viewport.style.getPropertyPriority(\"overflow-anchor\");\n\tlet active = true;\n\n\t// Native anchoring иначе успеет компенсировать prepend до restore и приведёт к двойному сдвигу.\n\tviewport.style.setProperty(\"overflow-anchor\", \"none\", \"important\");\n\t// В браузере без этого CSS-свойства native anchoring тоже отсутствует: сравниваем фактически принятый стиль.\n\tconst ownedStyle = viewport.style.getPropertyValue(\"overflow-anchor\");\n\tconst ownedPriority = viewport.style.getPropertyPriority(\"overflow-anchor\");\n\tconst ownsStyle = () =>\n\t\tviewport.style.getPropertyValue(\"overflow-anchor\") === ownedStyle &&\n\t\tviewport.style.getPropertyPriority(\"overflow-anchor\") === ownedPriority;\n\n\tconst operation: CapturedScrollAnchor = {\n\t\trelease() {\n\t\t\tif (!active) return;\n\t\t\tactive = false;\n\t\t\tactiveAnchors.delete(viewport);\n\t\t\t// Не затираем новое решение host, если он сам изменил свойство во время ожидания.\n\t\t\tif (!ownsStyle()) return;\n\t\t\tif (initialStyle) viewport.style.setProperty(\"overflow-anchor\", initialStyle, initialPriority);\n\t\t\telse viewport.style.removeProperty(\"overflow-anchor\");\n\t\t},\n\t\trestore() {\n\t\t\tif (!active) return false;\n\t\t\ttry {\n\t\t\t\tif (!viewport.isConnected || !anchor.isConnected || !viewport.contains(anchor) || !ownsStyle()) return false;\n\t\t\t\tconst currentOffset =\n\t\t\t\t\tanchor.getBoundingClientRect().top - viewport.getBoundingClientRect().top - viewport.clientTop + viewport.scrollTop;\n\t\t\t\tconst delta = currentOffset - initialOffset;\n\t\t\t\t// Content-space delta не отменяет ручную прокрутку между запросом и commit.\n\t\t\t\t// Instant не наследует CSS smooth; горизонтальная позиция остаётся неизменной.\n\t\t\t\tif (delta !== 0) viewport.scrollBy({ top: delta, behavior: \"instant\" });\n\t\t\t\treturn true;\n\t\t\t} finally {\n\t\t\t\toperation.release();\n\t\t\t}\n\t\t}\n\t};\n\tactiveAnchors.set(viewport, operation);\n\treturn operation;\n}\n","import { RefObject, useEffect } from \"react\";\n\nexport function useClickOutside(ref: RefObject<HTMLElement | null> | RefObject<HTMLElement | null>[], handler: () => void) {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (event: MouseEvent) => {\n\t\t\tif (Array.isArray(ref)) {\n\t\t\t\tlet isOutside = true;\n\t\t\t\tfor (const r of ref) {\n\t\t\t\t\tif (r.current && r.current.contains(event.target as Node)) {\n\t\t\t\t\t\tisOutside = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isOutside) {\n\t\t\t\t\thandler();\n\t\t\t\t}\n\t\t\t} else if (ref.current && !ref.current.contains(event.target as Node)) {\n\t\t\t\thandler();\n\t\t\t}\n\t\t};\n\n\t\tdocument.addEventListener(\"mousedown\", handleClickOutside);\n\t\treturn () => document.removeEventListener(\"mousedown\", handleClickOutside);\n\t}, [ref, handler]);\n}\n","import { type RefObject, useLayoutEffect, useState } from \"react\";\n\nexport function useElementHeightObserver<TElement extends HTMLElement>(elementRef: RefObject<TElement | null>) {\n\tconst [height, setHeight] = useState(0);\n\n\tuseLayoutEffect(() => {\n\t\tconst element = elementRef.current;\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tconst nextHeight = entries[0]?.contentRect.height ?? element.getBoundingClientRect().height;\n\t\t\tsetHeight(nextHeight);\n\t\t});\n\t\tobserver.observe(element);\n\n\t\treturn () => observer.disconnect();\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps, react-hooks/refs\n\t}, [elementRef.current]);\n\n\treturn height;\n}\n","import { RefObject, useEffect, useEffectEvent } from \"react\";\n\ninterface UseEscapeDismissOptions {\n\tactive: boolean;\n\tonDismiss: () => void;\n\tenabled?: boolean;\n\tdocumentTarget?: Document | null;\n\tcontainerRef?: RefObject<HTMLElement | null>;\n}\n\n/**\n * Подписывает overlay на закрытие по клавише Escape.\n */\nexport function useEscapeDismiss({ active, onDismiss, enabled = true, documentTarget, containerRef }: UseEscapeDismissOptions) {\n\tconst dismiss = useEffectEvent(() => onDismiss());\n\n\tuseEffect(() => {\n\t\tif (!active || !enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetDocument = documentTarget ?? (typeof document === \"undefined\" ? null : document);\n\t\tif (!targetDocument) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst handleKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key !== \"Escape\" /*|| event.defaultPrevented*/) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst activeElement = targetDocument.activeElement;\n\t\t\tconst container = containerRef?.current;\n\t\t\tif (container && activeElement instanceof Node && activeElement !== container && !container.contains(activeElement)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevent.preventDefault();\n\t\t\tdismiss();\n\t\t};\n\n\t\ttargetDocument.addEventListener(\"keydown\", handleKeyDown, true);\n\t\treturn () => targetDocument.removeEventListener(\"keydown\", handleKeyDown, true);\n\t}, [active, enabled, documentTarget, containerRef]);\n}\n","import { RefObject, useEffect, useEffectEvent, useRef } from \"react\";\n\nconst focusableElementsSelector =\n\t'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])';\n\nexport interface UseOverlayFocusOptions<T extends HTMLElement> {\n\tactive: boolean;\n\ttrapFocus?: boolean;\n\trestoreFocus?: boolean;\n\tinitialFocus?: \"auto\" | \"container\" | ((container: T) => HTMLElement | null | undefined);\n\trestoreFocusTarget?: () => HTMLElement | null | undefined;\n\tcontainerRef?: RefObject<T | null>;\n}\n\n/**\n * Возвращает ref overlay-контейнера и управляет начальными/возвратными переходами фокуса.\n * Открытие и закрытие не прокручивают документ: портал может получить фокус\n * до завершения позиционирования. Пользовательский Tab по-прежнему раскрывает\n * выбранный элемент в прокручиваемом содержимом overlay.\n */\nexport function useOverlayFocus<T extends HTMLElement>({\n\tactive,\n\ttrapFocus = false,\n\trestoreFocus = true,\n\tinitialFocus = \"auto\",\n\trestoreFocusTarget,\n\tcontainerRef\n}: UseOverlayFocusOptions<T>) {\n\tconst internalOverlayRef = useRef<T | null>(null);\n\tconst overlayRef = containerRef ?? internalOverlayRef;\n\tconst previousActiveElementRef = useRef<HTMLElement | null>(null);\n\n\t/**\n\t * Собирает фокусируемые элементы overlay в актуальном DOM-порядке.\n\t */\n\tconst getFocusableElements = useEffectEvent((container: T) =>\n\t\tArray.from(container.querySelectorAll<HTMLElement>(focusableElementsSelector)).filter(\n\t\t\t(element) => !element.hasAttribute(\"aria-hidden\")\n\t\t)\n\t);\n\n\t/**\n\t * Вычисляет стартовый фокус при открытии overlay.\n\t */\n\tconst resolveInitialFocus = useEffectEvent((container: T) => {\n\t\tif (initialFocus === \"container\") {\n\t\t\treturn container;\n\t\t}\n\n\t\tif (typeof initialFocus === \"function\") {\n\t\t\treturn initialFocus(container) ?? container;\n\t\t}\n\n\t\tconst focusableElements = getFocusableElements(container);\n\t\treturn (\n\t\t\tfocusableElements.find((element) => element.hasAttribute(\"autofocus\") || element.hasAttribute(\"autoFocus\")) ??\n\t\t\tfocusableElements[0] ??\n\t\t\tcontainer\n\t\t);\n\t});\n\n\t/**\n\t * Вычисляет элемент, которому нужно вернуть фокус после закрытия overlay.\n\t */\n\tconst resolveRestoreFocusTarget = useEffectEvent(() => restoreFocusTarget?.() ?? previousActiveElementRef.current);\n\n\tuseEffect(() => {\n\t\tif (!active) {\n\t\t\treturn;\n\t\t}\n\n\t\tpreviousActiveElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\tlet overlayElement: T | null = null;\n\t\tlet rafId = 0;\n\n\t\t/**\n\t\t * Цикл откладывает инициализацию, пока ref контейнера не будет привязан к DOM.\n\t\t */\n\t\tconst attachOverlay = () => {\n\t\t\toverlayElement = overlayRef.current;\n\t\t\tif (!overlayElement) {\n\t\t\t\trafId = window.requestAnimationFrame(attachOverlay);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst focusTarget = resolveInitialFocus(overlayElement);\n\t\t\tif (focusTarget instanceof HTMLElement && focusTarget.isConnected) {\n\t\t\t\tfocusTarget.focus({ preventScroll: true });\n\t\t\t}\n\n\t\t\tif (trapFocus) {\n\t\t\t\toverlayElement.addEventListener(\"keydown\", handleTabKey);\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Зацикливает Tab внутри overlay, пока он открыт как модальный слой.\n\t\t */\n\t\tconst handleTabKey = (event: KeyboardEvent) => {\n\t\t\tif (!trapFocus || event.key !== \"Tab\" || !overlayElement) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst focusableElements = getFocusableElements(overlayElement);\n\t\t\tif (focusableElements.length === 0) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\toverlayElement.focus();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstElement = focusableElements[0];\n\t\t\tconst lastElement = focusableElements[focusableElements.length - 1];\n\t\t\tconst activeElement = document.activeElement;\n\n\t\t\tif (event.shiftKey) {\n\t\t\t\tif (activeElement === firstElement || activeElement === overlayElement) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tlastElement.focus();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (activeElement === lastElement) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tfirstElement.focus();\n\t\t\t}\n\t\t};\n\n\t\tattachOverlay();\n\n\t\treturn () => {\n\t\t\twindow.cancelAnimationFrame(rafId);\n\t\t\tif (trapFocus && overlayElement) {\n\t\t\t\toverlayElement.removeEventListener(\"keydown\", handleTabKey);\n\t\t\t}\n\n\t\t\tif (!restoreFocus) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst restoreTarget = resolveRestoreFocusTarget();\n\t\t\tif (restoreTarget?.isConnected) {\n\t\t\t\trestoreTarget.focus({ preventScroll: true });\n\t\t\t}\n\t\t};\n\t}, [active, trapFocus, restoreFocus, overlayRef]);\n\n\treturn overlayRef;\n}\n","import { useOverlayFocus } from \"./useOverlayFocus\";\n\n/**\n * Совместимый wrapper для overlay с фокус-ловушкой.\n */\nexport const useFocusTrap = (isOpen: boolean) => {\n\treturn useOverlayFocus<HTMLDivElement>({ active: isOpen, trapFocus: true, restoreFocus: true, initialFocus: \"auto\" });\n};\n","import { useEffect, useState } from \"react\";\n\nexport function useIntersectionObserver(ref: React.RefObject<Element | null>, options?: IntersectionObserverInit) {\n\tconst [isIntersecting, setIsIntersecting] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst el = ref.current;\n\t\tif (!el) return;\n\n\t\tconst observer = new IntersectionObserver(([entry]) => {\n\t\t\tsetIsIntersecting(entry.isIntersecting);\n\t\t}, options);\n\n\t\tobserver.observe(el);\n\n\t\treturn () => {\n\t\t\tif (el) {\n\t\t\t\tobserver.unobserve(el);\n\t\t\t}\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [options, ref]); // не забыть, что ref.current может меняться\n\n\treturn { isIntersecting };\n}\n","import { useEffect, useState } from \"react\";\n\nexport const useIsTouchDevice = () => {\n\tconst [isTouchDevice, setIsTouchDevice] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst checkTouchDevice = () => {\n\t\t\tconst isTouch = window.matchMedia(\"(pointer: coarse)\").matches || \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\n\t\t\tsetIsTouchDevice(isTouch);\n\t\t};\n\n\t\tcheckTouchDevice();\n\n\t\t// Обработчик для изменений в типе устройства\n\t\twindow.addEventListener(\"resize\", checkTouchDevice);\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"resize\", checkTouchDevice);\n\t\t};\n\t}, []);\n\n\treturn isTouchDevice;\n};\n"],"mappings":"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"}
|