vzcode 2.11.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/assets/{index-BK1qsxog.js → index-858eZSOF.js} +98 -98
- package/dist/assets/{index-C5d5win4.css → index-DLm5FQ0E.css} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/client/VZSidebar/VisualEditor/CheckboxWidget.tsx +46 -0
- package/src/client/VZSidebar/VisualEditor/ColorWidget.tsx +173 -0
- package/src/client/VZSidebar/VisualEditor/DropdownWidget.tsx +84 -0
- package/src/client/VZSidebar/VisualEditor/SliderWidget.tsx +63 -0
- package/src/client/VZSidebar/VisualEditor/TextInputWidget.tsx +36 -0
- package/src/client/VZSidebar/{VisualEditor.tsx → VisualEditor/VisualEditor.tsx} +61 -334
- package/src/client/VZSidebar/VisualEditor/constants.ts +1 -0
- package/src/client/VZSidebar/VisualEditor/index.tsx +1 -0
- package/src/client/VZSidebar/VisualEditor/utils.ts +102 -0
- package/src/client/VZSidebar/styles.scss +32 -21
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-
|
|
24
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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
|
@@ -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
|
+
};
|