@ramesesinc/platform-core 0.1.6 → 0.1.9

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.
Files changed (90) hide show
  1. package/dist/components/action/LookupPage.js +9 -31
  2. package/dist/components/action/ViewPage.d.ts +2 -0
  3. package/dist/components/action/ViewPage.js +25 -31
  4. package/dist/components/common/UIComponent.js +4 -3
  5. package/dist/components/index.d.ts +3 -0
  6. package/dist/components/index.js +1 -0
  7. package/dist/components/table/DataList.js +2 -2
  8. package/dist/components/view/PopupView.d.ts +13 -0
  9. package/dist/components/view/PopupView.js +25 -20
  10. package/dist/core/DataContext.d.ts +7 -4
  11. package/dist/core/DataContext.js +16 -4
  12. package/dist/core/Page.js +25 -26
  13. package/dist/core/PageCache.js +7 -7
  14. package/dist/core/PageContext.js +17 -7
  15. package/dist/core/PageViewContext.d.ts +13 -1
  16. package/dist/core/PageViewContext.js +75 -2
  17. package/dist/core/PopupContext.d.ts +49 -0
  18. package/dist/core/PopupContext.js +380 -0
  19. package/dist/core/RowContext.js +1 -1
  20. package/dist/core/WindowContext.d.ts +15 -0
  21. package/dist/core/WindowContext.js +28 -0
  22. package/dist/core/index.d.ts +17 -0
  23. package/dist/core/index.js +1 -0
  24. package/dist/index.css +25 -7
  25. package/dist/lib/utils/BeanUtils.js +7 -7
  26. package/dist/templates/DataListTemplate.js +7 -2
  27. package/dist/templates/ExplorerTemplate.js +1 -1
  28. package/package.json +5 -5
  29. package/dist/components/action/AlertMessage.tsx +0 -38
  30. package/dist/components/action/Button.tsx +0 -230
  31. package/dist/components/action/CancelEdit.tsx +0 -40
  32. package/dist/components/action/DeleteData.tsx +0 -73
  33. package/dist/components/action/Edit.tsx +0 -40
  34. package/dist/components/action/LookupPage.tsx +0 -113
  35. package/dist/components/action/ProcessRunner.tsx +0 -337
  36. package/dist/components/action/Refresh.tsx +0 -35
  37. package/dist/components/action/SaveData.tsx +0 -74
  38. package/dist/components/action/SelectData.tsx +0 -47
  39. package/dist/components/action/Undo.tsx +0 -50
  40. package/dist/components/action/UpdateData.tsx +0 -49
  41. package/dist/components/action/UpdateState.tsx +0 -40
  42. package/dist/components/action/ViewBackPage.tsx +0 -46
  43. package/dist/components/action/ViewPage.tsx +0 -141
  44. package/dist/components/common/UIComponent.tsx +0 -86
  45. package/dist/components/common/UIInput.tsx +0 -49
  46. package/dist/components/common/UIMenu.tsx +0 -91
  47. package/dist/components/index.ts +0 -51
  48. package/dist/components/input/CodeEditor.tsx +0 -188
  49. package/dist/components/input/DateField.tsx +0 -274
  50. package/dist/components/input/DayPicker.tsx +0 -5
  51. package/dist/components/input/HtmlCode.tsx +0 -203
  52. package/dist/components/input/JsonCode.tsx +0 -205
  53. package/dist/components/input/MonthPicker.tsx +0 -5
  54. package/dist/components/input/ScriptCode.tsx +0 -195
  55. package/dist/components/input/Select.tsx +0 -78
  56. package/dist/components/input/SqlCode.tsx +0 -162
  57. package/dist/components/input/StringDecision.tsx +0 -64
  58. package/dist/components/input/Text.tsx +0 -57
  59. package/dist/components/input/YearPicker.tsx +0 -81
  60. package/dist/components/list/IconMenu.tsx +0 -115
  61. package/dist/components/list/TabMenu.tsx +0 -127
  62. package/dist/components/list/TreeMenu.tsx +0 -279
  63. package/dist/components/list/TxnTaskList.tsx +0 -198
  64. package/dist/components/output/Label.tsx +0 -50
  65. package/dist/components/table/DataList.tsx +0 -820
  66. package/dist/components/table/DataTable.tsx +0 -572
  67. package/dist/components/table/ListHandler.ts +0 -276
  68. package/dist/components/table/TableContext.tsx +0 -122
  69. package/dist/components/view/ComponentView.tsx +0 -102
  70. package/dist/components/view/FilterView.tsx +0 -21
  71. package/dist/components/view/HtmlForm.tsx +0 -176
  72. package/dist/components/view/HtmlView.tsx +0 -98
  73. package/dist/components/view/IFrameView.tsx +0 -48
  74. package/dist/components/view/Modal.tsx +0 -72
  75. package/dist/components/view/PageView.tsx +0 -131
  76. package/dist/components/view/PopupView.tsx +0 -160
  77. package/dist/components/view/RootView.tsx +0 -109
  78. package/dist/components/view/WizardView.tsx +0 -48
  79. package/dist/lib/layouts/BorderLayout.tsx +0 -31
  80. package/dist/lib/layouts/CardLayout.tsx +0 -73
  81. package/dist/lib/layouts/CenterLayout.tsx +0 -20
  82. package/dist/lib/layouts/GridLayout.tsx +0 -20
  83. package/dist/lib/layouts/HPanel.tsx +0 -31
  84. package/dist/lib/layouts/HorizontalLayout.tsx +0 -29
  85. package/dist/lib/layouts/MainLayout.tsx +0 -16
  86. package/dist/lib/layouts/PageLayout.tsx +0 -29
  87. package/dist/lib/layouts/VPanel.tsx +0 -27
  88. package/dist/lib/layouts/XLayout.tsx +0 -29
  89. package/dist/lib/layouts/YLayout.tsx +0 -29
  90. package/dist/lib/layouts/index.ts +0 -13
