vzcode 1.8.0 → 1.10.0

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/dist/index.html CHANGED
@@ -20,7 +20,7 @@
20
20
  href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
21
21
  rel="stylesheet"
22
22
  />
23
- <script type="module" crossorigin src="/assets/index-CU0jqXHm.js"></script>
23
+ <script type="module" crossorigin src="/assets/index-DXNuoOqQ.js"></script>
24
24
  <link rel="stylesheet" crossorigin href="/assets/index-BKRpkJER.css">
25
25
  </head>
26
26
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  "test-interactive": "cd test/sampleDirectories/kitchenSink && node ../../../src/server/index.js",
15
15
  "prettier": "prettier {*.*,**/*.*} --write",
16
16
  "tsc": "tsc --noEmit",
17
- "dev": "EDITOR_PORT=5173 concurrently \"npm run test-interactive\" \"vite\"",
17
+ "dev": "set EDITOR_PORT=5173 && concurrently \"npm run test-interactive\" \"vite\"",
18
18
  "build": "vite build",
19
19
  "build-release": "vite build --mode release",
20
20
  "preview": "concurrently \"npm run test-interactive\" \"vite preview\"",
@@ -140,14 +140,14 @@
140
140
  "json0-ot-diff": "^1.1.2",
141
141
  "ngrok": "^4.3.3",
142
142
  "open": "^10.1.0",
143
- "openai": "^4.52.3",
143
+ "openai": "^4.52.4",
144
144
  "prettier-plugin-svelte": "^3.2.5",
145
145
  "react": "^18.3.1",
146
146
  "react-bootstrap": "^2.10.4",
147
147
  "react-dom": "^18.3.1",
148
148
  "react-router-dom": "^6.24.1",
149
149
  "sharedb": "^5.0.2",
150
- "sharedb-client-browser": "^5.0.1",
150
+ "sharedb-client-browser": "^5.0.2",
151
151
  "vizhub-ui": "^3.23.0",
152
152
  "ws": "^8.18.0"
153
153
  },
@@ -160,10 +160,10 @@
160
160
  "sass": "^1.77.6",
161
161
  "typescript": "^5.5.3",
162
162
  "vite": "^5.3.3",
163
- "vitest": "^1.6.0"
163
+ "vitest": "^2.0.1"
164
164
  },
165
165
  "optionalDependencies": {
166
- "@rollup/rollup-darwin-arm64": "^4.18.0",
167
- "@rollup/rollup-win32-x64-msvc": "^4.18.0"
166
+ "@rollup/rollup-darwin-arm64": "^4.18.1",
167
+ "@rollup/rollup-win32-x64-msvc": "^4.18.1"
168
168
  }
169
169
  }
@@ -40,6 +40,8 @@ import { keymap } from '@codemirror/view';
40
40
  import { basicSetup } from './basicSetup';
41
41
  import { InteractRule } from '@replit/codemirror-interact';
42
42
  import rainbowBrackets from '../CodeEditor/rainbowBrackets';
43
+ import { cssLanguage } from '@codemirror/lang-css';
44
+ import { javascriptLanguage } from '@codemirror/lang-javascript';
43
45
 
44
46
  // Feature flag to enable TypeScript completions & TypeScript Linter.
45
47
  const enableTypeScriptCompletions = true;
@@ -49,6 +51,26 @@ const enableTypeScriptLinter = true;
49
51
  const tsx = () =>
50
52
  javascript({ jsx: true, typescript: true });
51
53
 
54
+ const htmlConfig = {
55
+ matchClosingTags: true,
56
+ selfClosingTags: false,
57
+ autoCloseTags: true,
58
+ extraTags: {},
59
+ extraGlobalAttributes: {},
60
+ nestedLanguages: [
61
+ {
62
+ tag: 'script',
63
+ language: javascript,
64
+ parser: javascriptLanguage.parser,
65
+ },
66
+ {
67
+ tag: 'style',
68
+ language: css,
69
+ parser: cssLanguage.parser,
70
+ },
71
+ ],
72
+ nestedAttributes: [],
73
+ };
52
74
  // Language extensions for CodeMirror.
