@pixerate/editor-react 0.29.0 → 0.31.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/vector/index.cjs +340 -155
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +25 -3
- package/dist/vector/index.d.ts +25 -3
- package/dist/vector/index.js +325 -137
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(vector_exports, {
|
|
|
26
26
|
VectorSceneNodes: () => VectorSceneNodes,
|
|
27
27
|
VectorStylePanel: () => VectorStylePanel,
|
|
28
28
|
VectorToolbar: () => VectorToolbar,
|
|
29
|
+
VectorWidthPointEditor: () => VectorWidthPointEditor,
|
|
29
30
|
useVectorCommands: () => useVectorCommands,
|
|
30
31
|
useVectorEditor: () => useVectorEditor,
|
|
31
32
|
useVectorEditorController: () => useVectorEditorController,
|
|
@@ -76,19 +77,104 @@ function useVectorCommands(registry, controller, options = {}) {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
// src/vector/VectorCanvas.tsx
|
|
80
|
+
var import_react3 = require("react");
|
|
81
|
+
var import_vector3 = require("@pixerate/editor/vector");
|
|
82
|
+
|
|
83
|
+
// src/vector/VectorWidthPointEditor.tsx
|
|
79
84
|
var import_react2 = require("react");
|
|
80
85
|
var import_vector2 = require("@pixerate/editor/vector");
|
|
81
86
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
87
|
+
var round = (v, digits) => String(Math.round(v * 10 ** digits) / 10 ** digits);
|
|
88
|
+
var fieldStyle = { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 6 };
|
|
89
|
+
var inputStyle = { width: 72, font: "inherit", padding: "1px 4px" };
|
|
90
|
+
function VectorWidthPointEditor({ controller, edit, accentColor = import_vector2.VECTOR_OVERLAY_THEME.accent, className, style }) {
|
|
91
|
+
const [position, setPosition] = (0, import_react2.useState)(() => round(edit.t * 100, 2));
|
|
92
|
+
const [left, setLeft] = (0, import_react2.useState)(() => round(edit.left, 3));
|
|
93
|
+
const [right, setRight] = (0, import_react2.useState)(() => round(edit.right, 3));
|
|
94
|
+
const formRef = (0, import_react2.useRef)(null);
|
|
95
|
+
const refocus = () => formRef.current?.closest("svg")?.focus?.({ preventScroll: true });
|
|
96
|
+
const close = () => {
|
|
97
|
+
refocus();
|
|
98
|
+
controller.closeWidthPointEdit();
|
|
99
|
+
};
|
|
100
|
+
const num = (v) => v.trim() !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
101
|
+
const apply = () => {
|
|
102
|
+
const t = num(position);
|
|
103
|
+
refocus();
|
|
104
|
+
controller.commitWidthPointEdit({ t: t === void 0 ? void 0 : Math.min(Math.max(t, 0), 100) / 100, left: num(left), right: num(right) });
|
|
105
|
+
};
|
|
106
|
+
const stop = (e) => e.stopPropagation();
|
|
107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
108
|
+
"form",
|
|
109
|
+
{
|
|
110
|
+
ref: formRef,
|
|
111
|
+
"data-vector-width-point-editor": "",
|
|
112
|
+
"aria-label": "Width point",
|
|
113
|
+
className,
|
|
114
|
+
style: {
|
|
115
|
+
display: "grid",
|
|
116
|
+
gap: 4,
|
|
117
|
+
padding: 8,
|
|
118
|
+
background: "#ffffff",
|
|
119
|
+
border: "1px solid rgba(0,0,0,0.15)",
|
|
120
|
+
borderRadius: 6,
|
|
121
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
|
|
122
|
+
font: "12px system-ui, sans-serif",
|
|
123
|
+
color: "#18181b",
|
|
124
|
+
...style
|
|
125
|
+
},
|
|
126
|
+
onPointerDown: stop,
|
|
127
|
+
onPointerMove: stop,
|
|
128
|
+
onPointerUp: stop,
|
|
129
|
+
onDoubleClick: stop,
|
|
130
|
+
onCopy: stop,
|
|
131
|
+
onCut: stop,
|
|
132
|
+
onPaste: stop,
|
|
133
|
+
onKeyDown: (e) => {
|
|
134
|
+
e.stopPropagation();
|
|
135
|
+
if (e.key === "Escape") {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
close();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
onSubmit: (e) => {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
apply();
|
|
143
|
+
},
|
|
144
|
+
children: [
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: fieldStyle, children: [
|
|
146
|
+
"Position %",
|
|
147
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": "Width point position", type: "number", min: 0, max: 100, step: "any", value: position, onChange: (e) => setPosition(e.target.value), style: inputStyle, autoFocus: true })
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: fieldStyle, children: [
|
|
150
|
+
"Left",
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": "Width point left side", type: "number", min: 0, step: "any", value: left, onChange: (e) => setLeft(e.target.value), style: inputStyle })
|
|
152
|
+
] }),
|
|
153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: fieldStyle, children: [
|
|
154
|
+
"Right",
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": "Width point right side", type: "number", min: 0, step: "any", value: right, onChange: (e) => setRight(e.target.value), style: inputStyle })
|
|
156
|
+
] }),
|
|
157
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 4, marginTop: 2 }, children: [
|
|
158
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: close, children: "Cancel" }),
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", style: { background: accentColor, color: "#ffffff", border: "none", borderRadius: 4, padding: "2px 8px" }, children: edit.index === null ? "Add" : "Apply" })
|
|
160
|
+
] })
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/vector/VectorCanvas.tsx
|
|
167
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
82
168
|
function VectorGradientDefs({ defs }) {
|
|
83
169
|
if (!defs.length) return null;
|
|
84
|
-
return /* @__PURE__ */ (0,
|
|
85
|
-
const stops = def.stops.map((s, i) => /* @__PURE__ */ (0,
|
|
86
|
-
return def.type === "radial" ? /* @__PURE__ */ (0,
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: defs.map((def) => {
|
|
171
|
+
const stops = def.stops.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: s.offset, stopColor: s.stopColor, stopOpacity: s.stopOpacity }, i));
|
|
172
|
+
return def.type === "radial" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("radialGradient", { id: def.id, ...def.attrs, children: stops }, def.id) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("linearGradient", { id: def.id, ...def.attrs, children: stops }, def.id);
|
|
87
173
|
}) });
|
|
88
174
|
}
|
|
89
175
|
function VectorSceneNodes({ nodes }) {
|
|
90
|
-
return /* @__PURE__ */ (0,
|
|
91
|
-
(node) => node.kind === "group" ? /* @__PURE__ */ (0,
|
|
176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map(
|
|
177
|
+
(node) => node.kind === "group" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-id": node.id, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: node.children }) }, node.id) : node.strokeParts ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorPartedPath, { node }, node.id) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
92
178
|
"path",
|
|
93
179
|
{
|
|
94
180
|
"data-vector-id": node.id,
|
|
@@ -111,15 +197,15 @@ function VectorPartedPath({ node }) {
|
|
|
111
197
|
const sp = node.strokeParts;
|
|
112
198
|
const clip = sp.clip;
|
|
113
199
|
const b = clip?.bounds;
|
|
114
|
-
return /* @__PURE__ */ (0,
|
|
115
|
-
clip && b && /* @__PURE__ */ (0,
|
|
116
|
-
/* @__PURE__ */ (0,
|
|
117
|
-
/* @__PURE__ */ (0,
|
|
200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-id": node.id, "data-vector-stroke-align": sp.align, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, children: [
|
|
201
|
+
clip && b && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: clip.kind === "clip" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("clipPath", { id: clip.id, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: node.d, clipRule: node.fillRule }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("mask", { id: clip.id, maskUnits: "userSpaceOnUse", x: b.x, y: b.y, width: b.width, height: b.height, children: [
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: b.x, y: b.y, width: b.width, height: b.height, fill: "#fff" }),
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: node.d, fill: "#000", fillRule: node.fillRule })
|
|
118
204
|
] }) }),
|
|
119
|
-
/* @__PURE__ */ (0,
|
|
205
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-part": "fill", d: node.d, fill: node.fill, fillRule: node.fillRule, stroke: "none" }),
|
|
120
206
|
sp.outline !== void 0 ? (
|
|
121
207
|
// A variable-width stroke: its outline, filled.
|
|
122
|
-
/* @__PURE__ */ (0,
|
|
208
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
123
209
|
"path",
|
|
124
210
|
{
|
|
125
211
|
"data-vector-part": "stroke-outline",
|
|
@@ -129,7 +215,7 @@ function VectorPartedPath({ node }) {
|
|
|
129
215
|
mask: clip?.kind === "mask" ? `url(#${clip.id})` : void 0
|
|
130
216
|
}
|
|
131
217
|
)
|
|
132
|
-
) : /* @__PURE__ */ (0,
|
|
218
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
133
219
|
"path",
|
|
134
220
|
{
|
|
135
221
|
"data-vector-part": "stroke",
|
|
@@ -144,26 +230,26 @@ function VectorPartedPath({ node }) {
|
|
|
144
230
|
mask: clip?.kind === "mask" ? `url(#${clip.id})` : void 0
|
|
145
231
|
}
|
|
146
232
|
),
|
|
147
|
-
sp.heads.map((head, i) => /* @__PURE__ */ (0,
|
|
233
|
+
sp.heads.map((head, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-part": "head", d: head, fill: node.stroke }, i))
|
|
148
234
|
] });
|
|
149
235
|
}
|
|
150
236
|
function VectorCanvas({
|
|
151
237
|
controller,
|
|
152
238
|
fitOnMount = true,
|
|
153
239
|
checkerboard = true,
|
|
154
|
-
accentColor =
|
|
155
|
-
guideColor =
|
|
240
|
+
accentColor = import_vector3.VECTOR_OVERLAY_THEME.accent,
|
|
241
|
+
guideColor = import_vector3.VECTOR_OVERLAY_THEME.guide,
|
|
156
242
|
className,
|
|
157
243
|
style,
|
|
158
244
|
"aria-label": ariaLabel = "Vector canvas"
|
|
159
245
|
}) {
|
|
160
246
|
const state = useVectorEditorState(controller);
|
|
161
|
-
const svgRef = (0,
|
|
162
|
-
const fitted = (0,
|
|
163
|
-
const uid = (0,
|
|
164
|
-
const scene = (0,
|
|
165
|
-
const overlay = (0,
|
|
166
|
-
(0,
|
|
247
|
+
const svgRef = (0, import_react3.useRef)(null);
|
|
248
|
+
const fitted = (0, import_react3.useRef)(!fitOnMount);
|
|
249
|
+
const uid = (0, import_react3.useId)().replace(/:/g, "");
|
|
250
|
+
const scene = (0, import_vector3.getVectorSceneRenderData)(state, { idPrefix: `ve${uid}-` });
|
|
251
|
+
const overlay = (0, import_vector3.getVectorOverlayRenderData)(state);
|
|
252
|
+
(0, import_react3.useEffect)(() => {
|
|
167
253
|
const el = svgRef.current;
|
|
168
254
|
if (!el || fitted.current) return;
|
|
169
255
|
const fit = () => {
|
|
@@ -178,12 +264,12 @@ function VectorCanvas({
|
|
|
178
264
|
observer.observe(el);
|
|
179
265
|
return () => observer.disconnect();
|
|
180
266
|
}, [controller]);
|
|
181
|
-
(0,
|
|
267
|
+
(0, import_react3.useEffect)(() => {
|
|
182
268
|
const el = svgRef.current;
|
|
183
269
|
if (!el) return;
|
|
184
270
|
const onWheel = (e) => {
|
|
185
271
|
e.preventDefault();
|
|
186
|
-
controller.wheel(local(e), { x: e.deltaX, y: e.deltaY }, (0,
|
|
272
|
+
controller.wheel(local(e), { x: e.deltaX, y: e.deltaY }, (0, import_vector3.toVectorPointerInput)(e));
|
|
187
273
|
};
|
|
188
274
|
el.addEventListener("wheel", onWheel, { passive: false });
|
|
189
275
|
return () => el.removeEventListener("wheel", onWheel);
|
|
@@ -207,10 +293,12 @@ function VectorCanvas({
|
|
|
207
293
|
event.preventDefault?.();
|
|
208
294
|
}
|
|
209
295
|
};
|
|
210
|
-
const hs =
|
|
211
|
-
const as =
|
|
296
|
+
const hs = import_vector3.VECTOR_OVERLAY_THEME.transformHandleSize;
|
|
297
|
+
const as = import_vector3.VECTOR_OVERLAY_THEME.anchorSize;
|
|
212
298
|
const box = overlay.selectionBox;
|
|
213
|
-
|
|
299
|
+
const edit = state.widthPointEdit;
|
|
300
|
+
const editAt = edit && { x: edit.point.x * state.viewport.zoom + state.viewport.x, y: edit.point.y * state.viewport.zoom + state.viewport.y };
|
|
301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
214
302
|
"svg",
|
|
215
303
|
{
|
|
216
304
|
ref: svgRef,
|
|
@@ -223,32 +311,32 @@ function VectorCanvas({
|
|
|
223
311
|
onPointerDown: (e) => {
|
|
224
312
|
svgRef.current?.focus({ preventScroll: true });
|
|
225
313
|
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
226
|
-
controller.pointerDown(local(e), (0,
|
|
314
|
+
controller.pointerDown(local(e), (0, import_vector3.toVectorPointerInput)(e));
|
|
227
315
|
},
|
|
228
|
-
onPointerMove: (e) => controller.pointerMove(local(e), (0,
|
|
316
|
+
onPointerMove: (e) => controller.pointerMove(local(e), (0, import_vector3.toVectorPointerInput)(e)),
|
|
229
317
|
onPointerUp: (e) => {
|
|
230
318
|
e.currentTarget.releasePointerCapture?.(e.pointerId);
|
|
231
|
-
controller.pointerUp(local(e), (0,
|
|
319
|
+
controller.pointerUp(local(e), (0, import_vector3.toVectorPointerInput)(e));
|
|
232
320
|
},
|
|
233
321
|
onPointerCancel: () => controller.cancelDrag(),
|
|
234
322
|
onPointerLeave: () => controller.pointerLeave(),
|
|
235
323
|
onDoubleClick: (e) => controller.doubleClick(local(e)),
|
|
236
324
|
onKeyDown: (e) => {
|
|
237
|
-
if ((0,
|
|
238
|
-
if (controller.keyDown((0,
|
|
325
|
+
if ((0, import_vector3.isVectorTextTarget)(e.target)) return;
|
|
326
|
+
if (controller.keyDown((0, import_vector3.toVectorKeyInput)(e))) e.preventDefault();
|
|
239
327
|
},
|
|
240
|
-
onKeyUp: (e) => controller.keyUp((0,
|
|
328
|
+
onKeyUp: (e) => controller.keyUp((0, import_vector3.toVectorKeyInput)(e)),
|
|
241
329
|
onCopy: clipboard("copy"),
|
|
242
330
|
onCut: clipboard("cut"),
|
|
243
331
|
onPaste: clipboard("paste"),
|
|
244
332
|
children: [
|
|
245
|
-
checkerboard && /* @__PURE__ */ (0,
|
|
246
|
-
/* @__PURE__ */ (0,
|
|
247
|
-
/* @__PURE__ */ (0,
|
|
248
|
-
/* @__PURE__ */ (0,
|
|
333
|
+
checkerboard && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("pattern", { id: `ve${uid}-checker`, width: 16, height: 16, patternUnits: "userSpaceOnUse", children: [
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { width: 16, height: 16, fill: "#ffffff" }),
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { width: 8, height: 8, fill: "#e5e7eb" }),
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: 8, y: 8, width: 8, height: 8, fill: "#e5e7eb" })
|
|
249
337
|
] }) }),
|
|
250
|
-
/* @__PURE__ */ (0,
|
|
251
|
-
/* @__PURE__ */ (0,
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorGradientDefs, { defs: scene.defs }),
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
252
340
|
"rect",
|
|
253
341
|
{
|
|
254
342
|
"data-vector-artboard": "",
|
|
@@ -260,84 +348,105 @@ function VectorCanvas({
|
|
|
260
348
|
stroke: "rgba(0,0,0,0.12)"
|
|
261
349
|
}
|
|
262
350
|
),
|
|
263
|
-
/* @__PURE__ */ (0,
|
|
264
|
-
/* @__PURE__ */ (0,
|
|
265
|
-
overlay.outlines.map((o) => /* @__PURE__ */ (0,
|
|
266
|
-
overlay.penPreview && /* @__PURE__ */ (0,
|
|
267
|
-
box && /* @__PURE__ */ (0,
|
|
268
|
-
/* @__PURE__ */ (0,
|
|
269
|
-
/* @__PURE__ */ (0,
|
|
351
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-scene": "", transform: scene.transform, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: scene.nodes }) }),
|
|
352
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-overlay": "", pointerEvents: "none", fill: "none", children: [
|
|
353
|
+
overlay.outlines.map((o) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: o.d, stroke: accentColor, strokeWidth: o.selected ? 1 : 1.5, opacity: o.selected ? 1 : 0.7 }, o.id)),
|
|
354
|
+
overlay.penPreview && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: overlay.penPreview, stroke: accentColor, strokeDasharray: "4 3" }),
|
|
355
|
+
box && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-selection": "", transform: box.transform || void 0, children: [
|
|
356
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: box.x, y: box.y, width: box.width, height: box.height, stroke: accentColor }),
|
|
357
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: box.x + box.width / 2, y1: box.y, x2: box.x + box.width / 2, y2: box.y - 24, stroke: accentColor }),
|
|
270
358
|
box.handles.map(
|
|
271
|
-
(h) => h.handle === "rotate" ? /* @__PURE__ */ (0,
|
|
359
|
+
(h) => h.handle === "rotate" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-handle": h.handle, cx: h.x, cy: h.y, r: hs / 2 + 1, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, h.handle) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { "data-handle": h.handle, x: h.x - hs / 2, y: h.y - hs / 2, width: hs, height: hs, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, h.handle)
|
|
272
360
|
)
|
|
273
361
|
] }),
|
|
274
|
-
overlay.handles.map((h) => /* @__PURE__ */ (0,
|
|
275
|
-
/* @__PURE__ */ (0,
|
|
276
|
-
/* @__PURE__ */ (0,
|
|
362
|
+
overlay.handles.map((h) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-handle": h.ref.handle, children: [
|
|
363
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: h.anchorX, y1: h.anchorY, x2: h.x, y2: h.y, stroke: accentColor }),
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: h.x, cy: h.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + (h.hovered ? 1 : 0), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor })
|
|
277
365
|
] }, `${h.ref.nodeId}:${h.ref.subpath}:${h.ref.index}:${h.ref.handle}`)),
|
|
278
366
|
overlay.anchors.map((a) => {
|
|
279
367
|
const size = as + (a.hovered ? 2 : 0);
|
|
280
|
-
const fill = a.selected ? accentColor :
|
|
368
|
+
const fill = a.selected ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill;
|
|
281
369
|
const key = `${a.ref.nodeId}:${a.ref.subpath}:${a.ref.index}`;
|
|
282
|
-
return a.type === "corner" ? /* @__PURE__ */ (0,
|
|
370
|
+
return a.type === "corner" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { "data-vector-anchor": a.ref.index, x: a.x - size / 2, y: a.y - size / 2, width: size, height: size, fill, stroke: accentColor }, key) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-anchor": a.ref.index, cx: a.x, cy: a.y, r: size / 2, fill, stroke: accentColor }, key);
|
|
283
371
|
}),
|
|
284
|
-
overlay.cornerWidgets.map((w) => /* @__PURE__ */ (0,
|
|
285
|
-
/* @__PURE__ */ (0,
|
|
286
|
-
/* @__PURE__ */ (0,
|
|
372
|
+
overlay.cornerWidgets.map((w) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-corner-widget": w.ref.index, "data-corner-kind": w.kind, children: [
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: w.x, cy: w.y, r: import_vector3.VECTOR_OVERLAY_THEME.cornerWidgetRadius + (w.hovered ? 1 : 0), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: w.x, cy: w.y, r: 1.5, fill: accentColor })
|
|
287
375
|
] }, `corner:${w.ref.nodeId}:${w.ref.subpath}:${w.ref.index}`)),
|
|
288
|
-
overlay.
|
|
289
|
-
/* @__PURE__ */ (0,
|
|
290
|
-
/* @__PURE__ */ (0,
|
|
376
|
+
overlay.blend.spines.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-blend-spine": sp.id, "data-replaced": sp.replaced || void 0, children: [
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: sp.d, fill: "none", stroke: accentColor, strokeDasharray: "4 3" }),
|
|
378
|
+
sp.keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: k.x, cy: k.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, i))
|
|
379
|
+
] }, `blend:${sp.id}`)),
|
|
380
|
+
overlay.blend.start && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-blend-start": "", children: [
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: overlay.blend.start.d, fill: "none", stroke: accentColor, strokeWidth: 2 }),
|
|
382
|
+
overlay.blend.start.anchor && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: overlay.blend.start.anchor.x, cy: overlay.blend.start.anchor.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + 1, fill: accentColor })
|
|
383
|
+
] }),
|
|
384
|
+
overlay.blend.anchors.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
385
|
+
"rect",
|
|
386
|
+
{
|
|
387
|
+
"data-vector-blend-anchor": i,
|
|
388
|
+
x: a.x - as / 2,
|
|
389
|
+
y: a.y - as / 2,
|
|
390
|
+
width: as,
|
|
391
|
+
height: as,
|
|
392
|
+
fill: a.hovered ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill,
|
|
393
|
+
stroke: accentColor
|
|
394
|
+
},
|
|
395
|
+
`blend-anchor:${i}`
|
|
396
|
+
)),
|
|
397
|
+
overlay.widthSpot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-width-spot": "", children: [
|
|
398
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: overlay.widthSpot.left.x, y1: overlay.widthSpot.left.y, x2: overlay.widthSpot.right.x, y2: overlay.widthSpot.right.y, stroke: accentColor, strokeDasharray: "3 2" }),
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: (0, import_vector3.vectorDiamondPath)(overlay.widthSpot.x, overlay.widthSpot.y), fill: "none", stroke: accentColor })
|
|
291
400
|
] }),
|
|
292
|
-
overlay.widthPoints.map((w) => /* @__PURE__ */ (0,
|
|
293
|
-
/* @__PURE__ */ (0,
|
|
294
|
-
/* @__PURE__ */ (0,
|
|
295
|
-
["left", "right"].map((side) => /* @__PURE__ */ (0,
|
|
401
|
+
overlay.widthPoints.map((w) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-width-point": w.ref.index, "data-selected": w.selected || void 0, children: [
|
|
402
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: w.left.x, y1: w.left.y, x2: w.right.x, y2: w.right.y, stroke: accentColor }),
|
|
403
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: (0, import_vector3.vectorDiamondPath)(w.x, w.y), fill: w.selected || w.active ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor, strokeWidth: w.hovered === "center" ? 2 : 1 }),
|
|
404
|
+
["left", "right"].map((side) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-width-side": side, cx: w[side].x, cy: w[side].y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + (w.hovered === side ? 1 : 0), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, side))
|
|
296
405
|
] }, `width:${w.ref.nodeId}:${w.ref.subpath}:${w.ref.index}`)),
|
|
297
|
-
state.tool === "pen" && overlay.anchors.some((a) => a.closes && a.hovered) && /* @__PURE__ */ (0,
|
|
298
|
-
overlay.builder && /* @__PURE__ */ (0,
|
|
299
|
-
overlay.builder.faces.map((d, i) => /* @__PURE__ */ (0,
|
|
406
|
+
state.tool === "pen" && overlay.anchors.some((a) => a.closes && a.hovered) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: overlay.anchors.find((a) => a.closes).x, cy: overlay.anchors.find((a) => a.closes).y, r: as, stroke: accentColor }),
|
|
407
|
+
overlay.builder && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-builder": overlay.builder.mode, children: [
|
|
408
|
+
overlay.builder.faces.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
300
409
|
"path",
|
|
301
410
|
{
|
|
302
411
|
"data-vector-builder-face": "",
|
|
303
412
|
d,
|
|
304
|
-
fill: overlay.builder.mode === "erase" ?
|
|
413
|
+
fill: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderEraseFill : import_vector3.VECTOR_OVERLAY_THEME.builderFill,
|
|
305
414
|
fillRule: "nonzero",
|
|
306
|
-
stroke: overlay.builder.mode === "erase" ?
|
|
415
|
+
stroke: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderErase : accentColor,
|
|
307
416
|
strokeWidth: 1
|
|
308
417
|
},
|
|
309
418
|
`f${i}`
|
|
310
419
|
)),
|
|
311
420
|
overlay.builder.hatches.map(
|
|
312
|
-
(d, i) => d ? /* @__PURE__ */ (0,
|
|
421
|
+
(d, i) => d ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
313
422
|
"path",
|
|
314
423
|
{
|
|
315
424
|
"data-vector-builder-hatch": "",
|
|
316
425
|
d,
|
|
317
426
|
fill: "none",
|
|
318
|
-
stroke: overlay.builder.mode === "erase" ?
|
|
319
|
-
strokeOpacity:
|
|
427
|
+
stroke: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderErase : accentColor,
|
|
428
|
+
strokeOpacity: import_vector3.VECTOR_OVERLAY_THEME.builderHatchOpacity,
|
|
320
429
|
strokeWidth: 1
|
|
321
430
|
},
|
|
322
431
|
`h${i}`
|
|
323
432
|
) : null
|
|
324
433
|
),
|
|
325
|
-
overlay.builder.lines.map((d, i) => /* @__PURE__ */ (0,
|
|
326
|
-
overlay.builder.trail && /* @__PURE__ */ (0,
|
|
434
|
+
overlay.builder.lines.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-line": "", d, fill: "none", stroke: import_vector3.VECTOR_OVERLAY_THEME.builderErase, strokeWidth: 3, strokeLinecap: "round" }, `l${i}`)),
|
|
435
|
+
overlay.builder.trail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-trail": "", d: overlay.builder.trail, fill: "none", stroke: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderErase : accentColor, strokeWidth: 1 })
|
|
327
436
|
] }),
|
|
328
|
-
overlay.toolStroke && /* @__PURE__ */ (0,
|
|
437
|
+
overlay.toolStroke && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
329
438
|
"path",
|
|
330
439
|
{
|
|
331
440
|
"data-vector-tool-stroke": overlay.toolStroke.tool,
|
|
332
441
|
d: overlay.toolStroke.d,
|
|
333
|
-
stroke: overlay.toolStroke.tool === "eraser" ?
|
|
442
|
+
stroke: overlay.toolStroke.tool === "eraser" ? import_vector3.VECTOR_OVERLAY_THEME.eraserFill : accentColor,
|
|
334
443
|
strokeWidth: overlay.toolStroke.tool === "eraser" ? overlay.toolStroke.width : 1,
|
|
335
444
|
strokeLinecap: "round",
|
|
336
445
|
strokeLinejoin: "round",
|
|
337
446
|
strokeDasharray: overlay.toolStroke.tool === "knife" ? "5 3" : void 0
|
|
338
447
|
}
|
|
339
448
|
),
|
|
340
|
-
overlay.pencilString && /* @__PURE__ */ (0,
|
|
449
|
+
overlay.pencilString && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
341
450
|
"line",
|
|
342
451
|
{
|
|
343
452
|
"data-vector-pencil-string": "",
|
|
@@ -349,8 +458,8 @@ function VectorCanvas({
|
|
|
349
458
|
strokeDasharray: "2 2"
|
|
350
459
|
}
|
|
351
460
|
),
|
|
352
|
-
overlay.cutPoint && /* @__PURE__ */ (0,
|
|
353
|
-
overlay.marquee && /* @__PURE__ */ (0,
|
|
461
|
+
overlay.cutPoint && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-cut-point": "", cx: overlay.cutPoint.x, cy: overlay.cutPoint.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + 1, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
462
|
+
overlay.marquee && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
354
463
|
"rect",
|
|
355
464
|
{
|
|
356
465
|
"data-vector-marquee": "",
|
|
@@ -358,13 +467,13 @@ function VectorCanvas({
|
|
|
358
467
|
y: overlay.marquee.y,
|
|
359
468
|
width: overlay.marquee.width,
|
|
360
469
|
height: overlay.marquee.height,
|
|
361
|
-
fill:
|
|
470
|
+
fill: import_vector3.VECTOR_OVERLAY_THEME.marqueeFill,
|
|
362
471
|
stroke: accentColor,
|
|
363
472
|
strokeDasharray: "3 2"
|
|
364
473
|
}
|
|
365
474
|
),
|
|
366
|
-
overlay.guides.lines.length > 0 && /* @__PURE__ */ (0,
|
|
367
|
-
overlay.guides.labels.map((l, i) => /* @__PURE__ */ (0,
|
|
475
|
+
overlay.guides.lines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-guides": "", stroke: guideColor, children: overlay.guides.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { "data-vector-guide": l.kind, x1: l.x1, y1: l.y1, x2: l.x2, y2: l.y2, strokeDasharray: l.kind === "construction" ? "4 3" : void 0 }, i)) }),
|
|
476
|
+
overlay.guides.labels.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
368
477
|
"text",
|
|
369
478
|
{
|
|
370
479
|
"data-vector-guide-label": l.kind,
|
|
@@ -380,46 +489,57 @@ function VectorCanvas({
|
|
|
380
489
|
},
|
|
381
490
|
i
|
|
382
491
|
)),
|
|
383
|
-
overlay.status && /* @__PURE__ */ (0,
|
|
384
|
-
] })
|
|
492
|
+
overlay.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { "data-vector-status": "", x: 8, y: "100%", dy: -8, fontSize: 11, fill: accentColor, style: { fontFamily: "system-ui, sans-serif" }, children: overlay.status })
|
|
493
|
+
] }),
|
|
494
|
+
edit && editAt && // Width Point Edit (double-click with the width tool), beside the point.
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("foreignObject", { "data-vector-width-point-edit": "", x: editAt.x + 12, y: editAt.y + 12, width: 180, height: 140, style: { overflow: "visible" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorWidthPointEditor, { controller, edit, accentColor }, `${edit.nodeId}:${edit.index}:${edit.t}`) })
|
|
385
496
|
]
|
|
386
497
|
}
|
|
387
498
|
);
|
|
388
499
|
}
|
|
389
500
|
|
|
390
501
|
// src/vector/VectorToolbar.tsx
|
|
391
|
-
var
|
|
392
|
-
var
|
|
502
|
+
var import_vector4 = require("@pixerate/editor/vector");
|
|
503
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
393
504
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
394
505
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
395
506
|
var buttonClass = "inline-flex h-8 min-w-8 items-center justify-center rounded-md border border-border bg-background px-2 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
396
|
-
function VectorToolbar({
|
|
507
|
+
function VectorToolbar({
|
|
508
|
+
controller,
|
|
509
|
+
tools = import_vector4.VECTOR_TOOLS,
|
|
510
|
+
showHistory = true,
|
|
511
|
+
showArrange = true,
|
|
512
|
+
showSnap = true,
|
|
513
|
+
showPathEdit = true,
|
|
514
|
+
showBlend = true,
|
|
515
|
+
className
|
|
516
|
+
}) {
|
|
397
517
|
const state = useVectorEditorState(controller);
|
|
398
518
|
const count = state.selection.length;
|
|
399
519
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
400
520
|
const editing = state.editing;
|
|
401
521
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
402
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
403
|
-
return /* @__PURE__ */ (0,
|
|
404
|
-
/* @__PURE__ */ (0,
|
|
522
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: buttonClass, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
405
525
|
"button",
|
|
406
526
|
{
|
|
407
527
|
type: "button",
|
|
408
528
|
"data-vector-tool": tool,
|
|
409
529
|
className: buttonClass,
|
|
410
530
|
"aria-pressed": state.tool === tool,
|
|
411
|
-
title: `${(0,
|
|
412
|
-
"aria-label": (0,
|
|
531
|
+
title: `${(0, import_vector4.vectorToolLabel)(tool)} (${import_vector4.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
532
|
+
"aria-label": (0, import_vector4.vectorToolLabel)(tool),
|
|
413
533
|
onClick: () => controller.setTool(tool),
|
|
414
|
-
children:
|
|
534
|
+
children: import_vector4.VECTOR_TOOL_GLYPHS[tool]
|
|
415
535
|
},
|
|
416
536
|
tool
|
|
417
537
|
)) }),
|
|
418
|
-
showHistory && /* @__PURE__ */ (0,
|
|
538
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
419
539
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
420
540
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
421
541
|
] }),
|
|
422
|
-
showSnap && /* @__PURE__ */ (0,
|
|
542
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
423
543
|
"button",
|
|
424
544
|
{
|
|
425
545
|
type: "button",
|
|
@@ -432,8 +552,8 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
432
552
|
children: "Snap"
|
|
433
553
|
}
|
|
434
554
|
) }),
|
|
435
|
-
showPathEdit && /* @__PURE__ */ (0,
|
|
436
|
-
|
|
555
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
556
|
+
import_vector4.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
437
557
|
"button",
|
|
438
558
|
{
|
|
439
559
|
type: "button",
|
|
@@ -447,7 +567,7 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
447
567
|
},
|
|
448
568
|
a.id
|
|
449
569
|
)),
|
|
450
|
-
|
|
570
|
+
import_vector4.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
451
571
|
"button",
|
|
452
572
|
{
|
|
453
573
|
type: "button",
|
|
@@ -461,9 +581,9 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
461
581
|
},
|
|
462
582
|
t.key
|
|
463
583
|
)),
|
|
464
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
584
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
465
585
|
"Smoothing",
|
|
466
|
-
/* @__PURE__ */ (0,
|
|
586
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
467
587
|
"input",
|
|
468
588
|
{
|
|
469
589
|
type: "range",
|
|
@@ -477,9 +597,9 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
477
597
|
}
|
|
478
598
|
)
|
|
479
599
|
] }),
|
|
480
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
600
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
481
601
|
"Size",
|
|
482
|
-
/* @__PURE__ */ (0,
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
483
603
|
"input",
|
|
484
604
|
{
|
|
485
605
|
type: "number",
|
|
@@ -495,7 +615,7 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
495
615
|
}
|
|
496
616
|
)
|
|
497
617
|
] }),
|
|
498
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
618
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
499
619
|
"button",
|
|
500
620
|
{
|
|
501
621
|
type: "button",
|
|
@@ -504,13 +624,14 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
504
624
|
"aria-pressed": editing.fillGap > 0,
|
|
505
625
|
title: "Close small gaps between path ends when filling",
|
|
506
626
|
"aria-label": "Close gaps",
|
|
507
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
627
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector4.VECTOR_FILL_GAP }),
|
|
508
628
|
children: "Gaps"
|
|
509
629
|
}
|
|
510
630
|
)
|
|
511
631
|
] }),
|
|
512
|
-
|
|
513
|
-
|
|
632
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VectorBlendControls, { controller }),
|
|
633
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
634
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
514
635
|
act("\u222A", "Union", () => controller.booleanOp("union"), count < 2),
|
|
515
636
|
act("\u2212", "Subtract", () => controller.booleanOp("subtract"), count < 2),
|
|
516
637
|
act("\u2229", "Intersect", () => controller.booleanOp("intersect"), count < 2),
|
|
@@ -518,7 +639,7 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
518
639
|
act("G", "Group", () => controller.group(), count < 1),
|
|
519
640
|
act("U", "Ungroup", () => controller.ungroup(), !groupSelected)
|
|
520
641
|
] }),
|
|
521
|
-
/* @__PURE__ */ (0,
|
|
642
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector4.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
522
643
|
"button",
|
|
523
644
|
{
|
|
524
645
|
type: "button",
|
|
@@ -532,7 +653,7 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
532
653
|
},
|
|
533
654
|
a.id
|
|
534
655
|
)) }),
|
|
535
|
-
/* @__PURE__ */ (0,
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
536
657
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
537
658
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
538
659
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -545,11 +666,74 @@ function VectorToolbar({ controller, tools = import_vector3.VECTOR_TOOLS, showHi
|
|
|
545
666
|
] })
|
|
546
667
|
] });
|
|
547
668
|
}
|
|
669
|
+
function VectorBlendControls({ controller }) {
|
|
670
|
+
const state = useVectorEditorState(controller);
|
|
671
|
+
const blend = (0, import_vector4.getVectorBlendControls)(state);
|
|
672
|
+
const o = blend.options;
|
|
673
|
+
const selected = blend.ids.length > 0;
|
|
674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
677
|
+
"select",
|
|
678
|
+
{
|
|
679
|
+
"aria-label": "Blend spacing",
|
|
680
|
+
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
681
|
+
value: o.spacing,
|
|
682
|
+
onChange: (e) => (0, import_vector4.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
683
|
+
children: import_vector4.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: sp, children: import_vector4.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
684
|
+
}
|
|
685
|
+
),
|
|
686
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
687
|
+
"input",
|
|
688
|
+
{
|
|
689
|
+
type: "number",
|
|
690
|
+
min: o.spacing === "steps" ? 1 : 0.5,
|
|
691
|
+
step: 1,
|
|
692
|
+
"aria-label": o.spacing === "steps" ? "Blend steps" : "Blend distance",
|
|
693
|
+
className: "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs",
|
|
694
|
+
value: o.spacing === "steps" ? o.steps : o.distance,
|
|
695
|
+
onChange: (e) => {
|
|
696
|
+
const n = parseFloat(e.target.value);
|
|
697
|
+
if (!Number.isFinite(n) || n <= 0) return;
|
|
698
|
+
(0, import_vector4.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
),
|
|
702
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
703
|
+
"button",
|
|
704
|
+
{
|
|
705
|
+
type: "button",
|
|
706
|
+
"data-vector-blend-action": "orient",
|
|
707
|
+
className: buttonClass,
|
|
708
|
+
"aria-pressed": o.orientToSpine,
|
|
709
|
+
title: "Orient steps to the spine",
|
|
710
|
+
"aria-label": "Orient to spine",
|
|
711
|
+
onClick: () => (0, import_vector4.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
712
|
+
children: "\u293F"
|
|
713
|
+
}
|
|
714
|
+
),
|
|
715
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
716
|
+
"button",
|
|
717
|
+
{
|
|
718
|
+
type: "button",
|
|
719
|
+
"data-vector-blend-action": "spine",
|
|
720
|
+
className: buttonClass,
|
|
721
|
+
title: "Replace Spine (select a blend and a path)",
|
|
722
|
+
"aria-label": "Replace Spine",
|
|
723
|
+
disabled: !blend.canReplaceSpine,
|
|
724
|
+
onClick: () => controller.replaceBlendSpine(),
|
|
725
|
+
children: "\u2307"
|
|
726
|
+
}
|
|
727
|
+
),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
730
|
+
] });
|
|
731
|
+
}
|
|
548
732
|
var selectClass = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
549
733
|
var numberClass = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
550
734
|
function VectorStylePanel({ controller, className }) {
|
|
551
735
|
const state = useVectorEditorState(controller);
|
|
552
|
-
const style = (0,
|
|
736
|
+
const style = (0, import_vector4.getVectorSelectionStyle)(state);
|
|
553
737
|
const d = state.defaults;
|
|
554
738
|
const source = style ?? {
|
|
555
739
|
fill: d.fill ?? null,
|
|
@@ -562,7 +746,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
562
746
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
563
747
|
startArrowScale: d.startArrowScale ?? 1,
|
|
564
748
|
endArrowScale: d.endArrowScale ?? 1,
|
|
565
|
-
widthProfile: (0,
|
|
749
|
+
widthProfile: (0, import_vector4.widthProfilePresetId)(d.strokeWidthProfile),
|
|
566
750
|
cornerRadius: d.cornerRadius,
|
|
567
751
|
cornerKind: d.cornerKind ?? "round",
|
|
568
752
|
corners: 1,
|
|
@@ -575,19 +759,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
575
759
|
};
|
|
576
760
|
const setProfile = (id) => {
|
|
577
761
|
if (style) controller.setWidthProfile(id);
|
|
578
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
762
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector4.widthProfilePreset)(id)?.length ? (0, import_vector4.widthProfilePreset)(id) : null });
|
|
579
763
|
};
|
|
580
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
764
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
581
765
|
const arrowRow = (end, label) => {
|
|
582
766
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
583
767
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
584
|
-
return /* @__PURE__ */ (0,
|
|
585
|
-
/* @__PURE__ */ (0,
|
|
586
|
-
/* @__PURE__ */ (0,
|
|
587
|
-
/* @__PURE__ */ (0,
|
|
588
|
-
|
|
768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
769
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
770
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
771
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "None" }),
|
|
772
|
+
import_vector4.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: h, children: import_vector4.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
589
773
|
] }),
|
|
590
|
-
/* @__PURE__ */ (0,
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
591
775
|
"input",
|
|
592
776
|
{
|
|
593
777
|
type: "number",
|
|
@@ -611,14 +795,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
611
795
|
};
|
|
612
796
|
const paintRow = (key, label) => {
|
|
613
797
|
const paint = source[key];
|
|
614
|
-
const hex = (0,
|
|
798
|
+
const hex = (0, import_vector4.vectorPaintToHex)(paint);
|
|
615
799
|
const on = paint !== null && paint !== "none";
|
|
616
|
-
return /* @__PURE__ */ (0,
|
|
617
|
-
/* @__PURE__ */ (0,
|
|
618
|
-
/* @__PURE__ */ (0,
|
|
800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
619
803
|
label
|
|
620
804
|
] }),
|
|
621
|
-
/* @__PURE__ */ (0,
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
622
806
|
"input",
|
|
623
807
|
{
|
|
624
808
|
type: "color",
|
|
@@ -629,17 +813,17 @@ function VectorStylePanel({ controller, className }) {
|
|
|
629
813
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
630
814
|
}
|
|
631
815
|
),
|
|
632
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
633
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
816
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
817
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
634
818
|
] });
|
|
635
819
|
};
|
|
636
|
-
return /* @__PURE__ */ (0,
|
|
637
|
-
/* @__PURE__ */ (0,
|
|
820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
638
822
|
paintRow("fill", "Fill"),
|
|
639
823
|
paintRow("stroke", "Stroke"),
|
|
640
|
-
/* @__PURE__ */ (0,
|
|
641
|
-
/* @__PURE__ */ (0,
|
|
642
|
-
/* @__PURE__ */ (0,
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Width" }),
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
643
827
|
"input",
|
|
644
828
|
{
|
|
645
829
|
type: "number",
|
|
@@ -655,14 +839,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
655
839
|
}
|
|
656
840
|
)
|
|
657
841
|
] }),
|
|
658
|
-
/* @__PURE__ */ (0,
|
|
659
|
-
/* @__PURE__ */ (0,
|
|
660
|
-
/* @__PURE__ */ (0,
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Align" }),
|
|
844
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector4.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: a, children: import_vector4.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
661
845
|
mixed("strokeAlign")
|
|
662
846
|
] }),
|
|
663
|
-
/* @__PURE__ */ (0,
|
|
664
|
-
/* @__PURE__ */ (0,
|
|
665
|
-
/* @__PURE__ */ (0,
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
849
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
666
850
|
"select",
|
|
667
851
|
{
|
|
668
852
|
"aria-label": "Width profile",
|
|
@@ -672,12 +856,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
672
856
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
673
857
|
},
|
|
674
858
|
children: [
|
|
675
|
-
|
|
676
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
859
|
+
import_vector4.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
860
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
677
861
|
]
|
|
678
862
|
}
|
|
679
863
|
),
|
|
680
|
-
/* @__PURE__ */ (0,
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
681
865
|
"button",
|
|
682
866
|
{
|
|
683
867
|
type: "button",
|
|
@@ -691,20 +875,20 @@ function VectorStylePanel({ controller, className }) {
|
|
|
691
875
|
),
|
|
692
876
|
mixed("widthProfile")
|
|
693
877
|
] }),
|
|
694
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
878
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
695
879
|
arrowRow("start", "Start"),
|
|
696
880
|
arrowRow("end", "End"),
|
|
697
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
698
|
-
/* @__PURE__ */ (0,
|
|
699
|
-
/* @__PURE__ */ (0,
|
|
700
|
-
/* @__PURE__ */ (0,
|
|
701
|
-
/* @__PURE__ */ (0,
|
|
881
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
885
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
702
886
|
] })
|
|
703
887
|
] })
|
|
704
888
|
] }),
|
|
705
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
706
|
-
/* @__PURE__ */ (0,
|
|
707
|
-
/* @__PURE__ */ (0,
|
|
889
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
891
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
708
892
|
"input",
|
|
709
893
|
{
|
|
710
894
|
type: "number",
|
|
@@ -719,12 +903,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
719
903
|
}
|
|
720
904
|
}
|
|
721
905
|
),
|
|
722
|
-
/* @__PURE__ */ (0,
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": "Corner kind", className: selectClass, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector4.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: k, children: import_vector4.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
723
907
|
mixed("cornerRadius")
|
|
724
908
|
] }),
|
|
725
|
-
style && /* @__PURE__ */ (0,
|
|
726
|
-
/* @__PURE__ */ (0,
|
|
727
|
-
/* @__PURE__ */ (0,
|
|
909
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
728
912
|
"input",
|
|
729
913
|
{
|
|
730
914
|
type: "range",
|
|
@@ -742,13 +926,13 @@ function VectorStylePanel({ controller, className }) {
|
|
|
742
926
|
}
|
|
743
927
|
|
|
744
928
|
// src/vector/VectorEditor.tsx
|
|
745
|
-
var
|
|
929
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
746
930
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
747
|
-
return /* @__PURE__ */ (0,
|
|
748
|
-
/* @__PURE__ */ (0,
|
|
749
|
-
/* @__PURE__ */ (0,
|
|
750
|
-
/* @__PURE__ */ (0,
|
|
751
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorToolbar, { controller, tools }),
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
935
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
752
936
|
] })
|
|
753
937
|
] });
|
|
754
938
|
}
|
|
@@ -760,6 +944,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
760
944
|
VectorSceneNodes,
|
|
761
945
|
VectorStylePanel,
|
|
762
946
|
VectorToolbar,
|
|
947
|
+
VectorWidthPointEditor,
|
|
763
948
|
useVectorCommands,
|
|
764
949
|
useVectorEditor,
|
|
765
950
|
useVectorEditorController,
|