@x-plat/design-system 0.14.13 → 0.14.15
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/components/DatePicker/index.cjs +46 -41
- package/dist/components/DatePicker/index.js +46 -41
- package/dist/components/Drawer/index.cjs +14 -9
- package/dist/components/Drawer/index.js +14 -9
- package/dist/components/Dropdown/index.cjs +21 -20
- package/dist/components/Dropdown/index.css +2 -2
- package/dist/components/Dropdown/index.js +21 -20
- package/dist/components/Modal/index.cjs +15 -10
- package/dist/components/Modal/index.js +15 -10
- package/dist/components/PopOver/index.cjs +21 -20
- package/dist/components/PopOver/index.js +21 -20
- package/dist/components/Select/index.cjs +21 -20
- package/dist/components/Select/index.css +4 -4
- package/dist/components/Select/index.js +21 -20
- package/dist/components/TimePicker/index.cjs +21 -20
- package/dist/components/TimePicker/index.js +21 -20
- package/dist/components/index.cjs +196 -193
- package/dist/components/index.css +6 -6
- package/dist/components/index.js +196 -193
- package/dist/index.cjs +196 -193
- package/dist/index.css +6 -6
- package/dist/index.js +196 -193
- package/guidelines/MIGRATION.md +28 -30
- package/package.json +1 -1
|
@@ -55,26 +55,27 @@ var findScrollParent = (el) => {
|
|
|
55
55
|
}
|
|
56
56
|
return null;
|
|
57
57
|
};
|
|
58
|
+
var TRIGGER_GAP = 8;
|
|
58
59
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
59
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
60
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
60
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
61
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
61
62
|
let direction;
|
|
62
63
|
let top;
|
|
63
64
|
let maxHeight = null;
|
|
64
65
|
if (popH <= roomBelow) {
|
|
65
66
|
direction = "bottom";
|
|
66
|
-
top = triggerRect.bottom;
|
|
67
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
67
68
|
} else if (popH <= roomAbove) {
|
|
68
69
|
direction = "top";
|
|
69
|
-
top = triggerRect.top - popH;
|
|
70
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
70
71
|
} else {
|
|
71
72
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
72
73
|
if (roomBelow >= roomAbove) {
|
|
73
74
|
direction = "bottom";
|
|
74
|
-
top = triggerRect.bottom;
|
|
75
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
75
76
|
} else {
|
|
76
77
|
direction = "top";
|
|
77
|
-
top = triggerRect.top - room;
|
|
78
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
78
79
|
}
|
|
79
80
|
maxHeight = room;
|
|
80
81
|
}
|
|
@@ -229,22 +230,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
229
230
|
return () => document.removeEventListener("keydown", onKey);
|
|
230
231
|
}, [enabled, onEscape]);
|
|
231
232
|
};
|
|
232
|
-
var
|
|
233
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
233
234
|
const onCloseRef = import_react3.default.useRef(onClose);
|
|
234
235
|
onCloseRef.current = onClose;
|
|
235
236
|
import_react3.default.useEffect(() => {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return () =>
|
|
247
|
-
}, [enabled,
|
|
237
|
+
const trigger = triggerRef.current;
|
|
238
|
+
if (!enabled || !trigger) return;
|
|
239
|
+
const observer = new IntersectionObserver(
|
|
240
|
+
([entry]) => {
|
|
241
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
242
|
+
},
|
|
243
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
244
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
245
|
+
);
|
|
246
|
+
observer.observe(trigger);
|
|
247
|
+
return () => observer.disconnect();
|
|
248
|
+
}, [enabled, triggerRef]);
|
|
248
249
|
};
|
|
249
250
|
|
|
250
251
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
@@ -274,7 +275,7 @@ var Dropdown = (props) => {
|
|
|
274
275
|
const menuRef = import_react4.default.useRef(null);
|
|
275
276
|
useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
276
277
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
277
|
-
|
|
278
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, () => setIsOpen(false));
|
|
278
279
|
useEscapeKey(isOpen, () => {
|
|
279
280
|
setIsOpen(false);
|
|
280
281
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
box-shadow: var(--semantic-shadow-md);
|
|
20
20
|
padding: var(--spacing-space-1) 0;
|
|
21
21
|
opacity: 0;
|
|
22
|
-
transform: translateY(
|
|
22
|
+
transform: translateY(4px);
|
|
23
23
|
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
24
24
|
}
|
|
25
25
|
.lib-xplat-dropdown-menu.bottom {
|
|
26
|
-
transform: translateY(4px);
|
|
26
|
+
transform: translateY(-4px);
|
|
27
27
|
}
|
|
28
28
|
.lib-xplat-dropdown-menu.visible {
|
|
29
29
|
opacity: 1;
|
|
@@ -19,26 +19,27 @@ var findScrollParent = (el) => {
|
|
|
19
19
|
}
|
|
20
20
|
return null;
|
|
21
21
|
};
|
|
22
|
+
var TRIGGER_GAP = 8;
|
|
22
23
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
23
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
24
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
24
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
25
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
25
26
|
let direction;
|
|
26
27
|
let top;
|
|
27
28
|
let maxHeight = null;
|
|
28
29
|
if (popH <= roomBelow) {
|
|
29
30
|
direction = "bottom";
|
|
30
|
-
top = triggerRect.bottom;
|
|
31
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
31
32
|
} else if (popH <= roomAbove) {
|
|
32
33
|
direction = "top";
|
|
33
|
-
top = triggerRect.top - popH;
|
|
34
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
34
35
|
} else {
|
|
35
36
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
36
37
|
if (roomBelow >= roomAbove) {
|
|
37
38
|
direction = "bottom";
|
|
38
|
-
top = triggerRect.bottom;
|
|
39
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
39
40
|
} else {
|
|
40
41
|
direction = "top";
|
|
41
|
-
top = triggerRect.top - room;
|
|
42
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
42
43
|
}
|
|
43
44
|
maxHeight = room;
|
|
44
45
|
}
|
|
@@ -193,22 +194,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
193
194
|
return () => document.removeEventListener("keydown", onKey);
|
|
194
195
|
}, [enabled, onEscape]);
|
|
195
196
|
};
|
|
196
|
-
var
|
|
197
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
197
198
|
const onCloseRef = React3.useRef(onClose);
|
|
198
199
|
onCloseRef.current = onClose;
|
|
199
200
|
React3.useEffect(() => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return () =>
|
|
211
|
-
}, [enabled,
|
|
201
|
+
const trigger = triggerRef.current;
|
|
202
|
+
if (!enabled || !trigger) return;
|
|
203
|
+
const observer = new IntersectionObserver(
|
|
204
|
+
([entry]) => {
|
|
205
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
206
|
+
},
|
|
207
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
208
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
209
|
+
);
|
|
210
|
+
observer.observe(trigger);
|
|
211
|
+
return () => observer.disconnect();
|
|
212
|
+
}, [enabled, triggerRef]);
|
|
212
213
|
};
|
|
213
214
|
|
|
214
215
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
@@ -238,7 +239,7 @@ var Dropdown = (props) => {
|
|
|
238
239
|
const menuRef = React4.useRef(null);
|
|
239
240
|
useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
240
241
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
241
|
-
|
|
242
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, () => setIsOpen(false));
|
|
242
243
|
useEscapeKey(isOpen, () => {
|
|
243
244
|
setIsOpen(false);
|
|
244
245
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -35,11 +35,16 @@ __export(Modal_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(Modal_exports);
|
|
36
36
|
|
|
37
37
|
// src/components/Modal/Modal.tsx
|
|
38
|
-
var
|
|
38
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
39
39
|
var import_react_dom = require("react-dom");
|
|
40
40
|
|
|
41
41
|
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
42
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
43
|
+
|
|
44
|
+
// src/tokens/hooks/useAutoPosition.ts
|
|
42
45
|
var import_react = __toESM(require("react"), 1);
|
|
46
|
+
|
|
47
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
43
48
|
var FOCUSABLE = [
|
|
44
49
|
"a[href]",
|
|
45
50
|
"button:not([disabled])",
|
|
@@ -53,7 +58,7 @@ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
|
53
58
|
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
54
59
|
);
|
|
55
60
|
var useEscapeKey = (enabled, onEscape) => {
|
|
56
|
-
|
|
61
|
+
import_react2.default.useEffect(() => {
|
|
57
62
|
if (!enabled) return;
|
|
58
63
|
const onKey = (e) => {
|
|
59
64
|
if (e.key !== "Escape") return;
|
|
@@ -67,8 +72,8 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
67
72
|
};
|
|
68
73
|
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
69
74
|
const { trap = false, initialFocus } = options;
|
|
70
|
-
const restoreRef =
|
|
71
|
-
|
|
75
|
+
const restoreRef = import_react2.default.useRef(null);
|
|
76
|
+
import_react2.default.useEffect(() => {
|
|
72
77
|
if (!enabled) return;
|
|
73
78
|
restoreRef.current = document.activeElement;
|
|
74
79
|
const raf = requestAnimationFrame(() => {
|
|
@@ -86,7 +91,7 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
|
86
91
|
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
87
92
|
};
|
|
88
93
|
}, [enabled, containerRef, initialFocus]);
|
|
89
|
-
|
|
94
|
+
import_react2.default.useEffect(() => {
|
|
90
95
|
if (!enabled || !trap) return;
|
|
91
96
|
const onKey = (e) => {
|
|
92
97
|
if (e.key !== "Tab") return;
|
|
@@ -134,13 +139,13 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
134
139
|
var ANIMATION_DURATION_MS = 200;
|
|
135
140
|
var Modal = (props) => {
|
|
136
141
|
const { isOpen, onClose, children } = props;
|
|
137
|
-
const [mounted, setMounted] =
|
|
138
|
-
const [visible, setVisible] =
|
|
139
|
-
const [settled, setSettled] =
|
|
140
|
-
const boxRef =
|
|
142
|
+
const [mounted, setMounted] = import_react3.default.useState(false);
|
|
143
|
+
const [visible, setVisible] = import_react3.default.useState(false);
|
|
144
|
+
const [settled, setSettled] = import_react3.default.useState(false);
|
|
145
|
+
const boxRef = import_react3.default.useRef(null);
|
|
141
146
|
useEscapeKey(isOpen, onClose);
|
|
142
147
|
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
143
|
-
|
|
148
|
+
import_react3.default.useEffect(() => {
|
|
144
149
|
if (isOpen) {
|
|
145
150
|
setMounted(true);
|
|
146
151
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
// src/components/Modal/Modal.tsx
|
|
2
|
-
import
|
|
2
|
+
import React3 from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
|
|
5
5
|
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
6
|
+
import React2 from "react";
|
|
7
|
+
|
|
8
|
+
// src/tokens/hooks/useAutoPosition.ts
|
|
6
9
|
import React from "react";
|
|
10
|
+
|
|
11
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
7
12
|
var FOCUSABLE = [
|
|
8
13
|
"a[href]",
|
|
9
14
|
"button:not([disabled])",
|
|
@@ -17,7 +22,7 @@ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
|
17
22
|
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
18
23
|
);
|
|
19
24
|
var useEscapeKey = (enabled, onEscape) => {
|
|
20
|
-
|
|
25
|
+
React2.useEffect(() => {
|
|
21
26
|
if (!enabled) return;
|
|
22
27
|
const onKey = (e) => {
|
|
23
28
|
if (e.key !== "Escape") return;
|
|
@@ -31,8 +36,8 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
31
36
|
};
|
|
32
37
|
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
33
38
|
const { trap = false, initialFocus } = options;
|
|
34
|
-
const restoreRef =
|
|
35
|
-
|
|
39
|
+
const restoreRef = React2.useRef(null);
|
|
40
|
+
React2.useEffect(() => {
|
|
36
41
|
if (!enabled) return;
|
|
37
42
|
restoreRef.current = document.activeElement;
|
|
38
43
|
const raf = requestAnimationFrame(() => {
|
|
@@ -50,7 +55,7 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
|
50
55
|
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
51
56
|
};
|
|
52
57
|
}, [enabled, containerRef, initialFocus]);
|
|
53
|
-
|
|
58
|
+
React2.useEffect(() => {
|
|
54
59
|
if (!enabled || !trap) return;
|
|
55
60
|
const onKey = (e) => {
|
|
56
61
|
if (e.key !== "Tab") return;
|
|
@@ -98,13 +103,13 @@ import { jsx } from "react/jsx-runtime";
|
|
|
98
103
|
var ANIMATION_DURATION_MS = 200;
|
|
99
104
|
var Modal = (props) => {
|
|
100
105
|
const { isOpen, onClose, children } = props;
|
|
101
|
-
const [mounted, setMounted] =
|
|
102
|
-
const [visible, setVisible] =
|
|
103
|
-
const [settled, setSettled] =
|
|
104
|
-
const boxRef =
|
|
106
|
+
const [mounted, setMounted] = React3.useState(false);
|
|
107
|
+
const [visible, setVisible] = React3.useState(false);
|
|
108
|
+
const [settled, setSettled] = React3.useState(false);
|
|
109
|
+
const boxRef = React3.useRef(null);
|
|
105
110
|
useEscapeKey(isOpen, onClose);
|
|
106
111
|
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
107
|
-
|
|
112
|
+
React3.useEffect(() => {
|
|
108
113
|
if (isOpen) {
|
|
109
114
|
setMounted(true);
|
|
110
115
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -55,26 +55,27 @@ var findScrollParent = (el) => {
|
|
|
55
55
|
}
|
|
56
56
|
return null;
|
|
57
57
|
};
|
|
58
|
+
var TRIGGER_GAP = 8;
|
|
58
59
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
59
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
60
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
60
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
61
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
61
62
|
let direction;
|
|
62
63
|
let top;
|
|
63
64
|
let maxHeight = null;
|
|
64
65
|
if (popH <= roomBelow) {
|
|
65
66
|
direction = "bottom";
|
|
66
|
-
top = triggerRect.bottom;
|
|
67
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
67
68
|
} else if (popH <= roomAbove) {
|
|
68
69
|
direction = "top";
|
|
69
|
-
top = triggerRect.top - popH;
|
|
70
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
70
71
|
} else {
|
|
71
72
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
72
73
|
if (roomBelow >= roomAbove) {
|
|
73
74
|
direction = "bottom";
|
|
74
|
-
top = triggerRect.bottom;
|
|
75
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
75
76
|
} else {
|
|
76
77
|
direction = "top";
|
|
77
|
-
top = triggerRect.top - room;
|
|
78
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
78
79
|
}
|
|
79
80
|
maxHeight = room;
|
|
80
81
|
}
|
|
@@ -229,22 +230,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
229
230
|
return () => document.removeEventListener("keydown", onKey);
|
|
230
231
|
}, [enabled, onEscape]);
|
|
231
232
|
};
|
|
232
|
-
var
|
|
233
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
233
234
|
const onCloseRef = import_react3.default.useRef(onClose);
|
|
234
235
|
onCloseRef.current = onClose;
|
|
235
236
|
import_react3.default.useEffect(() => {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return () =>
|
|
247
|
-
}, [enabled,
|
|
237
|
+
const trigger = triggerRef.current;
|
|
238
|
+
if (!enabled || !trigger) return;
|
|
239
|
+
const observer = new IntersectionObserver(
|
|
240
|
+
([entry]) => {
|
|
241
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
242
|
+
},
|
|
243
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
244
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
245
|
+
);
|
|
246
|
+
observer.observe(trigger);
|
|
247
|
+
return () => observer.disconnect();
|
|
248
|
+
}, [enabled, triggerRef]);
|
|
248
249
|
};
|
|
249
250
|
|
|
250
251
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
@@ -272,7 +273,7 @@ var PopOver = (props) => {
|
|
|
272
273
|
const [localOpen, setLocalOpen] = import_react4.default.useState(false);
|
|
273
274
|
const [eventTrigger, setEventTrigger] = import_react4.default.useState(false);
|
|
274
275
|
useClickOutside_default([popRef, triggerRef], onClose, isOpen);
|
|
275
|
-
|
|
276
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, onClose);
|
|
276
277
|
useEscapeKey(isOpen, () => {
|
|
277
278
|
onClose();
|
|
278
279
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -19,26 +19,27 @@ var findScrollParent = (el) => {
|
|
|
19
19
|
}
|
|
20
20
|
return null;
|
|
21
21
|
};
|
|
22
|
+
var TRIGGER_GAP = 8;
|
|
22
23
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
23
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
24
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
24
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
25
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
25
26
|
let direction;
|
|
26
27
|
let top;
|
|
27
28
|
let maxHeight = null;
|
|
28
29
|
if (popH <= roomBelow) {
|
|
29
30
|
direction = "bottom";
|
|
30
|
-
top = triggerRect.bottom;
|
|
31
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
31
32
|
} else if (popH <= roomAbove) {
|
|
32
33
|
direction = "top";
|
|
33
|
-
top = triggerRect.top - popH;
|
|
34
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
34
35
|
} else {
|
|
35
36
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
36
37
|
if (roomBelow >= roomAbove) {
|
|
37
38
|
direction = "bottom";
|
|
38
|
-
top = triggerRect.bottom;
|
|
39
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
39
40
|
} else {
|
|
40
41
|
direction = "top";
|
|
41
|
-
top = triggerRect.top - room;
|
|
42
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
42
43
|
}
|
|
43
44
|
maxHeight = room;
|
|
44
45
|
}
|
|
@@ -193,22 +194,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
193
194
|
return () => document.removeEventListener("keydown", onKey);
|
|
194
195
|
}, [enabled, onEscape]);
|
|
195
196
|
};
|
|
196
|
-
var
|
|
197
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
197
198
|
const onCloseRef = React3.useRef(onClose);
|
|
198
199
|
onCloseRef.current = onClose;
|
|
199
200
|
React3.useEffect(() => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return () =>
|
|
211
|
-
}, [enabled,
|
|
201
|
+
const trigger = triggerRef.current;
|
|
202
|
+
if (!enabled || !trigger) return;
|
|
203
|
+
const observer = new IntersectionObserver(
|
|
204
|
+
([entry]) => {
|
|
205
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
206
|
+
},
|
|
207
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
208
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
209
|
+
);
|
|
210
|
+
observer.observe(trigger);
|
|
211
|
+
return () => observer.disconnect();
|
|
212
|
+
}, [enabled, triggerRef]);
|
|
212
213
|
};
|
|
213
214
|
|
|
214
215
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
@@ -236,7 +237,7 @@ var PopOver = (props) => {
|
|
|
236
237
|
const [localOpen, setLocalOpen] = React4.useState(false);
|
|
237
238
|
const [eventTrigger, setEventTrigger] = React4.useState(false);
|
|
238
239
|
useClickOutside_default([popRef, triggerRef], onClose, isOpen);
|
|
239
|
-
|
|
240
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, onClose);
|
|
240
241
|
useEscapeKey(isOpen, () => {
|
|
241
242
|
onClose();
|
|
242
243
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -56,26 +56,27 @@ var findScrollParent = (el) => {
|
|
|
56
56
|
}
|
|
57
57
|
return null;
|
|
58
58
|
};
|
|
59
|
+
var TRIGGER_GAP = 8;
|
|
59
60
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
60
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
61
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
61
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
62
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
62
63
|
let direction;
|
|
63
64
|
let top;
|
|
64
65
|
let maxHeight = null;
|
|
65
66
|
if (popH <= roomBelow) {
|
|
66
67
|
direction = "bottom";
|
|
67
|
-
top = triggerRect.bottom;
|
|
68
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
68
69
|
} else if (popH <= roomAbove) {
|
|
69
70
|
direction = "top";
|
|
70
|
-
top = triggerRect.top - popH;
|
|
71
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
71
72
|
} else {
|
|
72
73
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
73
74
|
if (roomBelow >= roomAbove) {
|
|
74
75
|
direction = "bottom";
|
|
75
|
-
top = triggerRect.bottom;
|
|
76
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
76
77
|
} else {
|
|
77
78
|
direction = "top";
|
|
78
|
-
top = triggerRect.top - room;
|
|
79
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
79
80
|
}
|
|
80
81
|
maxHeight = room;
|
|
81
82
|
}
|
|
@@ -230,22 +231,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
230
231
|
return () => document.removeEventListener("keydown", onKey);
|
|
231
232
|
}, [enabled, onEscape]);
|
|
232
233
|
};
|
|
233
|
-
var
|
|
234
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
234
235
|
const onCloseRef = import_react3.default.useRef(onClose);
|
|
235
236
|
onCloseRef.current = onClose;
|
|
236
237
|
import_react3.default.useEffect(() => {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return () =>
|
|
248
|
-
}, [enabled,
|
|
238
|
+
const trigger = triggerRef.current;
|
|
239
|
+
if (!enabled || !trigger) return;
|
|
240
|
+
const observer = new IntersectionObserver(
|
|
241
|
+
([entry]) => {
|
|
242
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
243
|
+
},
|
|
244
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
245
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
246
|
+
);
|
|
247
|
+
observer.observe(trigger);
|
|
248
|
+
return () => observer.disconnect();
|
|
249
|
+
}, [enabled, triggerRef]);
|
|
249
250
|
};
|
|
250
251
|
|
|
251
252
|
// src/tokens/svg/action/CopyIcon.tsx
|
|
@@ -1403,7 +1404,7 @@ var SelectRoot = (props) => {
|
|
|
1403
1404
|
}, []);
|
|
1404
1405
|
const toggle = import_react6.default.useCallback(() => setOpen((prev) => !prev), []);
|
|
1405
1406
|
useClickOutside_default([contentRef, triggerRef], close, isOpen);
|
|
1406
|
-
|
|
1407
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, close);
|
|
1407
1408
|
useEscapeKey(isOpen, () => {
|
|
1408
1409
|
close();
|
|
1409
1410
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
transition: transform 0.2s ease, opacity 0.2s ease;
|
|
213
213
|
}
|
|
214
214
|
.lib-xplat-select-content.bottom {
|
|
215
|
-
transform: translateY(
|
|
215
|
+
transform: translateY(-4px);
|
|
216
216
|
}
|
|
217
217
|
.lib-xplat-select-content.bottom.visible {
|
|
218
218
|
opacity: 1;
|
|
@@ -220,12 +220,12 @@
|
|
|
220
220
|
}
|
|
221
221
|
.lib-xplat-select-content.bottom.exit {
|
|
222
222
|
opacity: 0;
|
|
223
|
-
transform: translateY(
|
|
223
|
+
transform: translateY(-4px);
|
|
224
224
|
}
|
|
225
225
|
.lib-xplat-select-content {
|
|
226
226
|
}
|
|
227
227
|
.lib-xplat-select-content.top {
|
|
228
|
-
transform: translateY(
|
|
228
|
+
transform: translateY(4px);
|
|
229
229
|
}
|
|
230
230
|
.lib-xplat-select-content.top.visible {
|
|
231
231
|
opacity: 1;
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
}
|
|
234
234
|
.lib-xplat-select-content.top.exit {
|
|
235
235
|
opacity: 0;
|
|
236
|
-
transform: translateY(
|
|
236
|
+
transform: translateY(4px);
|
|
237
237
|
}
|
|
238
238
|
.lib-xplat-select-content.sm .select-item {
|
|
239
239
|
padding: var(--spacing-space-2) var(--spacing-space-2);
|
|
@@ -19,26 +19,27 @@ var findScrollParent = (el) => {
|
|
|
19
19
|
}
|
|
20
20
|
return null;
|
|
21
21
|
};
|
|
22
|
+
var TRIGGER_GAP = 8;
|
|
22
23
|
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
23
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
24
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
24
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
25
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
25
26
|
let direction;
|
|
26
27
|
let top;
|
|
27
28
|
let maxHeight = null;
|
|
28
29
|
if (popH <= roomBelow) {
|
|
29
30
|
direction = "bottom";
|
|
30
|
-
top = triggerRect.bottom;
|
|
31
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
31
32
|
} else if (popH <= roomAbove) {
|
|
32
33
|
direction = "top";
|
|
33
|
-
top = triggerRect.top - popH;
|
|
34
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
34
35
|
} else {
|
|
35
36
|
const room = Math.max(roomBelow, roomAbove, 0);
|
|
36
37
|
if (roomBelow >= roomAbove) {
|
|
37
38
|
direction = "bottom";
|
|
38
|
-
top = triggerRect.bottom;
|
|
39
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
39
40
|
} else {
|
|
40
41
|
direction = "top";
|
|
41
|
-
top = triggerRect.top - room;
|
|
42
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
42
43
|
}
|
|
43
44
|
maxHeight = room;
|
|
44
45
|
}
|
|
@@ -193,22 +194,22 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
193
194
|
return () => document.removeEventListener("keydown", onKey);
|
|
194
195
|
}, [enabled, onEscape]);
|
|
195
196
|
};
|
|
196
|
-
var
|
|
197
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
197
198
|
const onCloseRef = React3.useRef(onClose);
|
|
198
199
|
onCloseRef.current = onClose;
|
|
199
200
|
React3.useEffect(() => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return () =>
|
|
211
|
-
}, [enabled,
|
|
201
|
+
const trigger = triggerRef.current;
|
|
202
|
+
if (!enabled || !trigger) return;
|
|
203
|
+
const observer = new IntersectionObserver(
|
|
204
|
+
([entry]) => {
|
|
205
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
206
|
+
},
|
|
207
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
208
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
209
|
+
);
|
|
210
|
+
observer.observe(trigger);
|
|
211
|
+
return () => observer.disconnect();
|
|
212
|
+
}, [enabled, triggerRef]);
|
|
212
213
|
};
|
|
213
214
|
|
|
214
215
|
// src/tokens/svg/action/CopyIcon.tsx
|
|
@@ -1366,7 +1367,7 @@ var SelectRoot = (props) => {
|
|
|
1366
1367
|
}, []);
|
|
1367
1368
|
const toggle = React6.useCallback(() => setOpen((prev) => !prev), []);
|
|
1368
1369
|
useClickOutside_default([contentRef, triggerRef], close, isOpen);
|
|
1369
|
-
|
|
1370
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, close);
|
|
1370
1371
|
useEscapeKey(isOpen, () => {
|
|
1371
1372
|
close();
|
|
1372
1373
|
triggerRef.current?.focus({ preventScroll: true });
|