@aster-ui/prefixed 0.12.86 → 0.12.88

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.
@@ -1,66 +1,66 @@
1
- import { jsxs as g, Fragment as F, jsx as t } from "react/jsx-runtime";
2
- import M, { useState as k, useRef as $, useCallback as N, useEffect as R, createContext as K, useContext as X } from "react";
3
- import { createPortal as Y } from "react-dom";
4
- import { useConfig as q } from "../providers/ConfigProvider.js";
5
- const E = "d-menu", D = "d-divider", j = K(null), P = () => {
6
- const e = X(j);
1
+ import { jsxs as w, Fragment as F, jsx as n } from "react/jsx-runtime";
2
+ import C, { useState as y, useRef as N, useCallback as E, useEffect as R, createContext as X, useContext as Y } from "react";
3
+ import { createPortal as q } from "react-dom";
4
+ import { useConfig as G } from "../providers/ConfigProvider.js";
5
+ const L = "d-menu", W = X(null), j = () => {
6
+ const e = Y(W);
7
7
  if (!e)
8
8
  throw new Error("ContextMenu compound components must be used within a ContextMenu");
9
9
  return e;
10
- }, W = ({
10
+ }, P = ({
11
11
  children: e,
12
- icon: l,
12
+ icon: s,
13
13
  disabled: a = !1,
14
14
  danger: c = !1,
15
- className: f = "",
16
- _key: s,
15
+ className: p = "",
16
+ _key: l,
17
17
  "data-testid": m
18
18
  }) => {
19
- const { onSelect: i, onClose: h, getTestId: o } = P(), d = m ?? (s ? o?.(`item-${s}`) : void 0);
20
- return /* @__PURE__ */ t("li", { className: f, role: "none", children: /* @__PURE__ */ g(
19
+ const { onSelect: i, onClose: h, getTestId: o } = j(), u = m ?? (l ? o?.(`item-${l}`) : void 0);
20
+ return /* @__PURE__ */ n("li", { className: p, role: "none", children: /* @__PURE__ */ w(
21
21
  "button",
22
22
  {
23
23
  onClick: () => {
24
- a || !s || (i(s), h());
24
+ a || !l || (i(l), h());
25
25
  },
26
26
  disabled: a,
27
27
  role: "menuitem",
28
28
  "aria-disabled": a,
29
- "data-testid": d,
29
+ "data-testid": u,
30
30
  className: `
31
31
  flex items-center gap-2 w-full px-4 py-2 text-left text-sm
32
32
  ${a ? "opacity-50 cursor-not-allowed" : "hover:bg-base-200"}
33
33
  ${c ? "text-error hover:bg-error/10" : ""}
34
34
  `,
35
35
  children: [
36
- l && /* @__PURE__ */ t("span", { className: "w-4 h-4", "aria-hidden": "true", children: l }),
37
- /* @__PURE__ */ t("span", { className: "flex-1", children: e })
36
+ s && /* @__PURE__ */ n("span", { className: "w-4 h-4", "aria-hidden": "true", children: s }),
37
+ /* @__PURE__ */ n("span", { className: "flex-1", children: e })
38
38
  ]
39
39
  }
40
40
  ) });
41
- }, G = ({ className: e = "", "data-testid": l }) => /* @__PURE__ */ t("li", { className: `${D} my-1 ${e}`, role: "separator", "data-testid": l }), I = ({
41
+ }, J = ({ className: e = "", "data-testid": s }) => /* @__PURE__ */ n("hr", { className: `border-base-300 my-1 ${e}`, role: "separator", "data-testid": s }), D = ({
42
42
  label: e,
43
- icon: l,
43
+ icon: s,
44
44
  disabled: a = !1,
45
45
  children: c,
46
- className: f = "",
47
- _key: s,
46
+ className: p = "",
47
+ _key: l,
48
48
  "data-testid": m
49
49
  }) => {
50
- const { getTestId: i } = P(), [h, o] = k(!1), d = $(null), u = m ?? (s ? i?.(`submenu-${s}`) : void 0), x = () => {
51
- a || (d.current && clearTimeout(d.current), o(!0));
52
- }, C = () => {
53
- d.current = setTimeout(() => o(!1), 100);
50
+ const { getTestId: i } = j(), [h, o] = y(!1), u = N(null), d = m ?? (l ? i?.(`submenu-${l}`) : void 0), f = () => {
51
+ a || (u.current && clearTimeout(u.current), o(!0));
52
+ }, x = () => {
53
+ u.current = setTimeout(() => o(!1), 100);
54
54
  };
55
- return /* @__PURE__ */ g(
55
+ return /* @__PURE__ */ w(
56
56
  "li",
57
57
  {
58
- onMouseEnter: x,
59
- onMouseLeave: C,
60
- className: `relative ${f}`,
58
+ onMouseEnter: f,
59
+ onMouseLeave: x,
60
+ className: `relative ${p}`,
61
61
  role: "none",
62
62
  children: [
63
- /* @__PURE__ */ g(
63
+ /* @__PURE__ */ w(
64
64
  "button",
65
65
  {
66
66
  disabled: a,
@@ -68,59 +68,59 @@ const E = "d-menu", D = "d-divider", j = K(null), P = () => {
68
68
  "aria-haspopup": "menu",
69
69
  "aria-expanded": h,
70
70
  "aria-disabled": a,
71
- "data-testid": u,
71
+ "data-testid": d,
72
72
  className: `
73
73
  flex items-center gap-2 w-full px-4 py-2 text-left text-sm
74
74
  ${a ? "opacity-50 cursor-not-allowed" : "hover:bg-base-200"}
75
75
  `,
76
76
  children: [
77
- l && /* @__PURE__ */ t("span", { className: "w-4 h-4", "aria-hidden": "true", children: l }),
78
- /* @__PURE__ */ t("span", { className: "flex-1", children: e }),
79
- /* @__PURE__ */ t("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
77
+ s && /* @__PURE__ */ n("span", { className: "w-4 h-4", "aria-hidden": "true", children: s }),
78
+ /* @__PURE__ */ n("span", { className: "flex-1", children: e }),
79
+ /* @__PURE__ */ n("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ n("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
80
80
  ]
81
81
  }
82
82
  ),
83
- h && /* @__PURE__ */ t(
83
+ h && /* @__PURE__ */ n(
84
84
  "ul",
85
85
  {
86
- className: `${E} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`,
87
- onMouseEnter: x,
88
- onMouseLeave: C,
86
+ className: `${L} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`,
87
+ onMouseEnter: f,
88
+ onMouseLeave: x,
89
89
  role: "menu",
90
- "data-testid": u ? `${u}-menu` : void 0,
90
+ "data-testid": d ? `${d}-menu` : void 0,
91
91
  children: c
92
92
  }
93
93
  )
94
94
  ]
95
95
  }
96
96
  );
97
- }, z = ({ item: e, onSelect: l, onClose: a, getTestId: c }) => {
98
- const [f, s] = k(!1), m = $(null), i = c?.(`item-${e.key}`);
97
+ }, V = ({ item: e, onSelect: s, onClose: a, getTestId: c }) => {
98
+ const [p, l] = y(!1), m = N(null), i = e["data-testid"] ?? c?.(`item-${e.key}`);
99
99
  if (e.divider)
100
- return /* @__PURE__ */ t("li", { className: `${D} my-1`, role: "separator", "data-testid": c?.(`separator-${e.key}`) });
100
+ return /* @__PURE__ */ n("hr", { className: "border-base-300 my-1", role: "separator", "data-testid": c?.(`separator-${e.key}`) });
101
101
  const h = () => {
102
- e.disabled || e.children && e.children.length > 0 || (l(e.key), a());
103
- }, o = e.children && e.children.length > 0, d = () => {
104
- o && (m.current && clearTimeout(m.current), s(!0));
105
- }, u = () => {
106
- o && (m.current = setTimeout(() => s(!1), 100));
102
+ e.disabled || e.children && e.children.length > 0 || (s(e.key), a());
103
+ }, o = e.children && e.children.length > 0, u = () => {
104
+ o && (m.current && clearTimeout(m.current), l(!0));
105
+ }, d = () => {
106
+ o && (m.current = setTimeout(() => l(!1), 100));
107
107
  };
108
- return /* @__PURE__ */ g(
108
+ return /* @__PURE__ */ w(
109
109
  "li",
110
110
  {
111
- onMouseEnter: d,
112
- onMouseLeave: u,
111
+ onMouseEnter: u,
112
+ onMouseLeave: d,
113
113
  className: "relative",
114
114
  role: "none",
115
115
  children: [
116
- /* @__PURE__ */ g(
116
+ /* @__PURE__ */ w(
117
117
  "button",
118
118
  {
119
119
  onClick: h,
120
120
  disabled: e.disabled,
121
121
  role: "menuitem",
122
122
  "aria-haspopup": o ? "menu" : void 0,
123
- "aria-expanded": o ? f : void 0,
123
+ "aria-expanded": o ? p : void 0,
124
124
  "aria-disabled": e.disabled,
125
125
  "data-testid": i,
126
126
  className: `
@@ -129,114 +129,107 @@ const E = "d-menu", D = "d-divider", j = K(null), P = () => {
129
129
  ${e.danger ? "text-error hover:bg-error/10" : ""}
130
130
  `,
131
131
  children: [
132
- e.icon && /* @__PURE__ */ t("span", { className: "w-4 h-4", "aria-hidden": "true", children: e.icon }),
133
- /* @__PURE__ */ t("span", { className: "flex-1", children: e.label }),
134
- o && /* @__PURE__ */ t("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
132
+ e.icon && /* @__PURE__ */ n("span", { className: "w-4 h-4", "aria-hidden": "true", children: e.icon }),
133
+ /* @__PURE__ */ n("span", { className: "flex-1", children: e.label }),
134
+ o && /* @__PURE__ */ n("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ n("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
135
135
  ]
136
136
  }
137
137
  ),
138
- o && f && /* @__PURE__ */ t(
138
+ o && p && /* @__PURE__ */ n(
139
139
  "ul",
140
140
  {
141
- className: `${E} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`,
142
- onMouseEnter: d,
143
- onMouseLeave: u,
141
+ className: `${L} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`,
142
+ onMouseEnter: u,
143
+ onMouseLeave: d,
144
144
  role: "menu",
145
145
  "data-testid": i ? `${i}-menu` : void 0,
146
- children: e.children.map((x) => /* @__PURE__ */ t(z, { item: x, onSelect: l, onClose: a, getTestId: c }, x.key))
146
+ children: e.children.map((f) => /* @__PURE__ */ n(V, { item: f, onSelect: s, onClose: a, getTestId: c }, f.key))
147
147
  }
148
148
  )
149
149
  ]
150
150
  }
151
151
  );
152
- }, J = ({
152
+ }, Q = ({
153
153
  children: e,
154
- items: l,
154
+ items: s,
155
155
  onSelect: a,
156
156
  disabled: c = !1,
157
- className: f = "",
158
- "data-testid": s
157
+ className: p = "",
158
+ "data-testid": l
159
159
  }) => {
160
- const { getPopupContainer: m } = q(), [i, h] = k(!1), [o, d] = k({ x: 0, y: 0 }), u = $(null), x = $(null), C = N(
161
- (n) => {
162
- if (c) return;
163
- n.preventDefault(), n.stopPropagation();
164
- let r = n.clientX, p = n.clientY;
165
- d({ x: r, y: p }), h(!0);
160
+ const { getPopupContainer: m } = G(), [i, h] = y(!1), [o, u] = y({ x: 0, y: 0 }), [d, f] = y(void 0), x = N(null), z = E(
161
+ (t) => {
162
+ c || (t.preventDefault(), t.stopPropagation(), u({ x: t.clientX, y: t.clientY }), f(typeof s == "function" ? s(t) : s), h(!0));
166
163
  },
167
- [c]
168
- ), b = N(() => {
164
+ [c, s]
165
+ ), v = E(() => {
169
166
  h(!1);
170
- }, []), L = N(
171
- (n) => {
172
- a?.(n);
167
+ }, []), S = E(
168
+ (t) => {
169
+ a?.(t);
173
170
  },
174
171
  [a]
175
172
  );
176
173
  R(() => {
177
- if (i && u.current) {
178
- const r = u.current.getBoundingClientRect(), p = window.innerWidth, v = window.innerHeight;
179
- let { x: w, y } = o;
180
- w + r.width > p && (w = p - r.width - 8), y + r.height > v && (y = v - r.height - 8), (w !== o.x || y !== o.y) && d({ x: w, y });
174
+ if (i && x.current) {
175
+ const r = x.current.getBoundingClientRect(), b = window.innerWidth, g = window.innerHeight;
176
+ let { x: k, y: $ } = o;
177
+ k + r.width > b && (k = b - r.width - 8), $ + r.height > g && ($ = g - r.height - 8), (k !== o.x || $ !== o.y) && u({ x: k, y: $ });
181
178
  }
182
179
  }, [i, o]), R(() => {
183
180
  if (!i) return;
184
- const n = (v) => {
185
- u.current && !u.current.contains(v.target) && b();
186
- }, r = (v) => {
187
- v.key === "Escape" && b();
188
- }, p = () => {
189
- b();
181
+ const t = (g) => {
182
+ x.current && !x.current.contains(g.target) && v();
183
+ }, r = (g) => {
184
+ g.key === "Escape" && v();
185
+ }, b = () => {
186
+ v();
190
187
  };
191
- return document.addEventListener("mousedown", n), document.addEventListener("keydown", r), document.addEventListener("scroll", p, !0), () => {
192
- document.removeEventListener("mousedown", n), document.removeEventListener("keydown", r), document.removeEventListener("scroll", p, !0);
188
+ return document.addEventListener("mousedown", t), document.addEventListener("keydown", r), document.addEventListener("scroll", b, !0), () => {
189
+ document.removeEventListener("mousedown", t), document.removeEventListener("keydown", r), document.removeEventListener("scroll", b, !0);
193
190
  };
194
- }, [i, b]);
195
- const B = (n) => M.Children.map(n, (r) => {
196
- if (M.isValidElement(r)) {
197
- const p = r.key != null ? String(r.key) : void 0;
198
- if (r.type === W || r.type === I)
199
- return M.cloneElement(r, { _key: p });
191
+ }, [i, v]);
192
+ const B = (t) => C.Children.map(t, (r) => {
193
+ if (C.isValidElement(r)) {
194
+ const b = r.key != null ? String(r.key) : void 0;
195
+ if (r.type === P || r.type === D)
196
+ return C.cloneElement(r, { _key: b });
200
197
  }
201
198
  return r;
202
- }), S = M.Children.toArray(e), V = S[0], A = B(S.slice(1)), H = l && l.length > 0, O = {
203
- onSelect: L,
204
- onClose: b,
205
- getTestId: s ? (n) => `${s}-${n}` : void 0
206
- }, T = (n) => s ? `${s}-${n}` : void 0;
207
- return /* @__PURE__ */ g(F, { children: [
208
- /* @__PURE__ */ t(
209
- "div",
210
- {
211
- ref: x,
212
- onContextMenu: C,
213
- className: "inline-block",
214
- "data-testid": s,
215
- children: V
216
- }
217
- ),
218
- i && Y(
219
- /* @__PURE__ */ t(j.Provider, { value: O, children: /* @__PURE__ */ t(
199
+ }), T = C.Children.toArray(e), M = T[0], H = B(T.slice(1)), A = d && d.length > 0, K = {
200
+ onSelect: S,
201
+ onClose: v,
202
+ getTestId: l ? (t) => `${l}-${t}` : void 0
203
+ }, I = (t) => l ? `${l}-${t}` : void 0, O = C.isValidElement(M) ? C.cloneElement(M, {
204
+ onContextMenu: (t) => {
205
+ const r = M.props.onContextMenu;
206
+ r && r(t), z(t);
207
+ }
208
+ }) : M;
209
+ return /* @__PURE__ */ w(F, { children: [
210
+ O,
211
+ i && q(
212
+ /* @__PURE__ */ n(W.Provider, { value: K, children: /* @__PURE__ */ n(
220
213
  "ul",
221
214
  {
222
- ref: u,
223
- className: `${E} bg-base-100 rounded-box shadow-lg border border-base-300 min-w-[160px] p-1 fixed z-[9999] ${f}`,
215
+ ref: x,
216
+ className: `${L} bg-base-100 rounded-box shadow-lg border border-base-300 min-w-[160px] p-1 fixed z-[9999] ${p}`,
224
217
  style: { left: o.x, top: o.y },
225
218
  role: "menu",
226
219
  "aria-label": "Context menu",
227
- "data-testid": T("menu"),
228
- children: H ? l.map((n) => /* @__PURE__ */ t(z, { item: n, onSelect: L, onClose: b, getTestId: T }, n.key)) : A
220
+ "data-testid": I("menu"),
221
+ children: A ? d.map((t) => /* @__PURE__ */ n(V, { item: t, onSelect: S, onClose: v, getTestId: I }, t.key)) : H
229
222
  }
230
223
  ) }),
231
224
  m ? m(document.body) : document.body
232
225
  )
233
226
  ] });
234
- }, ee = Object.assign(J, {
235
- Item: W,
236
- Divider: G,
237
- SubMenu: I
227
+ }, te = Object.assign(Q, {
228
+ Item: P,
229
+ Divider: J,
230
+ SubMenu: D
238
231
  });
239
232
  export {
240
- ee as ContextMenu
233
+ te as ContextMenu
241
234
  };
242
235
  //# sourceMappingURL=ContextMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.js","sources":["../../src/components/ContextMenu.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback, createContext, useContext } from 'react'\nimport { createPortal } from 'react-dom'\nimport { useConfig } from '../providers/ConfigProvider'\n\n// DaisyUI classes\nconst dMenu = 'd-menu'\nconst dDivider = 'd-divider'\n\nexport interface ContextMenuItem {\n key: string\n label: React.ReactNode\n icon?: React.ReactNode\n disabled?: boolean\n danger?: boolean\n divider?: boolean\n children?: ContextMenuItem[]\n}\n\nexport interface ContextMenuProps {\n /** Element that triggers the context menu on right-click */\n children: React.ReactNode\n /** Menu items (data-driven pattern) */\n items?: ContextMenuItem[]\n /** Callback when an item is selected */\n onSelect?: (key: string) => void\n /** Whether the context menu is disabled */\n disabled?: boolean\n /** Additional CSS classes for the menu */\n className?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuItemProps {\n /** Item content */\n children: React.ReactNode\n /** Icon to display before label */\n icon?: React.ReactNode\n /** Whether the item is disabled */\n disabled?: boolean\n /** Show as danger/destructive action */\n danger?: boolean\n /** Additional CSS classes */\n className?: string\n /** @internal */\n _key?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuDividerProps {\n /** Additional CSS classes */\n className?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuSubMenuProps {\n /** Submenu label */\n label: React.ReactNode\n /** Icon to display before label */\n icon?: React.ReactNode\n /** Whether the submenu is disabled */\n disabled?: boolean\n /** Submenu items */\n children: React.ReactNode\n /** Additional CSS classes */\n className?: string\n /** @internal */\n _key?: string\n 'data-testid'?: string\n}\n\ninterface ContextMenuContextValue {\n onSelect: (key: string) => void\n onClose: () => void\n getTestId?: (suffix: string) => string | undefined\n}\n\ninterface MenuPosition {\n x: number\n y: number\n}\n\nconst ContextMenuContext = createContext<ContextMenuContextValue | null>(null)\n\nconst useContextMenuContext = () => {\n const context = useContext(ContextMenuContext)\n if (!context) {\n throw new Error('ContextMenu compound components must be used within a ContextMenu')\n }\n return context\n}\n\n// Compound pattern components\nconst ContextMenuItemComponent: React.FC<ContextMenuItemProps> = ({\n children,\n icon,\n disabled = false,\n danger = false,\n className = '',\n _key,\n 'data-testid': testId,\n}) => {\n const { onSelect, onClose, getTestId } = useContextMenuContext()\n const itemTestId = testId ?? (_key ? getTestId?.(`item-${_key}`) : undefined)\n\n const handleClick = () => {\n if (disabled || !_key) return\n onSelect(_key)\n onClose()\n }\n\n return (\n <li className={className} role=\"none\">\n <button\n onClick={handleClick}\n disabled={disabled}\n role=\"menuitem\"\n aria-disabled={disabled}\n data-testid={itemTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n ${danger ? 'text-error hover:bg-error/10' : ''}\n `}\n >\n {icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n </button>\n </li>\n )\n}\n\nconst ContextMenuDividerComponent: React.FC<ContextMenuDividerProps> = ({ className = '', 'data-testid': testId }) => {\n return <li className={`${dDivider} my-1 ${className}`} role=\"separator\" data-testid={testId}></li>\n}\n\nconst ContextMenuSubMenuComponent: React.FC<ContextMenuSubMenuProps> = ({\n label,\n icon,\n disabled = false,\n children,\n className = '',\n _key: _unusedKey,\n 'data-testid': testId,\n}) => {\n const { getTestId } = useContextMenuContext()\n const [showSubmenu, setShowSubmenu] = useState(false)\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const submenuTestId = testId ?? (_unusedKey ? getTestId?.(`submenu-${_unusedKey}`) : undefined)\n\n const handleMouseEnter = () => {\n if (disabled) return\n if (timeoutRef.current) clearTimeout(timeoutRef.current)\n setShowSubmenu(true)\n }\n\n const handleMouseLeave = () => {\n timeoutRef.current = setTimeout(() => setShowSubmenu(false), 100)\n }\n\n return (\n <li\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className={`relative ${className}`}\n role=\"none\"\n >\n <button\n disabled={disabled}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={showSubmenu}\n aria-disabled={disabled}\n data-testid={submenuTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n `}\n >\n {icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{icon}</span>}\n <span className=\"flex-1\">{label}</span>\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n {showSubmenu && (\n <ul\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n role=\"menu\"\n data-testid={submenuTestId ? `${submenuTestId}-menu` : undefined}\n >\n {children}\n </ul>\n )}\n </li>\n )\n}\n\n// Data-driven pattern internal component\nconst MenuItem: React.FC<{\n item: ContextMenuItem\n onSelect: (key: string) => void\n onClose: () => void\n getTestId?: (suffix: string) => string | undefined\n}> = ({ item, onSelect, onClose, getTestId }) => {\n const [showSubmenu, setShowSubmenu] = useState(false)\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const itemTestId = getTestId?.(`item-${item.key}`)\n\n if (item.divider) {\n return <li className={`${dDivider} my-1`} role=\"separator\" data-testid={getTestId?.(`separator-${item.key}`)}></li>\n }\n\n const handleClick = () => {\n if (item.disabled) return\n if (item.children && item.children.length > 0) return\n onSelect(item.key)\n onClose()\n }\n\n const hasSubmenu = item.children && item.children.length > 0\n\n const handleMouseEnter = () => {\n if (!hasSubmenu) return\n if (timeoutRef.current) clearTimeout(timeoutRef.current)\n setShowSubmenu(true)\n }\n\n const handleMouseLeave = () => {\n if (!hasSubmenu) return\n timeoutRef.current = setTimeout(() => setShowSubmenu(false), 100)\n }\n\n return (\n <li\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className=\"relative\"\n role=\"none\"\n >\n <button\n onClick={handleClick}\n disabled={item.disabled}\n role=\"menuitem\"\n aria-haspopup={hasSubmenu ? 'menu' : undefined}\n aria-expanded={hasSubmenu ? showSubmenu : undefined}\n aria-disabled={item.disabled}\n data-testid={itemTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${item.disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n ${item.danger ? 'text-error hover:bg-error/10' : ''}\n `}\n >\n {item.icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{item.icon}</span>}\n <span className=\"flex-1\">{item.label}</span>\n {hasSubmenu && (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n )}\n </button>\n {hasSubmenu && showSubmenu && (\n <ul\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n role=\"menu\"\n data-testid={itemTestId ? `${itemTestId}-menu` : undefined}\n >\n {item.children!.map((child) => (\n <MenuItem key={child.key} item={child} onSelect={onSelect} onClose={onClose} getTestId={getTestId} />\n ))}\n </ul>\n )}\n </li>\n )\n}\n\nconst ContextMenuRoot: React.FC<ContextMenuProps> = ({\n children,\n items,\n onSelect,\n disabled = false,\n className = '',\n 'data-testid': testId,\n}) => {\n const { getPopupContainer } = useConfig()\n const [visible, setVisible] = useState(false)\n const [position, setPosition] = useState<MenuPosition>({ x: 0, y: 0 })\n const menuRef = useRef<HTMLUListElement>(null)\n const triggerRef = useRef<HTMLDivElement>(null)\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n if (disabled) return\n e.preventDefault()\n e.stopPropagation()\n\n // Calculate position, ensuring menu stays within viewport\n let x = e.clientX\n let y = e.clientY\n\n // We'll adjust after render when we know menu dimensions\n setPosition({ x, y })\n setVisible(true)\n },\n [disabled]\n )\n\n const handleClose = useCallback(() => {\n setVisible(false)\n }, [])\n\n const handleSelect = useCallback(\n (key: string) => {\n onSelect?.(key)\n },\n [onSelect]\n )\n\n // Adjust position after menu renders to keep it in viewport\n useEffect(() => {\n if (visible && menuRef.current) {\n const menu = menuRef.current\n const rect = menu.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n let { x, y } = position\n\n if (x + rect.width > viewportWidth) {\n x = viewportWidth - rect.width - 8\n }\n if (y + rect.height > viewportHeight) {\n y = viewportHeight - rect.height - 8\n }\n\n if (x !== position.x || y !== position.y) {\n setPosition({ x, y })\n }\n }\n }, [visible, position])\n\n // Close on click outside or escape\n useEffect(() => {\n if (!visible) return\n\n const handleClickOutside = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n handleClose()\n }\n }\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n handleClose()\n }\n }\n\n const handleScroll = () => {\n handleClose()\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleEscape)\n document.addEventListener('scroll', handleScroll, true)\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleEscape)\n document.removeEventListener('scroll', handleScroll, true)\n }\n }, [visible, handleClose])\n\n // Clone children to extract keys\n const cloneChildrenWithKeys = (children: React.ReactNode): React.ReactNode => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n const childKey = child.key != null ? String(child.key) : undefined\n if (child.type === ContextMenuItemComponent || child.type === ContextMenuSubMenuComponent) {\n return React.cloneElement(child as React.ReactElement<any>, { _key: childKey })\n }\n }\n return child\n })\n }\n\n // Determine if using data-driven or compound pattern\n // Find menu content children (not the trigger element)\n const childArray = React.Children.toArray(children)\n const triggerChild = childArray[0]\n const menuChildren = cloneChildrenWithKeys(childArray.slice(1))\n const useDataDriven = items && items.length > 0\n\n const contextValue: ContextMenuContextValue = {\n onSelect: handleSelect,\n onClose: handleClose,\n getTestId: testId ? (suffix: string) => `${testId}-${suffix}` : undefined,\n }\n const getTestId = (suffix: string) => (testId ? `${testId}-${suffix}` : undefined)\n\n return (\n <>\n <div\n ref={triggerRef}\n onContextMenu={handleContextMenu}\n className=\"inline-block\"\n data-testid={testId}\n >\n {triggerChild}\n </div>\n {visible &&\n createPortal(\n <ContextMenuContext.Provider value={contextValue}>\n <ul\n ref={menuRef}\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 min-w-[160px] p-1 fixed z-[9999] ${className}`}\n style={{ left: position.x, top: position.y }}\n role=\"menu\"\n aria-label=\"Context menu\"\n data-testid={getTestId('menu')}\n >\n {useDataDriven\n ? items!.map((item) => (\n <MenuItem key={item.key} item={item} onSelect={handleSelect} onClose={handleClose} getTestId={getTestId} />\n ))\n : menuChildren}\n </ul>\n </ContextMenuContext.Provider>,\n getPopupContainer ? getPopupContainer(document.body) : document.body\n )}\n </>\n )\n}\n\n// Assign compound components\nexport const ContextMenu = Object.assign(ContextMenuRoot, {\n Item: ContextMenuItemComponent,\n Divider: ContextMenuDividerComponent,\n SubMenu: ContextMenuSubMenuComponent,\n})\n"],"names":["dMenu","dDivider","ContextMenuContext","createContext","useContextMenuContext","context","useContext","ContextMenuItemComponent","children","icon","disabled","danger","className","_key","testId","onSelect","onClose","getTestId","itemTestId","jsx","jsxs","ContextMenuDividerComponent","ContextMenuSubMenuComponent","label","_unusedKey","showSubmenu","setShowSubmenu","useState","timeoutRef","useRef","submenuTestId","handleMouseEnter","handleMouseLeave","MenuItem","item","handleClick","hasSubmenu","child","ContextMenuRoot","items","getPopupContainer","useConfig","visible","setVisible","position","setPosition","menuRef","triggerRef","handleContextMenu","useCallback","e","x","y","handleClose","handleSelect","key","useEffect","rect","viewportWidth","viewportHeight","handleClickOutside","handleEscape","handleScroll","cloneChildrenWithKeys","React","childKey","childArray","triggerChild","menuChildren","useDataDriven","contextValue","suffix","Fragment","createPortal","ContextMenu"],"mappings":"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"}
1
+ {"version":3,"file":"ContextMenu.js","sources":["../../src/components/ContextMenu.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback, createContext, useContext } from 'react'\nimport { createPortal } from 'react-dom'\nimport { useConfig } from '../providers/ConfigProvider'\n\n// DaisyUI classes\nconst dMenu = 'd-menu'\n\nexport interface ContextMenuItem {\n key: string\n label?: React.ReactNode\n icon?: React.ReactNode\n disabled?: boolean\n danger?: boolean\n divider?: boolean\n children?: ContextMenuItem[]\n 'data-testid'?: string\n}\n\nexport interface ContextMenuProps {\n /** Element that triggers the context menu on right-click (first child) */\n children: React.ReactNode\n /** Menu items (data-driven pattern). Can be a static array or a function that receives the mouse event for dynamic items. */\n items?: ContextMenuItem[] | ((e: React.MouseEvent) => ContextMenuItem[])\n /** Callback when an item is selected */\n onSelect?: (key: string) => void\n /** Whether the context menu is disabled */\n disabled?: boolean\n /** Additional CSS classes for the menu */\n className?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuItemProps {\n /** Item content */\n children: React.ReactNode\n /** Icon to display before label */\n icon?: React.ReactNode\n /** Whether the item is disabled */\n disabled?: boolean\n /** Show as danger/destructive action */\n danger?: boolean\n /** Additional CSS classes */\n className?: string\n /** @internal */\n _key?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuDividerProps {\n /** Additional CSS classes */\n className?: string\n 'data-testid'?: string\n}\n\nexport interface ContextMenuSubMenuProps {\n /** Submenu label */\n label: React.ReactNode\n /** Icon to display before label */\n icon?: React.ReactNode\n /** Whether the submenu is disabled */\n disabled?: boolean\n /** Submenu items */\n children: React.ReactNode\n /** Additional CSS classes */\n className?: string\n /** @internal */\n _key?: string\n 'data-testid'?: string\n}\n\ninterface ContextMenuContextValue {\n onSelect: (key: string) => void\n onClose: () => void\n getTestId?: (suffix: string) => string | undefined\n}\n\ninterface MenuPosition {\n x: number\n y: number\n}\n\nconst ContextMenuContext = createContext<ContextMenuContextValue | null>(null)\n\nconst useContextMenuContext = () => {\n const context = useContext(ContextMenuContext)\n if (!context) {\n throw new Error('ContextMenu compound components must be used within a ContextMenu')\n }\n return context\n}\n\n// Compound pattern components\nconst ContextMenuItemComponent: React.FC<ContextMenuItemProps> = ({\n children,\n icon,\n disabled = false,\n danger = false,\n className = '',\n _key,\n 'data-testid': testId,\n}) => {\n const { onSelect, onClose, getTestId } = useContextMenuContext()\n const itemTestId = testId ?? (_key ? getTestId?.(`item-${_key}`) : undefined)\n\n const handleClick = () => {\n if (disabled || !_key) return\n onSelect(_key)\n onClose()\n }\n\n return (\n <li className={className} role=\"none\">\n <button\n onClick={handleClick}\n disabled={disabled}\n role=\"menuitem\"\n aria-disabled={disabled}\n data-testid={itemTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n ${danger ? 'text-error hover:bg-error/10' : ''}\n `}\n >\n {icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n </button>\n </li>\n )\n}\n\nconst ContextMenuDividerComponent: React.FC<ContextMenuDividerProps> = ({ className = '', 'data-testid': testId }) => {\n return <hr className={`border-base-300 my-1 ${className}`} role=\"separator\" data-testid={testId} />\n}\n\nconst ContextMenuSubMenuComponent: React.FC<ContextMenuSubMenuProps> = ({\n label,\n icon,\n disabled = false,\n children,\n className = '',\n _key,\n 'data-testid': testId,\n}) => {\n const { getTestId } = useContextMenuContext()\n const [showSubmenu, setShowSubmenu] = useState(false)\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const submenuTestId = testId ?? (_key ? getTestId?.(`submenu-${_key}`) : undefined)\n\n const handleMouseEnter = () => {\n if (disabled) return\n if (timeoutRef.current) clearTimeout(timeoutRef.current)\n setShowSubmenu(true)\n }\n\n const handleMouseLeave = () => {\n timeoutRef.current = setTimeout(() => setShowSubmenu(false), 100)\n }\n\n return (\n <li\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className={`relative ${className}`}\n role=\"none\"\n >\n <button\n disabled={disabled}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={showSubmenu}\n aria-disabled={disabled}\n data-testid={submenuTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n `}\n >\n {icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{icon}</span>}\n <span className=\"flex-1\">{label}</span>\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n {showSubmenu && (\n <ul\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n role=\"menu\"\n data-testid={submenuTestId ? `${submenuTestId}-menu` : undefined}\n >\n {children}\n </ul>\n )}\n </li>\n )\n}\n\n// Data-driven pattern internal component\nconst MenuItem: React.FC<{\n item: ContextMenuItem\n onSelect: (key: string) => void\n onClose: () => void\n getTestId?: (suffix: string) => string | undefined\n}> = ({ item, onSelect, onClose, getTestId }) => {\n const [showSubmenu, setShowSubmenu] = useState(false)\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const itemTestId = item['data-testid'] ?? getTestId?.(`item-${item.key}`)\n\n if (item.divider) {\n return <hr className=\"border-base-300 my-1\" role=\"separator\" data-testid={getTestId?.(`separator-${item.key}`)} />\n }\n\n const handleClick = () => {\n if (item.disabled) return\n if (item.children && item.children.length > 0) return\n onSelect(item.key)\n onClose()\n }\n\n const hasSubmenu = item.children && item.children.length > 0\n\n const handleMouseEnter = () => {\n if (!hasSubmenu) return\n if (timeoutRef.current) clearTimeout(timeoutRef.current)\n setShowSubmenu(true)\n }\n\n const handleMouseLeave = () => {\n if (!hasSubmenu) return\n timeoutRef.current = setTimeout(() => setShowSubmenu(false), 100)\n }\n\n return (\n <li\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className=\"relative\"\n role=\"none\"\n >\n <button\n onClick={handleClick}\n disabled={item.disabled}\n role=\"menuitem\"\n aria-haspopup={hasSubmenu ? 'menu' : undefined}\n aria-expanded={hasSubmenu ? showSubmenu : undefined}\n aria-disabled={item.disabled}\n data-testid={itemTestId}\n className={`\n flex items-center gap-2 w-full px-4 py-2 text-left text-sm\n ${item.disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-base-200'}\n ${item.danger ? 'text-error hover:bg-error/10' : ''}\n `}\n >\n {item.icon && <span className=\"w-4 h-4\" aria-hidden=\"true\">{item.icon}</span>}\n <span className=\"flex-1\">{item.label}</span>\n {hasSubmenu && (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n )}\n </button>\n {hasSubmenu && showSubmenu && (\n <ul\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 absolute left-full top-0 min-w-[160px] z-50 p-1`}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n role=\"menu\"\n data-testid={itemTestId ? `${itemTestId}-menu` : undefined}\n >\n {item.children!.map((child) => (\n <MenuItem key={child.key} item={child} onSelect={onSelect} onClose={onClose} getTestId={getTestId} />\n ))}\n </ul>\n )}\n </li>\n )\n}\n\nconst ContextMenuRoot: React.FC<ContextMenuProps> = ({\n children,\n items,\n onSelect,\n disabled = false,\n className = '',\n 'data-testid': testId,\n}) => {\n const { getPopupContainer } = useConfig()\n const [visible, setVisible] = useState(false)\n const [position, setPosition] = useState<MenuPosition>({ x: 0, y: 0 })\n const [resolvedItems, setResolvedItems] = useState<ContextMenuItem[] | undefined>(undefined)\n const menuRef = useRef<HTMLUListElement>(null)\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n if (disabled) return\n e.preventDefault()\n e.stopPropagation()\n\n setPosition({ x: e.clientX, y: e.clientY })\n if (typeof items === 'function') {\n setResolvedItems(items(e))\n } else {\n setResolvedItems(items)\n }\n setVisible(true)\n },\n [disabled, items]\n )\n\n const handleClose = useCallback(() => {\n setVisible(false)\n }, [])\n\n const handleSelect = useCallback(\n (key: string) => {\n onSelect?.(key)\n },\n [onSelect]\n )\n\n // Adjust position after menu renders to keep it in viewport\n useEffect(() => {\n if (visible && menuRef.current) {\n const menu = menuRef.current\n const rect = menu.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n let { x, y } = position\n\n if (x + rect.width > viewportWidth) {\n x = viewportWidth - rect.width - 8\n }\n if (y + rect.height > viewportHeight) {\n y = viewportHeight - rect.height - 8\n }\n\n if (x !== position.x || y !== position.y) {\n setPosition({ x, y })\n }\n }\n }, [visible, position])\n\n // Close on click outside or escape\n useEffect(() => {\n if (!visible) return\n\n const handleClickOutside = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n handleClose()\n }\n }\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n handleClose()\n }\n }\n\n const handleScroll = () => {\n handleClose()\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleEscape)\n document.addEventListener('scroll', handleScroll, true)\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleEscape)\n document.removeEventListener('scroll', handleScroll, true)\n }\n }, [visible, handleClose])\n\n // Clone children to extract keys\n const cloneChildrenWithKeys = (children: React.ReactNode): React.ReactNode => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n const childKey = child.key != null ? String(child.key) : undefined\n if (child.type === ContextMenuItemComponent || child.type === ContextMenuSubMenuComponent) {\n return React.cloneElement(child as React.ReactElement<any>, { _key: childKey })\n }\n }\n return child\n })\n }\n\n // Separate trigger (first child) from menu content children\n const childArray = React.Children.toArray(children)\n const trigger = childArray[0]\n const menuChildren = cloneChildrenWithKeys(childArray.slice(1))\n const hasDataItems = resolvedItems && resolvedItems.length > 0\n\n const contextValue: ContextMenuContextValue = {\n onSelect: handleSelect,\n onClose: handleClose,\n getTestId: testId ? (suffix: string) => `${testId}-${suffix}` : undefined,\n }\n const getTestId = (suffix: string) => (testId ? `${testId}-${suffix}` : undefined)\n\n // Attach onContextMenu directly to trigger via cloneElement — no wrapper div\n const triggerWithHandler = React.isValidElement(trigger)\n ? React.cloneElement(trigger as React.ReactElement<any>, {\n onContextMenu: (e: React.MouseEvent) => {\n const existing = (trigger as React.ReactElement<any>).props.onContextMenu\n if (existing) existing(e)\n handleContextMenu(e)\n },\n })\n : trigger\n\n return (\n <>\n {triggerWithHandler}\n {visible &&\n createPortal(\n <ContextMenuContext.Provider value={contextValue}>\n <ul\n ref={menuRef}\n className={`${dMenu} bg-base-100 rounded-box shadow-lg border border-base-300 min-w-[160px] p-1 fixed z-[9999] ${className}`}\n style={{ left: position.x, top: position.y }}\n role=\"menu\"\n aria-label=\"Context menu\"\n data-testid={getTestId('menu')}\n >\n {hasDataItems\n ? resolvedItems.map((item) => (\n <MenuItem key={item.key} item={item} onSelect={handleSelect} onClose={handleClose} getTestId={getTestId} />\n ))\n : menuChildren}\n </ul>\n </ContextMenuContext.Provider>,\n getPopupContainer ? getPopupContainer(document.body) : document.body\n )}\n </>\n )\n}\n\n// Assign compound components\nexport const ContextMenu = Object.assign(ContextMenuRoot, {\n Item: ContextMenuItemComponent,\n Divider: ContextMenuDividerComponent,\n SubMenu: ContextMenuSubMenuComponent,\n})\n"],"names":["dMenu","ContextMenuContext","createContext","useContextMenuContext","context","useContext","ContextMenuItemComponent","children","icon","disabled","danger","className","_key","testId","onSelect","onClose","getTestId","itemTestId","jsx","jsxs","ContextMenuDividerComponent","ContextMenuSubMenuComponent","label","showSubmenu","setShowSubmenu","useState","timeoutRef","useRef","submenuTestId","handleMouseEnter","handleMouseLeave","MenuItem","item","handleClick","hasSubmenu","child","ContextMenuRoot","items","getPopupContainer","useConfig","visible","setVisible","position","setPosition","resolvedItems","setResolvedItems","menuRef","handleContextMenu","useCallback","e","handleClose","handleSelect","key","useEffect","rect","viewportWidth","viewportHeight","x","y","handleClickOutside","handleEscape","handleScroll","cloneChildrenWithKeys","React","childKey","childArray","trigger","menuChildren","hasDataItems","contextValue","suffix","triggerWithHandler","existing","Fragment","createPortal","ContextMenu"],"mappings":";;;;AAKA,MAAMA,IAAQ,UA4ERC,IAAqBC,EAA8C,IAAI,GAEvEC,IAAwB,MAAM;AAClC,QAAMC,IAAUC,EAAWJ,CAAkB;AAC7C,MAAI,CAACG;AACH,UAAM,IAAI,MAAM,mEAAmE;AAErF,SAAOA;AACT,GAGME,IAA2D,CAAC;AAAA,EAChE,UAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,QAAAC,IAAS;AAAA,EACT,WAAAC,IAAY;AAAA,EACZ,MAAAC;AAAA,EACA,eAAeC;AACjB,MAAM;AACJ,QAAM,EAAE,UAAAC,GAAU,SAAAC,GAAS,WAAAC,EAAA,IAAcb,EAAA,GACnCc,IAAaJ,MAAWD,IAAOI,IAAY,QAAQJ,CAAI,EAAE,IAAI;AAQnE,SACE,gBAAAM,EAAC,MAAA,EAAG,WAAAP,GAAsB,MAAK,QAC7B,UAAA,gBAAAQ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SATc,MAAM;AACxB,QAAIV,KAAY,CAACG,MACjBE,EAASF,CAAI,GACbG,EAAA;AAAA,MACF;AAAA,MAMM,UAAAN;AAAA,MACA,MAAK;AAAA,MACL,iBAAeA;AAAA,MACf,eAAaQ;AAAA,MACb,WAAW;AAAA;AAAA,YAEPR,IAAW,kCAAkC,mBAAmB;AAAA,YAChEC,IAAS,iCAAiC,EAAE;AAAA;AAAA,MAG/C,UAAA;AAAA,QAAAF,uBAAS,QAAA,EAAK,WAAU,WAAU,eAAY,QAAQ,UAAAA,GAAK;AAAA,QAC5D,gBAAAU,EAAC,QAAA,EAAK,WAAU,UAAU,UAAAX,EAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAEvC;AAEJ,GAEMa,IAAiE,CAAC,EAAE,WAAAT,IAAY,IAAI,eAAeE,QAChG,gBAAAK,EAAC,QAAG,WAAW,wBAAwBP,CAAS,IAAI,MAAK,aAAY,eAAaE,EAAA,CAAQ,GAG7FQ,IAAiE,CAAC;AAAA,EACtE,OAAAC;AAAA,EACA,MAAAd;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,UAAAF;AAAA,EACA,WAAAI,IAAY;AAAA,EACZ,MAAAC;AAAA,EACA,eAAeC;AACjB,MAAM;AACJ,QAAM,EAAE,WAAAG,EAAA,IAAcb,EAAA,GAChB,CAACoB,GAAaC,CAAc,IAAIC,EAAS,EAAK,GAC9CC,IAAaC,EAA6C,IAAI,GAC9DC,IAAgBf,MAAWD,IAAOI,IAAY,WAAWJ,CAAI,EAAE,IAAI,SAEnEiB,IAAmB,MAAM;AAC7B,IAAIpB,MACAiB,EAAW,WAAS,aAAaA,EAAW,OAAO,GACvDF,EAAe,EAAI;AAAA,EACrB,GAEMM,IAAmB,MAAM;AAC7B,IAAAJ,EAAW,UAAU,WAAW,MAAMF,EAAe,EAAK,GAAG,GAAG;AAAA,EAClE;AAEA,SACE,gBAAAL;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,cAAcU;AAAA,MACd,cAAcC;AAAA,MACd,WAAW,YAAYnB,CAAS;AAAA,MAChC,MAAK;AAAA,MAEL,UAAA;AAAA,QAAA,gBAAAQ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,UAAAV;AAAA,YACA,MAAK;AAAA,YACL,iBAAc;AAAA,YACd,iBAAec;AAAA,YACf,iBAAed;AAAA,YACf,eAAamB;AAAA,YACb,WAAW;AAAA;AAAA,YAEPnB,IAAW,kCAAkC,mBAAmB;AAAA;AAAA,YAGnE,UAAA;AAAA,cAAAD,uBAAS,QAAA,EAAK,WAAU,WAAU,eAAY,QAAQ,UAAAA,GAAK;AAAA,cAC5D,gBAAAU,EAAC,QAAA,EAAK,WAAU,UAAU,UAAAI,GAAM;AAAA,cAChC,gBAAAJ,EAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,eAAY,QACzF,UAAA,gBAAAA,EAAC,QAAA,EAAK,eAAc,SAAQ,gBAAe,SAAQ,aAAa,GAAG,GAAE,eAAA,CAAe,EAAA,CACtF;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEDK,KACC,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,GAAGlB,CAAK;AAAA,YACnB,cAAc6B;AAAA,YACd,cAAcC;AAAA,YACd,MAAK;AAAA,YACL,eAAaF,IAAgB,GAAGA,CAAa,UAAU;AAAA,YAEtD,UAAArB;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR,GAGMwB,IAKD,CAAC,EAAE,MAAAC,GAAM,UAAAlB,GAAU,SAAAC,GAAS,WAAAC,QAAgB;AAC/C,QAAM,CAACO,GAAaC,CAAc,IAAIC,EAAS,EAAK,GAC9CC,IAAaC,EAA6C,IAAI,GAC9DV,IAAae,EAAK,aAAa,KAAKhB,IAAY,QAAQgB,EAAK,GAAG,EAAE;AAExE,MAAIA,EAAK;AACP,WAAO,gBAAAd,EAAC,MAAA,EAAG,WAAU,wBAAuB,MAAK,aAAY,eAAaF,IAAY,aAAagB,EAAK,GAAG,EAAE,EAAA,CAAG;AAGlH,QAAMC,IAAc,MAAM;AACxB,IAAID,EAAK,YACLA,EAAK,YAAYA,EAAK,SAAS,SAAS,MAC5ClB,EAASkB,EAAK,GAAG,GACjBjB,EAAA;AAAA,EACF,GAEMmB,IAAaF,EAAK,YAAYA,EAAK,SAAS,SAAS,GAErDH,IAAmB,MAAM;AAC7B,IAAKK,MACDR,EAAW,WAAS,aAAaA,EAAW,OAAO,GACvDF,EAAe,EAAI;AAAA,EACrB,GAEMM,IAAmB,MAAM;AAC7B,IAAKI,MACLR,EAAW,UAAU,WAAW,MAAMF,EAAe,EAAK,GAAG,GAAG;AAAA,EAClE;AAEA,SACE,gBAAAL;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,cAAcU;AAAA,MACd,cAAcC;AAAA,MACd,WAAU;AAAA,MACV,MAAK;AAAA,MAEL,UAAA;AAAA,QAAA,gBAAAX;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAASc;AAAA,YACT,UAAUD,EAAK;AAAA,YACf,MAAK;AAAA,YACL,iBAAeE,IAAa,SAAS;AAAA,YACrC,iBAAeA,IAAaX,IAAc;AAAA,YAC1C,iBAAeS,EAAK;AAAA,YACpB,eAAaf;AAAA,YACb,WAAW;AAAA;AAAA,YAEPe,EAAK,WAAW,kCAAkC,mBAAmB;AAAA,YACrEA,EAAK,SAAS,iCAAiC,EAAE;AAAA;AAAA,YAGpD,UAAA;AAAA,cAAAA,EAAK,0BAAS,QAAA,EAAK,WAAU,WAAU,eAAY,QAAQ,YAAK,KAAA,CAAK;AAAA,cACtE,gBAAAd,EAAC,QAAA,EAAK,WAAU,UAAU,YAAK,OAAM;AAAA,cACpCgB,uBACE,OAAA,EAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,eAAY,QACzF,UAAA,gBAAAhB,EAAC,QAAA,EAAK,eAAc,SAAQ,gBAAe,SAAQ,aAAa,GAAG,GAAE,eAAA,CAAe,EAAA,CACtF;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGHgB,KAAcX,KACb,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW,GAAGlB,CAAK;AAAA,YACnB,cAAc6B;AAAA,YACd,cAAcC;AAAA,YACd,MAAK;AAAA,YACL,eAAab,IAAa,GAAGA,CAAU,UAAU;AAAA,YAEhD,UAAAe,EAAK,SAAU,IAAI,CAACG,MACnB,gBAAAjB,EAACa,GAAA,EAAyB,MAAMI,GAAO,UAAArB,GAAoB,SAAAC,GAAkB,WAAAC,EAAA,GAA9DmB,EAAM,GAA8E,CACpG;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR,GAEMC,IAA8C,CAAC;AAAA,EACnD,UAAA7B;AAAA,EACA,OAAA8B;AAAA,EACA,UAAAvB;AAAA,EACA,UAAAL,IAAW;AAAA,EACX,WAAAE,IAAY;AAAA,EACZ,eAAeE;AACjB,MAAM;AACJ,QAAM,EAAE,mBAAAyB,EAAA,IAAsBC,EAAA,GACxB,CAACC,GAASC,CAAU,IAAIhB,EAAS,EAAK,GACtC,CAACiB,GAAUC,CAAW,IAAIlB,EAAuB,EAAE,GAAG,GAAG,GAAG,GAAG,GAC/D,CAACmB,GAAeC,CAAgB,IAAIpB,EAAwC,MAAS,GACrFqB,IAAUnB,EAAyB,IAAI,GAEvCoB,IAAoBC;AAAA,IACxB,CAACC,MAAwB;AACvB,MAAIxC,MACJwC,EAAE,eAAA,GACFA,EAAE,gBAAA,GAEFN,EAAY,EAAE,GAAGM,EAAE,SAAS,GAAGA,EAAE,SAAS,GAExCJ,EADE,OAAOR,KAAU,aACFA,EAAMY,CAAC,IAEPZ,CAFQ,GAI3BI,EAAW,EAAI;AAAA,IACjB;AAAA,IACA,CAAChC,GAAU4B,CAAK;AAAA,EAAA,GAGZa,IAAcF,EAAY,MAAM;AACpC,IAAAP,EAAW,EAAK;AAAA,EAClB,GAAG,CAAA,CAAE,GAECU,IAAeH;AAAA,IACnB,CAACI,MAAgB;AACf,MAAAtC,IAAWsC,CAAG;AAAA,IAChB;AAAA,IACA,CAACtC,CAAQ;AAAA,EAAA;AAIX,EAAAuC,EAAU,MAAM;AACd,QAAIb,KAAWM,EAAQ,SAAS;AAE9B,YAAMQ,IADOR,EAAQ,QACH,sBAAA,GACZS,IAAgB,OAAO,YACvBC,IAAiB,OAAO;AAE9B,UAAI,EAAE,GAAAC,GAAG,GAAAC,EAAA,IAAMhB;AAEf,MAAIe,IAAIH,EAAK,QAAQC,MACnBE,IAAIF,IAAgBD,EAAK,QAAQ,IAE/BI,IAAIJ,EAAK,SAASE,MACpBE,IAAIF,IAAiBF,EAAK,SAAS,KAGjCG,MAAMf,EAAS,KAAKgB,MAAMhB,EAAS,MACrCC,EAAY,EAAE,GAAAc,GAAG,GAAAC,GAAG;AAAA,IAExB;AAAA,EACF,GAAG,CAAClB,GAASE,CAAQ,CAAC,GAGtBW,EAAU,MAAM;AACd,QAAI,CAACb,EAAS;AAEd,UAAMmB,IAAqB,CAACV,MAAkB;AAC5C,MAAIH,EAAQ,WAAW,CAACA,EAAQ,QAAQ,SAASG,EAAE,MAAc,KAC/DC,EAAA;AAAA,IAEJ,GAEMU,IAAe,CAACX,MAAqB;AACzC,MAAIA,EAAE,QAAQ,YACZC,EAAA;AAAA,IAEJ,GAEMW,IAAe,MAAM;AACzB,MAAAX,EAAA;AAAA,IACF;AAEA,oBAAS,iBAAiB,aAAaS,CAAkB,GACzD,SAAS,iBAAiB,WAAWC,CAAY,GACjD,SAAS,iBAAiB,UAAUC,GAAc,EAAI,GAE/C,MAAM;AACX,eAAS,oBAAoB,aAAaF,CAAkB,GAC5D,SAAS,oBAAoB,WAAWC,CAAY,GACpD,SAAS,oBAAoB,UAAUC,GAAc,EAAI;AAAA,IAC3D;AAAA,EACF,GAAG,CAACrB,GAASU,CAAW,CAAC;AAGzB,QAAMY,IAAwB,CAACvD,MACtBwD,EAAM,SAAS,IAAIxD,GAAU,CAAC4B,MAAU;AAC7C,QAAI4B,EAAM,eAAe5B,CAAK,GAAG;AAC/B,YAAM6B,IAAW7B,EAAM,OAAO,OAAO,OAAOA,EAAM,GAAG,IAAI;AACzD,UAAIA,EAAM,SAAS7B,KAA4B6B,EAAM,SAASd;AAC5D,eAAO0C,EAAM,aAAa5B,GAAkC,EAAE,MAAM6B,GAAU;AAAA,IAElF;AACA,WAAO7B;AAAA,EACT,CAAC,GAIG8B,IAAaF,EAAM,SAAS,QAAQxD,CAAQ,GAC5C2D,IAAUD,EAAW,CAAC,GACtBE,IAAeL,EAAsBG,EAAW,MAAM,CAAC,CAAC,GACxDG,IAAexB,KAAiBA,EAAc,SAAS,GAEvDyB,IAAwC;AAAA,IAC5C,UAAUlB;AAAA,IACV,SAASD;AAAA,IACT,WAAWrC,IAAS,CAACyD,MAAmB,GAAGzD,CAAM,IAAIyD,CAAM,KAAK;AAAA,EAAA,GAE5DtD,IAAY,CAACsD,MAAoBzD,IAAS,GAAGA,CAAM,IAAIyD,CAAM,KAAK,QAGlEC,IAAqBR,EAAM,eAAeG,CAAO,IACnDH,EAAM,aAAaG,GAAoC;AAAA,IACrD,eAAe,CAACjB,MAAwB;AACtC,YAAMuB,IAAYN,EAAoC,MAAM;AAC5D,MAAIM,OAAmBvB,CAAC,GACxBF,EAAkBE,CAAC;AAAA,IACrB;AAAA,EAAA,CACD,IACDiB;AAEJ,SACE,gBAAA/C,EAAAsD,GAAA,EACG,UAAA;AAAA,IAAAF;AAAA,IACA/B,KACCkC;AAAA,MACE,gBAAAxD,EAACjB,EAAmB,UAAnB,EAA4B,OAAOoE,GAClC,UAAA,gBAAAnD;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,KAAK4B;AAAA,UACL,WAAW,GAAG9C,CAAK,8FAA8FW,CAAS;AAAA,UAC1H,OAAO,EAAE,MAAM+B,EAAS,GAAG,KAAKA,EAAS,EAAA;AAAA,UACzC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,eAAa1B,EAAU,MAAM;AAAA,UAE5B,cACG4B,EAAc,IAAI,CAACZ,wBAChBD,GAAA,EAAwB,MAAAC,GAAY,UAAUmB,GAAc,SAASD,GAAa,WAAAlC,EAAA,GAApEgB,EAAK,GAAqF,CAC1G,IACDmC;AAAA,QAAA;AAAA,MAAA,GAER;AAAA,MACA7B,IAAoBA,EAAkB,SAAS,IAAI,IAAI,SAAS;AAAA,IAAA;AAAA,EAClE,GACJ;AAEJ,GAGaqC,KAAc,OAAO,OAAOvC,GAAiB;AAAA,EACxD,MAAM9B;AAAA,EACN,SAASc;AAAA,EACT,SAASC;AACX,CAAC;"}
@@ -1,38 +1,38 @@
1
- import { jsx as M } from "react/jsx-runtime";
2
- import { forwardRef as H, useRef as a, useImperativeHandle as O, useEffect as B } from "react";
1
+ import { jsx as H } from "react/jsx-runtime";
2
+ import { forwardRef as $, useRef as m, useImperativeHandle as j, useEffect as z } from "react";
3
3
  import * as p from "@xterm/xterm";
4
4
  import * as g from "@xterm/addon-fit";
5
- import { useTheme as $ } from "../hooks/useTheme.js";
6
- const j = p.Terminal ?? p.default?.Terminal ?? p, X = g.FitAddon ?? g.default?.FitAddon ?? g;
7
- let k = !1;
8
- function E() {
9
- if (k || typeof document > "u") return;
10
- k = !0;
5
+ import { useTheme as X } from "../hooks/useTheme.js";
6
+ const E = p.Terminal ?? p.default?.Terminal ?? p, L = g.FitAddon ?? g.default?.FitAddon ?? g;
7
+ let I = !1;
8
+ function P() {
9
+ if (I || typeof document > "u") return;
10
+ I = !0;
11
11
  const u = document.createElement("style");
12
12
  u.setAttribute("data-xterm", ""), u.textContent = ".xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:.5}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}", document.head.appendChild(u);
13
13
  }
14
- const L = H(({
14
+ const W = $(({
15
15
  onData: u,
16
- onReady: z,
16
+ onReady: A,
17
17
  readline: y = !1,
18
18
  prompt: c = "$ ",
19
- onLine: I,
20
- convertEol: A = !0,
21
- options: F = {},
22
- className: C = "",
23
- style: R,
24
- "data-testid": T
25
- }, D) => {
26
- const m = a(null), o = a(null), h = a(null), { isDark: f, colors: n } = $(), d = a({
19
+ onLine: F,
20
+ convertEol: C = !0,
21
+ options: w = {},
22
+ className: R = "",
23
+ style: T,
24
+ "data-testid": D
25
+ }, S) => {
26
+ const a = m(null), o = m(null), h = m(null), { isDark: f, colors: n } = X(), d = m({
27
27
  buffer: "",
28
28
  cursor: 0,
29
29
  history: [],
30
30
  historyIndex: -1,
31
31
  savedBuffer: ""
32
- }), w = () => ({
32
+ }), v = () => ({
33
33
  background: n.background,
34
34
  foreground: n.foreground,
35
- cursor: n.primary,
35
+ cursor: n.foreground,
36
36
  cursorAccent: n.background,
37
37
  selectionBackground: n.primary + "40",
38
38
  selectionForeground: n.foreground,
@@ -53,7 +53,7 @@ const L = H(({
53
53
  brightCyan: n.accent,
54
54
  brightWhite: f ? "#eeeeec" : "#ffffff"
55
55
  });
56
- O(D, () => ({
56
+ j(S, () => ({
57
57
  terminal: o.current,
58
58
  write: (r) => o.current?.write(r),
59
59
  writeln: (r) => o.current?.writeln(r),
@@ -72,7 +72,7 @@ const L = H(({
72
72
  r.write("\r\x1B[K" + c + t.buffer);
73
73
  const e = t.buffer.length - t.cursor;
74
74
  e > 0 && r.write(`\x1B[${e}D`);
75
- }, S = (r) => {
75
+ }, M = (r) => {
76
76
  const t = o.current;
77
77
  if (!t) return;
78
78
  const e = d.current;
@@ -109,46 +109,49 @@ const L = H(({
109
109
  t.writeln("");
110
110
  const i = e.buffer;
111
111
  i.trim() && e.history.push(i), e.buffer = "", e.cursor = 0, e.historyIndex = -1, e.savedBuffer = "";
112
- const s = I?.(i);
112
+ const s = F?.(i);
113
113
  s && typeof s.then == "function" ? s.then(() => t.write(c)) : t.write(c);
114
114
  } else r === "" || r === "\b" ? e.cursor > 0 && (e.buffer = e.buffer.slice(0, e.cursor - 1) + e.buffer.slice(e.cursor), e.cursor--, l()) : r === "" ? (t.writeln("^C"), e.buffer = "", e.cursor = 0, e.historyIndex = -1, t.write(c)) : (r >= " " || r === " ") && (e.buffer = e.buffer.slice(0, e.cursor) + r + e.buffer.slice(e.cursor), e.cursor += r.length, l());
115
115
  };
116
- return B(() => {
117
- if (!m.current) return;
118
- E();
119
- const r = m.current;
116
+ return z(() => {
117
+ if (!a.current) return;
118
+ P();
119
+ const r = a.current;
120
120
  let t = null, e = null, i = null, s = !1, b = !1;
121
- const v = () => {
121
+ const B = () => {
122
122
  if (s || b || !r) return;
123
123
  const x = r.getBoundingClientRect();
124
- x.width === 0 || x.height === 0 || (s = !0, t = new j({
125
- theme: w(),
124
+ if (x.width === 0 || x.height === 0) return;
125
+ s = !0;
126
+ const { theme: k, ...O } = w;
127
+ t = new E({
128
+ theme: { ...v(), ...k },
126
129
  cursorBlink: !0,
127
- convertEol: A,
130
+ convertEol: C,
128
131
  fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
129
132
  fontSize: 14,
130
- ...F
131
- }), e = new X(), t.loadAddon(e), t.open(r), e.fit(), o.current = t, h.current = e, y ? t.onData(S) : u && t.onData(u), z?.(t), y && t.write(c));
133
+ ...O
134
+ }), e = new L(), t.loadAddon(e), t.open(r), e.fit(), o.current = t, h.current = e, y ? t.onData(M) : u && t.onData(u), A?.(t), y && t.write(c);
132
135
  };
133
136
  return i = new ResizeObserver((x) => {
134
- !x[0] || b || (s ? e && e.fit() : v());
135
- }), i.observe(r), requestAnimationFrame(v), () => {
137
+ !x[0] || b || (s ? e && e.fit() : B());
138
+ }), i.observe(r), requestAnimationFrame(B), () => {
136
139
  b = !0, i?.disconnect(), t?.dispose(), o.current = null, h.current = null;
137
140
  };
138
- }, []), B(() => {
139
- o.current && (o.current.options.theme = w());
140
- }, [f, n]), /* @__PURE__ */ M(
141
+ }, []), z(() => {
142
+ o.current && (o.current.options.theme = { ...v(), ...w.theme });
143
+ }, [f, n]), /* @__PURE__ */ H(
141
144
  "div",
142
145
  {
143
- ref: m,
144
- className: C,
145
- style: { width: "100%", height: "100%", ...R },
146
- "data-testid": T
146
+ ref: a,
147
+ className: R,
148
+ style: { width: "100%", height: "100%", ...T },
149
+ "data-testid": D
147
150
  }
148
151
  );
149
152
  });
150
- L.displayName = "Terminal";
153
+ W.displayName = "Terminal";
151
154
  export {
152
- L as Terminal
155
+ W as Terminal
153
156
  };
154
157
  //# sourceMappingURL=Terminal.js.map