@mpeggroup/mpeg-sdl-editor 1.4.2 → 1.4.3
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.
- package/README.md +2 -5
- package/bun.lock +2 -2
- package/html/index.html +1 -1
- package/package.json +25 -25
- package/src/App.tsx +29 -56
- package/src/codemirror/ruler.ts +3 -9
- package/src/components/DesktopPanels.tsx +2 -6
- package/src/components/Editor.tsx +94 -109
- package/src/components/MobileDrawer.tsx +8 -12
- package/src/components/Navbar.tsx +35 -42
- package/src/components/ResizableLayout.tsx +20 -24
- package/src/components/Settings.tsx +38 -49
- package/src/components/StatusBar.tsx +2 -6
- package/src/components/SubNav.tsx +1 -6
- package/src/hooks/useAutoDisplayCompletions.ts +2 -7
- package/src/hooks/useDragResize.ts +63 -57
- package/src/hooks/useFileOperations.ts +1 -3
- package/src/hooks/useMobileDetection.ts +2 -6
- package/src/hooks/usePrettier.ts +1 -3
- package/src/hooks/useRulerWidth.ts +1 -10
- package/src/hooks/useShowSemanticWarnings.ts +1 -3
- package/src/hooks/useShowSymanticErrors.ts +7 -9
- package/src/hooks/useShowSyntaxErrors.ts +7 -9
- package/src/hooks/useToast.ts +1 -5
- package/src/sdl/sdlComplete.ts +5 -17
- package/src/sdl/sdlLinter.ts +1 -6
- package/tailwind.config.ts +2 -6
- package/tests/Editor_test.tsx +1 -3
- package/tsconfig.json +6 -2
package/README.md
CHANGED
|
@@ -32,16 +32,13 @@ Bundle:
|
|
|
32
32
|
|
|
33
33
|
`bun run build`
|
|
34
34
|
|
|
35
|
-
**NOTE**: The following tasks use Deno as it excels at these and Bun does not
|
|
36
|
-
currently provide such functionality:
|
|
37
|
-
|
|
38
35
|
Format:
|
|
39
36
|
|
|
40
|
-
`
|
|
37
|
+
`bunx oxfmt`
|
|
41
38
|
|
|
42
39
|
Lint:
|
|
43
40
|
|
|
44
|
-
`
|
|
41
|
+
`bunx oxlint index.ts src/ tests/`
|
|
45
42
|
|
|
46
43
|
## Functional Tests
|
|
47
44
|
|
package/bun.lock
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"@codemirror/lint": "6.9.2",
|
|
10
10
|
"@lezer/common": "1.5.0",
|
|
11
11
|
"@lezer/highlight": "1.2.3",
|
|
12
|
-
"@mpeggroup/mpeg-sdl-parser": "4.1.
|
|
12
|
+
"@mpeggroup/mpeg-sdl-parser": "4.1.4",
|
|
13
13
|
"@types/wicg-file-system-access": "2023.10.7",
|
|
14
14
|
"@uiw/codemirror-theme-vscode": "4.25.10",
|
|
15
15
|
"@uiw/react-codemirror": "4.25.10",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
|
|
78
78
|
"@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="],
|
|
79
79
|
|
|
80
|
-
"@mpeggroup/mpeg-sdl-parser": ["@mpeggroup/mpeg-sdl-parser@4.1.
|
|
80
|
+
"@mpeggroup/mpeg-sdl-parser": ["@mpeggroup/mpeg-sdl-parser@4.1.4", "", { "dependencies": { "@codemirror/language": "6.12.3", "@codemirror/state": "6.5.4", "@lezer/common": "1.5.0", "@lezer/generator": "1.8.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.7", "prettier": "3.8.3" }, "peerDependencies": { "typescript": "6.0.3" } }, "sha512-xrnDQlEtUYIbz1yk1GUdWR1UdAMSawBMziYBgWIfggvuJz0uuZ7elZMug08mMeVv3GkVbX+WYlDtCRcKJgGy9g=="],
|
|
81
81
|
|
|
82
82
|
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Omj20SuiHBOUjUBIyqtkNjSUIjOtEOJwmbix/ZyFH4BaQ6OZTaaRWIR4TjHVz0yadHgli6lLTiAh1uarnvD49A=="],
|
|
83
83
|
|
package/html/index.html
CHANGED
package/package.json
CHANGED
|
@@ -1,46 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpeggroup/mpeg-sdl-editor",
|
|
3
|
+
"version": "1.4.3",
|
|
3
4
|
"description": "ISO/IEC 14496-34 Syntactic Description Language (MPEG SDL) web based editor",
|
|
4
|
-
"homepage": "https://github.com/MPEGGroup/mpeg-sdl-editor#readme",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/MPEGGroup/mpeg-sdl-editor.git"
|
|
8
|
-
},
|
|
9
|
-
"license": "MIT",
|
|
10
5
|
"keywords": [
|
|
11
6
|
"bun",
|
|
7
|
+
"editor",
|
|
12
8
|
"mpeg",
|
|
13
|
-
"sdl",
|
|
14
9
|
"parser",
|
|
15
|
-
"
|
|
10
|
+
"sdl"
|
|
16
11
|
],
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
12
|
+
"homepage": "https://github.com/MPEGGroup/mpeg-sdl-editor#readme",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/MPEGGroup/mpeg-sdl-editor.git"
|
|
21
17
|
},
|
|
18
|
+
"type": "module",
|
|
22
19
|
"publishConfig": {
|
|
23
20
|
"access": "public"
|
|
24
21
|
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"@testing-library/dom": "10.4.1",
|
|
28
|
-
"@testing-library/react": "16.3.2",
|
|
29
|
-
"@types/bun": "1.3.14",
|
|
30
|
-
"bun-plugin-tailwind": "0.1.2",
|
|
31
|
-
"happy-dom": "20.9.0"
|
|
32
|
-
},
|
|
33
|
-
"peerDependencies": {
|
|
34
|
-
"typescript": "6.0.3",
|
|
35
|
-
"@types/react": "19.2.15",
|
|
36
|
-
"@types/react-dom": "19.2.3"
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun build.ts"
|
|
37
24
|
},
|
|
38
25
|
"dependencies": {
|
|
39
26
|
"@codemirror/language": "6.12.1",
|
|
40
27
|
"@codemirror/lint": "6.9.2",
|
|
41
28
|
"@lezer/common": "1.5.0",
|
|
42
29
|
"@lezer/highlight": "1.2.3",
|
|
43
|
-
"@mpeggroup/mpeg-sdl-parser": "4.1.
|
|
30
|
+
"@mpeggroup/mpeg-sdl-parser": "4.1.4",
|
|
44
31
|
"@types/wicg-file-system-access": "2023.10.7",
|
|
45
32
|
"@uiw/codemirror-theme-vscode": "4.25.10",
|
|
46
33
|
"@uiw/react-codemirror": "4.25.10",
|
|
@@ -49,6 +36,19 @@
|
|
|
49
36
|
"react-dom": "19.2.6",
|
|
50
37
|
"tailwindcss": "4.3.0"
|
|
51
38
|
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@happy-dom/global-registrator": "20.9.0",
|
|
41
|
+
"@testing-library/dom": "10.4.1",
|
|
42
|
+
"@testing-library/react": "16.3.2",
|
|
43
|
+
"@types/bun": "1.3.14",
|
|
44
|
+
"bun-plugin-tailwind": "0.1.2",
|
|
45
|
+
"happy-dom": "20.9.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@types/react": "19.2.15",
|
|
49
|
+
"@types/react-dom": "19.2.3",
|
|
50
|
+
"typescript": "6.0.3"
|
|
51
|
+
},
|
|
52
52
|
"overrides": {
|
|
53
53
|
"@codemirror/language": "6.12.1",
|
|
54
54
|
"@codemirror/lint": "6.9.2",
|
package/src/App.tsx
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SemanticError,
|
|
3
|
-
SemanticWarning,
|
|
4
|
-
SyntaxError,
|
|
5
|
-
} from "@mpeggroup/mpeg-sdl-parser";
|
|
1
|
+
import { SemanticError, SemanticWarning, SyntaxError } from "@mpeggroup/mpeg-sdl-parser";
|
|
6
2
|
import { Editor } from "./components/Editor.tsx";
|
|
7
3
|
import type { EditorRef } from "./components/Editor.tsx";
|
|
8
4
|
import { Navbar } from "./components/Navbar.tsx";
|
|
@@ -36,12 +32,9 @@ function getInitialCodeFromHash(): string | null {
|
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
export function App() {
|
|
39
|
-
const defaultCode =
|
|
40
|
-
"// Start typing your SDL here... <Ctrl+Space> for completions\n";
|
|
35
|
+
const defaultCode = "// Start typing your SDL here... <Ctrl+Space> for completions\n";
|
|
41
36
|
|
|
42
|
-
const [code, setCodeInternal] = useState<string>(
|
|
43
|
-
() => getInitialCodeFromHash() ?? defaultCode,
|
|
44
|
-
);
|
|
37
|
+
const [code, setCodeInternal] = useState<string>(() => getInitialCodeFromHash() ?? defaultCode);
|
|
45
38
|
|
|
46
39
|
const setCode = useCallback((newCode: string) => {
|
|
47
40
|
setCodeInternal(newCode);
|
|
@@ -62,34 +55,29 @@ export function App() {
|
|
|
62
55
|
const isMobile = useMobileDetection();
|
|
63
56
|
const [isSettingsShown, setSettingsShown] = useState(false);
|
|
64
57
|
const { rulerWidth, setRulerWidth } = useRulerWidth();
|
|
65
|
-
const { autoDisplayCompletions, setAutoDisplayCompletions } =
|
|
66
|
-
useAutoDisplayCompletions();
|
|
58
|
+
const { autoDisplayCompletions, setAutoDisplayCompletions } = useAutoDisplayCompletions();
|
|
67
59
|
const { enableLinting, setEnableLinting } = useEnableLinting();
|
|
68
60
|
const { showSyntaxErrors, setShowSyntaxErrors } = useShowSyntaxErrors();
|
|
69
61
|
const { showSemanticErrors, setShowSemanticErrors } = useShowSemanticErrors();
|
|
70
|
-
const { showSemanticWarnings, setShowSemanticWarnings } =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
62
|
+
const { showSemanticWarnings, setShowSemanticWarnings } = useShowSemanticWarnings();
|
|
63
|
+
const [cursorPosition, setCursorPosition] = useState<{ line: number; col: number }>({
|
|
64
|
+
line: 1,
|
|
65
|
+
col: 1,
|
|
66
|
+
});
|
|
75
67
|
const editorRef = useRef<EditorRef>(null);
|
|
76
68
|
|
|
77
|
-
const onCursorChange = useCallback(
|
|
78
|
-
(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
[],
|
|
88
|
-
);
|
|
69
|
+
const onCursorChange = useCallback((position: { line: number; col: number }) => {
|
|
70
|
+
setCursorPosition((prev) => {
|
|
71
|
+
// Only update if position actually changed
|
|
72
|
+
if (prev.line !== position.line || prev.col !== position.col) {
|
|
73
|
+
return position;
|
|
74
|
+
}
|
|
75
|
+
return prev;
|
|
76
|
+
});
|
|
77
|
+
}, []);
|
|
89
78
|
const handleShare = useCallback(async () => {
|
|
90
79
|
const encoded = btoa(code);
|
|
91
|
-
const url =
|
|
92
|
-
`${globalThis.location.origin}${globalThis.location.pathname}#c=${encoded}`;
|
|
80
|
+
const url = `${globalThis.location.origin}${globalThis.location.pathname}#c=${encoded}`;
|
|
93
81
|
try {
|
|
94
82
|
await navigator.clipboard.writeText(url);
|
|
95
83
|
showToast("URL copied!");
|
|
@@ -98,11 +86,7 @@ export function App() {
|
|
|
98
86
|
}
|
|
99
87
|
}, [code, showToast]);
|
|
100
88
|
|
|
101
|
-
const {
|
|
102
|
-
handleSave,
|
|
103
|
-
handleLoad,
|
|
104
|
-
handleCopy,
|
|
105
|
-
} = useFileOperations({
|
|
89
|
+
const { handleSave, handleLoad, handleCopy } = useFileOperations({
|
|
106
90
|
code,
|
|
107
91
|
setCode,
|
|
108
92
|
showToast,
|
|
@@ -113,9 +97,7 @@ export function App() {
|
|
|
113
97
|
const characterCount = useMemo(() => code.length, [code]);
|
|
114
98
|
const [syntaxErrors, setSyntaxErrors] = useState<SyntaxError[]>([]);
|
|
115
99
|
const [semanticErrors, setSemanticErrors] = useState<SemanticError[]>([]);
|
|
116
|
-
const [semanticWarnings, setSemanticWarnings] = useState<SemanticWarning[]>(
|
|
117
|
-
[],
|
|
118
|
-
);
|
|
100
|
+
const [semanticWarnings, setSemanticWarnings] = useState<SemanticWarning[]>([]);
|
|
119
101
|
|
|
120
102
|
const onSyntaxErrorChange = useCallback((newErrors: SyntaxError[]) => {
|
|
121
103
|
setSyntaxErrors(newErrors);
|
|
@@ -125,24 +107,15 @@ export function App() {
|
|
|
125
107
|
setSemanticErrors(newErrors);
|
|
126
108
|
}, []);
|
|
127
109
|
|
|
128
|
-
const onSemanticWarningChange = useCallback(
|
|
129
|
-
(newErrors
|
|
130
|
-
|
|
131
|
-
},
|
|
132
|
-
[],
|
|
133
|
-
);
|
|
110
|
+
const onSemanticWarningChange = useCallback((newErrors: SemanticWarning[]) => {
|
|
111
|
+
setSemanticWarnings(newErrors);
|
|
112
|
+
}, []);
|
|
134
113
|
|
|
135
|
-
const syntaxErrorCount = useMemo(() => syntaxErrors.length, [
|
|
136
|
-
syntaxErrors,
|
|
137
|
-
]);
|
|
114
|
+
const syntaxErrorCount = useMemo(() => syntaxErrors.length, [syntaxErrors]);
|
|
138
115
|
|
|
139
|
-
const semanticErrorCount = useMemo(() => semanticErrors.length, [
|
|
140
|
-
semanticErrors,
|
|
141
|
-
]);
|
|
116
|
+
const semanticErrorCount = useMemo(() => semanticErrors.length, [semanticErrors]);
|
|
142
117
|
|
|
143
|
-
const semanticWarningCount = useMemo(() => semanticWarnings.length, [
|
|
144
|
-
semanticWarnings,
|
|
145
|
-
]);
|
|
118
|
+
const semanticWarningCount = useMemo(() => semanticWarnings.length, [semanticWarnings]);
|
|
146
119
|
|
|
147
120
|
const { handlePrettify } = usePrettier({
|
|
148
121
|
code,
|
|
@@ -251,8 +224,8 @@ export function App() {
|
|
|
251
224
|
toastState.type === "success"
|
|
252
225
|
? "alert-success"
|
|
253
226
|
: toastState.type === "warning"
|
|
254
|
-
|
|
255
|
-
|
|
227
|
+
? "alert-warning"
|
|
228
|
+
: "alert-error"
|
|
256
229
|
}`}
|
|
257
230
|
>
|
|
258
231
|
<span>{toastState.message}</span>
|
package/src/codemirror/ruler.ts
CHANGED
|
@@ -7,7 +7,7 @@ const baseTheme = EditorView.baseTheme({
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
const rulerWidth = Facet.define<number, number>({
|
|
10
|
-
combine: (values) => values.length ? Math.min(...values) : 10,
|
|
10
|
+
combine: (values) => (values.length ? Math.min(...values) : 10),
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
const showRuler = ViewPlugin.fromClass(
|
|
@@ -38,9 +38,7 @@ const showRuler = ViewPlugin.fromClass(
|
|
|
38
38
|
const defaultCharacterWidth = view.defaultCharacterWidth;
|
|
39
39
|
const gutterWidth = view.contentDOM.getBoundingClientRect().x;
|
|
40
40
|
|
|
41
|
-
this.rulerDiv.style.left = `${
|
|
42
|
-
gutterWidth + (column * defaultCharacterWidth) + 6
|
|
43
|
-
}px`;
|
|
41
|
+
this.rulerDiv.style.left = `${gutterWidth + column * defaultCharacterWidth + 6}px`;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
destroy() {
|
|
@@ -50,9 +48,5 @@ const showRuler = ViewPlugin.fromClass(
|
|
|
50
48
|
);
|
|
51
49
|
|
|
52
50
|
export function ruler(column: number): Extension {
|
|
53
|
-
return [
|
|
54
|
-
baseTheme,
|
|
55
|
-
rulerWidth.of(column),
|
|
56
|
-
showRuler,
|
|
57
|
-
];
|
|
51
|
+
return [baseTheme, rulerWidth.of(column), showRuler];
|
|
58
52
|
}
|
|
@@ -44,8 +44,7 @@ export function DesktopPanels({
|
|
|
44
44
|
? "bg-primary-content h-16"
|
|
45
45
|
: "group-hover:bg-base-content/50 group-hover:h-16"
|
|
46
46
|
}`}
|
|
47
|
-
>
|
|
48
|
-
</div>
|
|
47
|
+
></div>
|
|
49
48
|
</div>
|
|
50
49
|
</div>
|
|
51
50
|
)}
|
|
@@ -53,10 +52,7 @@ export function DesktopPanels({
|
|
|
53
52
|
{/* Right panel - only show when not collapsed */}
|
|
54
53
|
|
|
55
54
|
{isSettingsShown && (
|
|
56
|
-
<div
|
|
57
|
-
className="flex flex-col"
|
|
58
|
-
style={{ width: `${Math.max(100 - splitPercentage, 5)}%` }}
|
|
59
|
-
>
|
|
55
|
+
<div className="flex flex-col" style={{ width: `${Math.max(100 - splitPercentage, 5)}%` }}>
|
|
60
56
|
{rightChild}
|
|
61
57
|
</div>
|
|
62
58
|
)}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
forwardRef,
|
|
3
|
-
useCallback,
|
|
4
|
-
useImperativeHandle,
|
|
5
|
-
useMemo,
|
|
6
|
-
useRef,
|
|
7
|
-
} from "react";
|
|
1
|
+
import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef } from "react";
|
|
8
2
|
import CodeMirror, { ViewUpdate } from "@uiw/react-codemirror";
|
|
9
3
|
import {
|
|
10
4
|
codeFolding,
|
|
@@ -23,11 +17,7 @@ import {
|
|
|
23
17
|
vscodeLightStyle,
|
|
24
18
|
} from "@uiw/codemirror-theme-vscode";
|
|
25
19
|
import { EditorView } from "@codemirror/view";
|
|
26
|
-
import {
|
|
27
|
-
SemanticError,
|
|
28
|
-
SemanticWarning,
|
|
29
|
-
SyntaxError,
|
|
30
|
-
} from "@mpeggroup/mpeg-sdl-parser";
|
|
20
|
+
import { SemanticError, SemanticWarning, SyntaxError } from "@mpeggroup/mpeg-sdl-parser";
|
|
31
21
|
export { ViewUpdate } from "@codemirror/view";
|
|
32
22
|
import { lintGutter } from "@codemirror/lint";
|
|
33
23
|
import { autocompletion } from "@codemirror/autocomplete";
|
|
@@ -72,7 +62,7 @@ function extractThemeStyleAttributes(themeStyle: TagStyle[]) {
|
|
|
72
62
|
let attributes = "";
|
|
73
63
|
|
|
74
64
|
Object.keys(style).forEach((key) => {
|
|
75
|
-
if (
|
|
65
|
+
if (key !== "tag" && key !== "class") {
|
|
76
66
|
const value = style[key as keyof typeof style];
|
|
77
67
|
|
|
78
68
|
if (typeof value === "string") {
|
|
@@ -89,14 +79,14 @@ function extractThemeStyleAttributes(themeStyle: TagStyle[]) {
|
|
|
89
79
|
style.tag.forEach((tag) => {
|
|
90
80
|
const actualTag = tag as unknown as TagWithNameAndModified;
|
|
91
81
|
|
|
92
|
-
if (actualTag.name &&
|
|
82
|
+
if (actualTag.name && actualTag.modified.length === 0) {
|
|
93
83
|
styleAttributesByTagName.set(actualTag.name, attributes);
|
|
94
84
|
}
|
|
95
85
|
});
|
|
96
86
|
} else {
|
|
97
87
|
const actualTag = style.tag as unknown as TagWithNameAndModified;
|
|
98
88
|
|
|
99
|
-
if (actualTag.name &&
|
|
89
|
+
if (actualTag.name && actualTag.modified.length === 0) {
|
|
100
90
|
styleAttributesByTagName.set(actualTag.name, attributes);
|
|
101
91
|
}
|
|
102
92
|
}
|
|
@@ -105,21 +95,12 @@ function extractThemeStyleAttributes(themeStyle: TagStyle[]) {
|
|
|
105
95
|
return styleAttributesByTagName;
|
|
106
96
|
}
|
|
107
97
|
|
|
108
|
-
const lightStyleAttributesByTagName = extractThemeStyleAttributes(
|
|
109
|
-
|
|
110
|
-
);
|
|
111
|
-
const darkStyleAttributesByTagName = extractThemeStyleAttributes(
|
|
112
|
-
vscodeDarkStyle,
|
|
113
|
-
);
|
|
98
|
+
const lightStyleAttributesByTagName = extractThemeStyleAttributes(vscodeLightStyle);
|
|
99
|
+
const darkStyleAttributesByTagName = extractThemeStyleAttributes(vscodeDarkStyle);
|
|
114
100
|
|
|
115
|
-
function getStyledCode(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
theme: string,
|
|
119
|
-
): string {
|
|
120
|
-
const styleAttributesByTagName = theme === "dark"
|
|
121
|
-
? darkStyleAttributesByTagName
|
|
122
|
-
: lightStyleAttributesByTagName;
|
|
101
|
+
function getStyledCode(sdlLanguageSupport: LanguageSupport, code: string, theme: string): string {
|
|
102
|
+
const styleAttributesByTagName =
|
|
103
|
+
theme === "dark" ? darkStyleAttributesByTagName : lightStyleAttributesByTagName;
|
|
123
104
|
|
|
124
105
|
let richText = "";
|
|
125
106
|
|
|
@@ -148,7 +129,10 @@ function getStyledCode(
|
|
|
148
129
|
|
|
149
130
|
let span;
|
|
150
131
|
if (spanStyleAttributes) {
|
|
151
|
-
span =
|
|
132
|
+
span =
|
|
133
|
+
"<span style='" +
|
|
134
|
+
spanStyleAttributes +
|
|
135
|
+
"'>" +
|
|
152
136
|
p.innerHTML.replaceAll(" ", " ") +
|
|
153
137
|
"</span>";
|
|
154
138
|
} else {
|
|
@@ -204,10 +188,7 @@ export const Editor = forwardRef<EditorRef, EditorProps>(
|
|
|
204
188
|
const sdlLanguageSupport = useMemo(() => sdl(), []);
|
|
205
189
|
|
|
206
190
|
// Memoize static extensions that never change
|
|
207
|
-
const staticExtensions = useMemo(() => [
|
|
208
|
-
codeFolding(),
|
|
209
|
-
foldGutter(),
|
|
210
|
-
], []);
|
|
191
|
+
const staticExtensions = useMemo(() => [codeFolding(), foldGutter()], []);
|
|
211
192
|
|
|
212
193
|
const rulerExtension = useMemo(() => ruler(rulerWidth), [rulerWidth]);
|
|
213
194
|
|
|
@@ -216,44 +197,35 @@ export const Editor = forwardRef<EditorRef, EditorProps>(
|
|
|
216
197
|
[autoDisplayCompletions],
|
|
217
198
|
);
|
|
218
199
|
|
|
219
|
-
const stableOnSyntaxErrorChange = useCallback(
|
|
220
|
-
(errors
|
|
221
|
-
|
|
222
|
-
},
|
|
223
|
-
[],
|
|
224
|
-
);
|
|
200
|
+
const stableOnSyntaxErrorChange = useCallback((errors: SyntaxError[]) => {
|
|
201
|
+
onSyntaxErrorChangeRef.current(errors);
|
|
202
|
+
}, []);
|
|
225
203
|
|
|
226
|
-
const stableOnSemanticErrorChange = useCallback(
|
|
227
|
-
(errors
|
|
228
|
-
|
|
229
|
-
},
|
|
230
|
-
[],
|
|
231
|
-
);
|
|
204
|
+
const stableOnSemanticErrorChange = useCallback((errors: SemanticError[]) => {
|
|
205
|
+
onSemanticErrorChangeRef.current(errors);
|
|
206
|
+
}, []);
|
|
232
207
|
|
|
233
|
-
const stableOnSemanticWarningChange = useCallback(
|
|
234
|
-
(errors
|
|
235
|
-
|
|
236
|
-
},
|
|
237
|
-
[],
|
|
238
|
-
);
|
|
208
|
+
const stableOnSemanticWarningChange = useCallback((errors: SemanticWarning[]) => {
|
|
209
|
+
onSemanticWarningChangeRef.current(errors);
|
|
210
|
+
}, []);
|
|
239
211
|
|
|
240
212
|
// Memoize dynamic extensions that depend on props
|
|
241
213
|
const dynamicExtensions = useMemo(
|
|
242
214
|
() =>
|
|
243
215
|
enableLinting
|
|
244
216
|
? [
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
217
|
+
// TODO: only include the lint gutter if showSyntaxErrors, showSemanticErrors, or showSemanticWarnings is true
|
|
218
|
+
lintGutter(),
|
|
219
|
+
// TODO: pass showSyntaxErrors, showSemanticErrors, showSemanticWarnings to sdlLinter
|
|
220
|
+
sdlLinter({
|
|
221
|
+
onSyntaxErrorChange: stableOnSyntaxErrorChange,
|
|
222
|
+
onSemanticErrorChange: stableOnSemanticErrorChange,
|
|
223
|
+
onSemanticWarningChange: stableOnSemanticWarningChange,
|
|
224
|
+
showSyntaxErrors,
|
|
225
|
+
showSemanticErrors,
|
|
226
|
+
showSemanticWarnings,
|
|
227
|
+
}),
|
|
228
|
+
]
|
|
257
229
|
: [],
|
|
258
230
|
[
|
|
259
231
|
enableLinting,
|
|
@@ -266,19 +238,22 @@ export const Editor = forwardRef<EditorRef, EditorProps>(
|
|
|
266
238
|
],
|
|
267
239
|
);
|
|
268
240
|
|
|
269
|
-
const extensions = useMemo(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
241
|
+
const extensions = useMemo(
|
|
242
|
+
() => [
|
|
243
|
+
...staticExtensions,
|
|
244
|
+
rulerExtension,
|
|
245
|
+
autocompletionExtension,
|
|
246
|
+
sdlLanguageSupport,
|
|
247
|
+
...dynamicExtensions,
|
|
248
|
+
],
|
|
249
|
+
[
|
|
250
|
+
staticExtensions,
|
|
251
|
+
rulerExtension,
|
|
252
|
+
autocompletionExtension,
|
|
253
|
+
sdlLanguageSupport,
|
|
254
|
+
dynamicExtensions,
|
|
255
|
+
],
|
|
256
|
+
);
|
|
282
257
|
|
|
283
258
|
// Memoize imperative methods
|
|
284
259
|
const expandAll = useCallback(() => {
|
|
@@ -308,41 +283,51 @@ export const Editor = forwardRef<EditorRef, EditorProps>(
|
|
|
308
283
|
}, []);
|
|
309
284
|
|
|
310
285
|
// Expose methods via ref
|
|
311
|
-
useImperativeHandle(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
286
|
+
useImperativeHandle(
|
|
287
|
+
ref,
|
|
288
|
+
() => ({
|
|
289
|
+
expandAll,
|
|
290
|
+
collapseAll,
|
|
291
|
+
getStyledCode: () => {
|
|
292
|
+
return getStyledCode(sdlLanguageSupport, code, theme);
|
|
293
|
+
},
|
|
294
|
+
}),
|
|
295
|
+
[expandAll, collapseAll, sdlLanguageSupport, code, theme],
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const onInternalCodeChange = useCallback(
|
|
299
|
+
(newCode: string) => {
|
|
300
|
+
onCodeChange(newCode);
|
|
316
301
|
},
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
onCursorChange(newPosition);
|
|
302
|
+
[onCodeChange],
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
const onViewUpdate = useCallback(
|
|
306
|
+
(viewUpdate: ViewUpdate) => {
|
|
307
|
+
if (viewUpdate.state) {
|
|
308
|
+
const state = viewUpdate.state;
|
|
309
|
+
const selection = state.selection.main;
|
|
310
|
+
|
|
311
|
+
if (selection) {
|
|
312
|
+
const head = selection.head;
|
|
313
|
+
const line = state.doc.lineAt(head);
|
|
314
|
+
const lineNumber = line.number;
|
|
315
|
+
const columnNumber = head - line.from + 1;
|
|
316
|
+
|
|
317
|
+
// Only update if position actually changed
|
|
318
|
+
if (
|
|
319
|
+
lastCursorPosition.current.line !== lineNumber ||
|
|
320
|
+
lastCursorPosition.current.col !== columnNumber
|
|
321
|
+
) {
|
|
322
|
+
const newPosition = { line: lineNumber, col: columnNumber };
|
|
323
|
+
lastCursorPosition.current = newPosition;
|
|
324
|
+
onCursorChange(newPosition);
|
|
325
|
+
}
|
|
342
326
|
}
|
|
343
327
|
}
|
|
344
|
-
}
|
|
345
|
-
|
|
328
|
+
},
|
|
329
|
+
[onCursorChange],
|
|
330
|
+
);
|
|
346
331
|
|
|
347
332
|
return (
|
|
348
333
|
<div className="h-full w-full">
|
|
@@ -8,9 +8,12 @@ interface MobileDrawerProps {
|
|
|
8
8
|
children: React.ReactNode;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function MobileDrawer(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
export function MobileDrawer({
|
|
12
|
+
theme,
|
|
13
|
+
isSettingsShown,
|
|
14
|
+
onToggleSettings,
|
|
15
|
+
children,
|
|
16
|
+
}: MobileDrawerProps) {
|
|
14
17
|
return (
|
|
15
18
|
<>
|
|
16
19
|
{isSettingsShown && (
|
|
@@ -32,12 +35,7 @@ export function MobileDrawer(
|
|
|
32
35
|
}`}
|
|
33
36
|
title="Close settings"
|
|
34
37
|
>
|
|
35
|
-
<svg
|
|
36
|
-
className="w-6 h-6"
|
|
37
|
-
fill="none"
|
|
38
|
-
stroke="currentColor"
|
|
39
|
-
viewBox="0 0 24 24"
|
|
40
|
-
>
|
|
38
|
+
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
41
39
|
<path
|
|
42
40
|
strokeLinecap="round"
|
|
43
41
|
strokeLinejoin="round"
|
|
@@ -47,9 +45,7 @@ export function MobileDrawer(
|
|
|
47
45
|
</svg>
|
|
48
46
|
</button>
|
|
49
47
|
<div className="h-full p-4 pt-4 overflow-hidden">
|
|
50
|
-
<div className="overflow-y-auto h-full">
|
|
51
|
-
{children}
|
|
52
|
-
</div>
|
|
48
|
+
<div className="overflow-y-auto h-full">{children}</div>
|
|
53
49
|
</div>
|
|
54
50
|
</div>
|
|
55
51
|
</>
|