@ramesesinc/platform-core 0.1.6 → 0.1.8

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 (87) 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/table/DataList.js +2 -2
  6. package/dist/components/view/PopupView.d.ts +13 -0
  7. package/dist/components/view/PopupView.js +25 -20
  8. package/dist/core/DataContext.d.ts +7 -4
  9. package/dist/core/DataContext.js +16 -4
  10. package/dist/core/Page.js +25 -26
  11. package/dist/core/PageCache.js +7 -7
  12. package/dist/core/PageContext.js +17 -7
  13. package/dist/core/PageViewContext.d.ts +13 -1
  14. package/dist/core/PageViewContext.js +75 -2
  15. package/dist/core/PopupContext.d.ts +49 -0
  16. package/dist/core/PopupContext.js +380 -0
  17. package/dist/core/RowContext.js +1 -1
  18. package/dist/core/WindowContext.d.ts +15 -0
  19. package/dist/core/WindowContext.js +28 -0
  20. package/dist/core/index.d.ts +16 -0
  21. package/dist/index.css +25 -7
  22. package/dist/lib/utils/BeanUtils.js +7 -7
  23. package/dist/templates/DataListTemplate.js +7 -2
  24. package/dist/templates/ExplorerTemplate.js +1 -1
  25. package/package.json +5 -5
  26. package/dist/components/action/AlertMessage.tsx +0 -38
  27. package/dist/components/action/Button.tsx +0 -230
  28. package/dist/components/action/CancelEdit.tsx +0 -40
  29. package/dist/components/action/DeleteData.tsx +0 -73
  30. package/dist/components/action/Edit.tsx +0 -40
  31. package/dist/components/action/LookupPage.tsx +0 -113
  32. package/dist/components/action/ProcessRunner.tsx +0 -337
  33. package/dist/components/action/Refresh.tsx +0 -35
  34. package/dist/components/action/SaveData.tsx +0 -74
  35. package/dist/components/action/SelectData.tsx +0 -47
  36. package/dist/components/action/Undo.tsx +0 -50
  37. package/dist/components/action/UpdateData.tsx +0 -49
  38. package/dist/components/action/UpdateState.tsx +0 -40
  39. package/dist/components/action/ViewBackPage.tsx +0 -46
  40. package/dist/components/action/ViewPage.tsx +0 -141
  41. package/dist/components/common/UIComponent.tsx +0 -86
  42. package/dist/components/common/UIInput.tsx +0 -49
  43. package/dist/components/common/UIMenu.tsx +0 -91
  44. package/dist/components/index.ts +0 -51
  45. package/dist/components/input/CodeEditor.tsx +0 -188
  46. package/dist/components/input/DateField.tsx +0 -274
  47. package/dist/components/input/DayPicker.tsx +0 -5
  48. package/dist/components/input/HtmlCode.tsx +0 -203
  49. package/dist/components/input/JsonCode.tsx +0 -205
  50. package/dist/components/input/MonthPicker.tsx +0 -5
  51. package/dist/components/input/ScriptCode.tsx +0 -195
  52. package/dist/components/input/Select.tsx +0 -78
  53. package/dist/components/input/SqlCode.tsx +0 -162
  54. package/dist/components/input/StringDecision.tsx +0 -64
  55. package/dist/components/input/Text.tsx +0 -57
  56. package/dist/components/input/YearPicker.tsx +0 -81
  57. package/dist/components/list/IconMenu.tsx +0 -115
  58. package/dist/components/list/TabMenu.tsx +0 -127
  59. package/dist/components/list/TreeMenu.tsx +0 -279
  60. package/dist/components/list/TxnTaskList.tsx +0 -198
  61. package/dist/components/output/Label.tsx +0 -50
  62. package/dist/components/table/DataList.tsx +0 -820
  63. package/dist/components/table/DataTable.tsx +0 -572
  64. package/dist/components/table/ListHandler.ts +0 -276
  65. package/dist/components/table/TableContext.tsx +0 -122
  66. package/dist/components/view/ComponentView.tsx +0 -102
  67. package/dist/components/view/FilterView.tsx +0 -21
  68. package/dist/components/view/HtmlForm.tsx +0 -176
  69. package/dist/components/view/HtmlView.tsx +0 -98
  70. package/dist/components/view/IFrameView.tsx +0 -48
  71. package/dist/components/view/Modal.tsx +0 -72
  72. package/dist/components/view/PageView.tsx +0 -131
  73. package/dist/components/view/PopupView.tsx +0 -160
  74. package/dist/components/view/RootView.tsx +0 -109
  75. package/dist/components/view/WizardView.tsx +0 -48
  76. package/dist/lib/layouts/BorderLayout.tsx +0 -31
  77. package/dist/lib/layouts/CardLayout.tsx +0 -73
  78. package/dist/lib/layouts/CenterLayout.tsx +0 -20
  79. package/dist/lib/layouts/GridLayout.tsx +0 -20
  80. package/dist/lib/layouts/HPanel.tsx +0 -31
  81. package/dist/lib/layouts/HorizontalLayout.tsx +0 -29
  82. package/dist/lib/layouts/MainLayout.tsx +0 -16
  83. package/dist/lib/layouts/PageLayout.tsx +0 -29
  84. package/dist/lib/layouts/VPanel.tsx +0 -27
  85. package/dist/lib/layouts/XLayout.tsx +0 -29
  86. package/dist/lib/layouts/YLayout.tsx +0 -29
  87. 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;