vzcode 2.10.0 → 2.12.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,8 +20,8 @@
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-CsDf6ybm.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-Bjj9VRMn.css">
23
+ <script type="module" crossorigin src="/assets/index-858eZSOF.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-DLm5FQ0E.css">
25
25
  </head>
26
26
  <body>
27
27
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -110,7 +110,7 @@
110
110
  },
111
111
  "homepage": "https://github.com/vizhub-core/vzcode#readme",
112
112
  "dependencies": {
113
- "@codemirror/autocomplete": "^6.18.6",
113
+ "@codemirror/autocomplete": "^6.18.7",
114
114
  "@codemirror/lang-css": "^6.3.1",
115
115
  "@codemirror/lang-html": "^6.4.9",
116
116
  "@codemirror/lang-javascript": "^6.2.4",
@@ -119,9 +119,9 @@
119
119
  "@codemirror/lint": "^6.8.5",
120
120
  "@codemirror/state": "^6.5.2",
121
121
  "@codemirror/theme-one-dark": "^6.1.3",
122
- "@codemirror/view": "^6.38.1",
123
- "@langchain/core": "^0.3.71",
124
- "@langchain/openai": "^0.6.7",
122
+ "@codemirror/view": "^6.38.2",
123
+ "@langchain/core": "^0.3.73",
124
+ "@langchain/openai": "^0.6.11",
125
125
  "@lezer/highlight": "^1.2.1",
126
126
  "@livekit/components-react": "^2.9.14",
127
127
  "@replit/codemirror-indentation-markers": "^6.5.3",
@@ -141,8 +141,8 @@
141
141
  "@uiw/codemirror-themes": "^4.25.1",
142
142
  "@valtown/codemirror-ts": "^2.3.1",
143
143
  "@vizhub/runtime": "^4.4.0",
144
- "@vizhub/viz-types": "^0.4.0",
145
- "@vizhub/viz-utils": "^1.4.0",
144
+ "@vizhub/viz-types": "^0.5.0",
145
+ "@vizhub/viz-utils": "^1.5.0",
146
146
  "body-parser": "^2.2.0",
147
147
  "bootstrap-icons": "^1.13.1",
148
148
  "codemirror": "^6.0.2",
@@ -151,19 +151,20 @@
151
151
  "color-hash": "^2.0.2",
152
152
  "comlink": "^4.4.2",
153
153
  "d3-array": "^3.2.4",
154
+ "d3-color": "^3.1.0",
154
155
  "diff": "^8.0.2",
155
156
  "diff-match-patch": "^1.0.5",
156
157
  "diff2html": "^3.4.52",
157
- "dotenv": "^17.2.1",
158
+ "dotenv": "^17.2.2",
158
159
  "editcodewithai": "^2.3.0",
159
- "eslint-linter-browserify": "^9.33.0",
160
+ "eslint-linter-browserify": "^9.34.0",
160
161
  "express": "^5.1.0",
161
162
  "ignore": "^7.0.5",
162
163
  "json0-ot-diff": "^1.1.2",
163
164
  "jszip": "^3.10.1",
164
- "livekit-server-sdk": "^2.13.2",
165
+ "livekit-server-sdk": "^2.13.3",
165
166
  "llm-code-format": "^3.0.0",
166
- "lucide-react": "^0.539.0",
167
+ "lucide-react": "^0.542.0",
167
168
  "npm": "^11.5.2",
168
169
  "open": "^10.2.0",
169
170
  "prettier-plugin-svelte": "^3.4.0",
@@ -171,7 +172,7 @@
171
172
  "react-bootstrap": "^2.10.10",
172
173
  "react-dom": "^18",
173
174
  "react-markdown": "^10.1.0",
174
- "react-router-dom": "^7.8.1",
175
+ "react-router-dom": "^7.8.2",
175
176
  "remark-gfm": "^4.0.1",
176
177
  "sharedb": "^5.2.2",
177
178
  "sharedb-client-browser": "^5.2.2",
@@ -180,30 +181,31 @@
180
181
  "ws": "^8.18.3"
181
182
  },