@@ -1,205 +0,0 @@
1
- import Editor from "@monaco-editor/react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- import { usePageContext } from "../../core/PageContext";
4
- import CopyButton from "../../lib/components/CopyButton";
5
- import UIComponent from "../common/UIComponent";
6
- import useUIInput, { UIInputProps } from "../common/UIInput";
7
-
8
- type JsonCodeProps = UIInputProps & {
9
- height?: number | string;
10
- width?: number | string;
11
- showCopy?: boolean;
12
- onParsed?: (value: any) => void;
13
- };
14
-
15
- const JsonCode = (props: JsonCodeProps) => {
16
- const { height = 300, width = "100%", showCopy = true, onParsed } = props ?? {};
17
-
18
- const pageContext = usePageContext();
19
- const editorRef = useRef<any>(null);
20
- const [fontSize, setFontSize] = useState(14);
21
- const [error, setError] = useState("");
22
- const [readOnly, setReadOnly] = useState(true);
23
-
24
- const stringify = (val: any): string => {
25
- if (val == null) return "";
26
-
27
- try {
28
- return typeof val === "string" ? val : JSON.stringify(val, null, 2);
29
- } catch (error) {
30
- console.error("Error stringifying value:", error);
31
- return "";
32
- }
33
- };
34
-
35
- const onRefresh = () => {
36
- const val = getValue();
37
- updateValue(val);
38
- };
39
-
40
- // Initialize once from pageContext — no buffering
41
- const { initialValue, getValue, setValue } = useUIInput({ ...props, onRefresh });
42
-
43
- const [editorValue, setEditorValue] = useState<string | null>(stringify(initialValue));
44
-
45
- const updateValue = (value: any) => {
46
- if (error != null && error !== "") {
47
- // no updating of editor value if there's an error
48
- return;
49
- }
50
-
51
- const strValue = stringify(value);
52
- let strEditorValue = "";
53
- try {
54
- const parsedEditorValue = JSON.parse(editorValue ?? "");
55
- strEditorValue = stringify(parsedEditorValue);
56
- } catch (e) {}
57
-
58
- const matched = strValue === strEditorValue;
59
- // console.log("updateValue ", { value, strValue, strEditorValue, matched });
60
-
61
- if (!matched) {
62
- setEditorValue(strValue);
63
- }
64
- };
65
-
66
- useEffect(() => {
67
- const unsubscribe = pageContext?.dependsTo("editable", (val: any) => {
68
- const isEditable = val === true || val === "true";
69
- setReadOnly(!isEditable);
70
- setError("");
71
-
72
- if (!isEditable) {
73
- const val = getValue();
74
- updateValue(val);
75
- }
76
- });
77
- return unsubscribe;
78
- }, []);
79
-
80
- useEffect(() => {
81
- return () => {
82
- // console.log("unmount");
83
- editorRef.current = null;
84
- };
85
- }, []);
86
-
87
- const handleKeyDown = useCallback((e: KeyboardEvent) => {
88
- if (e.ctrlKey && e.key === "=") {
89
- e.preventDefault();
90
- setFontSize((prev) => Math.min(prev + 1, 40));
91
- }
92
- if (e.ctrlKey && e.key === "-") {
93
- e.preventDefault();
94
- setFontSize((prev) => Math.max(prev - 1, 8));
95
- }
96
- if (e.ctrlKey && e.key === "0") {
97
- e.preventDefault();
98
- setFontSize(14);
99
- }
100
- }, []);
101
-
102
- useEffect(() => {
103
- window.addEventListener("keydown", handleKeyDown);
104
- return () => window.removeEventListener("keydown", handleKeyDown);
105
- }, [handleKeyDown]);
106
-
107
- useEffect(() => {
108
- editorRef.current?.updateOptions({ fontSize });
109
- }, [fontSize]);
110
-
111
- useEffect(() => {
112
- editorRef.current?.updateOptions({ readOnly, domReadOnly: readOnly });
113
- }, [readOnly]);
114
-
115
- const handleEditorChange = (value?: string) => {
116
- if (readOnly) return;
117
- const safeValue = value ?? "";
118
- setEditorValue(safeValue);
119
-
120
- try {
121
- const parsed = JSON.parse(safeValue);
122
- setValue(parsed); // write through to pageContext immediately
123
- setError("");
124
- onParsed?.(parsed);
125
- } catch (e: any) {
126
- setError(e.message);
127
- }
128
- };
129
-
130
- const handleEditorDidMount = (editor: any, monaco: any) => {
131
- editorRef.current = editor;
132
-
133
- try {
134
- monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
135
- validate: true,
136
- allowComments: false,
137
- schemas: [],
138
- enableSchemaRequest: true,
139
- });
140
- } catch (e) {
141
- console.warn("Monaco JSON diagnostics setup failed:", e);
142
- }
143
-
144
- editor.updateOptions({
145
- minimap: { enabled: false },
146
- fontSize,
147
- lineNumbers: "on",
148
- renderWhitespace: "selection",
149
- folding: false,
150
- bracketPairColorization: { enabled: true },
151
- formatOnPaste: false,
152
- formatOnType: false,
153
- });
154
- };
155
-
156
- // useEffect(() => {
157
- // console.log("editor value changed", editorValue, getValue());
158
- // }, [editorValue]);
159
-
160
- return (
161
- <UIComponent {...(props ?? {})}>
162
- <div className="relative w-full bg-white">
163
- {showCopy && (
164
- <div className="absolute top-2 right-4 z-50">
165
- <CopyButton item={editorValue ?? ""} copySize={15} copiedSize={10} classNameCopied="!px-[15px] !py-[10px]" />
166
- </div>
167
- )}
168
- <Editor
169
- key="json-code-viewer"
170
- height={height}
171
- width={width}
172
- language="json"
173
- value={editorValue ?? ""}
174
- onChange={handleEditorChange}
175
- onMount={handleEditorDidMount}
176
- theme="vs-dark"
177
- options={{
178
- readOnly,
179
- domReadOnly: readOnly,
180
- padding: { top: 10 },
181
- selectOnLineNumbers: true,
182
- automaticLayout: true,
183
- minimap: { enabled: false },
184
- fontSize,
185
- wordWrap: "off",
186
- lineNumbers: "on",
187
- renderWhitespace: "selection",
188
- folding: false,
189
- bracketPairColorization: { enabled: true },
190
- formatOnType: false,
191
- formatOnPaste: false,
192
- scrollBeyondLastLine: false,
193
- smoothScrolling: true,
194
- cursorBlinking: "smooth",
195
- renderLineHighlight: "all",
196
- scrollbar: { vertical: "visible", horizontal: "visible" },
197
- }}
198
- />
199
- {error && !readOnly && <p className="text-red-500 text-xs mt-1 px-1">{error}</p>}
200
- </div>
201
- </UIComponent>
202
- );
203
- };
204
-
205
- export default JsonCode;
@@ -1,5 +0,0 @@
1
- const MonthPicker = () => {
2
- return <div>MonthPicker</div>;
3
- };
4
-
5
- export default MonthPicker;
@@ -1,195 +0,0 @@
1
- import Editor from "@monaco-editor/react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- import { usePageContext } from "../../core/PageContext";
4
- import CopyButton from "../../lib/components/CopyButton";
5
- import UIComponent from "../common/UIComponent";
6
- import useUIInput, { UIInputProps } from "../common/UIInput";
7
-
8
- type ScriptCodeProps = UIInputProps & {
9
- height?: number | string;
10
- width?: number | string;
11
- showCopy?: boolean;
12
- };
13
-
14
- const ScriptCode = (props: ScriptCodeProps) => {
15
- const { height = 300, width = "100%", showCopy = true } = props ?? {};
16
-
17
- const pageContext = usePageContext();
18
- const editorRef = useRef<any>(null);
19
- const [fontSize, setFontSize] = useState(14);
20
- const [error, setError] = useState("");
21
- const [readOnly, setReadOnly] = useState(true);
22
-
23
- const onRefresh = () => {
24
- const val = getValue();
25
- setEditorValue(val ?? "");
26
- };
27
-
28
- const { initialValue, getValue, setValue } = useUIInput({ ...props, onRefresh });
29
-
30
- const [editorValue, setEditorValue] = useState(() => initialValue ?? "");
31
-
32
- useEffect(() => {
33
- const unsubscribe = pageContext?.dependsTo("editable", (val: any) => {
34
- const isEditable = val === true || val === "true";
35
- setReadOnly(!isEditable);
36
-
37
- if (!isEditable) {
38
- setEditorValue(getValue() ?? "");
39
- setError("");
40
- }
41
- });
42
- return unsubscribe;
43
- }, []);
44
-
45
- useEffect(() => {
46
- return () => {
47
- editorRef.current = null;
48
- };
49
- }, []);
50
-
51
- const handleKeyDown = useCallback((e: KeyboardEvent) => {
52
- if (e.ctrlKey && e.key === "=") {
53
- e.preventDefault();
54
- setFontSize((prev) => Math.min(prev + 1, 40));
55
- }
56
- if (e.ctrlKey && e.key === "-") {
57
- e.preventDefault();
58
- setFontSize((prev) => Math.max(prev - 1, 8));
59
- }
60
- if (e.ctrlKey && e.key === "0") {
61
- e.preventDefault();
62
- setFontSize(14);
63
- }
64
- }, []);
65
-
66
- useEffect(() => {
67
- window.addEventListener("keydown", handleKeyDown);
68
- return () => window.removeEventListener("keydown", handleKeyDown);
69
- }, [handleKeyDown]);
70
-
71
- useEffect(() => {
72
- editorRef.current?.updateOptions({ fontSize });
73
- }, [fontSize]);
74
-
75
- useEffect(() => {
76
- editorRef.current?.updateOptions({ readOnly, domReadOnly: readOnly });
77
- }, [readOnly]);
78
-
79
- const validateScript = (code: string) => {
80
- if (!code.trim()) {
81
- setError("");
82
- return;
83
- }
84
-
85
- const errors: string[] = [];
86
- const lines = code.split("\n");
87
-
88
- let braceCount = 0;
89
- let parenCount = 0;
90
- let bracketCount = 0;
91
-
92
- for (let i = 0; i < lines.length; i++) {
93
- const line = lines[i];
94
- const lineNum = i + 1;
95
-
96
- for (const char of line) {
97
- if (char === "{") braceCount++;
98
- if (char === "}") braceCount--;
99
- if (char === "(") parenCount++;
100
- if (char === ")") parenCount--;
101
- if (char === "[") bracketCount++;
102
- if (char === "]") bracketCount--;
103
- }
104
-
105
- if (line.trim().match(/^(let|const|var)\s+\w+\s*=.*[^;{}\s]$/)) {
106
- errors.push(`Line ${lineNum}: Possible missing semicolon`);
107
- }
108
-
109
- if (line.includes("console.log") && !line.trim().endsWith(";") && !line.trim().endsWith("{")) {
110
- errors.push(`Line ${lineNum}: Missing semicolon after console.log`);
111
- }
112
- }
113
-
114
- if (braceCount !== 0) errors.push(`Unmatched braces: ${braceCount > 0 ? "missing closing" : "missing opening"} brace(s)`);
115
-
116
- if (parenCount !== 0) errors.push(`Unmatched parentheses: ${parenCount > 0 ? "missing closing" : "missing opening"}`);
117
-
118
- if (bracketCount !== 0) errors.push(`Unmatched brackets: ${bracketCount > 0 ? "missing closing" : "missing opening"}`);
119
-
120
- setError(errors.length > 0 ? errors.join("\n• ") : "");
121
- };
122
-
123
- const handleEditorChange = (value?: string) => {
124
- if (readOnly) return;
125
- const safeValue = value ?? "";
126
- setEditorValue(safeValue);
127
- setValue(safeValue); // JavaScript is always a string, write through immediately
128
- validateScript(safeValue);
129
- };
130
-
131
- const handleEditorDidMount = (editor: any) => {
132
- editorRef.current = editor;
133
-
134
- editor.updateOptions({
135
- minimap: { enabled: false },
136
- fontSize,
137
- lineNumbers: "on",
138
- renderWhitespace: "selection",
139
- folding: true,
140
- bracketPairColorization: { enabled: true },
141
- formatOnPaste: true,
142
- formatOnType: true,
143
- });
144
- };
145
-
146
- return (
147
- <UIComponent {...(props ?? {})}>
148
- <div className="relative w-full bg-white">
149
- {showCopy && (
150
- <div className="absolute top-2 right-4 z-50">
151
- <CopyButton item={editorValue} copySize={15} copiedSize={10} classNameCopied="!px-[15px] !py-[10px]" />
152
- </div>
153
- )}
154
- <Editor
155
- key="script-code-editor"
156
- height={height}
157
- width={width}
158
- language="javascript"
159
- value={editorValue}
160
- onChange={handleEditorChange}
161
- onMount={handleEditorDidMount}
162
- theme="vs-dark"
163
- options={{
164
- readOnly,
165
- domReadOnly: readOnly,
166
- padding: { top: 10 },
167
- selectOnLineNumbers: true,
168
- automaticLayout: true,
169
- minimap: { enabled: false },
170
- fontSize,
171
- wordWrap: "off",
172
- lineNumbers: "on",
173
- renderWhitespace: "selection",
174
- folding: true,
175
- bracketPairColorization: { enabled: true },
176
- formatOnPaste: true,
177
- formatOnType: true,
178
- scrollBeyondLastLine: false,
179
- smoothScrolling: true,
180
- cursorBlinking: "smooth",
181
- renderLineHighlight: "all",
182
- autoIndent: "full",
183
- suggestOnTriggerCharacters: true,
184
- quickSuggestions: true,
185
- parameterHints: { enabled: true },
186
- scrollbar: { vertical: "visible", horizontal: "visible" },
187
- }}
188
- />
189
- {error && !readOnly && <div className="mt-2 text-sm text-red-500 whitespace-pre-wrap">• {error}</div>}
190
- </div>
191
- </UIComponent>
192
- );
193
- };
194
-
195
- export default ScriptCode;
@@ -1,78 +0,0 @@
1
- import { useRef, useState } from "react";
2
- import UIComponent from "../common/UIComponent";
3
- import useUIInput, { UIInputProps } from "../common/UIInput";
4
-
5
- type SelectOption = {
6
- label: string;
7
- value: string;
8
- };
9
-
10
- type SelectFieldProps = UIInputProps & {
11
- required?: boolean;
12
- immediate?: boolean;
13
- options?: SelectOption[];
14
- placeholder?: string;
15
- onChange?: (value: string) => void;
16
- };
17
-
18
- const SelectField = (props: SelectFieldProps) => {
19
- const { immediate = true, options = [], placeholder } = props ?? {};
20
- const [focused, setFocused] = useState(false);
21
- const selectRef = useRef<HTMLSelectElement | null>(null);
22
- const valueRef = useRef<string>("");
23
-
24
- const className = "border rounded px-2 py-1 w-full";
25
-
26
- const handleFocus = () => {
27
- setFocused(true);
28
- };
29
-
30
- const handleBlur = () => {
31
- if (!immediate) {
32
- setValue(selectValue);
33
- }
34
- setFocused(false);
35
- };
36
-
37
- const onRefresh = () => {
38
- setSelectValue(getValue());
39
- };
40
-
41
- const { initialValue, getValue, setValue, binding } = useUIInput({ ...props, onRefresh });
42
- valueRef.current = initialValue ?? "";
43
- const [selectValue, setSelectValue] = useState(valueRef.current);
44
-
45
- const onChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
46
- const text = e.target.value ?? "";
47
-
48
- if (text !== selectValue) {
49
- valueRef.current = text;
50
- setSelectValue(valueRef.current);
51
- }
52
-
53
- if (immediate) {
54
- setValue(text);
55
- }
56
-
57
- props.onChange?.(text);
58
- };
59
-
60
- return (
61
- <UIComponent {...(props ?? {})}>
62
- <select ref={selectRef} onChange={onChange} value={selectValue} onFocus={handleFocus} onBlur={handleBlur} className={className}>
63
- {placeholder && (
64
- <option value="" disabled>
65
- {placeholder}
66
- </option>
67
- )}
68
- {options.map((opt) => (
69
- <option key={opt.value} value={opt.value}>
70
- {opt.label}
71
- </option>
72
- ))}
73
- </select>
74
- </UIComponent>
75
- );
76
- };
77
-
78
- export default SelectField;
@@ -1,162 +0,0 @@
1
- import Editor from "@monaco-editor/react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- import { usePageContext } from "../../core/PageContext";
4
- import CopyButton from "../../lib/components/CopyButton";
5
- import UIComponent from "../common/UIComponent";
6
- import useUIInput, { UIInputProps } from "../common/UIInput";
7
-
8
- type SqlCodeProps = UIInputProps & {
9
- height?: number | string;
10
- width?: number | string;
11
- showCopy?: boolean;
12
- };
13
-
14
- const SqlCode = (props: SqlCodeProps) => {
15
- const { height = 300, width = "100%", showCopy = true } = props ?? {};
16
-
17
- const pageContext = usePageContext();
18
- const editorRef = useRef<any>(null);
19
- const [fontSize, setFontSize] = useState(14);
20
- const [error, setError] = useState("");
21
- const [readOnly, setReadOnly] = useState(true);
22
-
23
- const onRefresh = () => {
24
- const val = getValue();
25
- setEditorValue(val ?? "");
26
- };
27
-
28
- const { initialValue, getValue, setValue } = useUIInput({ ...props, onRefresh });
29
-
30
- const [editorValue, setEditorValue] = useState(() => initialValue ?? "");
31
-
32
- useEffect(() => {
33
- const unsubscribe = pageContext?.dependsTo("editable", (val: any) => {
34
- const isEditable = val === true || val === "true";
35
- setReadOnly(!isEditable);
36
-
37
- if (!isEditable) {
38
- setEditorValue(getValue() ?? "");
39
- setError("");
40
- }
41
- });
42
- return unsubscribe;
43
- }, []);
44
-
45
- useEffect(() => {
46
- return () => {
47
- editorRef.current = null;
48
- };
49
- }, []);
50
-
51
- const handleKeyDown = useCallback((e: KeyboardEvent) => {
52
- if (e.ctrlKey && e.key === "=") {
53
- e.preventDefault();
54
- setFontSize((prev) => Math.min(prev + 1, 40));
55
- }
56
- if (e.ctrlKey && e.key === "-") {
57
- e.preventDefault();
58
- setFontSize((prev) => Math.max(prev - 1, 8));
59
- }
60
- if (e.ctrlKey && e.key === "0") {
61
- e.preventDefault();
62
- setFontSize(14);
63
- }
64
- }, []);
65
-
66
- useEffect(() => {
67
- window.addEventListener("keydown", handleKeyDown);
68
- return () => window.removeEventListener("keydown", handleKeyDown);
69
- }, [handleKeyDown]);
70
-
71
- useEffect(() => {
72
- editorRef.current?.updateOptions({ fontSize });
73
- }, [fontSize]);
74
-
75
- useEffect(() => {
76
- editorRef.current?.updateOptions({ readOnly, domReadOnly: readOnly });
77
- }, [readOnly]);
78
-
79
- const validateSql = (value: string) => {
80
- if (!value.trim()) {
81
- setError("");
82
- return;
83
- }
84
- const forbidden = /drop\s+table|delete\s+from/gi;
85
- if (forbidden.test(value)) {
86
- setError("Dangerous SQL statement detected.");
87
- } else {
88
- setError("");
89
- }
90
- };
91
-
92
- const handleEditorChange = (value?: string) => {
93
- if (readOnly) return;
94
- const safeValue = value ?? "";
95
- setEditorValue(safeValue);
96
- setValue(safeValue); // SQL is always a string, write through immediately
97
- validateSql(safeValue);
98
- };
99
-
100
- const handleEditorDidMount = (editor: any, monaco: any) => {
101
- editorRef.current = editor;
102
-
103
- monaco.languages.register({ id: "sql" });
104
-
105
- editor.updateOptions({
106
- minimap: { enabled: false },
107
- fontSize,
108
- lineNumbers: "on",
109
- renderWhitespace: "selection",
110
- folding: true,
111
- bracketPairColorization: { enabled: true },
112
- formatOnPaste: true,
113
- formatOnType: true,
114
- });
115
- };
116
-
117
- return (
118
- <UIComponent {...(props ?? {})}>
119
- <div className="relative w-full bg-white">
120
- {showCopy && (
121
- <div className="absolute top-2 right-4 z-50">
122
- <CopyButton item={editorValue} copySize={15} copiedSize={10} classNameCopied="!px-[15px] !py-[10px]" />
123
- </div>
124
- )}
125
- <Editor
126
- key="sql-code-editor"
127
- height={height}
128
- width={width}
129
- language="sql"
130
- value={editorValue}
131
- onChange={handleEditorChange}
132
- onMount={handleEditorDidMount}
133
- theme="vs-dark"
134
- options={{
135
- readOnly,
136
- domReadOnly: readOnly,
137
- padding: { top: 10 },
138
- selectOnLineNumbers: true,
139
- automaticLayout: true,
140
- minimap: { enabled: false },
141
- fontSize,
142
- wordWrap: "off",
143
- lineNumbers: "on",
144
- renderWhitespace: "selection",
145
- folding: true,
146
- bracketPairColorization: { enabled: true },
147
- formatOnPaste: true,
148
- formatOnType: true,
149
- scrollBeyondLastLine: false,
150
- smoothScrolling: true,
151
- cursorBlinking: "smooth",
152
- renderLineHighlight: "all",
153
- scrollbar: { vertical: "visible", horizontal: "visible" },
154
- }}
155
- />
156
- {error && !readOnly && <p className="text-red-500 text-xs mt-1 px-1">{error}</p>}
157
- </div>
158
- </UIComponent>
159
- );
160
- };
161
-
162
- export default SqlCode;