js-draw 0.1.4 → 0.1.7
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/.eslintrc.js +1 -0
- package/CHANGELOG.md +15 -0
- package/README.md +2 -2
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.js +6 -2
- package/dist/src/Editor.d.ts +1 -0
- package/dist/src/Editor.js +20 -9
- package/dist/src/EditorImage.d.ts +8 -13
- package/dist/src/EditorImage.js +51 -29
- package/dist/src/SVGLoader.js +6 -2
- package/dist/src/Viewport.d.ts +10 -2
- package/dist/src/Viewport.js +8 -6
- package/dist/src/commands/Command.d.ts +9 -8
- package/dist/src/commands/Command.js +15 -14
- package/dist/src/commands/Duplicate.d.ts +14 -0
- package/dist/src/commands/Duplicate.js +34 -0
- package/dist/src/commands/Erase.d.ts +5 -2
- package/dist/src/commands/Erase.js +28 -9
- package/dist/src/commands/SerializableCommand.d.ts +13 -0
- package/dist/src/commands/SerializableCommand.js +28 -0
- package/dist/src/commands/localization.d.ts +2 -0
- package/dist/src/commands/localization.js +2 -0
- package/dist/src/components/AbstractComponent.d.ts +15 -2
- package/dist/src/components/AbstractComponent.js +122 -26
- package/dist/src/components/SVGGlobalAttributesObject.d.ts +6 -1
- package/dist/src/components/SVGGlobalAttributesObject.js +23 -1
- package/dist/src/components/Stroke.d.ts +5 -0
- package/dist/src/components/Stroke.js +32 -1
- package/dist/src/components/Text.d.ts +11 -4
- package/dist/src/components/Text.js +57 -3
- package/dist/src/components/UnknownSVGObject.d.ts +2 -0
- package/dist/src/components/UnknownSVGObject.js +12 -1
- package/dist/src/components/util/describeComponentList.d.ts +4 -0
- package/dist/src/components/util/describeComponentList.js +14 -0
- package/dist/src/geometry/Path.d.ts +4 -1
- package/dist/src/geometry/Path.js +4 -0
- package/dist/src/localization.d.ts +2 -1
- package/dist/src/localization.js +2 -1
- package/dist/src/rendering/Display.d.ts +5 -0
- package/dist/src/rendering/Display.js +32 -0
- package/dist/src/rendering/RenderingStyle.d.ts +24 -0
- package/dist/src/rendering/RenderingStyle.js +32 -0
- package/dist/src/rendering/localization.d.ts +5 -0
- package/dist/src/rendering/localization.js +4 -0
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +1 -8
- package/dist/src/rendering/renderers/AbstractRenderer.js +1 -6
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +2 -1
- package/dist/src/rendering/renderers/DummyRenderer.d.ts +2 -1
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +2 -1
- package/dist/src/rendering/renderers/TextOnlyRenderer.d.ts +25 -0
- package/dist/src/rendering/renderers/TextOnlyRenderer.js +40 -0
- package/dist/src/toolbar/HTMLToolbar.d.ts +1 -1
- package/dist/src/toolbar/HTMLToolbar.js +52 -534
- package/dist/src/toolbar/icons.d.ts +5 -0
- package/dist/src/toolbar/icons.js +186 -13
- package/dist/src/toolbar/localization.d.ts +4 -0
- package/dist/src/toolbar/localization.js +4 -0
- package/dist/src/toolbar/makeColorInput.d.ts +5 -0
- package/dist/src/toolbar/makeColorInput.js +81 -0
- package/dist/src/toolbar/widgets/BaseToolWidget.d.ts +12 -0
- package/dist/src/toolbar/widgets/BaseToolWidget.js +44 -0
- package/dist/src/toolbar/widgets/BaseWidget.d.ts +32 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +148 -0
- package/dist/src/toolbar/widgets/EraserWidget.d.ts +6 -0
- package/dist/src/toolbar/widgets/EraserWidget.js +14 -0
- package/dist/src/toolbar/widgets/HandToolWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/HandToolWidget.js +133 -0
- package/dist/src/toolbar/widgets/PenWidget.d.ts +20 -0
- package/dist/src/toolbar/widgets/PenWidget.js +131 -0
- package/dist/src/toolbar/widgets/SelectionWidget.d.ts +11 -0
- package/dist/src/toolbar/widgets/SelectionWidget.js +56 -0
- package/dist/src/toolbar/widgets/TextToolWidget.d.ts +13 -0
- package/dist/src/toolbar/widgets/TextToolWidget.js +72 -0
- package/dist/src/tools/Pen.js +1 -1
- package/dist/src/tools/PipetteTool.d.ts +20 -0
- package/dist/src/tools/PipetteTool.js +40 -0
- package/dist/src/tools/SelectionTool.d.ts +2 -0
- package/dist/src/tools/SelectionTool.js +41 -23
- package/dist/src/tools/TextTool.d.ts +1 -0
- package/dist/src/tools/TextTool.js +5 -4
- package/dist/src/tools/ToolController.d.ts +3 -1
- package/dist/src/tools/ToolController.js +4 -0
- package/dist/src/tools/localization.d.ts +2 -1
- package/dist/src/tools/localization.js +3 -2
- package/dist/src/types.d.ts +7 -2
- package/dist/src/types.js +1 -0
- package/jest.config.js +2 -0
- package/package.json +6 -6
- package/src/Color4.ts +9 -3
- package/src/Editor.css +10 -0
- package/src/Editor.ts +24 -12
- package/src/EditorImage.test.ts +4 -4
- package/src/EditorImage.ts +61 -20
- package/src/SVGLoader.ts +9 -3
- package/src/Viewport.ts +7 -6
- package/src/commands/Command.ts +21 -19
- package/src/commands/Duplicate.ts +49 -0
- package/src/commands/Erase.ts +34 -13
- package/src/commands/SerializableCommand.ts +41 -0
- package/src/commands/localization.ts +5 -0
- package/src/components/AbstractComponent.ts +168 -26
- package/src/components/SVGGlobalAttributesObject.ts +34 -2
- package/src/components/Stroke.test.ts +53 -0
- package/src/components/Stroke.ts +37 -2
- package/src/components/Text.test.ts +38 -0
- package/src/components/Text.ts +80 -5
- package/src/components/UnknownSVGObject.test.ts +10 -0
- package/src/components/UnknownSVGObject.ts +15 -1
- package/src/components/builders/FreehandLineBuilder.ts +2 -1
- package/src/components/util/describeComponentList.ts +18 -0
- package/src/geometry/Path.ts +8 -1
- package/src/localization.ts +3 -1
- package/src/rendering/Display.ts +43 -1
- package/src/rendering/RenderingStyle.test.ts +68 -0
- package/src/rendering/RenderingStyle.ts +46 -0
- package/src/rendering/caching/RenderingCache.test.ts +1 -1
- package/src/rendering/localization.ts +10 -0
- package/src/rendering/renderers/AbstractRenderer.ts +1 -15
- package/src/rendering/renderers/CanvasRenderer.ts +2 -1
- package/src/rendering/renderers/DummyRenderer.ts +2 -1
- package/src/rendering/renderers/SVGRenderer.ts +2 -1
- package/src/rendering/renderers/TextOnlyRenderer.ts +52 -0
- package/src/toolbar/HTMLToolbar.ts +58 -660
- package/src/toolbar/icons.ts +205 -13
- package/src/toolbar/localization.ts +10 -2
- package/src/toolbar/makeColorInput.ts +105 -0
- package/src/toolbar/toolbar.css +116 -78
- package/src/toolbar/widgets/BaseToolWidget.ts +53 -0
- package/src/toolbar/widgets/BaseWidget.ts +175 -0
- package/src/toolbar/widgets/EraserWidget.ts +16 -0
- package/src/toolbar/widgets/HandToolWidget.ts +186 -0
- package/src/toolbar/widgets/PenWidget.ts +165 -0
- package/src/toolbar/widgets/SelectionWidget.ts +72 -0
- package/src/toolbar/widgets/TextToolWidget.ts +90 -0
- package/src/tools/Pen.ts +1 -1
- package/src/tools/PipetteTool.ts +56 -0
- package/src/tools/SelectionTool.test.ts +2 -4
- package/src/tools/SelectionTool.ts +47 -27
- package/src/tools/TextTool.ts +7 -3
- package/src/tools/ToolController.ts +10 -6
- package/src/tools/UndoRedoShortcut.test.ts +1 -1
- package/src/tools/localization.ts +6 -3
- package/src/types.ts +12 -1
package/src/toolbar/icons.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import Color4 from '../Color4';
|
1
2
|
import { ComponentBuilderFactory } from '../components/builders/types';
|
2
3
|
import { TextStyle } from '../components/Text';
|
3
4
|
import EventDispatcher from '../EventDispatcher';
|
@@ -14,6 +15,20 @@ const primaryForegroundFill = `
|
|
14
15
|
const primaryForegroundStrokeFill = `
|
15
16
|
style='fill: var(--primary-foreground-color); stroke: var(--primary-foreground-color);'
|
16
17
|
`;
|
18
|
+
const checkerboardPatternDef = `
|
19
|
+
<pattern
|
20
|
+
id='checkerboard'
|
21
|
+
viewBox='0,0,10,10'
|
22
|
+
width='20%'
|
23
|
+
height='20%'
|
24
|
+
patternUnits='userSpaceOnUse'
|
25
|
+
>
|
26
|
+
<rect x=0 y=0 width=10 height=10 fill='white'/>
|
27
|
+
<rect x=0 y=0 width=5 height=5 fill='gray'/>
|
28
|
+
<rect x=5 y=5 width=5 height=5 fill='gray'/>
|
29
|
+
</pattern>
|
30
|
+
`;
|
31
|
+
const checkerboardPatternRef = 'url(#checkerboard)';
|
17
32
|
|
18
33
|
export const makeUndoIcon = () => {
|
19
34
|
return makeRedoIcon(true);
|
@@ -91,7 +106,7 @@ export const makeSelectionIcon = () => {
|
|
91
106
|
export const makeHandToolIcon = () => {
|
92
107
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
93
108
|
|
94
|
-
// Draw a cursor-like shape
|
109
|
+
// Draw a cursor-like shape (like some of the other icons, made with Inkscape)
|
95
110
|
icon.innerHTML = `
|
96
111
|
<g>
|
97
112
|
<path d='
|
@@ -127,6 +142,139 @@ export const makeHandToolIcon = () => {
|
|
127
142
|
return icon;
|
128
143
|
};
|
129
144
|
|
145
|
+
export const makeTouchPanningIcon = () => {
|
146
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
147
|
+
icon.innerHTML = `
|
148
|
+
<path
|
149
|
+
d='
|
150
|
+
M 5,5.5
|
151
|
+
V 17.2
|
152
|
+
L 16.25,5.46
|
153
|
+
Z
|
154
|
+
|
155
|
+
m 33.75,0
|
156
|
+
L 50,17
|
157
|
+
V 5.5
|
158
|
+
Z
|
159
|
+
|
160
|
+
M 5,40.7
|
161
|
+
v 11.7
|
162
|
+
h 11.25
|
163
|
+
z
|
164
|
+
|
165
|
+
M 26,19
|
166
|
+
C 19.8,19.4 17.65,30.4 21.9,34.8
|
167
|
+
L 50,70
|
168
|
+
H 27.5
|
169
|
+
c -11.25,0 -11.25,17.6 0,17.6
|
170
|
+
H 61.25
|
171
|
+
C 94.9,87.8 95,87.6 95,40.7 78.125,23 67,29 55.6,46.5
|
172
|
+
L 33.1,23
|
173
|
+
C 30.3125,20.128192 27.9,19 25.830078,19.119756
|
174
|
+
Z
|
175
|
+
'
|
176
|
+
fill='none'
|
177
|
+
style='
|
178
|
+
stroke: var(--primary-foreground-color);
|
179
|
+
stroke-width: 2;
|
180
|
+
'
|
181
|
+
/>
|
182
|
+
`;
|
183
|
+
|
184
|
+
icon.setAttribute('viewBox', '0 0 100 100');
|
185
|
+
return icon;
|
186
|
+
};
|
187
|
+
|
188
|
+
export const makeAllDevicePanningIcon = () => {
|
189
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
190
|
+
icon.innerHTML = `
|
191
|
+
<path
|
192
|
+
d='
|
193
|
+
M 5 5
|
194
|
+
L 5 17.5
|
195
|
+
17.5 5
|
196
|
+
5 5
|
197
|
+
z
|
198
|
+
|
199
|
+
M 42.5 5
|
200
|
+
L 55 17.5
|
201
|
+
55 5
|
202
|
+
42.5 5
|
203
|
+
z
|
204
|
+
|
205
|
+
M 70 10
|
206
|
+
L 70 21
|
207
|
+
61 15
|
208
|
+
55.5 23
|
209
|
+
66 30
|
210
|
+
56 37
|
211
|
+
61 45
|
212
|
+
70 39
|
213
|
+
70 50
|
214
|
+
80 50
|
215
|
+
80 39
|
216
|
+
89 45
|
217
|
+
95 36
|
218
|
+
84 30
|
219
|
+
95 23
|
220
|
+
89 15
|
221
|
+
80 21
|
222
|
+
80 10
|
223
|
+
70 10
|
224
|
+
z
|
225
|
+
|
226
|
+
M 27.5 26.25
|
227
|
+
L 27.5 91.25
|
228
|
+
L 43.75 83.125
|
229
|
+
L 52 99
|
230
|
+
L 68 91
|
231
|
+
L 60 75
|
232
|
+
L 76.25 66.875
|
233
|
+
L 27.5 26.25
|
234
|
+
z
|
235
|
+
|
236
|
+
M 5 42.5
|
237
|
+
L 5 55
|
238
|
+
L 17.5 55
|
239
|
+
L 5 42.5
|
240
|
+
z
|
241
|
+
'
|
242
|
+
fill='none'
|
243
|
+
style='
|
244
|
+
stroke: var(--primary-foreground-color);
|
245
|
+
stroke-width: 2;
|
246
|
+
'
|
247
|
+
/>
|
248
|
+
`;
|
249
|
+
|
250
|
+
icon.setAttribute('viewBox', '0 0 100 100');
|
251
|
+
return icon;
|
252
|
+
};
|
253
|
+
|
254
|
+
export const makeZoomIcon = () => {
|
255
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
256
|
+
icon.setAttribute('viewBox', '0 0 100 100');
|
257
|
+
|
258
|
+
const addTextNode = (text: string, x: number, y: number) => {
|
259
|
+
const textNode = document.createElementNS(svgNamespace, 'text');
|
260
|
+
textNode.appendChild(document.createTextNode(text));
|
261
|
+
textNode.setAttribute('x', x.toString());
|
262
|
+
textNode.setAttribute('y', y.toString());
|
263
|
+
textNode.style.textAlign = 'center';
|
264
|
+
textNode.style.textAnchor = 'middle';
|
265
|
+
textNode.style.fontSize = '55px';
|
266
|
+
textNode.style.fill = 'var(--primary-foreground-color)';
|
267
|
+
textNode.style.fontFamily = 'monospace';
|
268
|
+
|
269
|
+
icon.appendChild(textNode);
|
270
|
+
};
|
271
|
+
|
272
|
+
addTextNode('+', 40, 45);
|
273
|
+
addTextNode('-', 70, 75);
|
274
|
+
|
275
|
+
return icon;
|
276
|
+
};
|
277
|
+
|
130
278
|
export const makeTextIcon = (textStyle: TextStyle) => {
|
131
279
|
const icon = document.createElementNS(svgNamespace, 'svg');
|
132
280
|
icon.setAttribute('viewBox', '0 0 100 100');
|
@@ -161,17 +309,7 @@ export const makePenIcon = (tipThickness: number, color: string) => {
|
|
161
309
|
const backgroundStrokeTipPath = `M14,63 L${50 - halfThickness},85 L${50 + halfThickness},83 L88,60 Z`;
|
162
310
|
icon.innerHTML = `
|
163
311
|
<defs>
|
164
|
-
|
165
|
-
id='checkerboard'
|
166
|
-
viewBox='0,0,10,10'
|
167
|
-
width='20%'
|
168
|
-
height='20%'
|
169
|
-
patternUnits='userSpaceOnUse'
|
170
|
-
>
|
171
|
-
<rect x=0 y=0 width=10 height=10 fill='white'/>
|
172
|
-
<rect x=0 y=0 width=5 height=5 fill='gray'/>
|
173
|
-
<rect x=5 y=5 width=5 height=5 fill='gray'/>
|
174
|
-
</pattern>
|
312
|
+
${checkerboardPatternDef}
|
175
313
|
</defs>
|
176
314
|
<g>
|
177
315
|
<!-- Pen grip -->
|
@@ -182,7 +320,7 @@ export const makePenIcon = (tipThickness: number, color: string) => {
|
|
182
320
|
</g>
|
183
321
|
<g>
|
184
322
|
<!-- Checkerboard background for slightly transparent pens -->
|
185
|
-
<path d='${backgroundStrokeTipPath}' fill='
|
323
|
+
<path d='${backgroundStrokeTipPath}' fill='${checkerboardPatternRef}'/>
|
186
324
|
|
187
325
|
<!-- Actual pen tip -->
|
188
326
|
<path
|
@@ -225,3 +363,57 @@ export const makeIconFromFactory = (pen: Pen, factory: ComponentBuilderFactory)
|
|
225
363
|
|
226
364
|
return icon;
|
227
365
|
};
|
366
|
+
|
367
|
+
export const makePipetteIcon = (color?: Color4) => {
|
368
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
369
|
+
const pipette = document.createElementNS(svgNamespace, 'path');
|
370
|
+
|
371
|
+
pipette.setAttribute('d', `
|
372
|
+
M 47,6
|
373
|
+
C 35,5 25,15 35,30
|
374
|
+
c -9.2,1.3 -15,0 -15,3
|
375
|
+
0,2 5,5 15,7
|
376
|
+
V 81
|
377
|
+
L 40,90
|
378
|
+
h 6
|
379
|
+
L 40,80
|
380
|
+
V 40
|
381
|
+
h 15
|
382
|
+
v 40
|
383
|
+
l -6,10
|
384
|
+
h 6
|
385
|
+
l 5,-9.2
|
386
|
+
V 40
|
387
|
+
C 70,38 75,35 75,33
|
388
|
+
75,30 69.2,31.2 60,30
|
389
|
+
65,15 65,5 47,6
|
390
|
+
Z
|
391
|
+
`);
|
392
|
+
pipette.style.fill = 'var(--primary-foreground-color)';
|
393
|
+
|
394
|
+
if (color) {
|
395
|
+
const defs = document.createElementNS(svgNamespace, 'defs');
|
396
|
+
defs.innerHTML = checkerboardPatternDef;
|
397
|
+
icon.appendChild(defs);
|
398
|
+
|
399
|
+
const fluidBackground = document.createElementNS(svgNamespace, 'path');
|
400
|
+
const fluid = document.createElementNS(svgNamespace, 'path');
|
401
|
+
|
402
|
+
const fluidPathData = `
|
403
|
+
m 40,50 c 5,5 10,0 15,-5 V 80 L 50,90 H 45 L 40,80 Z
|
404
|
+
`;
|
405
|
+
|
406
|
+
fluid.setAttribute('d', fluidPathData);
|
407
|
+
fluidBackground.setAttribute('d', fluidPathData);
|
408
|
+
|
409
|
+
fluid.style.fill = color.toHexString();
|
410
|
+
fluidBackground.style.fill = checkerboardPatternRef;
|
411
|
+
|
412
|
+
icon.appendChild(fluidBackground);
|
413
|
+
icon.appendChild(fluid);
|
414
|
+
}
|
415
|
+
icon.appendChild(pipette);
|
416
|
+
|
417
|
+
icon.setAttribute('viewBox', '0 0 100 100');
|
418
|
+
return icon;
|
419
|
+
};
|
@@ -18,12 +18,16 @@ export interface ToolbarLocalization {
|
|
18
18
|
thicknessLabel: string;
|
19
19
|
resizeImageToSelection: string;
|
20
20
|
deleteSelection: string;
|
21
|
+
duplicateSelection: string;
|
22
|
+
pickColorFronScreen: string;
|
21
23
|
undo: string;
|
22
24
|
redo: string;
|
25
|
+
zoom: string;
|
23
26
|
|
24
|
-
dropdownShown: (toolName: string)=>string;
|
25
|
-
dropdownHidden: (toolName: string)=>string;
|
27
|
+
dropdownShown: (toolName: string)=> string;
|
28
|
+
dropdownHidden: (toolName: string)=> string;
|
26
29
|
zoomLevel: (zoomPercentage: number)=> string;
|
30
|
+
colorChangedAnnouncement: (color: string)=> string;
|
27
31
|
}
|
28
32
|
|
29
33
|
export const defaultToolbarLocalization: ToolbarLocalization = {
|
@@ -31,14 +35,17 @@ export const defaultToolbarLocalization: ToolbarLocalization = {
|
|
31
35
|
eraser: 'Eraser',
|
32
36
|
select: 'Select',
|
33
37
|
handTool: 'Pan',
|
38
|
+
zoom: 'Zoom',
|
34
39
|
thicknessLabel: 'Thickness: ',
|
35
40
|
colorLabel: 'Color: ',
|
36
41
|
fontLabel: 'Font: ',
|
37
42
|
resizeImageToSelection: 'Resize image to selection',
|
38
43
|
deleteSelection: 'Delete selection',
|
44
|
+
duplicateSelection: 'Duplicate selection',
|
39
45
|
undo: 'Undo',
|
40
46
|
redo: 'Redo',
|
41
47
|
selectObjectType: 'Object type: ',
|
48
|
+
pickColorFronScreen: 'Pick color from screen',
|
42
49
|
|
43
50
|
touchPanning: 'Touchscreen panning',
|
44
51
|
anyDevicePanning: 'Any device panning',
|
@@ -52,4 +59,5 @@ export const defaultToolbarLocalization: ToolbarLocalization = {
|
|
52
59
|
dropdownShown: (toolName) => `Dropdown for ${toolName} shown`,
|
53
60
|
dropdownHidden: (toolName) => `Dropdown for ${toolName} hidden`,
|
54
61
|
zoomLevel: (zoomPercent: number) => `Zoom: ${zoomPercent}%`,
|
62
|
+
colorChangedAnnouncement: (color: string)=> `Color changed to ${color}`,
|
55
63
|
};
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import Color4 from '../Color4';
|
2
|
+
import Editor from '../Editor';
|
3
|
+
import PipetteTool from '../tools/PipetteTool';
|
4
|
+
import { ToolType } from '../tools/ToolController';
|
5
|
+
import { EditorEventType } from '../types';
|
6
|
+
import { makePipetteIcon } from './icons';
|
7
|
+
|
8
|
+
type OnColorChangeListener = (color: Color4)=>void;
|
9
|
+
|
10
|
+
|
11
|
+
// Returns [ input, container ].
|
12
|
+
export const makeColorInput = (editor: Editor, onColorChange: OnColorChangeListener): [ HTMLInputElement, HTMLElement ] => {
|
13
|
+
const colorInputContainer = document.createElement('span');
|
14
|
+
const colorInput = document.createElement('input');
|
15
|
+
|
16
|
+
colorInput.type = 'button';
|
17
|
+
colorInput.classList.add('coloris_input');
|
18
|
+
colorInputContainer.classList.add('color-input-container');
|
19
|
+
|
20
|
+
colorInputContainer.appendChild(colorInput);
|
21
|
+
addPipetteTool(editor, colorInputContainer, (color: Color4) => {
|
22
|
+
colorInput.value = color.toHexString();
|
23
|
+
handleColorInput();
|
24
|
+
|
25
|
+
// Update the color preview, if it exists (may be managed by Coloris).
|
26
|
+
const parentElem = colorInput.parentElement;
|
27
|
+
if (parentElem && parentElem.classList.contains('clr-field')) {
|
28
|
+
parentElem.style.color = colorInput.value;
|
29
|
+
}
|
30
|
+
});
|
31
|
+
|
32
|
+
let currentColor: Color4|undefined;
|
33
|
+
const handleColorInput = () => {
|
34
|
+
currentColor = Color4.fromHex(colorInput.value);
|
35
|
+
editor.announceForAccessibility(
|
36
|
+
editor.localization.colorChangedAnnouncement(currentColor.toHexString())
|
37
|
+
);
|
38
|
+
onColorChange(currentColor);
|
39
|
+
|
40
|
+
editor.notifier.dispatch(EditorEventType.ColorPickerColorSelected, {
|
41
|
+
kind: EditorEventType.ColorPickerColorSelected,
|
42
|
+
color: currentColor,
|
43
|
+
});
|
44
|
+
};
|
45
|
+
|
46
|
+
colorInput.oninput = handleColorInput;
|
47
|
+
colorInput.addEventListener('open', () => {
|
48
|
+
editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
|
49
|
+
kind: EditorEventType.ColorPickerToggled,
|
50
|
+
open: true,
|
51
|
+
});
|
52
|
+
});
|
53
|
+
colorInput.addEventListener('close', () => {
|
54
|
+
editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
|
55
|
+
kind: EditorEventType.ColorPickerToggled,
|
56
|
+
open: false,
|
57
|
+
});
|
58
|
+
});
|
59
|
+
|
60
|
+
return [ colorInput, colorInputContainer ];
|
61
|
+
};
|
62
|
+
|
63
|
+
const addPipetteTool = (editor: Editor, container: HTMLElement, onColorChange: OnColorChangeListener) => {
|
64
|
+
const pipetteButton = document.createElement('button');
|
65
|
+
pipetteButton.classList.add('pipetteButton');
|
66
|
+
pipetteButton.title = editor.localization.pickColorFronScreen;
|
67
|
+
pipetteButton.setAttribute('alt', pipetteButton.title);
|
68
|
+
|
69
|
+
const updatePipetteIcon = (color?: Color4) => {
|
70
|
+
pipetteButton.replaceChildren(makePipetteIcon(color));
|
71
|
+
};
|
72
|
+
updatePipetteIcon();
|
73
|
+
|
74
|
+
const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(ToolType.Pipette)[0] as PipetteTool|undefined;
|
75
|
+
const pipetteColorSelect = (color: Color4|null) => {
|
76
|
+
pipetteTool?.clearColorListener();
|
77
|
+
updatePipetteIcon();
|
78
|
+
pipetteButton.classList.remove('active');
|
79
|
+
|
80
|
+
if (color) {
|
81
|
+
onColorChange(color);
|
82
|
+
}
|
83
|
+
};
|
84
|
+
const pipetteColorPreview = (color: Color4|null) => {
|
85
|
+
if (color) {
|
86
|
+
updatePipetteIcon(color);
|
87
|
+
} else {
|
88
|
+
updatePipetteIcon();
|
89
|
+
}
|
90
|
+
};
|
91
|
+
|
92
|
+
pipetteButton.onclick = () => {
|
93
|
+
pipetteTool?.setColorListener(
|
94
|
+
pipetteColorPreview,
|
95
|
+
pipetteColorSelect,
|
96
|
+
);
|
97
|
+
if (pipetteTool) {
|
98
|
+
pipetteButton.classList.add('active');
|
99
|
+
}
|
100
|
+
};
|
101
|
+
|
102
|
+
container.appendChild(pipetteButton);
|
103
|
+
};
|
104
|
+
|
105
|
+
export default makeColorInput;
|
package/src/toolbar/toolbar.css
CHANGED
@@ -1,138 +1,176 @@
|
|
1
1
|
.toolbar-root {
|
2
|
-
|
2
|
+
background-color: var(--primary-background-color);
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
border: 1px solid var(--secondary-background-color);
|
5
|
+
border-radius: 2px;
|
6
|
+
flex-wrap: wrap;
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
box-sizing: border-box;
|
9
|
+
width: 100%;
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
display: flex;
|
12
|
+
flex-direction: row;
|
13
|
+
justify-content: center;
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
/* Display above selection dialogs, etc. */
|
16
|
+
z-index: 2;
|
17
17
|
|
18
|
-
|
18
|
+
font-family: system-ui, -apple-system, sans-serif;
|
19
19
|
}
|
20
20
|
|
21
|
-
.toolbar-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
.toolbar-root > .toolbar-toolContainer > .toolbar-button,
|
22
|
+
.toolbar-root > .toolbar-toolContainer > * > button,
|
23
|
+
.toolbar-root > .toolbar-buttonGroup > button {
|
24
|
+
width: min-content;
|
25
|
+
height: min(20vh, 60px);
|
26
|
+
}
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
.toolbar-dropdown .toolbar-button > .toolbar-icon {
|
29
|
+
max-width: 50px;
|
30
|
+
}
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
margin-right: 3px;
|
32
|
+
.toolbar-button.disabled {
|
33
|
+
filter: opacity(0.8) saturate(0.1);
|
34
|
+
}
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
.toolbar-button, .toolbar-root button {
|
37
|
+
cursor: pointer;
|
38
|
+
text-align: center;
|
39
|
+
border-radius: 6px;
|
40
40
|
|
41
|
-
|
41
|
+
background-color: var(--primary-background-color);
|
42
|
+
color: var(--primary-foreground-color);
|
43
|
+
border: none;
|
44
|
+
box-shadow: 0px 0px 2px var(--primary-shadow-color);
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
transition: background-color 0.25s ease, box-shadow 0.25s ease, opacity 0.3s ease;
|
47
|
+
}
|
48
|
+
|
49
|
+
.toolbar-button,
|
50
|
+
.toolbar-buttonGroup > button,
|
51
|
+
.toolbar-toolContainer > * > button,
|
52
|
+
.toolbar-root > button {
|
53
|
+
display: flex;
|
54
|
+
flex-direction: column;
|
55
|
+
align-items: center;
|
56
|
+
justify-content: center;
|
48
57
|
|
49
|
-
|
58
|
+
padding-left: 3px;
|
59
|
+
padding-right: 3px;
|
60
|
+
margin-left: 3px;
|
61
|
+
margin-right: 3px;
|
62
|
+
|
63
|
+
min-width: 40px;
|
64
|
+
max-width: 70px;
|
65
|
+
font-size: 11pt;
|
50
66
|
}
|
51
67
|
|
52
68
|
.toolbar-button:hover, .toolbar-root button:not(:disabled):hover {
|
53
|
-
|
69
|
+
box-shadow: 0px 2px 4px var(--primary-shadow-color);
|
54
70
|
}
|
55
71
|
|
56
72
|
.toolbar-root button:disabled {
|
57
|
-
|
58
|
-
|
73
|
+
cursor: inherit;
|
74
|
+
filter: opacity(0.5);
|
59
75
|
}
|
60
76
|
|
61
77
|
.toolbar-root .toolbar-icon {
|
62
|
-
|
63
|
-
|
78
|
+
flex-shrink: 1;
|
79
|
+
min-width: 30px;
|
80
|
+
min-height: 30px;
|
64
81
|
}
|
65
82
|
|
66
83
|
.toolbar-toolContainer.selected .toolbar-button {
|
67
|
-
|
68
|
-
|
84
|
+
background-color: var(--secondary-background-color);
|
85
|
+
color: var(--secondary-foreground-color);
|
69
86
|
}
|
70
87
|
|
71
|
-
.toolbar-toolContainer:not(.selected):not(.dropdownShowable) .toolbar-showHideDropdownIcon {
|
72
|
-
|
88
|
+
.toolbar-toolContainer:not(.selected):not(.dropdownShowable) > .toolbar-button > .toolbar-showHideDropdownIcon {
|
89
|
+
display: none;
|
73
90
|
}
|
74
91
|
|
75
|
-
.toolbar-toolContainer .toolbar-showHideDropdownIcon {
|
76
|
-
|
77
|
-
|
92
|
+
.toolbar-toolContainer > .toolbar-button > .toolbar-showHideDropdownIcon {
|
93
|
+
height: 10px;
|
94
|
+
transition: transform 0.5s ease;
|
78
95
|
}
|
79
96
|
|
80
|
-
.toolbar-toolContainer.dropdownVisible .toolbar-showHideDropdownIcon {
|
81
|
-
|
97
|
+
.toolbar-toolContainer.dropdownVisible > .toolbar-button > .toolbar-showHideDropdownIcon {
|
98
|
+
transform: rotate(180deg);
|
82
99
|
}
|
83
100
|
|
84
101
|
.toolbar-dropdown.hidden,
|
85
102
|
.toolbar-toolContainer:not(.selected):not(.dropdownShowable) > .toolbar-dropdown {
|
86
|
-
|
103
|
+
display: none;
|
87
104
|
}
|
88
105
|
|
89
106
|
.toolbar-dropdown {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
107
|
+
position: absolute;
|
108
|
+
padding: 15px;
|
109
|
+
padding-top: 5px;
|
110
|
+
|
111
|
+
/* Prevent overlap/being displayed under the undo/redo buttons */
|
112
|
+
z-index: 2;
|
113
|
+
background-color: var(--primary-background-color);
|
114
|
+
box-shadow: 0px 3px 3px var(--primary-shadow-color);
|
97
115
|
}
|
98
116
|
|
99
117
|
.toolbar-buttonGroup {
|
100
|
-
|
101
|
-
|
102
|
-
|
118
|
+
display: flex;
|
119
|
+
flex-direction: row;
|
120
|
+
justify-content: center;
|
103
121
|
}
|
104
122
|
|
105
123
|
.toolbar-closeColorPickerOverlay {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
124
|
+
display: none;
|
125
|
+
position: fixed;
|
126
|
+
top: 0;
|
127
|
+
left: 0;
|
128
|
+
bottom: 0;
|
129
|
+
right: 0;
|
112
130
|
|
113
|
-
|
114
|
-
|
131
|
+
background-color: var(--primary-background-color);
|
132
|
+
opacity: 0.3;
|
115
133
|
}
|
116
134
|
|
117
135
|
/* Make color selection buttons fill their containing label */
|
118
136
|
.toolbar-dropdown .clr-field button {
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
137
|
+
width: 100%;
|
138
|
+
height: 100%;
|
139
|
+
border-radius: 2px;
|
140
|
+
margin-left: 0;
|
141
|
+
margin-right: 0;
|
124
142
|
}
|
125
143
|
|
126
144
|
.toolbar-root .toolbar-zoomLevelEditor {
|
127
|
-
|
128
|
-
|
145
|
+
display: flex;
|
146
|
+
flex-direction: row;
|
129
147
|
}
|
130
148
|
|
131
149
|
.toolbar-root .toolbar-zoomLevelEditor .zoomDisplay {
|
132
|
-
|
150
|
+
flex-grow: 1;
|
133
151
|
}
|
134
152
|
|
135
153
|
.toolbar-root .toolbar-zoomLevelEditor button {
|
136
|
-
|
137
|
-
|
154
|
+
width: min-content;
|
155
|
+
height: min-content;
|
156
|
+
}
|
157
|
+
|
158
|
+
.color-input-container {
|
159
|
+
display: inline-flex;
|
160
|
+
flex-direction: row;
|
161
|
+
}
|
162
|
+
|
163
|
+
.color-input-container .pipetteButton {
|
164
|
+
width: 30px;
|
165
|
+
height: 30px;
|
166
|
+
padding: 0;
|
167
|
+
display: inline-flex;
|
168
|
+
}
|
169
|
+
|
170
|
+
.color-input-container .pipetteButton > svg {
|
171
|
+
width: 100%;
|
172
|
+
}
|
173
|
+
|
174
|
+
.color-input-container .pipetteButton.active {
|
175
|
+
background-color: var(--secondary-background-color);
|
138
176
|
}
|