182
183
  "devDependencies": {
183
- "@eslint/js": "^9.33.0",
184
- "@tauri-apps/cli": "^2.7.1",
184
+ "@eslint/js": "^9.34.0",
185
+ "@tauri-apps/cli": "^2.8.4",
186
+ "@types/d3-color": "^3.1.3",
185
187
  "@types/react": "^18",
186
188
  "@types/react-dom": "^18",
187
- "@typescript-eslint/eslint-plugin": "^8.39.1",
188
- "@typescript-eslint/parser": "^8.39.1",
189
- "@vitejs/plugin-react": "^5.0.0",
190
- "concurrently": "^9.2.0",
189
+ "@typescript-eslint/eslint-plugin": "^8.42.0",
190
+ "@typescript-eslint/parser": "^8.42.0",
191
+ "@vitejs/plugin-react": "^5.0.2",
192
+ "concurrently": "^9.2.1",
191
193
  "cross-env": "^10.0.0",
192
- "eslint": "^9.33.0",
194
+ "eslint": "^9.34.0",
193
195
  "eslint-plugin-jsx-a11y": "^6.10.2",
194
196
  "eslint-plugin-react": "^7.37.5",
195
197
  "eslint-plugin-react-hooks": "^5.2.0",
196
198
  "globals": "^16.3.0",
197
- "npm-check-updates": "^18.0.2",
199
+ "npm-check-updates": "^18.0.3",
198
200
  "prettier": "^3.6.2",
199
- "sass": "^1.90.0",
201
+ "sass": "^1.92.0",
200
202
  "ts-node": "^10.9.2",
201
203
  "typescript": "^5.9.2",
202
- "vite": "^7.1.2",
204
+ "vite": "^7.1.4",
203
205
  "vitest": "^3.2.4"
204
206
  },
205
207
  "optionalDependencies": {
206
- "@rollup/rollup-darwin-arm64": "^4.46.2",
207
- "@rollup/rollup-win32-x64-msvc": "^4.46.2"
208
+ "@rollup/rollup-darwin-arm64": "^4.50.0",
209
+ "@rollup/rollup-win32-x64-msvc": "^4.50.0"
208
210
  }
209
211
  }
@@ -15,6 +15,7 @@ interface MessageProps {
15
15
  isStreaming?: boolean;
16
16
  diffData?: UnifiedFilesDiff;
17
17
  chatId?: string;
18
+ showAdditionalWidgets?: boolean;
18
19
  }
19
20
 
