@particle-academy/react-fancy 5.60.1 → 5.61.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/CHANGELOG.md +78 -0
- package/dist/autocomplete.cjs +4 -3
- package/dist/autocomplete.js +3 -2
- package/dist/{chunk-EEMNTO7L.cjs → chunk-3DMVK74Q.cjs} +4 -4
- package/dist/{chunk-EEMNTO7L.cjs.map → chunk-3DMVK74Q.cjs.map} +1 -1
- package/dist/{chunk-M77BB2QI.cjs → chunk-3I6PE2US.cjs} +12 -12
- package/dist/{chunk-M77BB2QI.cjs.map → chunk-3I6PE2US.cjs.map} +1 -1
- package/dist/{chunk-TGBLDJ72.js → chunk-4FJWHVC7.js} +3 -3
- package/dist/{chunk-TGBLDJ72.js.map → chunk-4FJWHVC7.js.map} +1 -1
- package/dist/{chunk-EXQ33MJR.cjs → chunk-4HUD33OP.cjs} +4 -4
- package/dist/{chunk-EXQ33MJR.cjs.map → chunk-4HUD33OP.cjs.map} +1 -1
- package/dist/chunk-4JLFIPHZ.js +43 -0
- package/dist/chunk-4JLFIPHZ.js.map +1 -0
- package/dist/{chunk-BX7ZJ3HG.cjs → chunk-4TTBPEQX.cjs} +64 -28
- package/dist/chunk-4TTBPEQX.cjs.map +1 -0
- package/dist/{chunk-YQTKTEWS.js → chunk-5JFA7NYE.js} +3 -3
- package/dist/{chunk-YQTKTEWS.js.map → chunk-5JFA7NYE.js.map} +1 -1
- package/dist/chunk-5VMILVWD.js +3 -0
- package/dist/chunk-5VMILVWD.js.map +1 -0
- package/dist/{chunk-DN244T6G.cjs → chunk-6GBO7R25.cjs} +4 -4
- package/dist/{chunk-DN244T6G.cjs.map → chunk-6GBO7R25.cjs.map} +1 -1
- package/dist/{chunk-4FZOH7BJ.js → chunk-74MEJWMH.js} +3 -3
- package/dist/{chunk-4FZOH7BJ.js.map → chunk-74MEJWMH.js.map} +1 -1
- package/dist/{chunk-4DGXL6JC.cjs → chunk-7KTBVKNO.cjs} +4 -4
- package/dist/{chunk-4DGXL6JC.cjs.map → chunk-7KTBVKNO.cjs.map} +1 -1
- package/dist/{chunk-XQDGUXMS.js → chunk-BHUSI56C.js} +3 -3
- package/dist/{chunk-XQDGUXMS.js.map → chunk-BHUSI56C.js.map} +1 -1
- package/dist/{chunk-UIE5FP3A.js → chunk-BQFPC5FL.js} +3 -3
- package/dist/{chunk-UIE5FP3A.js.map → chunk-BQFPC5FL.js.map} +1 -1
- package/dist/{chunk-2OVDWUQ7.js → chunk-CEZVKKYW.js} +60 -24
- package/dist/chunk-CEZVKKYW.js.map +1 -0
- package/dist/{chunk-UZG6LO4Z.cjs → chunk-FU6K7XXZ.cjs} +4 -4
- package/dist/{chunk-UZG6LO4Z.cjs.map → chunk-FU6K7XXZ.cjs.map} +1 -1
- package/dist/{chunk-5ZNOLPIJ.cjs → chunk-H2YRZYKK.cjs} +5 -5
- package/dist/{chunk-5ZNOLPIJ.cjs.map → chunk-H2YRZYKK.cjs.map} +1 -1
- package/dist/{chunk-7R7HENZG.cjs → chunk-HRYM76ZE.cjs} +9 -9
- package/dist/{chunk-7R7HENZG.cjs.map → chunk-HRYM76ZE.cjs.map} +1 -1
- package/dist/{chunk-ZGQEKDG6.js → chunk-IHQHTJNN.js} +5 -5
- package/dist/{chunk-ZGQEKDG6.js.map → chunk-IHQHTJNN.js.map} +1 -1
- package/dist/{chunk-6HJF55U7.js → chunk-IY6LVALS.js} +3 -3
- package/dist/{chunk-6HJF55U7.js.map → chunk-IY6LVALS.js.map} +1 -1
- package/dist/{chunk-HTNQ5XUR.cjs → chunk-J4FKJ4IR.cjs} +4 -4
- package/dist/{chunk-HTNQ5XUR.cjs.map → chunk-J4FKJ4IR.cjs.map} +1 -1
- package/dist/{chunk-43ZRUYJC.cjs → chunk-JOWAS5A5.cjs} +9 -9
- package/dist/{chunk-43ZRUYJC.cjs.map → chunk-JOWAS5A5.cjs.map} +1 -1
- package/dist/{chunk-JRRYYW3Y.cjs → chunk-K6NADZ7O.cjs} +6 -6
- package/dist/{chunk-JRRYYW3Y.cjs.map → chunk-K6NADZ7O.cjs.map} +1 -1
- package/dist/{chunk-PAFTHGQD.js → chunk-L24LUSEE.js} +329 -7
- package/dist/chunk-L24LUSEE.js.map +1 -0
- package/dist/{chunk-5JA4ENMF.js → chunk-LMOPAY7Q.js} +3 -3
- package/dist/{chunk-5JA4ENMF.js.map → chunk-LMOPAY7Q.js.map} +1 -1
- package/dist/{chunk-DAJPPKPO.js → chunk-M52S3TFI.js} +3 -3
- package/dist/{chunk-DAJPPKPO.js.map → chunk-M52S3TFI.js.map} +1 -1
- package/dist/{chunk-GLGUQGAQ.cjs → chunk-M6MGQI6G.cjs} +4 -4
- package/dist/{chunk-GLGUQGAQ.cjs.map → chunk-M6MGQI6G.cjs.map} +1 -1
- package/dist/{chunk-34GALZRX.cjs → chunk-MCQJFMDP.cjs} +329 -6
- package/dist/chunk-MCQJFMDP.cjs.map +1 -0
- package/dist/chunk-MKHYENKR.cjs +4 -0
- package/dist/chunk-MKHYENKR.cjs.map +1 -0
- package/dist/{chunk-NHGU2BWT.js → chunk-MSGKIWYX.js} +3 -3
- package/dist/{chunk-NHGU2BWT.js.map → chunk-MSGKIWYX.js.map} +1 -1
- package/dist/{chunk-KQYOIPHQ.js → chunk-N7KUGFRG.js} +4 -4
- package/dist/{chunk-KQYOIPHQ.js.map → chunk-N7KUGFRG.js.map} +1 -1
- package/dist/{chunk-XB3H2EEL.js → chunk-NDLESFUH.js} +3 -3
- package/dist/{chunk-XB3H2EEL.js.map → chunk-NDLESFUH.js.map} +1 -1
- package/dist/chunk-NE3BZV3F.js +224 -0
- package/dist/chunk-NE3BZV3F.js.map +1 -0
- package/dist/{chunk-XYOT75HH.js → chunk-NORVXHRU.js} +3 -3
- package/dist/{chunk-XYOT75HH.js.map → chunk-NORVXHRU.js.map} +1 -1
- package/dist/chunk-O4HZVZMY.cjs +226 -0
- package/dist/chunk-O4HZVZMY.cjs.map +1 -0
- package/dist/{chunk-5H6IUCOD.cjs → chunk-P6V4QWJK.cjs} +4 -4
- package/dist/{chunk-5H6IUCOD.cjs.map → chunk-P6V4QWJK.cjs.map} +1 -1
- package/dist/{chunk-LZHGXRFD.js → chunk-PKFEJWVI.js} +3 -3
- package/dist/{chunk-LZHGXRFD.js.map → chunk-PKFEJWVI.js.map} +1 -1
- package/dist/chunk-QMCMRQ2G.cjs +53 -0
- package/dist/chunk-QMCMRQ2G.cjs.map +1 -0
- package/dist/{chunk-BJKKW77L.cjs → chunk-QXMQVLRQ.cjs} +4 -4
- package/dist/{chunk-BJKKW77L.cjs.map → chunk-QXMQVLRQ.cjs.map} +1 -1
- package/dist/{chunk-WHEXTDPV.js → chunk-RBCMKPBX.js} +7 -5
- package/dist/chunk-RBCMKPBX.js.map +1 -0
- package/dist/{chunk-LVE6ERRS.cjs → chunk-RRMQGTVB.cjs} +6 -6
- package/dist/{chunk-LVE6ERRS.cjs.map → chunk-RRMQGTVB.cjs.map} +1 -1
- package/dist/{chunk-T67FLC55.js → chunk-SHF44YGG.js} +3 -3
- package/dist/{chunk-T67FLC55.js.map → chunk-SHF44YGG.js.map} +1 -1
- package/dist/{chunk-NBZC6LOB.cjs → chunk-TI7D4QDM.cjs} +6 -3
- package/dist/chunk-TI7D4QDM.cjs.map +1 -0
- package/dist/{chunk-5JK2VDWY.cjs → chunk-TYTENEJQ.cjs} +6 -6
- package/dist/{chunk-5JK2VDWY.cjs.map → chunk-TYTENEJQ.cjs.map} +1 -1
- package/dist/{chunk-WW56U3RV.js → chunk-UBEOB55O.js} +3 -3
- package/dist/{chunk-WW56U3RV.js.map → chunk-UBEOB55O.js.map} +1 -1
- package/dist/chunk-UGXBTIV5.js +51 -0
- package/dist/chunk-UGXBTIV5.js.map +1 -0
- package/dist/{chunk-M6XBF2ZS.js → chunk-UJZJBHMH.js} +3 -3
- package/dist/{chunk-M6XBF2ZS.js.map → chunk-UJZJBHMH.js.map} +1 -1
- package/dist/{chunk-T45LBTXH.js → chunk-ULG4OA2T.js} +3 -3
- package/dist/{chunk-T45LBTXH.js.map → chunk-ULG4OA2T.js.map} +1 -1
- package/dist/{chunk-SIEPD6NR.cjs → chunk-UM4JXBRZ.cjs} +4 -4
- package/dist/{chunk-SIEPD6NR.cjs.map → chunk-UM4JXBRZ.cjs.map} +1 -1
- package/dist/{chunk-FGI2EC32.cjs → chunk-Z5OTOYWI.cjs} +4 -4
- package/dist/{chunk-FGI2EC32.cjs.map → chunk-Z5OTOYWI.cjs.map} +1 -1
- package/dist/chunk-ZPBCZPMD.cjs +48 -0
- package/dist/chunk-ZPBCZPMD.cjs.map +1 -0
- package/dist/command.cjs +5 -4
- package/dist/command.js +3 -2
- package/dist/composer.cjs +7 -6
- package/dist/composer.js +5 -4
- package/dist/content-renderer.cjs +4 -4
- package/dist/content-renderer.js +1 -1
- package/dist/context-menu.cjs +5 -4
- package/dist/context-menu.js +3 -2
- package/dist/drawer.cjs +5 -4
- package/dist/drawer.js +3 -2
- package/dist/dropdown.cjs +5 -4
- package/dist/dropdown.js +3 -2
- package/dist/editor.cjs +9 -4
- package/dist/editor.d.cts +53 -4
- package/dist/editor.d.ts +53 -4
- package/dist/editor.js +7 -2
- package/dist/full-screen.cjs +39 -0
- package/dist/full-screen.cjs.map +1 -0
- package/dist/full-screen.d.cts +54 -0
- package/dist/full-screen.d.ts +54 -0
- package/dist/full-screen.js +10 -0
- package/dist/full-screen.js.map +1 -0
- package/dist/index.cjs +157 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +36 -32
- package/dist/index.js.map +1 -1
- package/dist/input.cjs +6 -5
- package/dist/input.js +5 -4
- package/dist/inputs.cjs +17 -16
- package/dist/inputs.js +9 -8
- package/dist/json-editor.cjs +19 -18
- package/dist/json-editor.js +8 -7
- package/dist/magic-wand.cjs +4 -3
- package/dist/magic-wand.js +3 -2
- package/dist/mobile-menu.cjs +6 -4
- package/dist/mobile-menu.js +4 -2
- package/dist/modal.cjs +5 -4
- package/dist/modal.js +3 -2
- package/dist/paste-pills.cjs +17 -16
- package/dist/paste-pills.js +4 -3
- package/dist/popover.cjs +5 -4
- package/dist/popover.js +3 -2
- package/dist/portal.cjs +7 -2
- package/dist/portal.d.cts +12 -1
- package/dist/portal.d.ts +12 -1
- package/dist/portal.js +2 -1
- package/dist/prompt-input.cjs +7 -6
- package/dist/prompt-input.js +6 -5
- package/dist/reason-tag.cjs +5 -4
- package/dist/reason-tag.js +4 -3
- package/dist/select.cjs +4 -3
- package/dist/select.js +3 -2
- package/dist/sidebar.cjs +1 -0
- package/dist/sidebar.js +1 -0
- package/dist/toast.cjs +5 -4
- package/dist/toast.js +3 -2
- package/dist/tooltip.cjs +4 -3
- package/dist/tooltip.js +3 -2
- package/dist/use-full-screen-H2j6qXDB.d.cts +85 -0
- package/dist/use-full-screen-H2j6qXDB.d.ts +85 -0
- package/docs/Editor.md +24 -0
- package/docs/FullScreen.md +95 -0
- package/package.json +11 -1
- package/dist/chunk-2OVDWUQ7.js.map +0 -1
- package/dist/chunk-34GALZRX.cjs.map +0 -1
- package/dist/chunk-BX7ZJ3HG.cjs.map +0 -1
- package/dist/chunk-NBZC6LOB.cjs.map +0 -1
- package/dist/chunk-PAFTHGQD.js.map +0 -1
- package/dist/chunk-WHEXTDPV.js.map +0 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
2
|
+
import { useRef, useState, useCallback, useLayoutEffect, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
// src/utils/scroll-lock.ts
|
|
5
|
+
var holders = 0;
|
|
6
|
+
var saved = "";
|
|
7
|
+
function lockBodyScroll() {
|
|
8
|
+
if (holders === 0) {
|
|
9
|
+
saved = document.body.style.overflow;
|
|
10
|
+
document.body.style.overflow = "hidden";
|
|
11
|
+
}
|
|
12
|
+
holders++;
|
|
13
|
+
let released = false;
|
|
14
|
+
return () => {
|
|
15
|
+
if (released) return;
|
|
16
|
+
released = true;
|
|
17
|
+
holders--;
|
|
18
|
+
if (holders === 0) document.body.style.overflow = saved;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/hooks/use-full-screen.ts
|
|
23
|
+
var FOCUSABLE = [
|
|
24
|
+
"a[href]",
|
|
25
|
+
"button:not([disabled])",
|
|
26
|
+
"input:not([disabled])",
|
|
27
|
+
"textarea:not([disabled])",
|
|
28
|
+
"select:not([disabled])",
|
|
29
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
30
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
31
|
+
].join(", ");
|
|
32
|
+
var activeStack = [];
|
|
33
|
+
var OVERLAY_STYLE = {
|
|
34
|
+
position: "fixed",
|
|
35
|
+
top: 0,
|
|
36
|
+
right: 0,
|
|
37
|
+
bottom: 0,
|
|
38
|
+
left: 0,
|
|
39
|
+
width: "100%",
|
|
40
|
+
height: "100%",
|
|
41
|
+
maxWidth: "none",
|
|
42
|
+
maxHeight: "none",
|
|
43
|
+
margin: 0,
|
|
44
|
+
borderRadius: 0,
|
|
45
|
+
boxSizing: "border-box"
|
|
46
|
+
};
|
|
47
|
+
function useFullScreen(options = {}) {
|
|
48
|
+
const {
|
|
49
|
+
fullScreen: controlled,
|
|
50
|
+
defaultFullScreen = false,
|
|
51
|
+
onFullScreenChange,
|
|
52
|
+
mode = "overlay",
|
|
53
|
+
closeOnEscape = true,
|
|
54
|
+
lockScroll = true,
|
|
55
|
+
zIndex = 50,
|
|
56
|
+
labels
|
|
57
|
+
} = options;
|
|
58
|
+
const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);
|
|
59
|
+
const ref = useRef(null);
|
|
60
|
+
const token = useRef({});
|
|
61
|
+
const [nativeActive, setNativeActive] = useState(false);
|
|
62
|
+
const [portalContainer, setPortalContainer] = useState(null);
|
|
63
|
+
const [applied, setApplied] = useState(fullScreen);
|
|
64
|
+
const current = useRef(fullScreen);
|
|
65
|
+
current.current = fullScreen;
|
|
66
|
+
const setFullScreen = useCallback(
|
|
67
|
+
(next) => {
|
|
68
|
+
if (current.current === next) return;
|
|
69
|
+
current.current = next;
|
|
70
|
+
setState(next);
|
|
71
|
+
},
|
|
72
|
+
[setState]
|
|
73
|
+
);
|
|
74
|
+
const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
if (!fullScreen) return;
|
|
77
|
+
const el = ref.current;
|
|
78
|
+
if (!el) return;
|
|
79
|
+
const scrolled = [];
|
|
80
|
+
for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {
|
|
81
|
+
if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });
|
|
82
|
+
}
|
|
83
|
+
const winX = window.scrollX;
|
|
84
|
+
const winY = window.scrollY;
|
|
85
|
+
const release = lockScroll ? lockBodyScroll() : null;
|
|
86
|
+
activeStack.push(token.current);
|
|
87
|
+
setPortalContainer(el);
|
|
88
|
+
setApplied(true);
|
|
89
|
+
return () => {
|
|
90
|
+
const i = activeStack.indexOf(token.current);
|
|
91
|
+
if (i >= 0) activeStack.splice(i, 1);
|
|
92
|
+
release?.();
|
|
93
|
+
for (const m of scrolled) {
|
|
94
|
+
if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;
|
|
95
|
+
if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;
|
|
96
|
+
}
|
|
97
|
+
if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);
|
|
98
|
+
setPortalContainer(null);
|
|
99
|
+
setApplied(false);
|
|
100
|
+
};
|
|
101
|
+
}, [fullScreen, lockScroll]);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!fullScreen) return;
|
|
104
|
+
const el = ref.current;
|
|
105
|
+
if (!el) return;
|
|
106
|
+
const opener = document.activeElement instanceof HTMLElement && document.activeElement !== document.body ? document.activeElement : null;
|
|
107
|
+
if (!el.contains(document.activeElement)) {
|
|
108
|
+
el.querySelector(FOCUSABLE)?.focus({ preventScroll: true });
|
|
109
|
+
}
|
|
110
|
+
return () => {
|
|
111
|
+
const active = document.activeElement;
|
|
112
|
+
if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {
|
|
113
|
+
opener.focus({ preventScroll: true });
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}, [fullScreen]);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!fullScreen || mode !== "native") return;
|
|
119
|
+
const el = ref.current;
|
|
120
|
+
if (!el || typeof el.requestFullscreen !== "function" || document.fullscreenEnabled === false) return;
|
|
121
|
+
let cancelled = false;
|
|
122
|
+
let entered = false;
|
|
123
|
+
const onChange = () => {
|
|
124
|
+
if (document.fullscreenElement === el) {
|
|
125
|
+
entered = true;
|
|
126
|
+
setNativeActive(true);
|
|
127
|
+
} else if (entered) {
|
|
128
|
+
entered = false;
|
|
129
|
+
setNativeActive(false);
|
|
130
|
+
if (!cancelled) setFullScreen(false);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
document.addEventListener("fullscreenchange", onChange);
|
|
134
|
+
try {
|
|
135
|
+
Promise.resolve(el.requestFullscreen()).then(onChange, () => {
|
|
136
|
+
});
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
return () => {
|
|
140
|
+
cancelled = true;
|
|
141
|
+
document.removeEventListener("fullscreenchange", onChange);
|
|
142
|
+
if (document.fullscreenElement === el) {
|
|
143
|
+
try {
|
|
144
|
+
Promise.resolve(document.exitFullscreen()).catch(() => {
|
|
145
|
+
});
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
setNativeActive(false);
|
|
150
|
+
};
|
|
151
|
+
}, [fullScreen, mode, setFullScreen]);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!fullScreen || !closeOnEscape) return;
|
|
154
|
+
const onKey = (e) => {
|
|
155
|
+
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
156
|
+
const t = e.target;
|
|
157
|
+
if (t !== document.body && t !== document.documentElement && t !== document) return;
|
|
158
|
+
if (activeStack[activeStack.length - 1] !== token.current) return;
|
|
159
|
+
setFullScreen(false);
|
|
160
|
+
};
|
|
161
|
+
document.addEventListener("keydown", onKey);
|
|
162
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
163
|
+
}, [fullScreen, closeOnEscape, setFullScreen]);
|
|
164
|
+
const onKeyDown = useCallback(
|
|
165
|
+
(e) => {
|
|
166
|
+
if (!current.current || e.defaultPrevented) return;
|
|
167
|
+
const el = ref.current;
|
|
168
|
+
if (!el) return;
|
|
169
|
+
if (e.key === "Tab") {
|
|
170
|
+
const items = Array.from(el.querySelectorAll(FOCUSABLE));
|
|
171
|
+
if (items.length === 0) return;
|
|
172
|
+
const first = items[0];
|
|
173
|
+
const last = items[items.length - 1];
|
|
174
|
+
const active = document.activeElement;
|
|
175
|
+
if (e.shiftKey && (active === first || active === el)) {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
last.focus();
|
|
178
|
+
} else if (!e.shiftKey && active === last) {
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
first.focus();
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (e.key !== "Escape" || !closeOnEscape) return;
|
|
185
|
+
const layer = e.target.closest?.("[data-react-fancy-portal]");
|
|
186
|
+
if (layer && !layer.contains(el)) return;
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
e.stopPropagation();
|
|
189
|
+
setFullScreen(false);
|
|
190
|
+
},
|
|
191
|
+
[closeOnEscape, setFullScreen]
|
|
192
|
+
);
|
|
193
|
+
const activeMode = fullScreen ? nativeActive ? "native" : "overlay" : null;
|
|
194
|
+
const enterLabel = labels?.enter ?? "Enter full screen";
|
|
195
|
+
const exitLabel = labels?.exit ?? "Exit full screen";
|
|
196
|
+
return {
|
|
197
|
+
fullScreen,
|
|
198
|
+
setFullScreen,
|
|
199
|
+
toggle,
|
|
200
|
+
activeMode,
|
|
201
|
+
ref,
|
|
202
|
+
portalContainer,
|
|
203
|
+
targetProps: {
|
|
204
|
+
ref,
|
|
205
|
+
"data-fullscreen": fullScreen ? "true" : "false",
|
|
206
|
+
...activeMode ? { "data-fullscreen-mode": activeMode } : {},
|
|
207
|
+
...fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {},
|
|
208
|
+
onKeyDown
|
|
209
|
+
},
|
|
210
|
+
toggleProps: {
|
|
211
|
+
type: "button",
|
|
212
|
+
onClick: toggle,
|
|
213
|
+
"aria-pressed": fullScreen,
|
|
214
|
+
"aria-label": fullScreen ? exitLabel : enterLabel,
|
|
215
|
+
title: fullScreen ? exitLabel : enterLabel,
|
|
216
|
+
"data-react-fancy-fullscreen-toggle": "",
|
|
217
|
+
"data-fullscreen": fullScreen ? "true" : "false"
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export { useFullScreen };
|
|
223
|
+
//# sourceMappingURL=chunk-NE3BZV3F.js.map
|
|
224
|
+
//# sourceMappingURL=chunk-NE3BZV3F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/scroll-lock.ts","../src/hooks/use-full-screen.ts"],"names":[],"mappings":"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","file":"chunk-NE3BZV3F.js","sourcesContent":["/**\n * Reference-counted body scroll lock.\n *\n * Two surfaces locking independently with the save-and-restore pattern\n * (`const original = body.style.overflow`) only unwind correctly in strict LIFO\n * order. Exit them out of order and the first one out restores `\"\"` while the\n * second is still covering the viewport, so the page scrolls behind it. Counting\n * holders keeps the lock until the last one lets go, and restores the value that\n * was there before the FIRST took it.\n *\n * Call only from an effect: it touches `document`.\n */\nlet holders = 0;\nlet saved = \"\";\n\nexport function lockBodyScroll(): () => void {\n if (holders === 0) {\n saved = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n holders++;\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n holders--;\n if (holders === 0) document.body.style.overflow = saved;\n };\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport { useControllableState } from \"./use-controllable-state\";\nimport { lockBodyScroll } from \"../utils/scroll-lock\";\n\n/**\n * How a surface goes full screen.\n *\n * - `\"overlay\"` (default): the element itself becomes `position: fixed` over the\n * viewport, in place. It always works: inside an iframe without\n * `allow=\"fullscreen\"`, inside a dialog, without a user gesture. Nothing is\n * reparented, so an editor keeps its caret, undo stack and DOM.\n * - `\"native\"`: the browser Fullscreen API (`element.requestFullscreen()`),\n * which hides the browser chrome too. The overlay is applied first and stays\n * if the request is rejected or the API is missing, so the user gets full\n * screen either way; `activeMode` reports which one took.\n */\nexport type FullScreenMode = \"overlay\" | \"native\";\n\nexport interface UseFullScreenOptions {\n /** Controlled flag. Pair with `onFullScreenChange`. */\n fullScreen?: boolean;\n /** Initial flag when uncontrolled. @default false */\n defaultFullScreen?: boolean;\n /**\n * Fired with the requested state — from the toggle, Escape, an agent calling\n * `setFullScreen`, or the user leaving the browser's own full screen.\n */\n onFullScreenChange?: (fullScreen: boolean) => void;\n /** @default \"overlay\" */\n mode?: FullScreenMode;\n /** Leave full screen on Escape. @default true */\n closeOnEscape?: boolean;\n /** Stop the page behind from scrolling while active. @default true */\n lockScroll?: boolean;\n /** Stacking order of the overlay. Matches `Modal`. @default 50 */\n zIndex?: number;\n /** Accessible names for the toggle. */\n labels?: { enter?: string; exit?: string };\n}\n\nexport interface FullScreenTargetProps<T extends HTMLElement> {\n ref: RefObject<T | null>;\n \"data-fullscreen\": \"true\" | \"false\";\n \"data-fullscreen-mode\"?: FullScreenMode;\n style?: CSSProperties;\n onKeyDown: (event: ReactKeyboardEvent<T>) => void;\n}\n\nexport interface FullScreenToggleProps {\n type: \"button\";\n onClick: () => void;\n \"aria-pressed\": boolean;\n \"aria-label\": string;\n title: string;\n \"data-react-fancy-fullscreen-toggle\": \"\";\n \"data-fullscreen\": \"true\" | \"false\";\n}\n\nexport interface UseFullScreenResult<T extends HTMLElement = HTMLElement> {\n fullScreen: boolean;\n setFullScreen: (fullScreen: boolean) => void;\n toggle: () => void;\n /** The mechanism in effect while active; `null` when not full screen. */\n activeMode: FullScreenMode | null;\n /** Attach to the element that goes full screen. Also inside `targetProps`. */\n ref: RefObject<T | null>;\n /**\n * Spread onto the surface's root. Carries the ref, the `data-fullscreen`\n * handle, the overlay style and the Escape/Tab handler. Merge your own\n * `style` / `onKeyDown` if the root has them.\n */\n targetProps: FullScreenTargetProps<T>;\n /** Spread onto a `<button>` to make it the toggle. */\n toggleProps: FullScreenToggleProps;\n /**\n * The element to portal into while active, else `null`. Provide it through\n * `PortalContainerContext` so menus opened inside stay visible.\n */\n portalContainer: HTMLElement | null;\n}\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\n/** Active surfaces, innermost last. Only the top one answers a stray Escape. */\nconst activeStack: object[] = [];\n\nconst OVERLAY_STYLE: CSSProperties = {\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n maxWidth: \"none\",\n maxHeight: \"none\",\n margin: 0,\n borderRadius: 0,\n boxSizing: \"border-box\",\n};\n\ninterface ScrollMemo {\n el: Element;\n top: number;\n left: number;\n}\n\n/**\n * A controlled full-screen state for any surface: Editor today, DeckEditor and\n * SheetWorkbook next. Render-time output is pure (no `window`/`document`), so it\n * server-renders; everything that touches the DOM runs in effects.\n */\nexport function useFullScreen<T extends HTMLElement = HTMLElement>(\n options: UseFullScreenOptions = {},\n): UseFullScreenResult<T> {\n const {\n fullScreen: controlled,\n defaultFullScreen = false,\n onFullScreenChange,\n mode = \"overlay\",\n closeOnEscape = true,\n lockScroll = true,\n zIndex = 50,\n labels,\n } = options;\n\n const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);\n const ref = useRef<T | null>(null);\n const token = useRef({});\n const [nativeActive, setNativeActive] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);\n // Whether the overlay STYLE is on. It trails `fullScreen` by one synchronous\n // commit on entry, so the layout effect below reads scroll offsets while the\n // surface is still in flow. Read after the style lands and the browser has\n // already clamped every scroll container around it: a panel at 569 read as\n // 342 in Chromium, and that is where the user was sent back to. The re-render\n // happens inside the layout phase, before paint, so nothing flashes.\n // Initialised from `fullScreen` so a surface that starts full screen renders\n // the overlay on the server and on hydration alike.\n const [applied, setApplied] = useState(fullScreen);\n\n const current = useRef(fullScreen);\n current.current = fullScreen;\n\n // Only report real transitions: Escape on an inactive surface, or a second\n // click racing a re-render, must not fire `onFullScreenChange(false)` twice.\n const setFullScreen = useCallback(\n (next: boolean) => {\n if (current.current === next) return;\n current.current = next;\n setState(next);\n },\n [setState],\n );\n const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);\n\n // Enter / exit bookkeeping. A LAYOUT effect so the cleanup runs after the\n // overlay style has been removed from the DOM but before paint: scroll offsets\n // restored there never flash, and the surface is back in flow to measure.\n useLayoutEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n // Taking the surface out of flow shrinks every scroll container around it,\n // which clamps their scrollTop. Remember them so exit lands where it began.\n const scrolled: ScrollMemo[] = [];\n for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {\n if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });\n }\n const winX = window.scrollX;\n const winY = window.scrollY;\n\n const release = lockScroll ? lockBodyScroll() : null;\n activeStack.push(token.current);\n setPortalContainer(el);\n setApplied(true);\n\n return () => {\n const i = activeStack.indexOf(token.current);\n if (i >= 0) activeStack.splice(i, 1);\n release?.();\n for (const m of scrolled) {\n if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;\n if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;\n }\n if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);\n setPortalContainer(null);\n setApplied(false);\n };\n }, [fullScreen, lockScroll]);\n\n // Focus in and back out. A PASSIVE effect on purpose: React re-focuses\n // whatever had focus before a commit once the commit's mutations finish, so a\n // focus() issued from a layout-effect cleanup is silently undone.\n useEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n const opener =\n document.activeElement instanceof HTMLElement && document.activeElement !== document.body\n ? document.activeElement\n : null;\n\n // Focus must not stay behind the overlay, where the user cannot see it.\n if (!el.contains(document.activeElement)) {\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true });\n }\n\n return () => {\n // Give focus back only if it is still ours to give: inside the surface,\n // or lost to <body>. A user who clicked elsewhere keeps their choice.\n const active = document.activeElement;\n if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {\n opener.focus({ preventScroll: true });\n }\n };\n }, [fullScreen]);\n\n // The browser Fullscreen API, on top of the overlay.\n useEffect(() => {\n if (!fullScreen || mode !== \"native\") return;\n const el = ref.current;\n if (!el || typeof el.requestFullscreen !== \"function\" || document.fullscreenEnabled === false) return;\n\n let cancelled = false;\n let entered = false;\n\n const onChange = () => {\n if (document.fullscreenElement === el) {\n entered = true;\n setNativeActive(true);\n } else if (entered) {\n // The user left through the browser's own UI (Esc, F11, the close\n // pill). Keep the controlled state honest rather than leaving an\n // overlay up that they believe they dismissed.\n entered = false;\n setNativeActive(false);\n if (!cancelled) setFullScreen(false);\n }\n };\n document.addEventListener(\"fullscreenchange\", onChange);\n\n // Blocked requests (iframe without allow=\"fullscreen\", no user gesture, a\n // permissions policy) reject, and some engines throw instead. Either way\n // the overlay is already up, so the user stays full screen in it.\n try {\n Promise.resolve(el.requestFullscreen()).then(onChange, () => {});\n } catch {\n /* stay in the overlay */\n }\n\n return () => {\n cancelled = true;\n document.removeEventListener(\"fullscreenchange\", onChange);\n if (document.fullscreenElement === el) {\n try {\n Promise.resolve(document.exitFullscreen()).catch(() => {});\n } catch {\n /* already left */\n }\n }\n setNativeActive(false);\n };\n }, [fullScreen, mode, setFullScreen]);\n\n // Escape with nothing focused never reaches the surface's own handler.\n useEffect(() => {\n if (!fullScreen || !closeOnEscape) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented) return;\n const t = e.target;\n if (t !== document.body && t !== document.documentElement && t !== document) return;\n if (activeStack[activeStack.length - 1] !== token.current) return;\n setFullScreen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [fullScreen, closeOnEscape, setFullScreen]);\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<T>) => {\n if (!current.current || e.defaultPrevented) return;\n const el = ref.current;\n if (!el) return;\n\n if (e.key === \"Tab\") {\n // Keep Tab inside the surface; what is behind the overlay is invisible.\n const items = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE));\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (e.shiftKey && (active === first || active === el)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n return;\n }\n\n if (e.key !== \"Escape\" || !closeOnEscape) return;\n // An Escape from inside a layer opened FROM this surface (a menu, a\n // popover, a dialog) belongs to that layer. React bubbles portal events\n // through the component tree, so check the DOM: a portal wrapper that\n // does not contain this surface is nested inside it.\n const layer = (e.target as Element).closest?.(\"[data-react-fancy-portal]\");\n if (layer && !layer.contains(el)) return;\n // Stop it here so an enclosing dialog's document listener does not also\n // close: one Escape, one step back.\n e.preventDefault();\n e.stopPropagation();\n setFullScreen(false);\n },\n [closeOnEscape, setFullScreen],\n );\n\n const activeMode: FullScreenMode | null = fullScreen ? (nativeActive ? \"native\" : \"overlay\") : null;\n const enterLabel = labels?.enter ?? \"Enter full screen\";\n const exitLabel = labels?.exit ?? \"Exit full screen\";\n\n return {\n fullScreen,\n setFullScreen,\n toggle,\n activeMode,\n ref,\n portalContainer,\n targetProps: {\n ref,\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n ...(activeMode ? { \"data-fullscreen-mode\": activeMode } : {}),\n ...(fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {}),\n onKeyDown,\n },\n toggleProps: {\n type: \"button\",\n onClick: toggle,\n \"aria-pressed\": fullScreen,\n \"aria-label\": fullScreen ? exitLabel : enterLabel,\n title: fullScreen ? exitLabel : enterLabel,\n \"data-react-fancy-fullscreen-toggle\": \"\",\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n },\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useFloatingPosition } from './chunk-MQ6VGG62.js';
|
|
2
|
-
import { Portal } from './chunk-
|
|
2
|
+
import { Portal } from './chunk-RBCMKPBX.js';
|
|
3
3
|
import { useOutsideClick } from './chunk-RGANGU7X.js';
|
|
4
4
|
import { useEscapeKey } from './chunk-JXE5XID6.js';
|
|
5
5
|
import { cn } from './chunk-MMW2JGKZ.js';
|
|
@@ -114,5 +114,5 @@ var Popover = Object.assign(PopoverRoot, {
|
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
export { Popover, usePopover };
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-NORVXHRU.js.map
|
|
118
|
+
//# sourceMappingURL=chunk-NORVXHRU.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Popover/Popover.context.ts","../src/components/Popover/PopoverTrigger.tsx","../src/components/Popover/PopoverContent.tsx","../src/components/Popover/Popover.tsx"],"names":["jsx","useRef","useCallback"],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/components/Popover/Popover.context.ts","../src/components/Popover/PopoverTrigger.tsx","../src/components/Popover/PopoverContent.tsx","../src/components/Popover/Popover.tsx"],"names":["jsx","useRef","useCallback"],"mappings":"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","file":"chunk-NORVXHRU.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { PopoverContextValue } from \"./Popover.types\";\n\nexport const PopoverContext = createContext<PopoverContextValue | null>(null);\n\nexport function usePopover(): PopoverContextValue {\n const ctx = useContext(PopoverContext);\n if (!ctx) {\n throw new Error(\"Popover compound components must be used within <Popover>\");\n }\n return ctx;\n}\n","import { cn } from \"../../utils/cn\";\nimport { usePopover } from \"./Popover.context\";\nimport type { PopoverTriggerProps } from \"./Popover.types\";\n\nexport function PopoverTrigger({ children, className, ...rest }: PopoverTriggerProps) {\n const { setOpen, open, anchorRef, hover, onHoverEnter, onHoverLeave } = usePopover();\n\n return (\n <span\n {...rest}\n ref={anchorRef as React.RefObject<HTMLSpanElement>}\n data-react-fancy-popover-trigger=\"\"\n className={cn(\"inline-flex\", className)}\n onClick={hover ? undefined : () => setOpen(!open)}\n onMouseEnter={hover ? onHoverEnter : undefined}\n onMouseLeave={hover ? onHoverLeave : undefined}\n aria-expanded={open}\n aria-haspopup\n >\n {children}\n </span>\n );\n}\n\nPopoverTrigger.displayName = \"PopoverTrigger\";\n","import { useCallback, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { usePopover } from \"./Popover.context\";\nimport { useFloatingPosition } from \"../../hooks/use-floating-position\";\nimport { useOutsideClick } from \"../../hooks/use-outside-click\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport type { PopoverContentProps } from \"./Popover.types\";\n\nexport function PopoverContent({ children, className, style, ...rest }: PopoverContentProps) {\n const { open, setOpen, anchorRef, floatingRef, placement, offset, hover, onHoverEnter, onHoverLeave } = usePopover();\n const outsideRef = useRef<HTMLDivElement>(null);\n\n const position = useFloatingPosition(anchorRef, floatingRef, {\n placement,\n offset,\n enabled: open,\n });\n\n const close = useCallback(() => setOpen(false), [setOpen]);\n useOutsideClick(outsideRef, close, open && !hover, anchorRef);\n useEscapeKey(close, open);\n\n // Hide until position is calculated to prevent flash at (-9999, -9999)\n const positioned = position.x !== -9999 && position.y !== -9999;\n\n if (!open) return null;\n\n return (\n <Portal>\n <div\n {...rest}\n ref={(node) => {\n outsideRef.current = node;\n (floatingRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n data-react-fancy-popover=\"\"\n className={cn(\n \"fixed z-50 rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 text-zinc-700 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:text-zinc-200 dark:shadow-zinc-950/50\",\n positioned ? \"fancy-scale-in\" : \"invisible\",\n className,\n )}\n style={{ ...style, left: position.x, top: position.y }}\n onMouseEnter={hover ? onHoverEnter : undefined}\n onMouseLeave={hover ? onHoverLeave : undefined}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\nPopoverContent.displayName = \"PopoverContent\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { PopoverContext } from \"./Popover.context\";\nimport { PopoverTrigger } from \"./PopoverTrigger\";\nimport { PopoverContent } from \"./PopoverContent\";\nimport type { PopoverProps } from \"./Popover.types\";\n\nfunction PopoverRoot({\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n placement = \"bottom\",\n offset = 8,\n hover = false,\n hoverDelay = 200,\n hoverCloseDelay = 300,\n}: PopoverProps) {\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n\n const anchorRef = useRef<HTMLElement>(null);\n const floatingRef = useRef<HTMLDivElement>(null);\n const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n const onHoverEnter = useCallback(() => {\n if (!hover) return;\n clearTimeout(hoverTimeoutRef.current);\n hoverTimeoutRef.current = setTimeout(() => setOpen(true), hoverDelay);\n }, [hover, hoverDelay, setOpen]);\n\n const onHoverLeave = useCallback(() => {\n if (!hover) return;\n clearTimeout(hoverTimeoutRef.current);\n hoverTimeoutRef.current = setTimeout(() => setOpen(false), hoverCloseDelay);\n }, [hover, hoverCloseDelay, setOpen]);\n\n const ctx = useMemo(\n () => ({ open, setOpen, anchorRef, floatingRef, placement, offset, hover, onHoverEnter, onHoverLeave }),\n [open, setOpen, placement, offset, hover, onHoverEnter, onHoverLeave],\n );\n\n return (\n <PopoverContext.Provider value={ctx}>{children}</PopoverContext.Provider>\n );\n}\n\nexport const Popover = Object.assign(PopoverRoot, {\n Trigger: PopoverTrigger,\n Content: PopoverContent,\n});\n"]}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkSNHU2AI4_cjs = require('./chunk-SNHU2AI4.cjs');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
// src/utils/scroll-lock.ts
|
|
7
|
+
var holders = 0;
|
|
8
|
+
var saved = "";
|
|
9
|
+
function lockBodyScroll() {
|
|
10
|
+
if (holders === 0) {
|
|
11
|
+
saved = document.body.style.overflow;
|
|
12
|
+
document.body.style.overflow = "hidden";
|
|
13
|
+
}
|
|
14
|
+
holders++;
|
|
15
|
+
let released = false;
|
|
16
|
+
return () => {
|
|
17
|
+
if (released) return;
|
|
18
|
+
released = true;
|
|
19
|
+
holders--;
|
|
20
|
+
if (holders === 0) document.body.style.overflow = saved;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/hooks/use-full-screen.ts
|
|
25
|
+
var FOCUSABLE = [
|
|
26
|
+
"a[href]",
|
|
27
|
+
"button:not([disabled])",
|
|
28
|
+
"input:not([disabled])",
|
|
29
|
+
"textarea:not([disabled])",
|
|
30
|
+
"select:not([disabled])",
|
|
31
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
32
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
33
|
+
].join(", ");
|
|
34
|
+
var activeStack = [];
|
|
35
|
+
var OVERLAY_STYLE = {
|
|
36
|
+
position: "fixed",
|
|
37
|
+
top: 0,
|
|
38
|
+
right: 0,
|
|
39
|
+
bottom: 0,
|
|
40
|
+
left: 0,
|
|
41
|
+
width: "100%",
|
|
42
|
+
height: "100%",
|
|
43
|
+
maxWidth: "none",
|
|
44
|
+
maxHeight: "none",
|
|
45
|
+
margin: 0,
|
|
46
|
+
borderRadius: 0,
|
|
47
|
+
boxSizing: "border-box"
|
|
48
|
+
};
|
|
49
|
+
function useFullScreen(options = {}) {
|
|
50
|
+
const {
|
|
51
|
+
fullScreen: controlled,
|
|
52
|
+
defaultFullScreen = false,
|
|
53
|
+
onFullScreenChange,
|
|
54
|
+
mode = "overlay",
|
|
55
|
+
closeOnEscape = true,
|
|
56
|
+
lockScroll = true,
|
|
57
|
+
zIndex = 50,
|
|
58
|
+
labels
|
|
59
|
+
} = options;
|
|
60
|
+
const [fullScreen, setState] = chunkSNHU2AI4_cjs.useControllableState(controlled, defaultFullScreen, onFullScreenChange);
|
|
61
|
+
const ref = react.useRef(null);
|
|
62
|
+
const token = react.useRef({});
|
|
63
|
+
const [nativeActive, setNativeActive] = react.useState(false);
|
|
64
|
+
const [portalContainer, setPortalContainer] = react.useState(null);
|
|
65
|
+
const [applied, setApplied] = react.useState(fullScreen);
|
|
66
|
+
const current = react.useRef(fullScreen);
|
|
67
|
+
current.current = fullScreen;
|
|
68
|
+
const setFullScreen = react.useCallback(
|
|
69
|
+
(next) => {
|
|
70
|
+
if (current.current === next) return;
|
|
71
|
+
current.current = next;
|
|
72
|
+
setState(next);
|
|
73
|
+
},
|
|
74
|
+
[setState]
|
|
75
|
+
);
|
|
76
|
+
const toggle = react.useCallback(() => setFullScreen(!current.current), [setFullScreen]);
|
|
77
|
+
react.useLayoutEffect(() => {
|
|
78
|
+
if (!fullScreen) return;
|
|
79
|
+
const el = ref.current;
|
|
80
|
+
if (!el) return;
|
|
81
|
+
const scrolled = [];
|
|
82
|
+
for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {
|
|
83
|
+
if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });
|
|
84
|
+
}
|
|
85
|
+
const winX = window.scrollX;
|
|
86
|
+
const winY = window.scrollY;
|
|
87
|
+
const release = lockScroll ? lockBodyScroll() : null;
|
|
88
|
+
activeStack.push(token.current);
|
|
89
|
+
setPortalContainer(el);
|
|
90
|
+
setApplied(true);
|
|
91
|
+
return () => {
|
|
92
|
+
const i = activeStack.indexOf(token.current);
|
|
93
|
+
if (i >= 0) activeStack.splice(i, 1);
|
|
94
|
+
release?.();
|
|
95
|
+
for (const m of scrolled) {
|
|
96
|
+
if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;
|
|
97
|
+
if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;
|
|
98
|
+
}
|
|
99
|
+
if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);
|
|
100
|
+
setPortalContainer(null);
|
|
101
|
+
setApplied(false);
|
|
102
|
+
};
|
|
103
|
+
}, [fullScreen, lockScroll]);
|
|
104
|
+
react.useEffect(() => {
|
|
105
|
+
if (!fullScreen) return;
|
|
106
|
+
const el = ref.current;
|
|
107
|
+
if (!el) return;
|
|
108
|
+
const opener = document.activeElement instanceof HTMLElement && document.activeElement !== document.body ? document.activeElement : null;
|
|
109
|
+
if (!el.contains(document.activeElement)) {
|
|
110
|
+
el.querySelector(FOCUSABLE)?.focus({ preventScroll: true });
|
|
111
|
+
}
|
|
112
|
+
return () => {
|
|
113
|
+
const active = document.activeElement;
|
|
114
|
+
if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {
|
|
115
|
+
opener.focus({ preventScroll: true });
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}, [fullScreen]);
|
|
119
|
+
react.useEffect(() => {
|
|
120
|
+
if (!fullScreen || mode !== "native") return;
|
|
121
|
+
const el = ref.current;
|
|
122
|
+
if (!el || typeof el.requestFullscreen !== "function" || document.fullscreenEnabled === false) return;
|
|
123
|
+
let cancelled = false;
|
|
124
|
+
let entered = false;
|
|
125
|
+
const onChange = () => {
|
|
126
|
+
if (document.fullscreenElement === el) {
|
|
127
|
+
entered = true;
|
|
128
|
+
setNativeActive(true);
|
|
129
|
+
} else if (entered) {
|
|
130
|
+
entered = false;
|
|
131
|
+
setNativeActive(false);
|
|
132
|
+
if (!cancelled) setFullScreen(false);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
document.addEventListener("fullscreenchange", onChange);
|
|
136
|
+
try {
|
|
137
|
+
Promise.resolve(el.requestFullscreen()).then(onChange, () => {
|
|
138
|
+
});
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
return () => {
|
|
142
|
+
cancelled = true;
|
|
143
|
+
document.removeEventListener("fullscreenchange", onChange);
|
|
144
|
+
if (document.fullscreenElement === el) {
|
|
145
|
+
try {
|
|
146
|
+
Promise.resolve(document.exitFullscreen()).catch(() => {
|
|
147
|
+
});
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
setNativeActive(false);
|
|
152
|
+
};
|
|
153
|
+
}, [fullScreen, mode, setFullScreen]);
|
|
154
|
+
react.useEffect(() => {
|
|
155
|
+
if (!fullScreen || !closeOnEscape) return;
|
|
156
|
+
const onKey = (e) => {
|
|
157
|
+
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
158
|
+
const t = e.target;
|
|
159
|
+
if (t !== document.body && t !== document.documentElement && t !== document) return;
|
|
160
|
+
if (activeStack[activeStack.length - 1] !== token.current) return;
|
|
161
|
+
setFullScreen(false);
|
|
162
|
+
};
|
|
163
|
+
document.addEventListener("keydown", onKey);
|
|
164
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
165
|
+
}, [fullScreen, closeOnEscape, setFullScreen]);
|
|
166
|
+
const onKeyDown = react.useCallback(
|
|
167
|
+
(e) => {
|
|
168
|
+
if (!current.current || e.defaultPrevented) return;
|
|
169
|
+
const el = ref.current;
|
|
170
|
+
if (!el) return;
|
|
171
|
+
if (e.key === "Tab") {
|
|
172
|
+
const items = Array.from(el.querySelectorAll(FOCUSABLE));
|
|
173
|
+
if (items.length === 0) return;
|
|
174
|
+
const first = items[0];
|
|
175
|
+
const last = items[items.length - 1];
|
|
176
|
+
const active = document.activeElement;
|
|
177
|
+
if (e.shiftKey && (active === first || active === el)) {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
last.focus();
|
|
180
|
+
} else if (!e.shiftKey && active === last) {
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
first.focus();
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (e.key !== "Escape" || !closeOnEscape) return;
|
|
187
|
+
const layer = e.target.closest?.("[data-react-fancy-portal]");
|
|
188
|
+
if (layer && !layer.contains(el)) return;
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
e.stopPropagation();
|
|
191
|
+
setFullScreen(false);
|
|
192
|
+
},
|
|
193
|
+
[closeOnEscape, setFullScreen]
|
|
194
|
+
);
|
|
195
|
+
const activeMode = fullScreen ? nativeActive ? "native" : "overlay" : null;
|
|
196
|
+
const enterLabel = labels?.enter ?? "Enter full screen";
|
|
197
|
+
const exitLabel = labels?.exit ?? "Exit full screen";
|
|
198
|
+
return {
|
|
199
|
+
fullScreen,
|
|
200
|
+
setFullScreen,
|
|
201
|
+
toggle,
|
|
202
|
+
activeMode,
|
|
203
|
+
ref,
|
|
204
|
+
portalContainer,
|
|
205
|
+
targetProps: {
|
|
206
|
+
ref,
|
|
207
|
+
"data-fullscreen": fullScreen ? "true" : "false",
|
|
208
|
+
...activeMode ? { "data-fullscreen-mode": activeMode } : {},
|
|
209
|
+
...fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {},
|
|
210
|
+
onKeyDown
|
|
211
|
+
},
|
|
212
|
+
toggleProps: {
|
|
213
|
+
type: "button",
|
|
214
|
+
onClick: toggle,
|
|
215
|
+
"aria-pressed": fullScreen,
|
|
216
|
+
"aria-label": fullScreen ? exitLabel : enterLabel,
|
|
217
|
+
title: fullScreen ? exitLabel : enterLabel,
|
|
218
|
+
"data-react-fancy-fullscreen-toggle": "",
|
|
219
|
+
"data-fullscreen": fullScreen ? "true" : "false"
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
exports.useFullScreen = useFullScreen;
|
|
225
|
+
//# sourceMappingURL=chunk-O4HZVZMY.cjs.map
|
|
226
|
+
//# sourceMappingURL=chunk-O4HZVZMY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/scroll-lock.ts","../src/hooks/use-full-screen.ts"],"names":["useControllableState","useRef","useState","useCallback","useLayoutEffect","useEffect"],"mappings":"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","file":"chunk-O4HZVZMY.cjs","sourcesContent":["/**\n * Reference-counted body scroll lock.\n *\n * Two surfaces locking independently with the save-and-restore pattern\n * (`const original = body.style.overflow`) only unwind correctly in strict LIFO\n * order. Exit them out of order and the first one out restores `\"\"` while the\n * second is still covering the viewport, so the page scrolls behind it. Counting\n * holders keeps the lock until the last one lets go, and restores the value that\n * was there before the FIRST took it.\n *\n * Call only from an effect: it touches `document`.\n */\nlet holders = 0;\nlet saved = \"\";\n\nexport function lockBodyScroll(): () => void {\n if (holders === 0) {\n saved = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n holders++;\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n holders--;\n if (holders === 0) document.body.style.overflow = saved;\n };\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport { useControllableState } from \"./use-controllable-state\";\nimport { lockBodyScroll } from \"../utils/scroll-lock\";\n\n/**\n * How a surface goes full screen.\n *\n * - `\"overlay\"` (default): the element itself becomes `position: fixed` over the\n * viewport, in place. It always works: inside an iframe without\n * `allow=\"fullscreen\"`, inside a dialog, without a user gesture. Nothing is\n * reparented, so an editor keeps its caret, undo stack and DOM.\n * - `\"native\"`: the browser Fullscreen API (`element.requestFullscreen()`),\n * which hides the browser chrome too. The overlay is applied first and stays\n * if the request is rejected or the API is missing, so the user gets full\n * screen either way; `activeMode` reports which one took.\n */\nexport type FullScreenMode = \"overlay\" | \"native\";\n\nexport interface UseFullScreenOptions {\n /** Controlled flag. Pair with `onFullScreenChange`. */\n fullScreen?: boolean;\n /** Initial flag when uncontrolled. @default false */\n defaultFullScreen?: boolean;\n /**\n * Fired with the requested state — from the toggle, Escape, an agent calling\n * `setFullScreen`, or the user leaving the browser's own full screen.\n */\n onFullScreenChange?: (fullScreen: boolean) => void;\n /** @default \"overlay\" */\n mode?: FullScreenMode;\n /** Leave full screen on Escape. @default true */\n closeOnEscape?: boolean;\n /** Stop the page behind from scrolling while active. @default true */\n lockScroll?: boolean;\n /** Stacking order of the overlay. Matches `Modal`. @default 50 */\n zIndex?: number;\n /** Accessible names for the toggle. */\n labels?: { enter?: string; exit?: string };\n}\n\nexport interface FullScreenTargetProps<T extends HTMLElement> {\n ref: RefObject<T | null>;\n \"data-fullscreen\": \"true\" | \"false\";\n \"data-fullscreen-mode\"?: FullScreenMode;\n style?: CSSProperties;\n onKeyDown: (event: ReactKeyboardEvent<T>) => void;\n}\n\nexport interface FullScreenToggleProps {\n type: \"button\";\n onClick: () => void;\n \"aria-pressed\": boolean;\n \"aria-label\": string;\n title: string;\n \"data-react-fancy-fullscreen-toggle\": \"\";\n \"data-fullscreen\": \"true\" | \"false\";\n}\n\nexport interface UseFullScreenResult<T extends HTMLElement = HTMLElement> {\n fullScreen: boolean;\n setFullScreen: (fullScreen: boolean) => void;\n toggle: () => void;\n /** The mechanism in effect while active; `null` when not full screen. */\n activeMode: FullScreenMode | null;\n /** Attach to the element that goes full screen. Also inside `targetProps`. */\n ref: RefObject<T | null>;\n /**\n * Spread onto the surface's root. Carries the ref, the `data-fullscreen`\n * handle, the overlay style and the Escape/Tab handler. Merge your own\n * `style` / `onKeyDown` if the root has them.\n */\n targetProps: FullScreenTargetProps<T>;\n /** Spread onto a `<button>` to make it the toggle. */\n toggleProps: FullScreenToggleProps;\n /**\n * The element to portal into while active, else `null`. Provide it through\n * `PortalContainerContext` so menus opened inside stay visible.\n */\n portalContainer: HTMLElement | null;\n}\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\n/** Active surfaces, innermost last. Only the top one answers a stray Escape. */\nconst activeStack: object[] = [];\n\nconst OVERLAY_STYLE: CSSProperties = {\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n maxWidth: \"none\",\n maxHeight: \"none\",\n margin: 0,\n borderRadius: 0,\n boxSizing: \"border-box\",\n};\n\ninterface ScrollMemo {\n el: Element;\n top: number;\n left: number;\n}\n\n/**\n * A controlled full-screen state for any surface: Editor today, DeckEditor and\n * SheetWorkbook next. Render-time output is pure (no `window`/`document`), so it\n * server-renders; everything that touches the DOM runs in effects.\n */\nexport function useFullScreen<T extends HTMLElement = HTMLElement>(\n options: UseFullScreenOptions = {},\n): UseFullScreenResult<T> {\n const {\n fullScreen: controlled,\n defaultFullScreen = false,\n onFullScreenChange,\n mode = \"overlay\",\n closeOnEscape = true,\n lockScroll = true,\n zIndex = 50,\n labels,\n } = options;\n\n const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);\n const ref = useRef<T | null>(null);\n const token = useRef({});\n const [nativeActive, setNativeActive] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);\n // Whether the overlay STYLE is on. It trails `fullScreen` by one synchronous\n // commit on entry, so the layout effect below reads scroll offsets while the\n // surface is still in flow. Read after the style lands and the browser has\n // already clamped every scroll container around it: a panel at 569 read as\n // 342 in Chromium, and that is where the user was sent back to. The re-render\n // happens inside the layout phase, before paint, so nothing flashes.\n // Initialised from `fullScreen` so a surface that starts full screen renders\n // the overlay on the server and on hydration alike.\n const [applied, setApplied] = useState(fullScreen);\n\n const current = useRef(fullScreen);\n current.current = fullScreen;\n\n // Only report real transitions: Escape on an inactive surface, or a second\n // click racing a re-render, must not fire `onFullScreenChange(false)` twice.\n const setFullScreen = useCallback(\n (next: boolean) => {\n if (current.current === next) return;\n current.current = next;\n setState(next);\n },\n [setState],\n );\n const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);\n\n // Enter / exit bookkeeping. A LAYOUT effect so the cleanup runs after the\n // overlay style has been removed from the DOM but before paint: scroll offsets\n // restored there never flash, and the surface is back in flow to measure.\n useLayoutEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n // Taking the surface out of flow shrinks every scroll container around it,\n // which clamps their scrollTop. Remember them so exit lands where it began.\n const scrolled: ScrollMemo[] = [];\n for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {\n if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });\n }\n const winX = window.scrollX;\n const winY = window.scrollY;\n\n const release = lockScroll ? lockBodyScroll() : null;\n activeStack.push(token.current);\n setPortalContainer(el);\n setApplied(true);\n\n return () => {\n const i = activeStack.indexOf(token.current);\n if (i >= 0) activeStack.splice(i, 1);\n release?.();\n for (const m of scrolled) {\n if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;\n if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;\n }\n if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);\n setPortalContainer(null);\n setApplied(false);\n };\n }, [fullScreen, lockScroll]);\n\n // Focus in and back out. A PASSIVE effect on purpose: React re-focuses\n // whatever had focus before a commit once the commit's mutations finish, so a\n // focus() issued from a layout-effect cleanup is silently undone.\n useEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n const opener =\n document.activeElement instanceof HTMLElement && document.activeElement !== document.body\n ? document.activeElement\n : null;\n\n // Focus must not stay behind the overlay, where the user cannot see it.\n if (!el.contains(document.activeElement)) {\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true });\n }\n\n return () => {\n // Give focus back only if it is still ours to give: inside the surface,\n // or lost to <body>. A user who clicked elsewhere keeps their choice.\n const active = document.activeElement;\n if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {\n opener.focus({ preventScroll: true });\n }\n };\n }, [fullScreen]);\n\n // The browser Fullscreen API, on top of the overlay.\n useEffect(() => {\n if (!fullScreen || mode !== \"native\") return;\n const el = ref.current;\n if (!el || typeof el.requestFullscreen !== \"function\" || document.fullscreenEnabled === false) return;\n\n let cancelled = false;\n let entered = false;\n\n const onChange = () => {\n if (document.fullscreenElement === el) {\n entered = true;\n setNativeActive(true);\n } else if (entered) {\n // The user left through the browser's own UI (Esc, F11, the close\n // pill). Keep the controlled state honest rather than leaving an\n // overlay up that they believe they dismissed.\n entered = false;\n setNativeActive(false);\n if (!cancelled) setFullScreen(false);\n }\n };\n document.addEventListener(\"fullscreenchange\", onChange);\n\n // Blocked requests (iframe without allow=\"fullscreen\", no user gesture, a\n // permissions policy) reject, and some engines throw instead. Either way\n // the overlay is already up, so the user stays full screen in it.\n try {\n Promise.resolve(el.requestFullscreen()).then(onChange, () => {});\n } catch {\n /* stay in the overlay */\n }\n\n return () => {\n cancelled = true;\n document.removeEventListener(\"fullscreenchange\", onChange);\n if (document.fullscreenElement === el) {\n try {\n Promise.resolve(document.exitFullscreen()).catch(() => {});\n } catch {\n /* already left */\n }\n }\n setNativeActive(false);\n };\n }, [fullScreen, mode, setFullScreen]);\n\n // Escape with nothing focused never reaches the surface's own handler.\n useEffect(() => {\n if (!fullScreen || !closeOnEscape) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented) return;\n const t = e.target;\n if (t !== document.body && t !== document.documentElement && t !== document) return;\n if (activeStack[activeStack.length - 1] !== token.current) return;\n setFullScreen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [fullScreen, closeOnEscape, setFullScreen]);\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<T>) => {\n if (!current.current || e.defaultPrevented) return;\n const el = ref.current;\n if (!el) return;\n\n if (e.key === \"Tab\") {\n // Keep Tab inside the surface; what is behind the overlay is invisible.\n const items = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE));\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (e.shiftKey && (active === first || active === el)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n return;\n }\n\n if (e.key !== \"Escape\" || !closeOnEscape) return;\n // An Escape from inside a layer opened FROM this surface (a menu, a\n // popover, a dialog) belongs to that layer. React bubbles portal events\n // through the component tree, so check the DOM: a portal wrapper that\n // does not contain this surface is nested inside it.\n const layer = (e.target as Element).closest?.(\"[data-react-fancy-portal]\");\n if (layer && !layer.contains(el)) return;\n // Stop it here so an enclosing dialog's document listener does not also\n // close: one Escape, one step back.\n e.preventDefault();\n e.stopPropagation();\n setFullScreen(false);\n },\n [closeOnEscape, setFullScreen],\n );\n\n const activeMode: FullScreenMode | null = fullScreen ? (nativeActive ? \"native\" : \"overlay\") : null;\n const enterLabel = labels?.enter ?? \"Enter full screen\";\n const exitLabel = labels?.exit ?? \"Exit full screen\";\n\n return {\n fullScreen,\n setFullScreen,\n toggle,\n activeMode,\n ref,\n portalContainer,\n targetProps: {\n ref,\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n ...(activeMode ? { \"data-fullscreen-mode\": activeMode } : {}),\n ...(fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {}),\n onKeyDown,\n },\n toggleProps: {\n type: \"button\",\n onClick: toggle,\n \"aria-pressed\": fullScreen,\n \"aria-label\": fullScreen ? exitLabel : enterLabel,\n title: fullScreen ? exitLabel : enterLabel,\n \"data-react-fancy-fullscreen-toggle\": \"\",\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n },\n };\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var chunkTXTRTTG7_cjs = require('./chunk-TXTRTTG7.cjs');
|
|
4
4
|
var chunkFQZE5N2N_cjs = require('./chunk-FQZE5N2N.cjs');
|
|
5
|
-
var
|
|
5
|
+
var chunkTI7D4QDM_cjs = require('./chunk-TI7D4QDM.cjs');
|
|
6
6
|
var chunkRXDRYWVD_cjs = require('./chunk-RXDRYWVD.cjs');
|
|
7
7
|
var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
8
8
|
var react = require('react');
|
|
@@ -203,7 +203,7 @@ function DrawerRoot({
|
|
|
203
203
|
]
|
|
204
204
|
}
|
|
205
205
|
);
|
|
206
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: ctx, children: isViewport ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
206
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: ctx, children: isViewport ? /* @__PURE__ */ jsxRuntime.jsx(chunkTI7D4QDM_cjs.Portal, { children: frame }) : frame });
|
|
207
207
|
}
|
|
208
208
|
var Drawer = Object.assign(DrawerRoot, {
|
|
209
209
|
Header: DrawerHeader,
|
|
@@ -214,5 +214,5 @@ var Drawer = Object.assign(DrawerRoot, {
|
|
|
214
214
|
|
|
215
215
|
exports.Drawer = Drawer;
|
|
216
216
|
exports.useDrawer = useDrawer;
|
|
217
|
-
//# sourceMappingURL=chunk-
|
|
218
|
-
//# sourceMappingURL=chunk-
|
|
217
|
+
//# sourceMappingURL=chunk-P6V4QWJK.cjs.map
|
|
218
|
+
//# sourceMappingURL=chunk-P6V4QWJK.cjs.map
|