@aster-ui/prefixed 0.12.85 → 0.12.87

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,29 +1,29 @@
1
1
  import { jsx as N } from "react/jsx-runtime";
2
- import { forwardRef as W, useRef as d, useEffect as g } from "react";
2
+ import { forwardRef as O, useRef as d, useEffect as g } from "react";
3
3
  import { EditorState as b } from "@codemirror/state";
4
- import { EditorView as e, highlightSpecialChars as _, drawSelection as D, dropCursor as I, rectangularSelection as J, crosshairCursor as P, keymap as R, lineNumbers as Q, highlightActiveLine as U, highlightActiveLineGutter as X } from "@codemirror/view";
5
- import { indentOnInput as Y, syntaxHighlighting as Z, defaultHighlightStyle as tt, foldKeymap as et, foldGutter as ot, bracketMatching as rt } from "@codemirror/language";
6
- import { history as it, defaultKeymap as nt, historyKeymap as ct, indentWithTab as st } from "@codemirror/commands";
7
- import { highlightSelectionMatches as lt, searchKeymap as at } from "@codemirror/search";
8
- import { closeBracketsKeymap as ut, completionKeymap as mt, closeBrackets as ft, autocompletion as pt } from "@codemirror/autocomplete";
9
- import { lintKeymap as ht } from "@codemirror/lint";
4
+ import { EditorView as t, highlightSpecialChars as W, drawSelection as D, dropCursor as I, rectangularSelection as J, crosshairCursor as P, keymap as R, lineNumbers as Q, highlightActiveLine as U, highlightActiveLineGutter as X } from "@codemirror/view";
5
+ import { indentOnInput as Y, syntaxHighlighting as Z, defaultHighlightStyle as ee, foldKeymap as te, foldGutter as oe, bracketMatching as re } from "@codemirror/language";
6
+ import { history as ie, defaultKeymap as ne, historyKeymap as ce, indentWithTab as se } from "@codemirror/commands";
7
+ import { highlightSelectionMatches as le, searchKeymap as ae } from "@codemirror/search";
8
+ import { closeBracketsKeymap as ue, completionKeymap as me, closeBrackets as fe, autocompletion as pe } from "@codemirror/autocomplete";
9
+ import { lintKeymap as he } from "@codemirror/lint";
10
10
  import { javascript as s } from "@codemirror/lang-javascript";
