@tsdraw/react 0.6.2 → 0.7.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.cjs +132 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -4
- package/dist/index.d.ts +27 -4
- package/dist/index.js +133 -77
- package/dist/index.js.map +1 -1
- package/dist/tsdraw.css +26 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
import { ColorStyle, DashStyle, FillStyle, SizeStyle, ToolId, Editor, ToolDefinition } from '@tsdraw/core';
|
|
4
|
+
|
|
5
|
+
type TsdrawStylePanelPartItem = 'colors' | 'dashes' | 'fills' | 'sizes' | (string & {});
|
|
6
|
+
interface TsdrawStylePanelRenderContext {
|
|
7
|
+
drawColor: ColorStyle;
|
|
8
|
+
drawDash: DashStyle;
|
|
9
|
+
drawFill: FillStyle;
|
|
10
|
+
drawSize: SizeStyle;
|
|
11
|
+
onColorSelect: (color: ColorStyle) => void;
|
|
12
|
+
onDashSelect: (dash: DashStyle) => void;
|
|
13
|
+
onFillSelect: (fill: FillStyle) => void;
|
|
14
|
+
onSizeSelect: (size: SizeStyle) => void;
|
|
15
|
+
}
|
|
16
|
+
interface TsdrawStylePanelCustomPart {
|
|
17
|
+
id: string;
|
|
18
|
+
render: (context: TsdrawStylePanelRenderContext) => ReactNode;
|
|
19
|
+
}
|
|
4
20
|
|
|
5
21
|
interface TsdrawCursorContext {
|
|
6
22
|
currentTool: ToolId;
|
|
@@ -32,6 +48,7 @@ interface TsdrawMountApi {
|
|
|
32
48
|
applyDrawStyle: (partial: Partial<{
|
|
33
49
|
color: ColorStyle;
|
|
34
50
|
dash: DashStyle;
|
|
51
|
+
fill: FillStyle;
|
|
35
52
|
size: SizeStyle;
|
|
36
53
|
}>) => void;
|
|
37
54
|
}
|
|
@@ -45,7 +62,10 @@ interface TsdrawCustomTool {
|
|
|
45
62
|
icon: ReactNode;
|
|
46
63
|
iconSelected?: ReactNode;
|
|
47
64
|
definition: ToolDefinition;
|
|
48
|
-
|
|
65
|
+
stylePanel?: {
|
|
66
|
+
parts?: TsdrawStylePanelPartItem[];
|
|
67
|
+
customParts?: TsdrawStylePanelCustomPart[];
|
|
68
|
+
};
|
|
49
69
|
}
|
|
50
70
|
type TsdrawToolbarBuiltInAction = 'undo' | 'redo';
|
|
51
71
|
type ToolbarPartItem = ToolId | TsdrawToolbarBuiltInAction;
|
|
@@ -57,10 +77,12 @@ interface TsdrawUiPlacement {
|
|
|
57
77
|
}
|
|
58
78
|
interface TsdrawUiOptions {
|
|
59
79
|
toolbar?: {
|
|
80
|
+
hide?: boolean;
|
|
60
81
|
placement?: TsdrawUiPlacement;
|
|
61
82
|
parts?: ToolbarPartItem[][];
|
|
62
83
|
};
|
|
63
84
|
stylePanel?: {
|
|
85
|
+
hide?: boolean;
|
|
64
86
|
placement?: TsdrawUiPlacement;
|
|
65
87
|
};
|
|
66
88
|
customElements?: TsdrawCustomElement[];
|
|
@@ -81,6 +103,7 @@ interface TsdrawCustomElementRenderArgs {
|
|
|
81
103
|
applyDrawStyle: (partial: Partial<{
|
|
82
104
|
color: ColorStyle;
|
|
83
105
|
dash: DashStyle;
|
|
106
|
+
fill: FillStyle;
|
|
84
107
|
size: SizeStyle;
|
|
85
108
|
}>) => void;
|
|
86
109
|
}
|
|
@@ -125,4 +148,4 @@ interface ToolbarPart {
|
|
|
125
148
|
}
|
|
126
149
|
declare function getDefaultToolbarIcon(toolId: ToolId, isActive: boolean): ReactNode;
|
|
127
150
|
|
|
128
|
-
export { type ToolbarActionItem, type ToolbarPart, type ToolbarPartItem, type ToolbarRenderItem, type ToolbarToolItem, Tsdraw, TsdrawCanvas, type TsdrawCanvasProps, type TsdrawCursorContext, type TsdrawCustomElement, type TsdrawCustomElementRenderArgs, type TsdrawCustomTool, type TsdrawMountApi, type TsdrawProps, type TsdrawToolOverlayState, type TsdrawToolbarBuiltInAction, type TsdrawUiOptions, type TsdrawUiPlacement, type UiAnchor, getDefaultToolbarIcon };
|
|
151
|
+
export { type ToolbarActionItem, type ToolbarPart, type ToolbarPartItem, type ToolbarRenderItem, type ToolbarToolItem, Tsdraw, TsdrawCanvas, type TsdrawCanvasProps, type TsdrawCursorContext, type TsdrawCustomElement, type TsdrawCustomElementRenderArgs, type TsdrawCustomTool, type TsdrawMountApi, type TsdrawProps, type TsdrawStylePanelCustomPart, type TsdrawStylePanelPartItem, type TsdrawStylePanelRenderContext, type TsdrawToolOverlayState, type TsdrawToolbarBuiltInAction, type TsdrawUiOptions, type TsdrawUiPlacement, type UiAnchor, getDefaultToolbarIcon };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
import { ColorStyle, DashStyle, FillStyle, SizeStyle, ToolId, Editor, ToolDefinition } from '@tsdraw/core';
|
|
4
|
+
|
|
5
|
+
type TsdrawStylePanelPartItem = 'colors' | 'dashes' | 'fills' | 'sizes' | (string & {});
|
|
6
|
+
interface TsdrawStylePanelRenderContext {
|
|
7
|
+
drawColor: ColorStyle;
|
|
8
|
+
drawDash: DashStyle;
|
|
9
|
+
drawFill: FillStyle;
|
|
10
|
+
drawSize: SizeStyle;
|
|
11
|
+
onColorSelect: (color: ColorStyle) => void;
|
|
12
|
+
onDashSelect: (dash: DashStyle) => void;
|
|
13
|
+
onFillSelect: (fill: FillStyle) => void;
|
|
14
|
+
onSizeSelect: (size: SizeStyle) => void;
|
|
15
|
+
}
|
|
16
|
+
interface TsdrawStylePanelCustomPart {
|
|
17
|
+
id: string;
|
|
18
|
+
render: (context: TsdrawStylePanelRenderContext) => ReactNode;
|
|
19
|
+
}
|
|
4
20
|
|
|
5
21
|
interface TsdrawCursorContext {
|
|
6
22
|
currentTool: ToolId;
|
|
@@ -32,6 +48,7 @@ interface TsdrawMountApi {
|
|
|
32
48
|
applyDrawStyle: (partial: Partial<{
|
|
33
49
|
color: ColorStyle;
|
|
34
50
|
dash: DashStyle;
|
|
51
|
+
fill: FillStyle;
|
|
35
52
|
size: SizeStyle;
|
|
36
53
|
}>) => void;
|
|
37
54
|
}
|
|
@@ -45,7 +62,10 @@ interface TsdrawCustomTool {
|
|
|
45
62
|
icon: ReactNode;
|
|
46
63
|
iconSelected?: ReactNode;
|
|
47
64
|
definition: ToolDefinition;
|
|
48
|
-
|
|
65
|
+
stylePanel?: {
|
|
66
|
+
parts?: TsdrawStylePanelPartItem[];
|
|
67
|
+
customParts?: TsdrawStylePanelCustomPart[];
|
|
68
|
+
};
|
|
49
69
|
}
|
|
50
70
|
type TsdrawToolbarBuiltInAction = 'undo' | 'redo';
|
|
51
71
|
type ToolbarPartItem = ToolId | TsdrawToolbarBuiltInAction;
|
|
@@ -57,10 +77,12 @@ interface TsdrawUiPlacement {
|
|
|
57
77
|
}
|
|
58
78
|
interface TsdrawUiOptions {
|
|
59
79
|
toolbar?: {
|
|
80
|
+
hide?: boolean;
|
|
60
81
|
placement?: TsdrawUiPlacement;
|
|
61
82
|
parts?: ToolbarPartItem[][];
|
|
62
83
|
};
|
|
63
84
|
stylePanel?: {
|
|
85
|
+
hide?: boolean;
|
|
64
86
|
placement?: TsdrawUiPlacement;
|
|
65
87
|
};
|
|
66
88
|
customElements?: TsdrawCustomElement[];
|
|
@@ -81,6 +103,7 @@ interface TsdrawCustomElementRenderArgs {
|
|
|
81
103
|
applyDrawStyle: (partial: Partial<{
|
|
82
104
|
color: ColorStyle;
|
|
83
105
|
dash: DashStyle;
|
|
106
|
+
fill: FillStyle;
|
|
84
107
|
size: SizeStyle;
|
|
85
108
|
}>) => void;
|
|
86
109
|
}
|
|
@@ -125,4 +148,4 @@ interface ToolbarPart {
|
|
|
125
148
|
}
|
|
126
149
|
declare function getDefaultToolbarIcon(toolId: ToolId, isActive: boolean): ReactNode;
|
|
127
150
|
|
|
128
|
-
export { type ToolbarActionItem, type ToolbarPart, type ToolbarPartItem, type ToolbarRenderItem, type ToolbarToolItem, Tsdraw, TsdrawCanvas, type TsdrawCanvasProps, type TsdrawCursorContext, type TsdrawCustomElement, type TsdrawCustomElementRenderArgs, type TsdrawCustomTool, type TsdrawMountApi, type TsdrawProps, type TsdrawToolOverlayState, type TsdrawToolbarBuiltInAction, type TsdrawUiOptions, type TsdrawUiPlacement, type UiAnchor, getDefaultToolbarIcon };
|
|
151
|
+
export { type ToolbarActionItem, type ToolbarPart, type ToolbarPartItem, type ToolbarRenderItem, type ToolbarToolItem, Tsdraw, TsdrawCanvas, type TsdrawCanvasProps, type TsdrawCursorContext, type TsdrawCustomElement, type TsdrawCustomElementRenderArgs, type TsdrawCustomTool, type TsdrawMountApi, type TsdrawProps, type TsdrawStylePanelCustomPart, type TsdrawStylePanelPartItem, type TsdrawStylePanelRenderContext, type TsdrawToolOverlayState, type TsdrawToolbarBuiltInAction, type TsdrawUiOptions, type TsdrawUiPlacement, type UiAnchor, getDefaultToolbarIcon };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useMemo, useEffect, useCallback, useRef } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { DEFAULT_COLORS, getSelectionBoundsPage, buildTransformSnapshots, Editor, STROKE_WIDTHS, ERASER_MARGIN, resolveThemeColor, getTopShapeAtPoint, buildStartPositions, applyRotation, applyResize, applyMove, normalizeSelectionBounds, getShapesInBounds, isSelectTool } from '@tsdraw/core';
|
|
4
|
-
import { IconPointer, IconPencil, IconEraser, IconHandStop, IconArrowBackUp, IconArrowForwardUp } from '@tabler/icons-react';
|
|
4
|
+
import { IconPointer, IconPencil, IconSquare, IconCircle, IconEraser, IconHandStop, IconArrowBackUp, IconArrowForwardUp } from '@tabler/icons-react';
|
|
5
5
|
|
|
6
6
|
// src/components/TsdrawCanvas.tsx
|
|
7
7
|
function SelectionOverlay({
|
|
@@ -98,66 +98,106 @@ function SelectionOverlay({
|
|
|
98
98
|
}
|
|
99
99
|
var STYLE_COLORS = Object.entries(DEFAULT_COLORS).filter(([key]) => key !== "white").map(([value]) => ({ value }));
|
|
100
100
|
var STYLE_DASHES = ["draw", "solid", "dashed", "dotted"];
|
|
101
|
+
var STYLE_FILLS = ["none", "blank", "semi", "solid"];
|
|
101
102
|
var STYLE_SIZES = ["s", "m", "l", "xl"];
|
|
102
103
|
function StylePanel({
|
|
103
104
|
visible,
|
|
105
|
+
parts,
|
|
106
|
+
customParts,
|
|
104
107
|
style,
|
|
105
108
|
theme,
|
|
106
109
|
drawColor,
|
|
107
110
|
drawDash,
|
|
111
|
+
drawFill,
|
|
108
112
|
drawSize,
|
|
109
113
|
onColorSelect,
|
|
110
114
|
onDashSelect,
|
|
115
|
+
onFillSelect,
|
|
111
116
|
onSizeSelect
|
|
112
117
|
}) {
|
|
113
|
-
if (!visible) return null;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
118
|
+
if (!visible || parts.length === 0) return null;
|
|
119
|
+
const context = {
|
|
120
|
+
drawColor,
|
|
121
|
+
drawDash,
|
|
122
|
+
drawFill,
|
|
123
|
+
drawSize,
|
|
124
|
+
onColorSelect,
|
|
125
|
+
onDashSelect,
|
|
126
|
+
onFillSelect,
|
|
127
|
+
onSizeSelect
|
|
128
|
+
};
|
|
129
|
+
const customPartMap = new Map((customParts ?? []).map((customPart) => [customPart.id, customPart]));
|
|
130
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-panel", style, "aria-label": "Draw style panel", children: parts.map((part) => {
|
|
131
|
+
if (part === "colors") {
|
|
132
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-colors", children: STYLE_COLORS.map((item) => /* @__PURE__ */ jsx(
|
|
133
|
+
"button",
|
|
134
|
+
{
|
|
135
|
+
type: "button",
|
|
136
|
+
className: "tsdraw-style-color",
|
|
137
|
+
"data-active": drawColor === item.value ? "true" : void 0,
|
|
138
|
+
"aria-label": `Color ${item.value}`,
|
|
139
|
+
title: item.value,
|
|
140
|
+
onClick: () => onColorSelect(item.value),
|
|
141
|
+
children: /* @__PURE__ */ jsx(
|
|
142
|
+
"span",
|
|
143
|
+
{
|
|
144
|
+
className: "tsdraw-style-color-dot",
|
|
145
|
+
style: { background: resolveThemeColor(item.value, theme) }
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
},
|
|
149
|
+
item.value
|
|
150
|
+
)) }, part);
|
|
151
|
+
}
|
|
152
|
+
if (part === "dashes") {
|
|
153
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-section", children: STYLE_DASHES.map((dash) => /* @__PURE__ */ jsx(
|
|
154
|
+
"button",
|
|
155
|
+
{
|
|
156
|
+
type: "button",
|
|
157
|
+
className: "tsdraw-style-row",
|
|
158
|
+
"data-active": drawDash === dash ? "true" : void 0,
|
|
159
|
+
"aria-label": `Stroke ${dash}`,
|
|
160
|
+
title: dash,
|
|
161
|
+
onClick: () => onDashSelect(dash),
|
|
162
|
+
children: /* @__PURE__ */ jsx("span", { className: "tsdraw-style-preview", children: /* @__PURE__ */ jsx("span", { className: `tsdraw-style-preview-line tsdraw-style-preview-line--${dash}` }) })
|
|
163
|
+
},
|
|
164
|
+
dash
|
|
165
|
+
)) }, part);
|
|
166
|
+
}
|
|
167
|
+
if (part === "fills") {
|
|
168
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-section", children: STYLE_FILLS.map((fill) => /* @__PURE__ */ jsx(
|
|
169
|
+
"button",
|
|
170
|
+
{
|
|
171
|
+
type: "button",
|
|
172
|
+
className: "tsdraw-style-row",
|
|
173
|
+
"data-active": drawFill === fill ? "true" : void 0,
|
|
174
|
+
"aria-label": `Fill ${fill}`,
|
|
175
|
+
title: fill,
|
|
176
|
+
onClick: () => onFillSelect(fill),
|
|
177
|
+
children: /* @__PURE__ */ jsx("span", { className: "tsdraw-style-preview", children: /* @__PURE__ */ jsx("span", { className: `tsdraw-style-fill tsdraw-style-fill--${fill}` }) })
|
|
178
|
+
},
|
|
179
|
+
fill
|
|
180
|
+
)) }, part);
|
|
181
|
+
}
|
|
182
|
+
if (part === "sizes") {
|
|
183
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-section", children: STYLE_SIZES.map((size) => /* @__PURE__ */ jsx(
|
|
184
|
+
"button",
|
|
185
|
+
{
|
|
186
|
+
type: "button",
|
|
187
|
+
className: "tsdraw-style-row",
|
|
188
|
+
"data-active": drawSize === size ? "true" : void 0,
|
|
189
|
+
"aria-label": `Thickness ${size}`,
|
|
190
|
+
title: size,
|
|
191
|
+
onClick: () => onSizeSelect(size),
|
|
192
|
+
children: /* @__PURE__ */ jsx("span", { className: "tsdraw-style-preview", children: /* @__PURE__ */ jsx("span", { className: `tsdraw-style-size tsdraw-style-size--${size}` }) })
|
|
193
|
+
},
|
|
194
|
+
size
|
|
195
|
+
)) }, part);
|
|
196
|
+
}
|
|
197
|
+
const customPart = customPartMap.get(part);
|
|
198
|
+
if (!customPart) return null;
|
|
199
|
+
return /* @__PURE__ */ jsx("div", { className: "tsdraw-style-section tsdraw-style-section--custom", children: customPart.render(context) }, part);
|
|
200
|
+
}) });
|
|
161
201
|
}
|
|
162
202
|
function ToolOverlay({
|
|
163
203
|
visible,
|
|
@@ -197,6 +237,8 @@ function ToolOverlay({
|
|
|
197
237
|
function getDefaultToolbarIcon(toolId, isActive) {
|
|
198
238
|
if (toolId === "select") return /* @__PURE__ */ jsx(IconPointer, { size: 16, stroke: 1.8, fill: isActive ? "currentColor" : "none" });
|
|
199
239
|
if (toolId === "pen") return /* @__PURE__ */ jsx(IconPencil, { size: 16, stroke: 1.8, fill: isActive ? "currentColor" : "none" });
|
|
240
|
+
if (toolId === "square") return /* @__PURE__ */ jsx(IconSquare, { size: 16, stroke: 1.8, fill: isActive ? "currentColor" : "none" });
|
|
241
|
+
if (toolId === "circle") return /* @__PURE__ */ jsx(IconCircle, { size: 16, stroke: 1.8, fill: isActive ? "currentColor" : "none" });
|
|
200
242
|
if (toolId === "eraser") return /* @__PURE__ */ jsx(IconEraser, { size: 16, stroke: 1.8, fill: isActive ? "currentColor" : "none" });
|
|
201
243
|
if (toolId === "hand") return /* @__PURE__ */ jsx(IconHandStop, { size: 16, stroke: isActive ? 1 : 1.8, fill: isActive ? "currentColor" : "none", style: isActive ? { stroke: "#000000" } : void 0 });
|
|
202
244
|
return null;
|
|
@@ -388,8 +430,6 @@ function resolveDrawColor(colorStyle, theme) {
|
|
|
388
430
|
return resolveThemeColor(colorStyle, theme);
|
|
389
431
|
}
|
|
390
432
|
function useTsdrawCanvasController(options = {}) {
|
|
391
|
-
const stylePanelToolIds = options.stylePanelToolIds ?? ["pen"];
|
|
392
|
-
const stylePanelToolIdsRef = useRef(stylePanelToolIds);
|
|
393
433
|
const onMountRef = useRef(options.onMount);
|
|
394
434
|
const containerRef = useRef(null);
|
|
395
435
|
const canvasRef = useRef(null);
|
|
@@ -424,6 +464,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
424
464
|
const [currentTool, setCurrentToolState] = useState(options.initialTool ?? "pen");
|
|
425
465
|
const [drawColor, setDrawColor] = useState("black");
|
|
426
466
|
const [drawDash, setDrawDash] = useState("draw");
|
|
467
|
+
const [drawFill, setDrawFill] = useState("none");
|
|
427
468
|
const [drawSize, setDrawSize] = useState("m");
|
|
428
469
|
const [selectedShapeIds, setSelectedShapeIds] = useState([]);
|
|
429
470
|
const [selectionBrush, setSelectionBrush] = useState(null);
|
|
@@ -440,9 +481,6 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
440
481
|
useEffect(() => {
|
|
441
482
|
currentToolRef.current = currentTool;
|
|
442
483
|
}, [currentTool]);
|
|
443
|
-
useEffect(() => {
|
|
444
|
-
stylePanelToolIdsRef.current = stylePanelToolIds;
|
|
445
|
-
}, [stylePanelToolIds]);
|
|
446
484
|
useEffect(() => {
|
|
447
485
|
onMountRef.current = options.onMount;
|
|
448
486
|
}, [options.onMount]);
|
|
@@ -454,7 +492,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
454
492
|
}, [selectionRotationDeg]);
|
|
455
493
|
useEffect(() => {
|
|
456
494
|
schedulePersistRef.current?.();
|
|
457
|
-
}, [selectedShapeIds, currentTool, drawColor, drawDash, drawSize]);
|
|
495
|
+
}, [selectedShapeIds, currentTool, drawColor, drawDash, drawFill, drawSize]);
|
|
458
496
|
const render = useCallback(() => {
|
|
459
497
|
const canvas = canvasRef.current;
|
|
460
498
|
const editor = editorRef.current;
|
|
@@ -590,6 +628,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
590
628
|
const initialStyle = editor.getCurrentDrawStyle();
|
|
591
629
|
setDrawColor(initialStyle.color);
|
|
592
630
|
setDrawDash(initialStyle.dash);
|
|
631
|
+
setDrawFill(initialStyle.fill);
|
|
593
632
|
setDrawSize(initialStyle.size);
|
|
594
633
|
const resize = () => {
|
|
595
634
|
const dpr = window.devicePixelRatio ?? 1;
|
|
@@ -671,6 +710,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
671
710
|
const nextDrawStyle = editor.getCurrentDrawStyle();
|
|
672
711
|
setDrawColor(nextDrawStyle.color);
|
|
673
712
|
setDrawDash(nextDrawStyle.dash);
|
|
713
|
+
setDrawFill(nextDrawStyle.fill);
|
|
674
714
|
setDrawSize(nextDrawStyle.size);
|
|
675
715
|
setSelectionRotationDeg(0);
|
|
676
716
|
render();
|
|
@@ -1049,6 +1089,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1049
1089
|
editor.setCurrentDrawStyle(partial);
|
|
1050
1090
|
if (partial.color) setDrawColor(partial.color);
|
|
1051
1091
|
if (partial.dash) setDrawDash(partial.dash);
|
|
1092
|
+
if (partial.fill) setDrawFill(partial.fill);
|
|
1052
1093
|
if (partial.size) setDrawSize(partial.size);
|
|
1053
1094
|
render();
|
|
1054
1095
|
}
|
|
@@ -1106,6 +1147,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1106
1147
|
editor.setCurrentDrawStyle(partial);
|
|
1107
1148
|
if (partial.color) setDrawColor(partial.color);
|
|
1108
1149
|
if (partial.dash) setDrawDash(partial.dash);
|
|
1150
|
+
if (partial.fill) setDrawFill(partial.fill);
|
|
1109
1151
|
if (partial.size) setDrawSize(partial.size);
|
|
1110
1152
|
render();
|
|
1111
1153
|
},
|
|
@@ -1173,6 +1215,7 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1173
1215
|
currentTool,
|
|
1174
1216
|
drawColor,
|
|
1175
1217
|
drawDash,
|
|
1218
|
+
drawFill,
|
|
1176
1219
|
drawSize,
|
|
1177
1220
|
selectedShapeIds,
|
|
1178
1221
|
selectionBrush,
|
|
@@ -1182,7 +1225,6 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1182
1225
|
cursorContext,
|
|
1183
1226
|
toolOverlay,
|
|
1184
1227
|
isPersistenceReady,
|
|
1185
|
-
showStylePanel: stylePanelToolIdsRef.current.includes(currentTool),
|
|
1186
1228
|
canUndo,
|
|
1187
1229
|
canRedo,
|
|
1188
1230
|
undo,
|
|
@@ -1193,12 +1235,21 @@ function useTsdrawCanvasController(options = {}) {
|
|
|
1193
1235
|
handleRotatePointerDown
|
|
1194
1236
|
};
|
|
1195
1237
|
}
|
|
1196
|
-
var DEFAULT_TOOLBAR_PARTS = [["undo", "redo"], ["select", "hand", "pen", "eraser"]];
|
|
1238
|
+
var DEFAULT_TOOLBAR_PARTS = [["undo", "redo"], ["select", "hand", "pen", "eraser", "square", "circle"]];
|
|
1197
1239
|
var EMPTY_CUSTOM_TOOLS = [];
|
|
1198
1240
|
var EMPTY_CUSTOM_ELEMENTS = [];
|
|
1241
|
+
var EMPTY_STYLE_PANEL_PARTS = [];
|
|
1242
|
+
var EMPTY_STYLE_PANEL_CUSTOM_PARTS = [];
|
|
1243
|
+
var DEFAULT_STYLE_PANEL_PARTS_BY_TOOL = {
|
|
1244
|
+
pen: ["colors", "dashes", "sizes"],
|
|
1245
|
+
square: ["colors", "dashes", "fills", "sizes"],
|
|
1246
|
+
circle: ["colors", "dashes", "fills", "sizes"]
|
|
1247
|
+
};
|
|
1199
1248
|
var DEFAULT_TOOL_LABELS = {
|
|
1200
1249
|
select: "Select",
|
|
1201
1250
|
pen: "Pen",
|
|
1251
|
+
square: "Rectangle",
|
|
1252
|
+
circle: "Ellipse",
|
|
1202
1253
|
eraser: "Eraser",
|
|
1203
1254
|
hand: "Hand"
|
|
1204
1255
|
};
|
|
@@ -1270,21 +1321,6 @@ function Tsdraw(props) {
|
|
|
1270
1321
|
() => customTools.filter((customTool) => toolbarToolIds.has(customTool.id)).map((customTool) => customTool.definition),
|
|
1271
1322
|
[customTools, toolbarToolIds]
|
|
1272
1323
|
);
|
|
1273
|
-
const stylePanelToolIds = useMemo(
|
|
1274
|
-
() => {
|
|
1275
|
-
const nextToolIds = /* @__PURE__ */ new Set();
|
|
1276
|
-
if (toolbarToolIds.has("pen")) {
|
|
1277
|
-
nextToolIds.add("pen");
|
|
1278
|
-
}
|
|
1279
|
-
for (const customTool of customTools) {
|
|
1280
|
-
if ((customTool.showStylePanel ?? false) && toolbarToolIds.has(customTool.id)) {
|
|
1281
|
-
nextToolIds.add(customTool.id);
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
return [...nextToolIds];
|
|
1285
|
-
},
|
|
1286
|
-
[customTools, toolbarToolIds]
|
|
1287
|
-
);
|
|
1288
1324
|
const firstToolbarTool = useMemo(() => {
|
|
1289
1325
|
for (const toolbarPart of toolbarPartIds) {
|
|
1290
1326
|
for (const item of toolbarPart) {
|
|
@@ -1313,6 +1349,7 @@ function Tsdraw(props) {
|
|
|
1313
1349
|
currentTool,
|
|
1314
1350
|
drawColor,
|
|
1315
1351
|
drawDash,
|
|
1352
|
+
drawFill,
|
|
1316
1353
|
drawSize,
|
|
1317
1354
|
selectedShapeIds,
|
|
1318
1355
|
selectionBrush,
|
|
@@ -1322,7 +1359,6 @@ function Tsdraw(props) {
|
|
|
1322
1359
|
cursorContext,
|
|
1323
1360
|
toolOverlay,
|
|
1324
1361
|
isPersistenceReady,
|
|
1325
|
-
showStylePanel,
|
|
1326
1362
|
canUndo,
|
|
1327
1363
|
canRedo,
|
|
1328
1364
|
undo,
|
|
@@ -1336,11 +1372,12 @@ function Tsdraw(props) {
|
|
|
1336
1372
|
initialTool,
|
|
1337
1373
|
theme: resolvedTheme,
|
|
1338
1374
|
persistenceKey: props.persistenceKey,
|
|
1339
|
-
stylePanelToolIds,
|
|
1340
1375
|
onMount: props.onMount
|
|
1341
1376
|
});
|
|
1342
1377
|
const toolbarPlacementStyle = resolvePlacementStyle(props.uiOptions?.toolbar?.placement, "bottom-center", 0, 14);
|
|
1343
1378
|
const stylePanelPlacementStyle = resolvePlacementStyle(props.uiOptions?.stylePanel?.placement, "top-right", 8, 8);
|
|
1379
|
+
const isToolbarHidden = props.uiOptions?.toolbar?.hide === true;
|
|
1380
|
+
const isStylePanelHidden = props.uiOptions?.stylePanel?.hide === true;
|
|
1344
1381
|
const canvasCursor = props.uiOptions?.cursor?.getCursor?.(cursorContext) ?? defaultCanvasCursor;
|
|
1345
1382
|
const defaultToolOverlay = /* @__PURE__ */ jsx(
|
|
1346
1383
|
ToolOverlay,
|
|
@@ -1362,9 +1399,24 @@ function Tsdraw(props) {
|
|
|
1362
1399
|
const onDashSelect = useCallback((dash) => {
|
|
1363
1400
|
applyDrawStyle({ dash });
|
|
1364
1401
|
}, [applyDrawStyle]);
|
|
1402
|
+
const onFillSelect = useCallback((fill) => {
|
|
1403
|
+
applyDrawStyle({ fill });
|
|
1404
|
+
}, [applyDrawStyle]);
|
|
1365
1405
|
const onSizeSelect = useCallback((size) => {
|
|
1366
1406
|
applyDrawStyle({ size });
|
|
1367
1407
|
}, [applyDrawStyle]);
|
|
1408
|
+
const activeCustomTool = customToolMap.get(currentTool);
|
|
1409
|
+
const stylePanelParts = useMemo(
|
|
1410
|
+
() => {
|
|
1411
|
+
const fromCustomTool = activeCustomTool?.stylePanel?.parts;
|
|
1412
|
+
if (fromCustomTool && fromCustomTool.length > 0) return fromCustomTool;
|
|
1413
|
+
if (activeCustomTool?.stylePanel?.customParts && activeCustomTool.stylePanel.customParts.length > 0) return activeCustomTool.stylePanel.customParts.map((customPart) => customPart.id);
|
|
1414
|
+
if (currentTool in DEFAULT_STYLE_PANEL_PARTS_BY_TOOL) return DEFAULT_STYLE_PANEL_PARTS_BY_TOOL[currentTool] ?? EMPTY_STYLE_PANEL_PARTS;
|
|
1415
|
+
return EMPTY_STYLE_PANEL_PARTS;
|
|
1416
|
+
},
|
|
1417
|
+
[activeCustomTool, currentTool]
|
|
1418
|
+
);
|
|
1419
|
+
const stylePanelCustomParts = activeCustomTool?.stylePanel?.customParts ?? EMPTY_STYLE_PANEL_CUSTOM_PARTS;
|
|
1368
1420
|
const toolbarParts = useMemo(
|
|
1369
1421
|
() => toolbarPartIds.map((toolbarPart, partIndex) => {
|
|
1370
1422
|
const items = toolbarPart.map((item) => {
|
|
@@ -1453,14 +1505,18 @@ function Tsdraw(props) {
|
|
|
1453
1505
|
/* @__PURE__ */ jsx(
|
|
1454
1506
|
StylePanel,
|
|
1455
1507
|
{
|
|
1456
|
-
visible: isPersistenceReady &&
|
|
1508
|
+
visible: !isStylePanelHidden && isPersistenceReady && stylePanelParts.length > 0,
|
|
1509
|
+
parts: stylePanelParts,
|
|
1510
|
+
customParts: stylePanelCustomParts,
|
|
1457
1511
|
style: stylePanelPlacementStyle,
|
|
1458
1512
|
theme: resolvedTheme,
|
|
1459
1513
|
drawColor,
|
|
1460
1514
|
drawDash,
|
|
1515
|
+
drawFill,
|
|
1461
1516
|
drawSize,
|
|
1462
1517
|
onColorSelect,
|
|
1463
1518
|
onDashSelect,
|
|
1519
|
+
onFillSelect,
|
|
1464
1520
|
onSizeSelect
|
|
1465
1521
|
}
|
|
1466
1522
|
),
|
|
@@ -1477,7 +1533,7 @@ function Tsdraw(props) {
|
|
|
1477
1533
|
},
|
|
1478
1534
|
customElement.id
|
|
1479
1535
|
)),
|
|
1480
|
-
/* @__PURE__ */ jsx(
|
|
1536
|
+
!isToolbarHidden ? /* @__PURE__ */ jsx(
|
|
1481
1537
|
Toolbar,
|
|
1482
1538
|
{
|
|
1483
1539
|
parts: toolbarParts,
|
|
@@ -1486,7 +1542,7 @@ function Tsdraw(props) {
|
|
|
1486
1542
|
onToolChange: setTool,
|
|
1487
1543
|
disabled: !isPersistenceReady
|
|
1488
1544
|
}
|
|
1489
|
-
)
|
|
1545
|
+
) : null
|
|
1490
1546
|
]
|
|
1491
1547
|
}
|
|
1492
1548
|
);
|