20
21
  const MessageComponent = ({
@@ -25,6 +26,7 @@ const MessageComponent = ({
25
26
  isStreaming,
26
27
  diffData,
27
28
  chatId,
29
+ showAdditionalWidgets = false,
28
30
  }: MessageProps) => {
29
31
  const { additionalWidgets, handleSendMessage } =
30
32
  useContext(VZCodeContext);
@@ -56,7 +58,8 @@ const MessageComponent = ({
56
58
  Object.keys(diffData).length > 0 && (
57
59
  <DiffView diffData={diffData} />
58
60
  )}
59
- {additionalWidgets &&
61
+ {showAdditionalWidgets &&
62
+ additionalWidgets &&
60
63
  chatId &&
61
64
  additionalWidgets({
62
65
  messageId: id,
@@ -152,13 +152,24 @@ const MessageListComponent = ({
152
152
  aiScratchpad && aiScratchpad.trim(),
153
153
  );
154
154
 
155
+ // Find the most recent assistant message index
156
+ const lastAssistantMessageIndex = messages
157
+ .map((m, i) => (m.role === 'assistant' ? i : -1))
158
+ .filter((i) => i !== -1)
159
+ .pop();
160
+
155
161
  return (
156
162
  <div
157
163
  className="ai-chat-messages"
158
164
  ref={messagesContainerRef}
159
165
  onScroll={handleScroll}
160
166
  >
161
- {messages.map((msg, _index) => {
167
+ {messages.map((msg, index) => {
168
+ // Only show additionalWidgets for the most recent assistant message
169
+ const showAdditionalWidgets =
170
+ msg.role === 'assistant' &&
171
+ index === lastAssistantMessageIndex;
172
+
162
173
  return (
163
174
  <Message
164
175
  key={msg.id}
@@ -168,6 +179,7 @@ const MessageListComponent = ({
168
179
  timestamp={msg.timestamp}
169
180
  diffData={(msg as any).diffData}
170
181
  chatId={chatId}
182
+ showAdditionalWidgets={showAdditionalWidgets}
171
183
  />
172
184
  );
173
185
  })}
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+
3
+ interface CheckboxWidgetProps {
4
+ property: string;
5
+ label: string;
6
+ currentValue: boolean;
7
+ onChange: (
8
+ event: React.ChangeEvent<HTMLInputElement>,
9
+ ) => void;
10
+ }
11
+
12
+ export const CheckboxWidget: React.FC<
13
+ CheckboxWidgetProps
14
+ > = ({ property, label, currentValue, onChange }) => {
15
+ return (
16
+ <div className="visual-editor-checkbox">
17
+ <div className="checkbox-header">
18
+ <label
19
+ htmlFor={property}
20
+ className="checkbox-label"
21
+ >
22
+ {label}
23
+ </label>
24
+ <span className="checkbox-value">
25
+ {currentValue ? 'On' : 'Off'}
26
+ </span>
27
+ </div>
28
+ <div className="checkbox-container">
29
+ <input
30
+ type="checkbox"
31
+ id={property}
32
+ className="checkbox-input"
33
+ checked={currentValue}
34
+ onChange={onChange}
35
+ />
36
+ <div className="checkbox-visual">
37
+ <div
38
+ className={`checkbox-indicator ${
39
+ currentValue ? 'checked' : ''
40
+ }`}
41
+ />
42
+ </div>
43
+ </div>
44
+ </div>
45
+ );
46
+ };
@@ -0,0 +1,173 @@
1
+ import React, { useRef, useEffect } from 'react';
2
+ import { renderSliderBackground } from './utils';
3
+
4
+ interface ColorWidgetProps {
5
+ property: string;
6
+ label: string;
7
+ currentHex: string;
8
+ currentH: number;
9
+ currentC: number;
10
+ currentL: number;
11
+ onColorChange: (
12
+ property: string,
13
+ lchComponent: 'l' | 'c' | 'h',
14
+ ) => (event: React.ChangeEvent<HTMLInputElement>) => void;
15
+ }
16
+
17
+ export const ColorWidget: React.FC<ColorWidgetProps> = ({
18
+ property,
19
+ label,
20
+ currentHex,
21
+ currentH,
22
+ currentC,
23
+ currentL,
24
+ onColorChange,
25
+ }) => {
26
+ // Refs for canvas elements (for color slider backgrounds)
27
+ const canvasRefs = useRef<{
28
+ [key: string]: HTMLCanvasElement | null;
29
+ }>({});
30
+
31
+ // Update color slider backgrounds when values change
32
+ useEffect(() => {
33
+ const values = {
34
+ h: currentH,
35
+ c: currentC,
36
+ l: currentL,
37
+ };
38
+
39
+ // Render backgrounds for each slider
40
+ renderSliderBackground(
41
+ canvasRefs.current[`${property}_l_bg`],
42
+ 'l',
43
+ values,
44
+ );
45
+ renderSliderBackground(
46
+ canvasRefs.current[`${property}_c_bg`],
47
+ 'c',
48
+ values,
49
+ );
50
+ renderSliderBackground(
51
+ canvasRefs.current[`${property}_h_bg`],
52
+ 'h',
53
+ values,
54
+ );
55
+ }, [property, currentH, currentC, currentL]);
56
+
57
+ return (
58
+ <div className="visual-editor-color">
59
+ <div className="color-header">
60
+ <label className="color-label">{label}</label>
61
+ <span className="color-value">{currentHex}</span>
62
+ </div>
63
+
64
+ <div
65
+ className="color-preview"
66
+ style={{ backgroundColor: currentHex }}
67
+ />
68
+
69
+ <div className="lch-sliders">
70
+ {/* Lightness Slider */}
71
+ <div className="lch-slider">
72
+ <div className="slider-header">
73
+ <label className="slider-label">
74
+ Lightness
75
+ </label>
76
+ <span className="slider-value">
77
+ {Math.round(currentL)}
78
+ </span>
79
+ </div>
80
+ <div className="slider-container">
81
+ <canvas
82
+ ref={(canvas) => {
83
+ canvasRefs.current[`${property}_l_bg`] =
84
+ canvas;
85
+ }}
86
+ className="slider-bg-canvas"
87
+ width={200}
88
+ />
89
+ <input
90
+ type="range"
91
+ className="slider-input"
92
+ min={0}
93
+ max={100}
94
+ step={1}
95
+ value={currentL}
96
+ onChange={onColorChange(property, 'l')}
97
+ />
98
+ </div>
99
+ <div className="slider-bounds">
100
+ <span className="min-value">0</span>
101
+ <span className="max-value">100</span>
102
+ </div>
103
+ </div>
104
+
105
+ {/* Chroma Slider */}
106
+ <div className="lch-slider">
107
+ <div className="slider-header">
108
+ <label className="slider-label">Chroma</label>
109
+ <span className="slider-value">
110
+ {Math.round(currentC)}
111
+ </span>
112
+ </div>
113
+ <div className="slider-container">
114
+ <canvas
115
+ ref={(canvas) => {
116
+ canvasRefs.current[`${property}_c_bg`] =
117
+ canvas;
118
+ }}
119
+ className="slider-bg-canvas"
120
+ width={200}
121
+ />
122
+ <input
123
+ type="range"
124
+ className="slider-input"
125
+ min={0}
126
+ max={100}
127
+ step={1}
128
+ value={currentC}
129
+ onChange={onColorChange(property, 'c')}
130
+ />
131
+ </div>
132
+ <div className="slider-bounds">
133
+ <span className="min-value">0</span>
134
+ <span className="max-value">100</span>
135
+ </div>
136
+ </div>
137
+
138
+ {/* Hue Slider */}
139
+ <div className="lch-slider">
140
+ <div className="slider-header">
141
+ <label className="slider-label">Hue</label>
142
+ <span className="slider-value">
143
+ {Math.round(currentH)}°
144
+ </span>
145
+ </div>
146
+ <div className="slider-container">
147
+ <canvas
148
+ ref={(canvas) => {
149
+ canvasRefs.current[`${property}_h_bg`] =
150
+ canvas;
151
+ }}
152
+ className="slider-bg-canvas"
153
+ width={200}
154
+ />
155
+ <input
156
+ type="range"
157
+ className="slider-input"
158
+ min={0}
159
+ max={360}
160
+ step={1}
161
+ value={currentH}
162
+ onChange={onColorChange(property, 'h')}
163
+ />
164
+ </div>
165
+ <div className="slider-bounds">
166
+ <span className="min-value">0°</span>
167
+ <span className="max-value">360°</span>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ );
173
+ };
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+
3
+ interface DropdownWidgetProps {
4
+ property: string;
5
+ label: string;
6
+ options: string[];
7
+ currentValue: string;
8
+ isOpen: boolean;
9
+ onToggle: () => void;
10
+ onOptionClick: (value: string) => void;
11
+ }
12
+
13
+ export const DropdownWidget: React.FC<
14
+ DropdownWidgetProps
15
+ > = ({
16
+ property,
17
+ label,
18
+ options,
19
+ currentValue,
20
+ isOpen,
21
+ onToggle,
22
+ onOptionClick,
23
+ }) => {
24
+ return (
25
+ <div className="visual-editor-dropdown">
26
+ <div className="dropdown-header">
27
+ <label
28
+ htmlFor={property}
29
+ className="dropdown-label"
30
+ >
31
+ {label}
32
+ </label>
33
+ </div>
34
+ <div className="dropdown-container">
35
+ <button
36
+ type="button"
37
+ className={`dropdown-button ${isOpen ? 'open' : ''}`}
38
+ onClick={onToggle}
39
+ aria-expanded={isOpen}
40
+ aria-haspopup="listbox"
41
+ >
42
+ <span className="dropdown-button-text">
43
+ {currentValue}
44
+ </span>
45
+ <div
46
+ className={`dropdown-arrow ${isOpen ? 'open' : ''}`}
47
+ >
48
+ <svg
49
+ width="12"
50
+ height="8"
51
+ viewBox="0 0 12 8"
52
+ fill="none"
53
+ xmlns="http://www.w3.org/2000/svg"
54
+ >
55
+ <path
56
+ d="M1 1.5L6 6.5L11 1.5"
57
+ stroke="currentColor"
58
+ strokeWidth="2"
59
+ strokeLinecap="round"
60
+ strokeLinejoin="round"
61
+ />
62
+ </svg>
63
+ </div>
64
+ </button>
65
+ {isOpen && (
66
+ <div className="dropdown-options">
67
+ {options.map((option) => (
68
+ <button
69
+ key={option}
70
+ type="button"
71
+ className={`dropdown-option ${
72
+ option === currentValue ? 'selected' : ''
73
+ }`}
74
+ onClick={() => onOptionClick(option)}
75
+ >
76
+ {option}
77
+ </button>
78
+ ))}
79
+ </div>
80
+ )}
81
+ </div>
82
+ </div>
83
+ );
84
+ };
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import { calculatePercentage, formatValue } from './utils';
3
+
4
+ interface SliderWidgetProps {
5
+ property: string;
6
+ label: string;
7
+ min: number;
8
+ max: number;
9
+ step: number;
10
+ currentValue: number;
11
+ onChange: (
12
+ event: React.ChangeEvent<HTMLInputElement>,
13
+ ) => void;
14
+ }
15
+
16
+ export const SliderWidget: React.FC<SliderWidgetProps> = ({
17
+ property,
18
+ label,
19
+ min,
20
+ max,
21
+ step,
22
+ currentValue,
23
+ onChange,
24
+ }) => {
25
+ const percentage = calculatePercentage(
26
+ currentValue,
27
+ min,
28
+ max,
29
+ );
30
+
31
+ return (
32
+ <div className="visual-editor-slider">
33
+ <div className="slider-header">
34
+ <label htmlFor={property} className="slider-label">
35
+ {label}
36
+ </label>
37
+ <span className="slider-value">
38
+ {formatValue(currentValue, min, max)}
39
+ </span>
40
+ </div>
41
+ <div className="slider-container">
42
+ <input
43
+ type="range"
44
+ id={property}
45
+ className="slider-input"
46
+ min={min}
47
+ max={max}
48
+ step={step}
49
+ value={currentValue}
50
+ onChange={onChange}
51
+ />
52
+ <div
53
+ className="slider-track-fill"
54
+ style={{ width: `${percentage}%` }}
55
+ />
56
+ </div>
57
+ <div className="slider-bounds">
58
+ <span className="min-value">{min}</span>
59
+ <span className="max-value">{max}</span>
60
+ </div>
61
+ </div>
62
+ );
63
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ interface TextInputWidgetProps {
4
+ property: string;
5
+ label: string;
6
+ currentValue: string;
7
+ onChange: (
8
+ event: React.ChangeEvent<HTMLInputElement>,
9
+ ) => void;
10
+ }
11
+
12
+ export const TextInputWidget: React.FC<
13
+ TextInputWidgetProps
14
+ > = ({ property, label, currentValue, onChange }) => {
15
+ return (
16
+ <div className="visual-editor-text-input">
17
+ <div className="text-input-header">
18
+ <label
19
+ htmlFor={property}
20
+ className="text-input-label"
21
+ >
22
+ {label}
23
+ </label>
24
+ </div>
25
+ <div className="text-input-container">
26
+ <input
27
+ type="text"
28
+ id={property}
29
+ className="text-input-field"
30
+ value={currentValue || ''}
31
+ onChange={onChange}
32
+ />
33
+ </div>
34
+ </div>
35
+ );
36
+ };