@x-plat/design-system 0.5.10 → 0.5.12

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.
@@ -35,7 +35,7 @@ __export(Dropdown_exports, {
35
35
  module.exports = __toCommonJS(Dropdown_exports);
36
36
 
37
37
  // src/components/Dropdown/Dropdown.tsx
38
- var import_react3 = __toESM(require("react"), 1);
38
+ var import_react4 = __toESM(require("react"), 1);
39
39
 
40
40
  // src/tokens/hooks/useAutoPosition.ts
41
41
  var import_react = __toESM(require("react"), 1);
@@ -48,28 +48,38 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
48
48
  if (!triggerRef.current || !popRef.current) return;
49
49
  const triggerRect = triggerRef.current.getBoundingClientRect();
50
50
  const popRect = popRef.current.getBoundingClientRect();
51
- const viewportWidth = window.innerWidth;
52
51
  const viewportHeight = window.innerHeight;
53
- const position2 = {};
52
+ const viewportWidth = window.innerWidth;
54
53
  let direction = "bottom";
55
- if (triggerRect.bottom + popRect.height > viewportHeight) {
54
+ let top;
55
+ let left = triggerRect.left;
56
+ if (triggerRect.bottom + popRect.height > viewportHeight && triggerRect.top - popRect.height > 0) {
56
57
  direction = "top";
58
+ top = triggerRect.top - popRect.height;
59
+ } else {
60
+ top = triggerRect.bottom;
57
61
  }
58
- if (triggerRect.left + popRect.width > viewportWidth) {
59
- position2["right"] = 10;
60
- }
61
- if (triggerRect.left < 0) {
62
- position2["left"] = 10;
62
+ if (left + popRect.width > viewportWidth) {
63
+ left = viewportWidth - popRect.width - 8;
63
64
  }
65
+ if (left < 8) left = 8;
64
66
  setPosition({
65
- position: position2,
67
+ position: { top, left, width: triggerRect.width },
66
68
  direction
67
69
  });
68
70
  }, [triggerRef, popRef]);
69
71
  import_react.default.useEffect(() => {
70
- calculatePosition();
72
+ if (!enabled) return;
73
+ const raf = requestAnimationFrame(() => {
74
+ calculatePosition();
75
+ });
71
76
  window.addEventListener("resize", calculatePosition);
72
- return () => window.removeEventListener("resize", calculatePosition);
77
+ window.addEventListener("scroll", calculatePosition, true);
78
+ return () => {
79
+ cancelAnimationFrame(raf);
80
+ window.removeEventListener("resize", calculatePosition);
81
+ window.removeEventListener("scroll", calculatePosition, true);
82
+ };
73
83
  }, [calculatePosition, enabled]);
74
84
  return position;
75
85
  };
@@ -100,6 +110,24 @@ var useClickOutside = (refs, handler, enabled = true) => {
100
110
  };
101
111
  var useClickOutside_default = useClickOutside;
102
112
 
113
+ // src/tokens/hooks/Portal.tsx
114
+ var import_react3 = __toESM(require("react"), 1);
115
+ var import_react_dom = __toESM(require("react-dom"), 1);
116
+ var import_jsx_runtime = require("react/jsx-runtime");
117
+ var PortalContainerContext = import_react3.default.createContext(null);
118
+ var Portal = ({ children }) => {
119
+ const contextContainer = import_react3.default.useContext(PortalContainerContext);
120
+ const [fallback, setFallback] = import_react3.default.useState(null);
121
+ import_react3.default.useEffect(() => {
122
+ if (!contextContainer) setFallback(document.body);
123
+ }, [contextContainer]);
124
+ const container = contextContainer ?? fallback;
125
+ if (!container) return null;
126
+ return import_react_dom.default.createPortal(children, container);
127
+ };
128
+ Portal.displayName = "Portal";
129
+ var Portal_default = Portal;
130
+
103
131
  // ../../node_modules/clsx/dist/clsx.mjs
104
132
  function r(e) {
105
133
  var t, f, n = "";
@@ -117,17 +145,17 @@ function clsx() {
117
145
  var clsx_default = clsx;
118
146
 
119
147
  // src/components/Dropdown/Dropdown.tsx
120
- var import_jsx_runtime = require("react/jsx-runtime");
148
+ var import_jsx_runtime2 = require("react/jsx-runtime");
121
149
  var Dropdown = (props) => {
122
150
  const { items, children } = props;
123
- const [isOpen, setIsOpen] = import_react3.default.useState(false);
124
- const [mounted, setMounted] = import_react3.default.useState(false);
125
- const [visible, setVisible] = import_react3.default.useState(false);
126
- const triggerRef = import_react3.default.useRef(null);
127
- const menuRef = import_react3.default.useRef(null);
128
- const { position, direction } = useAutoPosition_default(triggerRef, menuRef, isOpen);
129
- useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false));
130
- import_react3.default.useEffect(() => {
151
+ const [isOpen, setIsOpen] = import_react4.default.useState(false);
152
+ const [mounted, setMounted] = import_react4.default.useState(false);
153
+ const [visible, setVisible] = import_react4.default.useState(false);
154
+ const triggerRef = import_react4.default.useRef(null);
155
+ const menuRef = import_react4.default.useRef(null);
156
+ const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
157
+ useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
158
+ import_react4.default.useEffect(() => {
131
159
  if (isOpen) {
132
160
  setMounted(true);
133
161
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -142,8 +170,8 @@ var Dropdown = (props) => {
142
170
  item.onClick?.();
143
171
  setIsOpen(false);
144
172
  };
145
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-dropdown", children: [
146
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
173
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "lib-xplat-dropdown", children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
147
175
  "div",
148
176
  {
149
177
  ref: triggerRef,
@@ -152,14 +180,14 @@ var Dropdown = (props) => {
152
180
  children
153
181
  }
154
182
  ),
155
- mounted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
183
+ mounted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
156
184
  "div",
157
185
  {
158
186
  ref: menuRef,
159
- className: clsx_default("dropdown-menu", direction, { visible }),
187
+ className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
160
188
  style: { top: position.top, left: position.left },
161
189
  role: "menu",
162
- children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
190
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
163
191
  "button",
164
192
  {
165
193
  className: clsx_default("dropdown-item", {
@@ -174,7 +202,7 @@ var Dropdown = (props) => {
174
202
  item.key
175
203
  ))
176
204
  }
177
- )
205
+ ) })
178
206
  ] });
179
207
  };
180
208
  Dropdown.displayName = "Dropdown";
@@ -7,9 +7,9 @@
7
7
  .lib-xplat-dropdown .dropdown-trigger {
8
8
  cursor: pointer;
9
9
  }
10
- .lib-xplat-dropdown .dropdown-menu {
11
- position: absolute;
12
- z-index: 100;
10
+ .lib-xplat-dropdown-menu {
11
+ position: fixed;
12
+ z-index: 1000;
13
13
  min-width: 160px;
14
14
  background: var(--semantic-surface-neutral-default);
15
15
  border: 1px solid var(--semantic-border-default);
@@ -20,14 +20,14 @@
20
20
  transform: translateY(-4px);
21
21
  transition: opacity 0.15s ease, transform 0.15s ease;
22
22
  }
23
- .lib-xplat-dropdown .dropdown-menu.bottom {
23
+ .lib-xplat-dropdown-menu.bottom {
24
24
  transform: translateY(4px);
25
25
  }
26
- .lib-xplat-dropdown .dropdown-menu.visible {
26
+ .lib-xplat-dropdown-menu.visible {
27
27
  opacity: 1;
28
28
  transform: translateY(0);
29
29
  }
30
- .lib-xplat-dropdown .dropdown-item {
30
+ .lib-xplat-dropdown-menu .dropdown-item {
31
31
  display: flex;
32
32
  align-items: center;
33
33
  width: 100%;
@@ -40,16 +40,16 @@
40
40
  text-align: left;
41
41
  transition: background-color 0.15s;
42
42
  }
43
- .lib-xplat-dropdown .dropdown-item:hover:not(:disabled) {
43
+ .lib-xplat-dropdown-menu .dropdown-item:hover:not(:disabled) {
44
44
  background-color: var(--semantic-surface-neutral-subtle);
45
45
  }
46
- .lib-xplat-dropdown .dropdown-item.danger {
46
+ .lib-xplat-dropdown-menu .dropdown-item.danger {
47
47
  color: var(--semantic-text-error);
48
48
  }
49
- .lib-xplat-dropdown .dropdown-item.danger:hover:not(:disabled) {
49
+ .lib-xplat-dropdown-menu .dropdown-item.danger:hover:not(:disabled) {
50
50
  background-color: var(--semantic-surface-error-subtle);
51
51
  }
52
- .lib-xplat-dropdown .dropdown-item:disabled {
52
+ .lib-xplat-dropdown-menu .dropdown-item:disabled {
53
53
  color: var(--semantic-text-disabled);
54
54
  cursor: not-allowed;
55
55
  }
@@ -1,5 +1,5 @@
1
1
  // src/components/Dropdown/Dropdown.tsx
2
- import React3 from "react";
2
+ import React4 from "react";
3
3
 
4
4
  // src/tokens/hooks/useAutoPosition.ts
5
5
  import React from "react";
@@ -12,28 +12,38 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
12
12
  if (!triggerRef.current || !popRef.current) return;
13
13
  const triggerRect = triggerRef.current.getBoundingClientRect();
14
14
  const popRect = popRef.current.getBoundingClientRect();
15
- const viewportWidth = window.innerWidth;
16
15
  const viewportHeight = window.innerHeight;
17
- const position2 = {};
16
+ const viewportWidth = window.innerWidth;
18
17
  let direction = "bottom";
19
- if (triggerRect.bottom + popRect.height > viewportHeight) {
18
+ let top;
19
+ let left = triggerRect.left;
20
+ if (triggerRect.bottom + popRect.height > viewportHeight && triggerRect.top - popRect.height > 0) {
20
21
  direction = "top";
22
+ top = triggerRect.top - popRect.height;
23
+ } else {
24
+ top = triggerRect.bottom;
21
25
  }
22
- if (triggerRect.left + popRect.width > viewportWidth) {
23
- position2["right"] = 10;
24
- }
25
- if (triggerRect.left < 0) {
26
- position2["left"] = 10;
26
+ if (left + popRect.width > viewportWidth) {
27
+ left = viewportWidth - popRect.width - 8;
27
28
  }
29
+ if (left < 8) left = 8;
28
30
  setPosition({
29
- position: position2,
31
+ position: { top, left, width: triggerRect.width },
30
32
  direction
31
33
  });
32
34
  }, [triggerRef, popRef]);
33
35
  React.useEffect(() => {
34
- calculatePosition();
36
+ if (!enabled) return;
37
+ const raf = requestAnimationFrame(() => {
38
+ calculatePosition();
39
+ });
35
40
  window.addEventListener("resize", calculatePosition);
36
- return () => window.removeEventListener("resize", calculatePosition);
41
+ window.addEventListener("scroll", calculatePosition, true);
42
+ return () => {
43
+ cancelAnimationFrame(raf);
44
+ window.removeEventListener("resize", calculatePosition);
45
+ window.removeEventListener("scroll", calculatePosition, true);
46
+ };
37
47
  }, [calculatePosition, enabled]);
38
48
  return position;
39
49
  };
@@ -64,6 +74,24 @@ var useClickOutside = (refs, handler, enabled = true) => {
64
74
  };
65
75
  var useClickOutside_default = useClickOutside;
66
76
 
77
+ // src/tokens/hooks/Portal.tsx
78
+ import React3 from "react";
79
+ import ReactDOM from "react-dom";
80
+ import { jsx } from "react/jsx-runtime";
81
+ var PortalContainerContext = React3.createContext(null);
82
+ var Portal = ({ children }) => {
83
+ const contextContainer = React3.useContext(PortalContainerContext);
84
+ const [fallback, setFallback] = React3.useState(null);
85
+ React3.useEffect(() => {
86
+ if (!contextContainer) setFallback(document.body);
87
+ }, [contextContainer]);
88
+ const container = contextContainer ?? fallback;
89
+ if (!container) return null;
90
+ return ReactDOM.createPortal(children, container);
91
+ };
92
+ Portal.displayName = "Portal";
93
+ var Portal_default = Portal;
94
+
67
95
  // ../../node_modules/clsx/dist/clsx.mjs
68
96
  function r(e) {
69
97
  var t, f, n = "";
@@ -81,17 +109,17 @@ function clsx() {
81
109
  var clsx_default = clsx;
82
110
 
83
111
  // src/components/Dropdown/Dropdown.tsx
84
- import { jsx, jsxs } from "react/jsx-runtime";
112
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
85
113
  var Dropdown = (props) => {
86
114
  const { items, children } = props;
87
- const [isOpen, setIsOpen] = React3.useState(false);
88
- const [mounted, setMounted] = React3.useState(false);
89
- const [visible, setVisible] = React3.useState(false);
90
- const triggerRef = React3.useRef(null);
91
- const menuRef = React3.useRef(null);
92
- const { position, direction } = useAutoPosition_default(triggerRef, menuRef, isOpen);
93
- useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false));
94
- React3.useEffect(() => {
115
+ const [isOpen, setIsOpen] = React4.useState(false);
116
+ const [mounted, setMounted] = React4.useState(false);
117
+ const [visible, setVisible] = React4.useState(false);
118
+ const triggerRef = React4.useRef(null);
119
+ const menuRef = React4.useRef(null);
120
+ const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
121
+ useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
122
+ React4.useEffect(() => {
95
123
  if (isOpen) {
96
124
  setMounted(true);
97
125
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -107,7 +135,7 @@ var Dropdown = (props) => {
107
135
  setIsOpen(false);
108
136
  };
109
137
  return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-dropdown", children: [
110
- /* @__PURE__ */ jsx(
138
+ /* @__PURE__ */ jsx2(
111
139
  "div",
112
140
  {
113
141
  ref: triggerRef,
@@ -116,14 +144,14 @@ var Dropdown = (props) => {
116
144
  children
117
145
  }
118
146
  ),
119
- mounted && /* @__PURE__ */ jsx(
147
+ mounted && /* @__PURE__ */ jsx2(Portal_default, { children: /* @__PURE__ */ jsx2(
120
148
  "div",
121
149
  {
122
150
  ref: menuRef,
123
- className: clsx_default("dropdown-menu", direction, { visible }),
151
+ className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
124
152
  style: { top: position.top, left: position.left },
125
153
  role: "menu",
126
- children: items.map((item) => /* @__PURE__ */ jsx(
154
+ children: items.map((item) => /* @__PURE__ */ jsx2(
127
155
  "button",
128
156
  {
129
157
  className: clsx_default("dropdown-item", {
@@ -138,7 +166,7 @@ var Dropdown = (props) => {
138
166
  item.key
139
167
  ))
140
168
  }
141
- )
169
+ ) })
142
170
  ] });
143
171
  };
144
172
  Dropdown.displayName = "Dropdown";
@@ -35,8 +35,26 @@ __export(Modal_exports, {
35
35
  module.exports = __toCommonJS(Modal_exports);
36
36
 
37
37
  // src/components/Modal/Modal.tsx
38
+ var import_react2 = __toESM(require("react"), 1);
39
+ var import_react_dom2 = require("react-dom");
40
+
41
+ // src/tokens/hooks/Portal.tsx
38
42
  var import_react = __toESM(require("react"), 1);
39
- var import_react_dom = require("react-dom");
43
+ var import_react_dom = __toESM(require("react-dom"), 1);
44
+ var import_jsx_runtime = require("react/jsx-runtime");
45
+ var PortalContainerContext = import_react.default.createContext(null);
46
+ var PortalProvider = ({ container, children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PortalContainerContext.Provider, { value: container, children });
47
+ var Portal = ({ children }) => {
48
+ const contextContainer = import_react.default.useContext(PortalContainerContext);
49
+ const [fallback, setFallback] = import_react.default.useState(null);
50
+ import_react.default.useEffect(() => {
51
+ if (!contextContainer) setFallback(document.body);
52
+ }, [contextContainer]);
53
+ const container = contextContainer ?? fallback;
54
+ if (!container) return null;
55
+ return import_react_dom.default.createPortal(children, container);
56
+ };
57
+ Portal.displayName = "Portal";
40
58
 
41
59
  // ../../node_modules/clsx/dist/clsx.mjs
42
60
  function r(e) {
@@ -55,13 +73,14 @@ function clsx() {
55
73
  var clsx_default = clsx;
56
74
 
57
75
  // src/components/Modal/Modal.tsx
58
- var import_jsx_runtime = require("react/jsx-runtime");
76
+ var import_jsx_runtime2 = require("react/jsx-runtime");
59
77
  var ANIMATION_DURATION_MS = 200;
60
78
  var Modal = (props) => {
61
79
  const { isOpen, onClose, children } = props;
62
- const [mounted, setMounted] = import_react.default.useState(false);
63
- const [visible, setVisible] = import_react.default.useState(false);
64
- import_react.default.useEffect(() => {
80
+ const [mounted, setMounted] = import_react2.default.useState(false);
81
+ const [visible, setVisible] = import_react2.default.useState(false);
82
+ const boxRef = import_react2.default.useRef(null);
83
+ import_react2.default.useEffect(() => {
65
84
  if (isOpen) {
66
85
  setMounted(true);
67
86
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -74,20 +93,21 @@ var Modal = (props) => {
74
93
  if (typeof document === "undefined") return null;
75
94
  if (!mounted) return null;
76
95
  const stateClass = visible ? "enter" : "exit";
77
- return (0, import_react_dom.createPortal)(
78
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
96
+ return (0, import_react_dom2.createPortal)(
97
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
79
98
  "div",
80
99
  {
81
100
  className: clsx_default("lib-xplat-modal", "dim", stateClass),
82
101
  onClick: onClose,
83
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
102
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
84
103
  "div",
85
104
  {
105
+ ref: boxRef,
86
106
  className: clsx_default("lib-xplat-modal", "modal-box", stateClass),
87
107
  role: "dialog",
88
108
  "aria-modal": "true",
89
109
  onClick: (e) => e.stopPropagation(),
90
- children
110
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PortalProvider, { container: boxRef.current, children })
91
111
  }
92
112
  )
93
113
  }
@@ -2,9 +2,6 @@ import React from 'react';
2
2
 
3
3
  interface ModalProps {
4
4
  isOpen: boolean;
5
- /**
6
- * open 값 false 로 변경 필수
7
- */
8
5
  onClose: () => void;
9
6
  children?: React.ReactNode;
10
7
  }
@@ -2,9 +2,6 @@ import React from 'react';
2
2
 
3
3
  interface ModalProps {
4
4
  isOpen: boolean;
5
- /**
6
- * open 값 false 로 변경 필수
7
- */
8
5
  onClose: () => void;
9
6
  children?: React.ReactNode;
10
7
  }
@@ -1,7 +1,25 @@
1
1
  // src/components/Modal/Modal.tsx
2
- import React from "react";
2
+ import React2 from "react";
3
3
  import { createPortal } from "react-dom";
4
4
 
5
+ // src/tokens/hooks/Portal.tsx
6
+ import React from "react";
7
+ import ReactDOM from "react-dom";
8
+ import { jsx } from "react/jsx-runtime";
9
+ var PortalContainerContext = React.createContext(null);
10
+ var PortalProvider = ({ container, children }) => /* @__PURE__ */ jsx(PortalContainerContext.Provider, { value: container, children });
11
+ var Portal = ({ children }) => {
12
+ const contextContainer = React.useContext(PortalContainerContext);
13
+ const [fallback, setFallback] = React.useState(null);
14
+ React.useEffect(() => {
15
+ if (!contextContainer) setFallback(document.body);
16
+ }, [contextContainer]);
17
+ const container = contextContainer ?? fallback;
18
+ if (!container) return null;
19
+ return ReactDOM.createPortal(children, container);
20
+ };
21
+ Portal.displayName = "Portal";
22
+
5
23
  // ../../node_modules/clsx/dist/clsx.mjs
6
24
  function r(e) {
7
25
  var t, f, n = "";
@@ -19,13 +37,14 @@ function clsx() {
19
37
  var clsx_default = clsx;
20
38
 
21
39
  // src/components/Modal/Modal.tsx
22
- import { jsx } from "react/jsx-runtime";
40
+ import { jsx as jsx2 } from "react/jsx-runtime";
23
41
  var ANIMATION_DURATION_MS = 200;
24
42
  var Modal = (props) => {
25
43
  const { isOpen, onClose, children } = props;
26
- const [mounted, setMounted] = React.useState(false);
27
- const [visible, setVisible] = React.useState(false);
28
- React.useEffect(() => {
44
+ const [mounted, setMounted] = React2.useState(false);
45
+ const [visible, setVisible] = React2.useState(false);
46
+ const boxRef = React2.useRef(null);
47
+ React2.useEffect(() => {
29
48
  if (isOpen) {
30
49
  setMounted(true);
31
50
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -39,19 +58,20 @@ var Modal = (props) => {
39
58
  if (!mounted) return null;
40
59
  const stateClass = visible ? "enter" : "exit";
41
60
  return createPortal(
42
- /* @__PURE__ */ jsx(
61
+ /* @__PURE__ */ jsx2(
43
62
  "div",
44
63
  {
45
64
  className: clsx_default("lib-xplat-modal", "dim", stateClass),
46
65
  onClick: onClose,
47
- children: /* @__PURE__ */ jsx(
66
+ children: /* @__PURE__ */ jsx2(
48
67
  "div",
49
68
  {
69
+ ref: boxRef,
50
70
  className: clsx_default("lib-xplat-modal", "modal-box", stateClass),
51
71
  role: "dialog",
52
72
  "aria-modal": "true",
53
73
  onClick: (e) => e.stopPropagation(),
54
- children
74
+ children: /* @__PURE__ */ jsx2(PortalProvider, { container: boxRef.current, children })
55
75
  }
56
76
  )
57
77
  }
@@ -35,7 +35,7 @@ __export(PopOver_exports, {
35
35
  module.exports = __toCommonJS(PopOver_exports);
36
36
 
37
37
  // src/components/PopOver/PopOver.tsx
38
- var import_react3 = __toESM(require("react"), 1);
38
+ var import_react4 = __toESM(require("react"), 1);
39
39
 
40
40
  // src/tokens/hooks/useAutoPosition.ts
41
41
  var import_react = __toESM(require("react"), 1);
@@ -48,28 +48,38 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
48
48
  if (!triggerRef.current || !popRef.current) return;
49
49
  const triggerRect = triggerRef.current.getBoundingClientRect();
50
50
  const popRect = popRef.current.getBoundingClientRect();
51
- const viewportWidth = window.innerWidth;
52
51
  const viewportHeight = window.innerHeight;
53
- const position2 = {};
52
+ const viewportWidth = window.innerWidth;
54
53
  let direction = "bottom";
55
- if (triggerRect.bottom + popRect.height > viewportHeight) {
54
+ let top;
55
+ let left = triggerRect.left;
56
+ if (triggerRect.bottom + popRect.height > viewportHeight && triggerRect.top - popRect.height > 0) {
56
57
  direction = "top";
58
+ top = triggerRect.top - popRect.height;
59
+ } else {
60
+ top = triggerRect.bottom;
57
61
  }
58
- if (triggerRect.left + popRect.width > viewportWidth) {
59
- position2["right"] = 10;
60
- }
61
- if (triggerRect.left < 0) {
62
- position2["left"] = 10;
62
+ if (left + popRect.width > viewportWidth) {
63
+ left = viewportWidth - popRect.width - 8;
63
64
  }
65
+ if (left < 8) left = 8;
64
66
  setPosition({
65
- position: position2,
67
+ position: { top, left, width: triggerRect.width },
66
68
  direction
67
69
  });
68
70
  }, [triggerRef, popRef]);
69
71
  import_react.default.useEffect(() => {
70
- calculatePosition();
72
+ if (!enabled) return;
73
+ const raf = requestAnimationFrame(() => {
74
+ calculatePosition();
75
+ });
71
76
  window.addEventListener("resize", calculatePosition);
72
- return () => window.removeEventListener("resize", calculatePosition);
77
+ window.addEventListener("scroll", calculatePosition, true);
78
+ return () => {
79
+ cancelAnimationFrame(raf);
80
+ window.removeEventListener("resize", calculatePosition);
81
+ window.removeEventListener("scroll", calculatePosition, true);
82
+ };
73
83
  }, [calculatePosition, enabled]);
74
84
  return position;
75
85
  };
@@ -100,6 +110,24 @@ var useClickOutside = (refs, handler, enabled = true) => {
100
110
  };
101
111
  var useClickOutside_default = useClickOutside;
102
112
 
113
+ // src/tokens/hooks/Portal.tsx
114
+ var import_react3 = __toESM(require("react"), 1);
115
+ var import_react_dom = __toESM(require("react-dom"), 1);
116
+ var import_jsx_runtime = require("react/jsx-runtime");
117
+ var PortalContainerContext = import_react3.default.createContext(null);
118
+ var Portal = ({ children }) => {
119
+ const contextContainer = import_react3.default.useContext(PortalContainerContext);
120
+ const [fallback, setFallback] = import_react3.default.useState(null);
121
+ import_react3.default.useEffect(() => {
122
+ if (!contextContainer) setFallback(document.body);
123
+ }, [contextContainer]);
124
+ const container = contextContainer ?? fallback;
125
+ if (!container) return null;
126
+ return import_react_dom.default.createPortal(children, container);
127
+ };
128
+ Portal.displayName = "Portal";
129
+ var Portal_default = Portal;
130
+
103
131
  // ../../node_modules/clsx/dist/clsx.mjs
104
132
  function r(e) {
105
133
  var t, f, n = "";
@@ -117,16 +145,16 @@ function clsx() {
117
145
  var clsx_default = clsx;
118
146
 
119
147
  // src/components/PopOver/PopOver.tsx
120
- var import_jsx_runtime = require("react/jsx-runtime");
148
+ var import_jsx_runtime2 = require("react/jsx-runtime");
121
149
  var PopOver = (props) => {
122
150
  const { children, isOpen, onClose, PopOverEl } = props;
123
- const popRef = import_react3.default.useRef(null);
124
- const triggerRef = import_react3.default.useRef(null);
125
- const [localOpen, setLocalOpen] = import_react3.default.useState(false);
126
- const [eventTrigger, setEventTrigger] = import_react3.default.useState(false);
151
+ const popRef = import_react4.default.useRef(null);
152
+ const triggerRef = import_react4.default.useRef(null);
153
+ const [localOpen, setLocalOpen] = import_react4.default.useState(false);
154
+ const [eventTrigger, setEventTrigger] = import_react4.default.useState(false);
127
155
  useClickOutside_default([popRef, triggerRef], onClose, isOpen);
128
156
  const position = useAutoPosition_default(triggerRef, popRef, localOpen);
129
- import_react3.default.useEffect(() => {
157
+ import_react4.default.useEffect(() => {
130
158
  if (isOpen) {
131
159
  setLocalOpen(isOpen);
132
160
  setTimeout(() => {
@@ -139,7 +167,7 @@ var PopOver = (props) => {
139
167
  }, 200);
140
168
  }
141
169
  }, [isOpen]);
142
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
170
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
143
171
  "div",
144
172
  {
145
173
  className: "lib-xplat-pop-over",
@@ -149,11 +177,11 @@ var PopOver = (props) => {
149
177
  },
150
178
  children: [
151
179
  children,
152
- localOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
180
+ localOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
153
181
  "div",
154
182
  {
155
183
  className: clsx_default(
156
- "content-wrap",
184
+ "lib-xplat-pop-over-content",
157
185
  position.direction,
158
186
  eventTrigger && "visible"
159
187
  ),
@@ -163,7 +191,7 @@ var PopOver = (props) => {
163
191
  },
164
192
  children: PopOverEl
165
193
  }
166
- )
194
+ ) })
167
195
  ]
168
196
  }
169
197
  );