11
- import { python as dt } from "@codemirror/lang-python";
12
- import { html as gt } from "@codemirror/lang-html";
13
- import { css as bt } from "@codemirror/lang-css";
14
- import { json as yt } from "@codemirror/lang-json";
15
- import { markdown as vt } from "@codemirror/lang-markdown";
16
- import { sql as St } from "@codemirror/lang-sql";
17
- import { xml as kt } from "@codemirror/lang-xml";
18
- import { useConfig as xt } from "../providers/ConfigProvider.js";
19
- const Ct = {
11
+ import { python as de } from "@codemirror/lang-python";
12
+ import { html as ge } from "@codemirror/lang-html";
13
+ import { css as be } from "@codemirror/lang-css";
14
+ import { json as ve } from "@codemirror/lang-json";
15
+ import { markdown as ye } from "@codemirror/lang-markdown";
16
+ import { sql as Se } from "@codemirror/lang-sql";
17
+ import { xml as ke } from "@codemirror/lang-xml";
18
+ import { useConfig as xe } from "../providers/ConfigProvider.js";
19
+ const Ce = {
20
20
  xs: { fontSize: "11px", lineHeight: "1.4" },
21
21
  sm: { fontSize: "12px", lineHeight: "1.5" },
22
22
  md: { fontSize: "14px", lineHeight: "1.6" },
23
23
  lg: { fontSize: "16px", lineHeight: "1.6" },
24
24
  xl: { fontSize: "18px", lineHeight: "1.7" }
25
25
  };
26
- function zt(o) {
26
+ function we(o) {
27
27
  switch (o) {
28
28
  case "javascript":
29
29
  return s();
@@ -34,24 +34,24 @@ function zt(o) {
34
34
  case "tsx":
35
35
  return s({ jsx: !0, typescript: !0 });
36
36
  case "python":
37
- return dt();
37
+ return de();
38
38
  case "html":
39
- return gt();
39
+ return ge();
40
40
  case "css":
41
- return bt();
41
+ return be();
42
42
  case "json":
43
- return yt();
43
+ return ve();
44
44
  case "markdown":
45
- return vt();
45
+ return ye();
46
46
  case "sql":
47
- return St();
47
+ return Se();
48
48
  case "xml":
49
- return kt();
49
+ return ke();
50
50
  default:
51
51
  return null;
52
52
  }
53
53
  }
54
- const wt = e.theme({
54
+ const ze = t.theme({
55
55
  "&": {
56
56
  backgroundColor: "oklch(var(--b1))",
57
57
  color: "oklch(var(--bc))"
@@ -90,19 +90,19 @@ const wt = e.theme({
90
90
  color: "oklch(var(--bc) / 0.4)",
91
91
  fontStyle: "italic"
92
92
  }
93
- }), jt = W(
93
+ }), je = O(
94
94
  ({
95
95
  value: o = "",
96
96
  onChange: l,
97
- language: y = "plaintext",
97
+ language: v = "plaintext",
98
98
  placeholder: i,
99
- readOnly: v = !1,
99
+ readOnly: y = !1,
100
100
  autoFocus: S = !1,
101
101
  lineNumbers: k = !0,
102
102
  foldGutter: x = !0,
103
103
  highlightActiveLine: C = !0,
104
- bracketMatching: z = !0,
105
- closeBrackets: w = !0,
104
+ bracketMatching: w = !0,
105
+ closeBrackets: z = !0,
106
106
  autocompletion: j = !0,
107
107
  indentWithTab: E = !0,
108
108
  minHeight: a = 200,
@@ -111,41 +111,41 @@ const wt = e.theme({
111
111
  bordered: G = !0,
112
112
  extensions: H = [],
113
113
  onEditorReady: u,
114
- className: B = "",
115
- "data-testid": q = "code-editor",
116
- ...A
117
- }, T) => {
118
- const { componentSize: V } = xt(), K = $ ?? V ?? "md", m = d(null), f = d(null), p = d(l);
114
+ className: _ = "",
115
+ "data-testid": B = "code-editor",
116
+ ...q
117
+ }, A) => {
118
+ const { componentSize: T } = xe(), K = $ ?? T ?? "md", m = d(null), f = d(null), p = d(l);
119
119
  g(() => {
120
120
  p.current = l;
121
121
  }, [l]), g(() => {
122
122
  if (!m.current) return;
123
- const t = [
124
- wt,
125
- _(),
126
- it(),
123
+ const e = [
124
+ ze,
125
+ W(),
126
+ ie(),
127
127
  D(),
128
128
  I(),
129
129
  b.allowMultipleSelections.of(!0),
130
130
  Y(),
131
- Z(tt, { fallback: !0 }),
131
+ Z(ee, { fallback: !0 }),
132
132
  J(),
133
133
  P(),
134
- lt(),
134
+ le(),
135
135
  R.of([
136
- ...ut,
137
- ...nt,
138
- ...at,
139
- ...ct,
140
- ...et,
141
- ...mt,
142
- ...ht
136
+ ...ue,
137
+ ...ne,
138
+ ...ae,
139
+ ...ce,
140
+ ...te,
141
+ ...me,
142
+ ...he
143
143
  ])
144
144
  ];
145
- k && t.push(Q()), x && t.push(ot()), C && (t.push(U()), t.push(X())), z && t.push(rt()), w && t.push(ft()), j && t.push(pt()), E && t.push(R.of([st]));
146
- const r = zt(y);
147
- r && t.push(r), i && (t.push(e.contentAttributes.of({ "aria-placeholder": i })), t.push(
148
- e.theme({
145
+ k && e.push(Q()), x && e.push(oe()), C && (e.push(U()), e.push(X())), w && e.push(re()), z && e.push(fe()), j && e.push(pe()), E && e.push(R.of([se]));
146
+ const r = we(v);
147
+ r && e.push(r), i && (e.push(t.contentAttributes.of({ "aria-placeholder": i })), e.push(
148
+ t.theme({
149
149
  ".cm-content:has(.cm-line:only-child:empty)::before": {
150
150
  content: `"${i}"`,
151
151
  position: "absolute",
@@ -154,14 +154,14 @@ const wt = e.theme({
154
154
  pointerEvents: "none"
155
155
  }
156
156
  })
157
- )), v && (t.push(b.readOnly.of(!0)), t.push(e.editable.of(!1))), t.push(
158
- e.updateListener.of((M) => {
157
+ )), y && (e.push(b.readOnly.of(!0)), e.push(t.editable.of(!1))), e.push(
158
+ t.updateListener.of((M) => {
159
159
  M.docChanged && p.current && p.current(M.state.doc.toString());
160
160
  })
161
161
  );
162
- const h = Ct[K];
163
- t.push(
164
- e.theme({
162
+ const h = Ce[K];
163
+ e.push(
164
+ t.theme({
165
165
  ".cm-content": {
166
166
  fontSize: h.fontSize,
167
167
  lineHeight: h.lineHeight
@@ -170,26 +170,26 @@ const wt = e.theme({
170
170
  fontSize: h.fontSize
171
171
  }
172
172
  })
173
- ), t.push(...H);
174
- const O = b.create({
173
+ ), e.push(...H);
174
+ const F = b.create({
175
175
  doc: o,
176
- extensions: t
177
- }), c = new e({
178
- state: O,
176
+ extensions: e
177
+ }), c = new t({
178
+ state: F,
179
179
  parent: m.current
180
180
  });
181
181
  return f.current = c, S && c.focus(), u && u(c), () => {
182
182
  c.destroy(), f.current = null;
183
183
  };
184
184
  }, [
185
- y,
186
- i,
187
185
  v,
186
+ i,
187
+ y,
188
188
  k,
189
189
  x,
190
190
  C,
191
- z,
192
191
  w,
192
+ z,
193
193
  j,
194
194
  E,
195
195
  K,
@@ -197,10 +197,10 @@ const wt = e.theme({
197
197
  H,
198
198
  u
199
199
  ]), g(() => {
200
- const t = f.current;
201
- if (!t) return;
202
- const r = t.state.doc.toString();
203
- o !== r && t.dispatch({
200
+ const e = f.current;
201
+ if (!e) return;
202
+ const r = e.state.doc.toString();
203
+ o !== r && e.dispatch({
204
204
  changes: {
205
205
  from: 0,
206
206
  to: r.length,
@@ -208,25 +208,25 @@ const wt = e.theme({
208
208
  }
209
209
  });
210
210
  }, [o]);
211
- const F = typeof a == "number" ? `${a}px` : a, L = n ? typeof n == "number" ? `${n}px` : n : void 0;
211
+ const V = typeof a == "number" ? `${a}px` : a, L = n ? typeof n == "number" ? `${n}px` : n : void 0;
212
212
  return /* @__PURE__ */ N(
213
213
  "div",
214
214
  {
215
- ref: T,
215
+ ref: A,
216
216
  className: `
217
217
  bg-base-100 rounded-lg overflow-hidden
218
218
  ${G ? "border border-base-300" : ""}
219
- ${B}
219
+ ${_}
220
220
  `,
221
- "data-testid": q,
222
- ...A,
221
+ "data-testid": B,
222
+ ...q,
223
223
  children: /* @__PURE__ */ N(
224
224
  "div",
225
225
  {
226
226
  ref: m,
227
- className: "[&_.cm-editor]:outline-none",
227
+ className: "h-full [&_.cm-editor]:outline-none [&_.cm-editor]:h-full [&_.cm-editor]:!overflow-hidden [&_.cm-scroller]:!overflow-auto",
228
228
  style: {
229
- minHeight: F,
229
+ minHeight: V,
230
230
  maxHeight: L,
231
231
  overflow: L ? "auto" : void 0
232
232
  }
@@ -236,9 +236,9 @@ const wt = e.theme({
236
236
  );
237
237
  }
238
238
  );
239
- jt.displayName = "CodeEditor";
239
+ je.displayName = "CodeEditor";
240
240
  export {
241
- jt as CodeEditor,
242
- jt as default
241
+ je as CodeEditor,
242
+ je as default
243
243
  };
244
244
  //# sourceMappingURL=CodeEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeEditor.js","sources":["../../src/components/CodeEditor.tsx"],"sourcesContent":["import React, { forwardRef, useEffect, useRef } from 'react'\nimport { EditorState, type Extension } from '@codemirror/state'\nimport { EditorView, keymap, lineNumbers, highlightActiveLine, highlightActiveLineGutter, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightSpecialChars } from '@codemirror/view'\nimport { defaultHighlightStyle, syntaxHighlighting, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language'\nimport { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands'\nimport { searchKeymap, highlightSelectionMatches } from '@codemirror/search'\nimport { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'\nimport { lintKeymap } from '@codemirror/lint'\nimport { javascript } from '@codemirror/lang-javascript'\nimport { python } from '@codemirror/lang-python'\nimport { html } from '@codemirror/lang-html'\nimport { css } from '@codemirror/lang-css'\nimport { json } from '@codemirror/lang-json'\nimport { markdown } from '@codemirror/lang-markdown'\nimport { sql } from '@codemirror/lang-sql'\nimport { xml } from '@codemirror/lang-xml'\nimport { useConfig } from '../providers/ConfigProvider'\n\nexport type CodeEditorLanguage =\n | 'javascript'\n | 'typescript'\n | 'jsx'\n | 'tsx'\n | 'python'\n | 'html'\n | 'css'\n | 'json'\n | 'markdown'\n | 'sql'\n | 'xml'\n | 'plaintext'\n\nexport interface CodeEditorProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Code content */\n value?: string\n /** Callback when content changes */\n onChange?: (value: string) => void\n /** Programming language for syntax highlighting */\n language?: CodeEditorLanguage\n /** Placeholder text when empty */\n placeholder?: string\n /** Make editor read-only */\n readOnly?: boolean\n /** Auto focus on mount */\n autoFocus?: boolean\n /** Show line numbers */\n lineNumbers?: boolean\n /** Enable code folding */\n foldGutter?: boolean\n /** Highlight active line */\n highlightActiveLine?: boolean\n /** Enable bracket matching */\n bracketMatching?: boolean\n /** Enable auto-closing brackets */\n closeBrackets?: boolean\n /** Enable autocompletion */\n autocompletion?: boolean\n /** Allow tab key for indentation */\n indentWithTab?: boolean\n /** Minimum height of the editor */\n minHeight?: string | number\n /** Maximum height of the editor (enables scrolling) */\n maxHeight?: string | number\n /** Editor size variant */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n /** Show border around editor */\n bordered?: boolean\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Callback with editor view instance */\n onEditorReady?: (view: EditorView) => void\n 'data-testid'?: string\n}\n\nconst sizeClasses = {\n xs: { fontSize: '11px', lineHeight: '1.4' },\n sm: { fontSize: '12px', lineHeight: '1.5' },\n md: { fontSize: '14px', lineHeight: '1.6' },\n lg: { fontSize: '16px', lineHeight: '1.6' },\n xl: { fontSize: '18px', lineHeight: '1.7' },\n}\n\nfunction getLanguageExtension(language: CodeEditorLanguage): Extension | null {\n switch (language) {\n case 'javascript':\n return javascript()\n case 'typescript':\n return javascript({ typescript: true })\n case 'jsx':\n return javascript({ jsx: true })\n case 'tsx':\n return javascript({ jsx: true, typescript: true })\n case 'python':\n return python()\n case 'html':\n return html()\n case 'css':\n return css()\n case 'json':\n return json()\n case 'markdown':\n return markdown()\n case 'sql':\n return sql()\n case 'xml':\n return xml()\n case 'plaintext':\n default:\n return null\n }\n}\n\nconst baseTheme = EditorView.theme({\n '&': {\n backgroundColor: 'oklch(var(--b1))',\n color: 'oklch(var(--bc))',\n },\n '.cm-content': {\n caretColor: 'oklch(var(--bc))',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n },\n '.cm-cursor, .cm-dropCursor': {\n borderLeftColor: 'oklch(var(--bc))',\n },\n '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {\n backgroundColor: 'oklch(var(--p) / 0.2)',\n },\n '.cm-activeLine': {\n backgroundColor: 'oklch(var(--bc) / 0.05)',\n },\n '.cm-activeLineGutter': {\n backgroundColor: 'oklch(var(--bc) / 0.05)',\n },\n '.cm-gutters': {\n backgroundColor: 'oklch(var(--b2))',\n color: 'oklch(var(--bc) / 0.5)',\n borderRight: '1px solid oklch(var(--b3))',\n },\n '.cm-lineNumbers .cm-gutterElement': {\n padding: '0 8px 0 16px',\n },\n '.cm-foldGutter .cm-gutterElement': {\n padding: '0 4px',\n },\n '.cm-scroller': {\n overflow: 'auto',\n },\n '.cm-placeholder': {\n color: 'oklch(var(--bc) / 0.4)',\n fontStyle: 'italic',\n },\n})\n\nexport const CodeEditor = forwardRef<HTMLDivElement, CodeEditorProps>(\n (\n {\n value = '',\n onChange,\n language = 'plaintext',\n placeholder,\n readOnly = false,\n autoFocus = false,\n lineNumbers: showLineNumbers = true,\n foldGutter: showFoldGutter = true,\n highlightActiveLine: showHighlightActiveLine = true,\n bracketMatching: enableBracketMatching = true,\n closeBrackets: enableCloseBrackets = true,\n autocompletion: enableAutocompletion = true,\n indentWithTab: enableIndentWithTab = true,\n minHeight = 200,\n maxHeight,\n size,\n bordered = true,\n extensions: additionalExtensions = [],\n onEditorReady,\n className = '',\n 'data-testid': testId = 'code-editor',\n ...rest\n },\n ref\n ) => {\n const { componentSize } = useConfig()\n const effectiveSize = size ?? componentSize ?? 'md'\n\n const containerRef = useRef<HTMLDivElement>(null)\n const viewRef = useRef<EditorView | null>(null)\n const onChangeRef = useRef(onChange)\n\n // Keep onChange ref updated\n useEffect(() => {\n onChangeRef.current = onChange\n }, [onChange])\n\n // Create and manage editor\n useEffect(() => {\n if (!containerRef.current) return\n\n const extensions: Extension[] = [\n baseTheme,\n highlightSpecialChars(),\n history(),\n drawSelection(),\n dropCursor(),\n EditorState.allowMultipleSelections.of(true),\n indentOnInput(),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n rectangularSelection(),\n crosshairCursor(),\n highlightSelectionMatches(),\n keymap.of([\n ...closeBracketsKeymap,\n ...defaultKeymap,\n ...searchKeymap,\n ...historyKeymap,\n ...foldKeymap,\n ...completionKeymap,\n ...lintKeymap,\n ]),\n ]\n\n if (showLineNumbers) {\n extensions.push(lineNumbers())\n }\n\n if (showFoldGutter) {\n extensions.push(foldGutter())\n }\n\n if (showHighlightActiveLine) {\n extensions.push(highlightActiveLine())\n extensions.push(highlightActiveLineGutter())\n }\n\n if (enableBracketMatching) {\n extensions.push(bracketMatching())\n }\n\n if (enableCloseBrackets) {\n extensions.push(closeBrackets())\n }\n\n if (enableAutocompletion) {\n extensions.push(autocompletion())\n }\n\n if (enableIndentWithTab) {\n extensions.push(keymap.of([indentWithTab]))\n }\n\n const langExtension = getLanguageExtension(language)\n if (langExtension) {\n extensions.push(langExtension)\n }\n\n if (placeholder) {\n extensions.push(EditorView.contentAttributes.of({ 'aria-placeholder': placeholder }))\n extensions.push(\n EditorView.theme({\n '.cm-content:has(.cm-line:only-child:empty)::before': {\n content: `\"${placeholder}\"`,\n position: 'absolute',\n color: 'oklch(var(--bc) / 0.4)',\n fontStyle: 'italic',\n pointerEvents: 'none',\n },\n })\n )\n }\n\n if (readOnly) {\n extensions.push(EditorState.readOnly.of(true))\n extensions.push(EditorView.editable.of(false))\n }\n\n // Update listener\n extensions.push(\n EditorView.updateListener.of((update) => {\n if (update.docChanged && onChangeRef.current) {\n onChangeRef.current(update.state.doc.toString())\n }\n })\n )\n\n // Size styling\n const sizeStyle = sizeClasses[effectiveSize]\n extensions.push(\n EditorView.theme({\n '.cm-content': {\n fontSize: sizeStyle.fontSize,\n lineHeight: sizeStyle.lineHeight,\n },\n '.cm-gutters': {\n fontSize: sizeStyle.fontSize,\n },\n })\n )\n\n // Add user extensions\n extensions.push(...additionalExtensions)\n\n const state = EditorState.create({\n doc: value,\n extensions,\n })\n\n const view = new EditorView({\n state,\n parent: containerRef.current,\n })\n\n viewRef.current = view\n\n if (autoFocus) {\n view.focus()\n }\n\n if (onEditorReady) {\n onEditorReady(view)\n }\n\n return () => {\n view.destroy()\n viewRef.current = null\n }\n }, [\n language,\n placeholder,\n readOnly,\n showLineNumbers,\n showFoldGutter,\n showHighlightActiveLine,\n enableBracketMatching,\n enableCloseBrackets,\n enableAutocompletion,\n enableIndentWithTab,\n effectiveSize,\n autoFocus,\n additionalExtensions,\n onEditorReady,\n ])\n\n // Sync value prop changes\n useEffect(() => {\n const view = viewRef.current\n if (!view) return\n\n const currentValue = view.state.doc.toString()\n if (value !== currentValue) {\n view.dispatch({\n changes: {\n from: 0,\n to: currentValue.length,\n insert: value,\n },\n })\n }\n }, [value])\n\n const minHeightStyle = typeof minHeight === 'number' ? `${minHeight}px` : minHeight\n const maxHeightStyle = maxHeight\n ? typeof maxHeight === 'number'\n ? `${maxHeight}px`\n : maxHeight\n : undefined\n\n return (\n <div\n ref={ref}\n className={`\n bg-base-100 rounded-lg overflow-hidden\n ${bordered ? 'border border-base-300' : ''}\n ${className}\n `}\n data-testid={testId}\n {...rest}\n >\n <div\n ref={containerRef}\n className=\"[&_.cm-editor]:outline-none\"\n style={{\n minHeight: minHeightStyle,\n maxHeight: maxHeightStyle,\n overflow: maxHeightStyle ? 'auto' : undefined,\n }}\n />\n </div>\n )\n }\n)\n\nCodeEditor.displayName = 'CodeEditor'\n\nexport default CodeEditor\n"],"names":["sizeClasses","getLanguageExtension","language","javascript","python","html","css","json","markdown","sql","xml","baseTheme","EditorView","CodeEditor","forwardRef","value","onChange","placeholder","readOnly","autoFocus","showLineNumbers","showFoldGutter","showHighlightActiveLine","enableBracketMatching","enableCloseBrackets","enableAutocompletion","enableIndentWithTab","minHeight","maxHeight","size","bordered","additionalExtensions","onEditorReady","className","testId","rest","ref","componentSize","useConfig","effectiveSize","containerRef","useRef","viewRef","onChangeRef","useEffect","extensions","highlightSpecialChars","history","drawSelection","dropCursor","EditorState","indentOnInput","syntaxHighlighting","defaultHighlightStyle","rectangularSelection","crosshairCursor","highlightSelectionMatches","keymap","closeBracketsKeymap","defaultKeymap","searchKeymap","historyKeymap","foldKeymap","completionKeymap","lintKeymap","lineNumbers","foldGutter","highlightActiveLine","highlightActiveLineGutter","bracketMatching","closeBrackets","autocompletion","indentWithTab","langExtension","update","sizeStyle","state","view","currentValue","minHeightStyle","maxHeightStyle","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"CodeEditor.js","sources":["../../src/components/CodeEditor.tsx"],"sourcesContent":["import React, { forwardRef, useEffect, useRef } from 'react'\nimport { EditorState, type Extension } from '@codemirror/state'\nimport { EditorView, keymap, lineNumbers, highlightActiveLine, highlightActiveLineGutter, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightSpecialChars } from '@codemirror/view'\nimport { defaultHighlightStyle, syntaxHighlighting, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language'\nimport { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands'\nimport { searchKeymap, highlightSelectionMatches } from '@codemirror/search'\nimport { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'\nimport { lintKeymap } from '@codemirror/lint'\nimport { javascript } from '@codemirror/lang-javascript'\nimport { python } from '@codemirror/lang-python'\nimport { html } from '@codemirror/lang-html'\nimport { css } from '@codemirror/lang-css'\nimport { json } from '@codemirror/lang-json'\nimport { markdown } from '@codemirror/lang-markdown'\nimport { sql } from '@codemirror/lang-sql'\nimport { xml } from '@codemirror/lang-xml'\nimport { useConfig } from '../providers/ConfigProvider'\n\nexport type CodeEditorLanguage =\n | 'javascript'\n | 'typescript'\n | 'jsx'\n | 'tsx'\n | 'python'\n | 'html'\n | 'css'\n | 'json'\n | 'markdown'\n | 'sql'\n | 'xml'\n | 'plaintext'\n\nexport interface CodeEditorProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Code content */\n value?: string\n /** Callback when content changes */\n onChange?: (value: string) => void\n /** Programming language for syntax highlighting */\n language?: CodeEditorLanguage\n /** Placeholder text when empty */\n placeholder?: string\n /** Make editor read-only */\n readOnly?: boolean\n /** Auto focus on mount */\n autoFocus?: boolean\n /** Show line numbers */\n lineNumbers?: boolean\n /** Enable code folding */\n foldGutter?: boolean\n /** Highlight active line */\n highlightActiveLine?: boolean\n /** Enable bracket matching */\n bracketMatching?: boolean\n /** Enable auto-closing brackets */\n closeBrackets?: boolean\n /** Enable autocompletion */\n autocompletion?: boolean\n /** Allow tab key for indentation */\n indentWithTab?: boolean\n /** Minimum height of the editor */\n minHeight?: string | number\n /** Maximum height of the editor (enables scrolling) */\n maxHeight?: string | number\n /** Editor size variant */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n /** Show border around editor */\n bordered?: boolean\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Callback with editor view instance */\n onEditorReady?: (view: EditorView) => void\n 'data-testid'?: string\n}\n\nconst sizeClasses = {\n xs: { fontSize: '11px', lineHeight: '1.4' },\n sm: { fontSize: '12px', lineHeight: '1.5' },\n md: { fontSize: '14px', lineHeight: '1.6' },\n lg: { fontSize: '16px', lineHeight: '1.6' },\n xl: { fontSize: '18px', lineHeight: '1.7' },\n}\n\nfunction getLanguageExtension(language: CodeEditorLanguage): Extension | null {\n switch (language) {\n case 'javascript':\n return javascript()\n case 'typescript':\n return javascript({ typescript: true })\n case 'jsx':\n return javascript({ jsx: true })\n case 'tsx':\n return javascript({ jsx: true, typescript: true })\n case 'python':\n return python()\n case 'html':\n return html()\n case 'css':\n return css()\n case 'json':\n return json()\n case 'markdown':\n return markdown()\n case 'sql':\n return sql()\n case 'xml':\n return xml()\n case 'plaintext':\n default:\n return null\n }\n}\n\nconst baseTheme = EditorView.theme({\n '&': {\n backgroundColor: 'oklch(var(--b1))',\n color: 'oklch(var(--bc))',\n },\n '.cm-content': {\n caretColor: 'oklch(var(--bc))',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n },\n '.cm-cursor, .cm-dropCursor': {\n borderLeftColor: 'oklch(var(--bc))',\n },\n '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {\n backgroundColor: 'oklch(var(--p) / 0.2)',\n },\n '.cm-activeLine': {\n backgroundColor: 'oklch(var(--bc) / 0.05)',\n },\n '.cm-activeLineGutter': {\n backgroundColor: 'oklch(var(--bc) / 0.05)',\n },\n '.cm-gutters': {\n backgroundColor: 'oklch(var(--b2))',\n color: 'oklch(var(--bc) / 0.5)',\n borderRight: '1px solid oklch(var(--b3))',\n },\n '.cm-lineNumbers .cm-gutterElement': {\n padding: '0 8px 0 16px',\n },\n '.cm-foldGutter .cm-gutterElement': {\n padding: '0 4px',\n },\n '.cm-scroller': {\n overflow: 'auto',\n },\n '.cm-placeholder': {\n color: 'oklch(var(--bc) / 0.4)',\n fontStyle: 'italic',\n },\n})\n\nexport const CodeEditor = forwardRef<HTMLDivElement, CodeEditorProps>(\n (\n {\n value = '',\n onChange,\n language = 'plaintext',\n placeholder,\n readOnly = false,\n autoFocus = false,\n lineNumbers: showLineNumbers = true,\n foldGutter: showFoldGutter = true,\n highlightActiveLine: showHighlightActiveLine = true,\n bracketMatching: enableBracketMatching = true,\n closeBrackets: enableCloseBrackets = true,\n autocompletion: enableAutocompletion = true,\n indentWithTab: enableIndentWithTab = true,\n minHeight = 200,\n maxHeight,\n size,\n bordered = true,\n extensions: additionalExtensions = [],\n onEditorReady,\n className = '',\n 'data-testid': testId = 'code-editor',\n ...rest\n },\n ref\n ) => {\n const { componentSize } = useConfig()\n const effectiveSize = size ?? componentSize ?? 'md'\n\n const containerRef = useRef<HTMLDivElement>(null)\n const viewRef = useRef<EditorView | null>(null)\n const onChangeRef = useRef(onChange)\n\n // Keep onChange ref updated\n useEffect(() => {\n onChangeRef.current = onChange\n }, [onChange])\n\n // Create and manage editor\n useEffect(() => {\n if (!containerRef.current) return\n\n const extensions: Extension[] = [\n baseTheme,\n highlightSpecialChars(),\n history(),\n drawSelection(),\n dropCursor(),\n EditorState.allowMultipleSelections.of(true),\n indentOnInput(),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n rectangularSelection(),\n crosshairCursor(),\n highlightSelectionMatches(),\n keymap.of([\n ...closeBracketsKeymap,\n ...defaultKeymap,\n ...searchKeymap,\n ...historyKeymap,\n ...foldKeymap,\n ...completionKeymap,\n ...lintKeymap,\n ]),\n ]\n\n if (showLineNumbers) {\n extensions.push(lineNumbers())\n }\n\n if (showFoldGutter) {\n extensions.push(foldGutter())\n }\n\n if (showHighlightActiveLine) {\n extensions.push(highlightActiveLine())\n extensions.push(highlightActiveLineGutter())\n }\n\n if (enableBracketMatching) {\n extensions.push(bracketMatching())\n }\n\n if (enableCloseBrackets) {\n extensions.push(closeBrackets())\n }\n\n if (enableAutocompletion) {\n extensions.push(autocompletion())\n }\n\n if (enableIndentWithTab) {\n extensions.push(keymap.of([indentWithTab]))\n }\n\n const langExtension = getLanguageExtension(language)\n if (langExtension) {\n extensions.push(langExtension)\n }\n\n if (placeholder) {\n extensions.push(EditorView.contentAttributes.of({ 'aria-placeholder': placeholder }))\n extensions.push(\n EditorView.theme({\n '.cm-content:has(.cm-line:only-child:empty)::before': {\n content: `\"${placeholder}\"`,\n position: 'absolute',\n color: 'oklch(var(--bc) / 0.4)',\n fontStyle: 'italic',\n pointerEvents: 'none',\n },\n })\n )\n }\n\n if (readOnly) {\n extensions.push(EditorState.readOnly.of(true))\n extensions.push(EditorView.editable.of(false))\n }\n\n // Update listener\n extensions.push(\n EditorView.updateListener.of((update) => {\n if (update.docChanged && onChangeRef.current) {\n onChangeRef.current(update.state.doc.toString())\n }\n })\n )\n\n // Size styling\n const sizeStyle = sizeClasses[effectiveSize]\n extensions.push(\n EditorView.theme({\n '.cm-content': {\n fontSize: sizeStyle.fontSize,\n lineHeight: sizeStyle.lineHeight,\n },\n '.cm-gutters': {\n fontSize: sizeStyle.fontSize,\n },\n })\n )\n\n // Add user extensions\n extensions.push(...additionalExtensions)\n\n const state = EditorState.create({\n doc: value,\n extensions,\n })\n\n const view = new EditorView({\n state,\n parent: containerRef.current,\n })\n\n viewRef.current = view\n\n if (autoFocus) {\n view.focus()\n }\n\n if (onEditorReady) {\n onEditorReady(view)\n }\n\n return () => {\n view.destroy()\n viewRef.current = null\n }\n }, [\n language,\n placeholder,\n readOnly,\n showLineNumbers,\n showFoldGutter,\n showHighlightActiveLine,\n enableBracketMatching,\n enableCloseBrackets,\n enableAutocompletion,\n enableIndentWithTab,\n effectiveSize,\n autoFocus,\n additionalExtensions,\n onEditorReady,\n ])\n\n // Sync value prop changes\n useEffect(() => {\n const view = viewRef.current\n if (!view) return\n\n const currentValue = view.state.doc.toString()\n if (value !== currentValue) {\n view.dispatch({\n changes: {\n from: 0,\n to: currentValue.length,\n insert: value,\n },\n })\n }\n }, [value])\n\n const minHeightStyle = typeof minHeight === 'number' ? `${minHeight}px` : minHeight\n const maxHeightStyle = maxHeight\n ? typeof maxHeight === 'number'\n ? `${maxHeight}px`\n : maxHeight\n : undefined\n\n return (\n <div\n ref={ref}\n className={`\n bg-base-100 rounded-lg overflow-hidden\n ${bordered ? 'border border-base-300' : ''}\n ${className}\n `}\n data-testid={testId}\n {...rest}\n >\n <div\n ref={containerRef}\n className=\"h-full [&_.cm-editor]:outline-none [&_.cm-editor]:h-full [&_.cm-editor]:!overflow-hidden [&_.cm-scroller]:!overflow-auto\"\n style={{\n minHeight: minHeightStyle,\n maxHeight: maxHeightStyle,\n overflow: maxHeightStyle ? 'auto' : undefined,\n }}\n />\n </div>\n )\n }\n)\n\nCodeEditor.displayName = 'CodeEditor'\n\nexport default CodeEditor\n"],"names":["sizeClasses","getLanguageExtension","language","javascript","python","html","css","json","markdown","sql","xml","baseTheme","EditorView","CodeEditor","forwardRef","value","onChange","placeholder","readOnly","autoFocus","showLineNumbers","showFoldGutter","showHighlightActiveLine","enableBracketMatching","enableCloseBrackets","enableAutocompletion","enableIndentWithTab","minHeight","maxHeight","size","bordered","additionalExtensions","onEditorReady","className","testId","rest","ref","componentSize","useConfig","effectiveSize","containerRef","useRef","viewRef","onChangeRef","useEffect","extensions","highlightSpecialChars","history","drawSelection","dropCursor","EditorState","indentOnInput","syntaxHighlighting","defaultHighlightStyle","rectangularSelection","crosshairCursor","highlightSelectionMatches","keymap","closeBracketsKeymap","defaultKeymap","searchKeymap","historyKeymap","foldKeymap","completionKeymap","lintKeymap","lineNumbers","foldGutter","highlightActiveLine","highlightActiveLineGutter","bracketMatching","closeBrackets","autocompletion","indentWithTab","langExtension","update","sizeStyle","state","view","currentValue","minHeightStyle","maxHeightStyle","jsx"],"mappings":"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"}
@@ -1,18 +1,19 @@
1
1
  import { default as React } from 'react';
2
2
  export interface ContextMenuItem {
3
3
  key: string;
4
- label: React.ReactNode;
4
+ label?: React.ReactNode;
5
5
  icon?: React.ReactNode;
6
6
  disabled?: boolean;
7
7
  danger?: boolean;
8
8
  divider?: boolean;
9
9
  children?: ContextMenuItem[];
10
+ 'data-testid'?: string;
10
11
  }
11
12
  export interface ContextMenuProps {
12
- /** Element that triggers the context menu on right-click */
13
+ /** Element that triggers the context menu on right-click (first child) */
13
14
  children: React.ReactNode;
14
- /** Menu items (data-driven pattern) */
15
- items?: ContextMenuItem[];
15
+ /** Menu items (data-driven pattern). Can be a static array or a function that receives the mouse event for dynamic items. */
16
+ items?: ContextMenuItem[] | ((e: React.MouseEvent) => ContextMenuItem[]);
16
17
  /** Callback when an item is selected */
17
18
  onSelect?: (key: string) => void;
18
19
  /** Whether the context menu is disabled */
@@ -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":"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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"Terminal.js","sources":["../../src/components/Terminal.tsx"],"sourcesContent":["import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'\nimport * as XTermPkg from '@xterm/xterm'\nimport * as FitAddonPkg from '@xterm/addon-fit'\nimport type { Terminal as XTermType, ITerminalOptions, ITerminalInitOnlyOptions } from '@xterm/xterm'\nimport type { FitAddon as FitAddonType } from '@xterm/addon-fit'\nimport { useTheme } from '../hooks/useTheme'\n\n// Handle both ESM and CJS module formats\nconst XTerm = (XTermPkg as { Terminal?: typeof XTermType }).Terminal\n ?? (XTermPkg as { default?: { Terminal: typeof XTermType } }).default?.Terminal\n ?? (XTermPkg as unknown as typeof XTermType)\nconst FitAddon = (FitAddonPkg as { FitAddon?: typeof FitAddonType }).FitAddon\n ?? (FitAddonPkg as { default?: { FitAddon: typeof FitAddonType } }).default?.FitAddon\n ?? (FitAddonPkg as unknown as typeof FitAddonType)\n\n// Inject xterm.css once (inlined for reliability across bundlers)\nlet cssInjected = false\nfunction injectXtermCSS() {\n if (cssInjected || typeof document === 'undefined') return\n cssInjected = true\n\n const style = document.createElement('style')\n style.setAttribute('data-xterm', '')\n style.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}`\n document.head.appendChild(style)\n}\n\nexport interface TerminalRef {\n /** The underlying xterm.js Terminal instance */\n terminal: XTermType | null\n /** Write data to the terminal */\n write: (data: string) => void\n /** Write a line to the terminal (with newline) */\n writeln: (data: string) => void\n /** Clear the terminal */\n clear: () => void\n /** Focus the terminal */\n focus: () => void\n /** Fit the terminal to its container */\n fit: () => void\n /** Command history (only available with readline mode) */\n history: string[]\n /** Clear command history (only available with readline mode) */\n clearHistory: () => void\n}\n\nexport interface TerminalProps {\n /** Callback when user types in the terminal (raw input) */\n onData?: (data: string) => void\n /** Callback when terminal is ready */\n onReady?: (terminal: XTermType) => void\n /** Enable readline mode with line editing and history */\n readline?: boolean\n /** Prompt string for readline mode (supports ANSI colors) */\n prompt?: string\n /** Callback when user submits a line in readline mode. Return a Promise to defer the next prompt. */\n onLine?: (line: string) => void | Promise<void>\n /** Convert LF to CRLF for proper newline handling (default: true) */\n convertEol?: boolean\n /** xterm.js options (theme is auto-applied unless you override it) */\n options?: ITerminalOptions & ITerminalInitOnlyOptions\n /** Additional CSS classes for the container */\n className?: string\n /** Container style */\n style?: React.CSSProperties\n 'data-testid'?: string\n}\n\nexport const Terminal = forwardRef<TerminalRef, TerminalProps>(({\n onData,\n onReady,\n readline = false,\n prompt = '$ ',\n onLine,\n convertEol = true,\n options = {},\n className = '',\n style,\n 'data-testid': testId,\n}, ref) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const terminalRef = useRef<XTermType | null>(null)\n const fitAddonRef = useRef<FitAddonType | null>(null)\n const { isDark, colors } = useTheme()\n\n // Readline state\n const readlineState = useRef({\n buffer: '',\n cursor: 0,\n history: [] as string[],\n historyIndex: -1,\n savedBuffer: '',\n })\n\n // Build theme from DaisyUI colors\n const getTheme = () => ({\n background: colors.background,\n foreground: colors.foreground,\n cursor: colors.primary,\n cursorAccent: colors.background,\n selectionBackground: colors.primary + '40',\n selectionForeground: colors.foreground,\n black: isDark ? '#000000' : '#2e3436',\n red: colors.error,\n green: colors.success,\n yellow: colors.warning,\n blue: colors.info,\n magenta: colors.secondary,\n cyan: colors.accent,\n white: isDark ? '#d3d7cf' : '#eeeeec',\n brightBlack: '#555753',\n brightRed: colors.error,\n brightGreen: colors.success,\n brightYellow: colors.warning,\n brightBlue: colors.info,\n brightMagenta: colors.secondary,\n brightCyan: colors.accent,\n brightWhite: isDark ? '#eeeeec' : '#ffffff',\n })\n\n useImperativeHandle(ref, () => ({\n terminal: terminalRef.current,\n write: (data: string) => terminalRef.current?.write(data),\n writeln: (data: string) => terminalRef.current?.writeln(data),\n clear: () => terminalRef.current?.clear(),\n focus: () => terminalRef.current?.focus(),\n fit: () => fitAddonRef.current?.fit(),\n history: readlineState.current.history,\n clearHistory: () => { readlineState.current.history = [] },\n }), [])\n\n // Redraw the current line in readline mode\n const redrawLine = () => {\n const term = terminalRef.current\n if (!term) return\n const s = readlineState.current\n // Move to start of line, clear line, write prompt + buffer, position cursor\n term.write('\\r\\x1b[K' + prompt + s.buffer)\n // Move cursor to correct position\n const moveBack = s.buffer.length - s.cursor\n if (moveBack > 0) {\n term.write(`\\x1b[${moveBack}D`)\n }\n }\n\n // Handle readline input\n const handleReadlineData = (data: string) => {\n const term = terminalRef.current\n if (!term) return\n const s = readlineState.current\n\n // Handle escape sequences (arrow keys)\n if (data === '\\x1b[A') {\n // Up arrow - history previous\n if (s.history.length > 0 && s.historyIndex < s.history.length - 1) {\n if (s.historyIndex === -1) s.savedBuffer = s.buffer\n s.historyIndex++\n s.buffer = s.history[s.history.length - 1 - s.historyIndex]\n s.cursor = s.buffer.length\n redrawLine()\n }\n return\n }\n if (data === '\\x1b[B') {\n // Down arrow - history next\n if (s.historyIndex > -1) {\n s.historyIndex--\n s.buffer = s.historyIndex === -1 ? s.savedBuffer : s.history[s.history.length - 1 - s.historyIndex]\n s.cursor = s.buffer.length\n redrawLine()\n }\n return\n }\n if (data === '\\x1b[C') {\n // Right arrow\n if (s.cursor < s.buffer.length) {\n s.cursor++\n term.write('\\x1b[C')\n }\n return\n }\n if (data === '\\x1b[D') {\n // Left arrow\n if (s.cursor > 0) {\n s.cursor--\n term.write('\\x1b[D')\n }\n return\n }\n if (data === '\\x1b[H' || data === '\\x1bOH' || data === '\\x1b[1~') {\n // Home - move to start of line\n if (s.cursor > 0) {\n term.write(`\\x1b[${s.cursor}D`)\n s.cursor = 0\n }\n return\n }\n if (data === '\\x1b[F' || data === '\\x1bOF' || data === '\\x1b[4~') {\n // End - move to end of line\n if (s.cursor < s.buffer.length) {\n term.write(`\\x1b[${s.buffer.length - s.cursor}C`)\n s.cursor = s.buffer.length\n }\n return\n }\n if (data === '\\x1b[3~') {\n // Delete key - delete character at cursor\n if (s.cursor < s.buffer.length) {\n s.buffer = s.buffer.slice(0, s.cursor) + s.buffer.slice(s.cursor + 1)\n redrawLine()\n }\n return\n }\n\n // Ignore other escape sequences\n if (data.startsWith('\\x1b')) return\n\n if (data === '\\r') {\n // Enter\n term.writeln('')\n const line = s.buffer\n if (line.trim()) {\n s.history.push(line)\n }\n s.buffer = ''\n s.cursor = 0\n s.historyIndex = -1\n s.savedBuffer = ''\n const result = onLine?.(line)\n if (result && typeof (result as any).then === 'function') {\n (result as any).then(() => term.write(prompt))\n } else {\n term.write(prompt)\n }\n } else if (data === '\\x7f' || data === '\\b') {\n // Backspace\n if (s.cursor > 0) {\n s.buffer = s.buffer.slice(0, s.cursor - 1) + s.buffer.slice(s.cursor)\n s.cursor--\n redrawLine()\n }\n } else if (data === '\\x03') {\n // Ctrl+C\n term.writeln('^C')\n s.buffer = ''\n s.cursor = 0\n s.historyIndex = -1\n term.write(prompt)\n } else if (data >= ' ' || data === '\\t') {\n // Printable characters\n s.buffer = s.buffer.slice(0, s.cursor) + data + s.buffer.slice(s.cursor)\n s.cursor += data.length\n redrawLine()\n }\n }\n\n // Initialize terminal\n useEffect(() => {\n if (!containerRef.current) return\n\n injectXtermCSS()\n\n const container = containerRef.current\n let terminal: XTermType | null = null\n let fitAddon: FitAddonType | null = null\n let resizeObserver: ResizeObserver | null = null\n let initialized = false\n let disposed = false\n\n const initTerminal = () => {\n if (initialized || disposed || !container) return\n\n // Check container has dimensions before opening\n const rect = container.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return\n\n initialized = true\n\n terminal = new XTerm({\n theme: getTheme(),\n cursorBlink: true,\n convertEol,\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n fontSize: 14,\n ...options,\n })\n fitAddon = new FitAddon()\n\n terminal.loadAddon(fitAddon)\n terminal.open(container)\n fitAddon.fit()\n\n terminalRef.current = terminal\n fitAddonRef.current = fitAddon\n\n if (readline) {\n terminal.onData(handleReadlineData)\n } else if (onData) {\n terminal.onData(onData)\n }\n\n onReady?.(terminal)\n\n // Write initial prompt after onReady so welcome messages appear first\n if (readline) {\n terminal.write(prompt)\n }\n }\n\n // Use ResizeObserver to wait for container to have dimensions\n resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry || disposed) return\n\n if (!initialized) {\n initTerminal()\n } else if (fitAddon) {\n fitAddon.fit()\n }\n })\n resizeObserver.observe(container)\n\n // Also try immediately in case container already has dimensions\n requestAnimationFrame(initTerminal)\n\n return () => {\n disposed = true\n resizeObserver?.disconnect()\n terminal?.dispose()\n terminalRef.current = null\n fitAddonRef.current = null\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update theme when colors change\n useEffect(() => {\n if (!terminalRef.current) return\n terminalRef.current.options.theme = getTheme()\n }, [isDark, colors]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n data-testid={testId}\n />\n )\n})\n\nTerminal.displayName = 'Terminal'\n"],"names":["XTerm","XTermPkg","FitAddon","FitAddonPkg","cssInjected","injectXtermCSS","style","Terminal","forwardRef","onData","onReady","readline","prompt","onLine","convertEol","options","className","testId","ref","containerRef","useRef","terminalRef","fitAddonRef","isDark","colors","useTheme","readlineState","getTheme","useImperativeHandle","data","redrawLine","term","s","moveBack","handleReadlineData","line","result","useEffect","container","terminal","fitAddon","resizeObserver","initialized","disposed","initTerminal","rect","entries","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"Terminal.js","sources":["../../src/components/Terminal.tsx"],"sourcesContent":["import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'\nimport * as XTermPkg from '@xterm/xterm'\nimport * as FitAddonPkg from '@xterm/addon-fit'\nimport type { Terminal as XTermType, ITerminalOptions, ITerminalInitOnlyOptions } from '@xterm/xterm'\nimport type { FitAddon as FitAddonType } from '@xterm/addon-fit'\nimport { useTheme } from '../hooks/useTheme'\n\n// Handle both ESM and CJS module formats\nconst XTerm = (XTermPkg as { Terminal?: typeof XTermType }).Terminal\n ?? (XTermPkg as { default?: { Terminal: typeof XTermType } }).default?.Terminal\n ?? (XTermPkg as unknown as typeof XTermType)\nconst FitAddon = (FitAddonPkg as { FitAddon?: typeof FitAddonType }).FitAddon\n ?? (FitAddonPkg as { default?: { FitAddon: typeof FitAddonType } }).default?.FitAddon\n ?? (FitAddonPkg as unknown as typeof FitAddonType)\n\n// Inject xterm.css once (inlined for reliability across bundlers)\nlet cssInjected = false\nfunction injectXtermCSS() {\n if (cssInjected || typeof document === 'undefined') return\n cssInjected = true\n\n const style = document.createElement('style')\n style.setAttribute('data-xterm', '')\n style.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}`\n document.head.appendChild(style)\n}\n\nexport interface TerminalRef {\n /** The underlying xterm.js Terminal instance */\n terminal: XTermType | null\n /** Write data to the terminal */\n write: (data: string) => void\n /** Write a line to the terminal (with newline) */\n writeln: (data: string) => void\n /** Clear the terminal */\n clear: () => void\n /** Focus the terminal */\n focus: () => void\n /** Fit the terminal to its container */\n fit: () => void\n /** Command history (only available with readline mode) */\n history: string[]\n /** Clear command history (only available with readline mode) */\n clearHistory: () => void\n}\n\nexport interface TerminalProps {\n /** Callback when user types in the terminal (raw input) */\n onData?: (data: string) => void\n /** Callback when terminal is ready */\n onReady?: (terminal: XTermType) => void\n /** Enable readline mode with line editing and history */\n readline?: boolean\n /** Prompt string for readline mode (supports ANSI colors) */\n prompt?: string\n /** Callback when user submits a line in readline mode. Return a Promise to defer the next prompt. */\n onLine?: (line: string) => void | Promise<void>\n /** Convert LF to CRLF for proper newline handling (default: true) */\n convertEol?: boolean\n /** xterm.js options (theme is auto-applied unless you override it) */\n options?: ITerminalOptions & ITerminalInitOnlyOptions\n /** Additional CSS classes for the container */\n className?: string\n /** Container style */\n style?: React.CSSProperties\n 'data-testid'?: string\n}\n\nexport const Terminal = forwardRef<TerminalRef, TerminalProps>(({\n onData,\n onReady,\n readline = false,\n prompt = '$ ',\n onLine,\n convertEol = true,\n options = {},\n className = '',\n style,\n 'data-testid': testId,\n}, ref) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const terminalRef = useRef<XTermType | null>(null)\n const fitAddonRef = useRef<FitAddonType | null>(null)\n const { isDark, colors } = useTheme()\n\n // Readline state\n const readlineState = useRef({\n buffer: '',\n cursor: 0,\n history: [] as string[],\n historyIndex: -1,\n savedBuffer: '',\n })\n\n // Build theme from DaisyUI colors\n const getTheme = () => ({\n background: colors.background,\n foreground: colors.foreground,\n cursor: colors.foreground,\n cursorAccent: colors.background,\n selectionBackground: colors.primary + '40',\n selectionForeground: colors.foreground,\n black: isDark ? '#000000' : '#2e3436',\n red: colors.error,\n green: colors.success,\n yellow: colors.warning,\n blue: colors.info,\n magenta: colors.secondary,\n cyan: colors.accent,\n white: isDark ? '#d3d7cf' : '#eeeeec',\n brightBlack: '#555753',\n brightRed: colors.error,\n brightGreen: colors.success,\n brightYellow: colors.warning,\n brightBlue: colors.info,\n brightMagenta: colors.secondary,\n brightCyan: colors.accent,\n brightWhite: isDark ? '#eeeeec' : '#ffffff',\n })\n\n useImperativeHandle(ref, () => ({\n terminal: terminalRef.current,\n write: (data: string) => terminalRef.current?.write(data),\n writeln: (data: string) => terminalRef.current?.writeln(data),\n clear: () => terminalRef.current?.clear(),\n focus: () => terminalRef.current?.focus(),\n fit: () => fitAddonRef.current?.fit(),\n history: readlineState.current.history,\n clearHistory: () => { readlineState.current.history = [] },\n }), [])\n\n // Redraw the current line in readline mode\n const redrawLine = () => {\n const term = terminalRef.current\n if (!term) return\n const s = readlineState.current\n // Move to start of line, clear line, write prompt + buffer, position cursor\n term.write('\\r\\x1b[K' + prompt + s.buffer)\n // Move cursor to correct position\n const moveBack = s.buffer.length - s.cursor\n if (moveBack > 0) {\n term.write(`\\x1b[${moveBack}D`)\n }\n }\n\n // Handle readline input\n const handleReadlineData = (data: string) => {\n const term = terminalRef.current\n if (!term) return\n const s = readlineState.current\n\n // Handle escape sequences (arrow keys)\n if (data === '\\x1b[A') {\n // Up arrow - history previous\n if (s.history.length > 0 && s.historyIndex < s.history.length - 1) {\n if (s.historyIndex === -1) s.savedBuffer = s.buffer\n s.historyIndex++\n s.buffer = s.history[s.history.length - 1 - s.historyIndex]\n s.cursor = s.buffer.length\n redrawLine()\n }\n return\n }\n if (data === '\\x1b[B') {\n // Down arrow - history next\n if (s.historyIndex > -1) {\n s.historyIndex--\n s.buffer = s.historyIndex === -1 ? s.savedBuffer : s.history[s.history.length - 1 - s.historyIndex]\n s.cursor = s.buffer.length\n redrawLine()\n }\n return\n }\n if (data === '\\x1b[C') {\n // Right arrow\n if (s.cursor < s.buffer.length) {\n s.cursor++\n term.write('\\x1b[C')\n }\n return\n }\n if (data === '\\x1b[D') {\n // Left arrow\n if (s.cursor > 0) {\n s.cursor--\n term.write('\\x1b[D')\n }\n return\n }\n if (data === '\\x1b[H' || data === '\\x1bOH' || data === '\\x1b[1~') {\n // Home - move to start of line\n if (s.cursor > 0) {\n term.write(`\\x1b[${s.cursor}D`)\n s.cursor = 0\n }\n return\n }\n if (data === '\\x1b[F' || data === '\\x1bOF' || data === '\\x1b[4~') {\n // End - move to end of line\n if (s.cursor < s.buffer.length) {\n term.write(`\\x1b[${s.buffer.length - s.cursor}C`)\n s.cursor = s.buffer.length\n }\n return\n }\n if (data === '\\x1b[3~') {\n // Delete key - delete character at cursor\n if (s.cursor < s.buffer.length) {\n s.buffer = s.buffer.slice(0, s.cursor) + s.buffer.slice(s.cursor + 1)\n redrawLine()\n }\n return\n }\n\n // Ignore other escape sequences\n if (data.startsWith('\\x1b')) return\n\n if (data === '\\r') {\n // Enter\n term.writeln('')\n const line = s.buffer\n if (line.trim()) {\n s.history.push(line)\n }\n s.buffer = ''\n s.cursor = 0\n s.historyIndex = -1\n s.savedBuffer = ''\n const result = onLine?.(line)\n if (result && typeof (result as any).then === 'function') {\n (result as any).then(() => term.write(prompt))\n } else {\n term.write(prompt)\n }\n } else if (data === '\\x7f' || data === '\\b') {\n // Backspace\n if (s.cursor > 0) {\n s.buffer = s.buffer.slice(0, s.cursor - 1) + s.buffer.slice(s.cursor)\n s.cursor--\n redrawLine()\n }\n } else if (data === '\\x03') {\n // Ctrl+C\n term.writeln('^C')\n s.buffer = ''\n s.cursor = 0\n s.historyIndex = -1\n term.write(prompt)\n } else if (data >= ' ' || data === '\\t') {\n // Printable characters\n s.buffer = s.buffer.slice(0, s.cursor) + data + s.buffer.slice(s.cursor)\n s.cursor += data.length\n redrawLine()\n }\n }\n\n // Initialize terminal\n useEffect(() => {\n if (!containerRef.current) return\n\n injectXtermCSS()\n\n const container = containerRef.current\n let terminal: XTermType | null = null\n let fitAddon: FitAddonType | null = null\n let resizeObserver: ResizeObserver | null = null\n let initialized = false\n let disposed = false\n\n const initTerminal = () => {\n if (initialized || disposed || !container) return\n\n // Check container has dimensions before opening\n const rect = container.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return\n\n initialized = true\n\n const { theme: userTheme, ...restOptions } = options\n terminal = new XTerm({\n theme: { ...getTheme(), ...userTheme },\n cursorBlink: true,\n convertEol,\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n fontSize: 14,\n ...restOptions,\n })\n fitAddon = new FitAddon()\n\n terminal.loadAddon(fitAddon)\n terminal.open(container)\n fitAddon.fit()\n\n terminalRef.current = terminal\n fitAddonRef.current = fitAddon\n\n if (readline) {\n terminal.onData(handleReadlineData)\n } else if (onData) {\n terminal.onData(onData)\n }\n\n onReady?.(terminal)\n\n // Write initial prompt after onReady so welcome messages appear first\n if (readline) {\n terminal.write(prompt)\n }\n }\n\n // Use ResizeObserver to wait for container to have dimensions\n resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry || disposed) return\n\n if (!initialized) {\n initTerminal()\n } else if (fitAddon) {\n fitAddon.fit()\n }\n })\n resizeObserver.observe(container)\n\n // Also try immediately in case container already has dimensions\n requestAnimationFrame(initTerminal)\n\n return () => {\n disposed = true\n resizeObserver?.disconnect()\n terminal?.dispose()\n terminalRef.current = null\n fitAddonRef.current = null\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Update theme when colors change\n useEffect(() => {\n if (!terminalRef.current) return\n terminalRef.current.options.theme = { ...getTheme(), ...options.theme }\n }, [isDark, colors]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n data-testid={testId}\n />\n )\n})\n\nTerminal.displayName = 'Terminal'\n"],"names":["XTerm","XTermPkg","FitAddon","FitAddonPkg","cssInjected","injectXtermCSS","style","Terminal","forwardRef","onData","onReady","readline","prompt","onLine","convertEol","options","className","testId","ref","containerRef","useRef","terminalRef","fitAddonRef","isDark","colors","useTheme","readlineState","getTheme","useImperativeHandle","data","redrawLine","term","s","moveBack","handleReadlineData","line","result","useEffect","container","terminal","fitAddon","resizeObserver","initialized","disposed","initTerminal","rect","userTheme","restOptions","entries","jsx"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aster-ui/prefixed",
3
- "version": "0.12.85",
3
+ "version": "0.12.87",
4
4
  "description": "React UI component library with DaisyUI (prefixed classes)",
5
5
  "homepage": "https://asterui.com",
6
6
  "repository": {