53
75
  // Keys are file extensions.
54
76
  // Values are CodeMirror extensions.
@@ -59,7 +81,7 @@ const languageExtensions = {
59
81
  js: tsx,
60
82
  jsx: tsx,
61
83
  ts: tsx,
62
- html,
84
+ html: () => html(htmlConfig),
63
85
  css,
64
86
  md: markdown,
65
87
  svelte,
@@ -146,6 +168,7 @@ export const getOrCreateEditor = ({
146
168
  let themeCompartment = new Compartment();
147
169
 
148
170
  // The CodeMirror extensions to use.
171
+ // const extensions = [autocompletion(), html(htmlConfig)]
149
172
  const extensions = [];
150
173
 
151
174
  // This plugin implements multiplayer editing,
@@ -266,18 +289,28 @@ export const getOrCreateEditor = ({
266
289
  // );
267
290
 
268
291
  // Add the extension that provides TypeScript completions.
269
- if (enableTypeScriptCompletions) {
270
- extensions.push(
271
- autocompletion({
272
- override: [
273
- typeScriptCompletions({
274
- typeScriptWorker,
275
- fileName: name,
276
- }),
277
- ],
278
- }),
279
- );
280
- }
292
+ // only add this if it's TS-compatible (.js, .jsx, .ts, .tsx)
293
+ const isTypeScript =
294
+ fileExtension === 'js' ||
295
+ fileExtension === 'jsx' ||
296
+ fileExtension === 'ts' ||
297
+ fileExtension === 'tsx';
298
+
299
+ extensions.push(
300
+ autocompletion(
301
+ isTypeScript
302
+ ? {
303
+ override: [
304
+ typeScriptCompletions({
305
+ typeScriptWorker,
306
+ fileName: name,
307
+ }),
308
+ ],
309
+ }
310
+ : undefined,
311
+ ),
312
+ );
313
+
281
314
  if (shareDBDoc && enableTypeScriptLinter) {
282
315
  extensions.push(
283
316
  linter(
@@ -13,7 +13,6 @@ export { QuestionMarkSVG } from './QuestionMarkSVG';
13
13
  export { PinSVG } from './PinSVG';
14
14
  export { FolderSVG } from './FolderSVG';
15
15
  export { SearchSVG } from './SearchSVG';
16
- export { SearchFileSVG } from './SearchFileSVG';
17
16
  export { JavaScriptSVG } from './JavaScriptSVG';
18
17
  export { TypeScriptSVG } from './TypeScriptSVG';
19
18
  export { ReactSVG } from './ReactSVG';
@@ -1,9 +1,45 @@
1
1
  import { useCallback, useContext } from 'react';
2
2
  import { Item } from './Item';
3
3
  import { FileId } from '../../types';
4
- import { FileSVG } from '../Icons';
4
+ import {
5
+ FileSVG,
6
+ JavaScriptSVG,
7
+ TypeScriptSVG,
8
+ ReactSVG,
9
+ SvelteSVG,
10
+ JsonSVG,
11
+ MarkdownSVG,
12
+ HtmlSVG,
13
+ CssSVG,
14
+ } from '../Icons';
5
15
  import { VZCodeContext } from '../VZCodeContext';
6
16
 
17
+ export function getExtensionIcon(fileName: string) {
18
+ const extension = fileName.split('.');
19
+
20
+ switch (extension[extension.length - 1]) {
21
+ case 'jsx':
22
+ case 'tsx':
23
+ return <ReactSVG />;
24
+ case 'js':
25
+ return <JavaScriptSVG />;
26
+ case 'ts':
27
+ return <TypeScriptSVG />;
28
+ case 'json':
29
+ return <JsonSVG />;
30
+ case 'md':
31
+ return <MarkdownSVG />;
32
+ case 'html':
33
+ return <HtmlSVG />;
34
+ case 'css':
35
+ return <CssSVG />;
36
+ case 'svelte':
37
+ return <SvelteSVG />;
38
+ default:
39
+ return <FileSVG />;
40
+ }
41
+ }
42
+
7
43
  export const FileListing = ({
8
44
  name,
9
45
  fileId,
@@ -49,9 +85,7 @@ export const FileListing = ({
49
85
  handleRenameClick={handleRenameClick}
50
86
  isActive={isActive}
51
87
  >
52
- <i className="file-icon">
53
- <FileSVG />
54
- </i>
88
+ <i className="file-icon">{getExtensionIcon(name)}</i>
55
89
  {name}
56
90
  </Item>
57
91
  );
@@ -12,6 +12,7 @@ import { Tooltip, OverlayTrigger } from '../bootstrap';
12
12
  import { DeleteConfirmationModal } from './DeleteConfirmationModal';
13
13
  import { VZCodeContext } from '../VZCodeContext';
14
14
  import { ItemId } from '../../types';
15
+ import { getExtensionIcon } from './FileListing';
15
16
 
16
17
  // TODO support renaming directories
17
18
  // See https://github.com/vizhub-core/vzcode/issues/103
@@ -169,7 +170,7 @@ export const Item = ({
169
170
  {isRenaming ? (
170
171
  <>
171
172
  <i className="file-icon">
172
- <FileSVG />
173
+ {getExtensionIcon(renameValue)}
173
174
  </i>
174
175
  <input
175
176
  className="rename-input"
@@ -1,16 +1,3 @@
1
- import {
2
- JavaScriptSVG,
3
- TypeScriptSVG,
4
- ReactSVG,
5
- SvelteSVG,
6
- JsonSVG,
7
- MarkdownSVG,
8
- HtmlSVG,
9
- CssSVG,
10
- SearchFileSVG,
11
- DirectoryArrowSVG,
12
- CloseSVG,
13
- } from '../Icons';
14
1
  import {
15
2
  useRef,
16
3
  useEffect,
@@ -21,30 +8,8 @@ import { Form } from '../bootstrap';
21
8
  import { VZCodeContext } from '../VZCodeContext';
22
9
  import { SearchFile } from '../../types';
23
10
  import { EditorView } from 'codemirror';
24
-
25
- function getExtensionIcon(extension: string) {
26
- switch (extension) {
27
- case 'jsx':
28
- case 'tsx':
29
- return <ReactSVG />;
30
- case 'js':
31
- return <JavaScriptSVG />;
32
- case 'ts':
33
- return <TypeScriptSVG />;
34
- case 'json':
35
- return <JsonSVG />;
36
- case 'md':
37
- return <MarkdownSVG />;
38
- case 'html':
39
- return <HtmlSVG />;
40
- case 'css':
41
- return <CssSVG />;
42
- case 'svelte':
43
- return <SvelteSVG />;
44
- default:
45
- return <SearchFileSVG />;
46
- }
47
- }
11
+ import { getExtensionIcon } from './FileListing';
12
+ import { CloseSVG, DirectoryArrowSVG } from '../Icons';
48
13
 
49
14
  function jumpToPattern(
50
15
  editor: EditorView,
@@ -102,6 +67,7 @@ export const Search = () => {
102
67
  return () => clearTimeout(delaySearch);
103
68
  } else {
104
69
  setIsMounted(true);
70
+ inputRef.current.focus();
105
71
  }
106
72
  }, [pattern]);
107
73
 
@@ -151,9 +117,7 @@ export const Search = () => {
151
117
  <DirectoryArrowSVG />
152
118
  </div>
153
119
  <div className="search-file-name">
154
- {getExtensionIcon(
155
- file.name.split('.')[1],
156
- )}
120
+ {getExtensionIcon(file.name)}
157
121
  <h5>{file.name}</h5>
158
122
  </div>
159
123
  </div>
@@ -4,6 +4,7 @@ import { syntaxTree } from '@codemirror/language';
4
4
  import { SyntaxNode, SyntaxNodeRef } from '@lezer/common';
5
5
  import { EditorView } from '@codemirror/view';
6
6
  import { EditorState } from '@codemirror/state';
7
+ import { FileId } from '../types';
7
8
 
8
9
  /*
9
10
  The following is a helpful resource for the following Code Mirror Syntax Tree methods below
@@ -170,6 +171,17 @@ export const useKeyboardShortcuts = ({
170
171
  sidebarRef,
171
172
  editorCache,
172
173
  codeEditorRef,
174
+ }: {
175
+ closeTabs: (fileIds: FileId[]) => void;
176
+ activeFileId: FileId | null;
177
+ handleOpenCreateFileModal: () => void;
178
+ setActiveFileLeft: () => void;
179
+ setActiveFileRight: () => void;
180
+ runPrettierRef: React.MutableRefObject<() => void>;
181
+ runCodeRef: React.MutableRefObject<() => void>;
182
+ sidebarRef: React.RefObject<HTMLDivElement>;
183
+ editorCache: Map<string, { editor: EditorView }>;
184
+ codeEditorRef: React.RefObject<HTMLDivElement>;
173
185
  }) => {
174
186
  useEffect(() => {
175
187
  const handleKeyPress = (event: KeyboardEvent) => {
@@ -205,7 +217,9 @@ export const useKeyboardShortcuts = ({
205
217
  // TODO clean this up so we can remove `activeFileId`
206
218
  // as a dependency
207
219
  // TODO closeActiveTab()
208
- closeTabs([activeFileId]);
220
+ if (activeFileId) {
221
+ closeTabs([activeFileId]);
222
+ }
209
223
  return;
210
224
  }
211
225
 
@@ -261,7 +275,8 @@ export const useKeyboardShortcuts = ({
261
275
  const jumpToDefinitionHandler = (
262
276
  event: MouseEvent,
263
277
  ): void => {
264
- // Ensure the current destination node is defined and current cursor position matches highlighted element
278
+ // Ensure the current destination node is defined
279
+ // and current cursor position matches highlighted element
265
280
  if (
266
281
  !definingNode ||
267
282
  (event.target as HTMLSpanElement) !==
@@ -270,6 +285,11 @@ export const useKeyboardShortcuts = ({
270
285
  return;
271
286
  }
272
287
 
288
+ // Don't crash if no active file
289
+ if (!activeFileId) {
290
+ return;
291
+ }
292
+
273
293
  // Move current cursor and center view in the editor to destination node
274
294
  const editor: EditorView =
275
295
  editorCache.get(activeFileId).editor;
@@ -300,6 +320,10 @@ export const useKeyboardShortcuts = ({
300
320
  };
301
321
 
302
322
  const handleMouseOver = (event: MouseEvent) => {
323
+ if (!activeFileId) {
324
+ return;
325
+ }
326
+
303
327
  const editor: EditorView =
304
328
  editorCache.get(activeFileId).editor;
305
329
  const tree = syntaxTree(editor.state);
@@ -18,4 +18,5 @@ export const createInitialState = ({
18
18
  isDocOpen: false,
19
19
  editorWantsFocus: false,
20
20
  username: initialUsername,
21
+ enableAutoFollow: false,
21
22
  });
@@ -1,19 +0,0 @@
1
- export const SearchFileSVG = () => {
2
- return (
3
- <svg
4
- xmlns="http://www.w3.org/2000/svg"
5
- width="24"
6
- height="24"
7
- fill="none"
8
- viewBox="0 0 24 24"
9
- >
10
- <path
11
- stroke="currentColor"
12
- strokeLinecap="round"
13
- strokeLinejoin="round"
14
- strokeWidth="1.5"
15
- d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
16
- />
17
- </svg>
18
- );
19
- };