@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 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
- `deno fmt`
37
+ `bunx oxfmt`
41
38
 
42
39
  Lint:
43
40
 
44
- `deno lint src/ tests/`
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.2",
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.2", "", { "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-GKTSu4cSFgpN3Hl7i5be5JIG4PPMemz0ylDGD27Ef6fBKp92yLTk/mYPUI38GR3D1+TR/2WBRNU+gx6Sn9TG2g=="],
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
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en" data-theme="light">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
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
- "editor"
10
+ "sdl"
16
11
  ],
17
- "type": "module",
18
- "version": "1.4.2",
19
- "scripts": {
20
- "build": "bun build.ts"
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
- "devDependencies": {
26
- "@happy-dom/global-registrator": "20.9.0",
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.2",
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
- useShowSemanticWarnings();
72
- const [cursorPosition, setCursorPosition] = useState<
73
- { line: number; col: number }
74
- >({ line: 1, col: 1 });
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
- (position: { line: number; col: number }) => {
79
- setCursorPosition((prev) => {
80
- // Only update if position actually changed
81
- if (prev.line !== position.line || prev.col !== position.col) {
82
- return position;
83
- }
84
- return prev;
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: SemanticWarning[]) => {
130
- setSemanticWarnings(newErrors);
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
- ? "alert-warning"
255
- : "alert-error"
227
+ ? "alert-warning"
228
+ : "alert-error"
256
229
  }`}
257
230
  >
258
231
  <span>{toastState.message}</span>
@@ -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 ((key !== "tag") && (key !== "class")) {
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 && (actualTag.modified.length === 0)) {
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 && (actualTag.modified.length === 0)) {
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
- vscodeLightStyle,
110
- );
111
- const darkStyleAttributesByTagName = extractThemeStyleAttributes(
112
- vscodeDarkStyle,
113
- );
98
+ const lightStyleAttributesByTagName = extractThemeStyleAttributes(vscodeLightStyle);
99
+ const darkStyleAttributesByTagName = extractThemeStyleAttributes(vscodeDarkStyle);
114
100
 
115
- function getStyledCode(
116
- sdlLanguageSupport: LanguageSupport,
117
- code: string,
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 = "<span style='" + spanStyleAttributes + "'>" +
132
+ span =
133
+ "<span style='" +
134
+ spanStyleAttributes +
135
+ "'>" +
152
136
  p.innerHTML.replaceAll(" ", "&nbsp;") +
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: SyntaxError[]) => {
221
- onSyntaxErrorChangeRef.current(errors);
222
- },
223
- [],
224
- );
200
+ const stableOnSyntaxErrorChange = useCallback((errors: SyntaxError[]) => {
201
+ onSyntaxErrorChangeRef.current(errors);
202
+ }, []);
225
203
 
226
- const stableOnSemanticErrorChange = useCallback(
227
- (errors: SemanticError[]) => {
228
- onSemanticErrorChangeRef.current(errors);
229
- },
230
- [],
231
- );
204
+ const stableOnSemanticErrorChange = useCallback((errors: SemanticError[]) => {
205
+ onSemanticErrorChangeRef.current(errors);
206
+ }, []);
232
207
 
233
- const stableOnSemanticWarningChange = useCallback(
234
- (errors: SemanticWarning[]) => {
235
- onSemanticWarningChangeRef.current(errors);
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
- // TODO: only include the lint gutter if showSyntaxErrors, showSemanticErrors, or showSemanticWarnings is true
246
- lintGutter(),
247
- // TODO: pass showSyntaxErrors, showSemanticErrors, showSemanticWarnings to sdlLinter
248
- sdlLinter({
249
- onSyntaxErrorChange: stableOnSyntaxErrorChange,
250
- onSemanticErrorChange: stableOnSemanticErrorChange,
251
- onSemanticWarningChange: stableOnSemanticWarningChange,
252
- showSyntaxErrors,
253
- showSemanticErrors,
254
- showSemanticWarnings,
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
- ...staticExtensions,
271
- rulerExtension,
272
- autocompletionExtension,
273
- sdlLanguageSupport,
274
- ...dynamicExtensions,
275
- ], [
276
- staticExtensions,
277
- rulerExtension,
278
- autocompletionExtension,
279
- sdlLanguageSupport,
280
- dynamicExtensions,
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(ref, () => ({
312
- expandAll,
313
- collapseAll,
314
- getStyledCode: () => {
315
- return getStyledCode(sdlLanguageSupport, code, theme);
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
- }), [expandAll, collapseAll, sdlLanguageSupport, code, theme]);
318
-
319
- const onInternalCodeChange = useCallback((newCode: string) => {
320
- onCodeChange(newCode);
321
- }, [onCodeChange]);
322
-
323
- const onViewUpdate = useCallback((viewUpdate: ViewUpdate) => {
324
- if (viewUpdate.state) {
325
- const state = viewUpdate.state;
326
- const selection = state.selection.main;
327
-
328
- if (selection) {
329
- const head = selection.head;
330
- const line = state.doc.lineAt(head);
331
- const lineNumber = line.number;
332
- const columnNumber = head - line.from + 1;
333
-
334
- // Only update if position actually changed
335
- if (
336
- lastCursorPosition.current.line !== lineNumber ||
337
- lastCursorPosition.current.col !== columnNumber
338
- ) {
339
- const newPosition = { line: lineNumber, col: columnNumber };
340
- lastCursorPosition.current = newPosition;
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
- }, [onCursorChange]);
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
- { theme, isSettingsShown, onToggleSettings, children }: MobileDrawerProps,
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
  </>