@pixerate/editor-react 0.74.0 → 0.75.1
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/paint-editor/index.cjs +216 -19
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +31 -6
- package/dist/paint-editor/index.d.ts +31 -6
- package/dist/paint-editor/index.js +244 -34
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/vector/index.cjs +328 -220
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +22 -1
- package/dist/vector/index.d.ts +22 -1
- package/dist/vector/index.js +318 -212
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function useVectorCommands(registry, controller, options = {}) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// src/vector/VectorCanvas.tsx
|
|
47
|
-
import React2, { useEffect as useEffect2, useId, useRef as useRef3 } from "react";
|
|
47
|
+
import React2, { useEffect as useEffect2, useId, useRef as useRef3, useState as useState2 } from "react";
|
|
48
48
|
import {
|
|
49
49
|
VECTOR_OVERLAY_THEME as THEME2,
|
|
50
50
|
getVectorOverlayRenderData,
|
|
@@ -227,48 +227,19 @@ function VectorTextElement({ node }) {
|
|
|
227
227
|
)) });
|
|
228
228
|
}
|
|
229
229
|
function VectorSceneNodes({ nodes }) {
|
|
230
|
-
return /* @__PURE__ */ jsx2(Fragment, { children: nodes.map(
|
|
231
|
-
(node) => node.kind === "text" ? /* @__PURE__ */ jsx2(VectorTextElement, { node }, node.id) : node.kind === "group" ? /* @__PURE__ */ jsx2(
|
|
232
|
-
"g",
|
|
233
|
-
{
|
|
234
|
-
"data-vector-id": node.id,
|
|
235
|
-
"data-vector-mask": node.mask?.type,
|
|
236
|
-
transform: node.transform,
|
|
237
|
-
opacity: node.opacity < 1 ? node.opacity : void 0,
|
|
238
|
-
filter: node.filter,
|
|
239
|
-
style: blendStyle(node.blendMode),
|
|
240
|
-
children: node.mask ? /* @__PURE__ */ jsx2(VectorMaskedNodes, { mask: node.mask, nodes: node.children }) : /* @__PURE__ */ jsx2(VectorSceneNodes, { nodes: node.children })
|
|
241
|
-
},
|
|
242
|
-
node.id
|
|
243
|
-
) : node.layers ? (
|
|
244
|
-
// Fill and stroke stacks: each layer in order, bottom to top.
|
|
245
|
-
/* @__PURE__ */ jsx2(
|
|
246
|
-
"g",
|
|
247
|
-
{
|
|
248
|
-
"data-vector-id": node.id,
|
|
249
|
-
transform: node.transform,
|
|
250
|
-
opacity: node.opacity < 1 ? node.opacity : void 0,
|
|
251
|
-
filter: node.filter,
|
|
252
|
-
style: blendStyle(node.blendMode),
|
|
253
|
-
children: node.layers.map((layer) => /* @__PURE__ */ jsx2(VectorPaintPath, { paint: layer, d: node.d, fillRule: node.fillRule, layer: `${layer.kind}-${layer.index}` }, `${layer.kind}-${layer.index}`))
|
|
254
|
-
},
|
|
255
|
-
node.id
|
|
256
|
-
)
|
|
257
|
-
) : /* @__PURE__ */ jsx2(
|
|
258
|
-
VectorPaintPath,
|
|
259
|
-
{
|
|
260
|
-
paint: node,
|
|
261
|
-
d: node.d,
|
|
262
|
-
fillRule: node.fillRule,
|
|
263
|
-
id: node.id,
|
|
264
|
-
transform: node.transform,
|
|
265
|
-
filter: node.filter,
|
|
266
|
-
blendMode: node.blendMode
|
|
267
|
-
},
|
|
268
|
-
node.id
|
|
269
|
-
)
|
|
270
|
-
) });
|
|
230
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: nodes.map((node) => /* @__PURE__ */ jsx2(VectorSceneNode, { node }, node.id)) });
|
|
271
231
|
}
|
|
232
|
+
var VectorSceneNode = React2.memo(function VectorSceneNode2({ node }) {
|
|
233
|
+
if (node.kind === "text") return /* @__PURE__ */ jsx2(VectorTextElement, { node });
|
|
234
|
+
if (node.kind === "group")
|
|
235
|
+
return /* @__PURE__ */ jsx2("g", { "data-vector-id": node.id, "data-vector-mask": node.mask?.type, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, filter: node.filter, style: blendStyle(node.blendMode), children: node.mask ? /* @__PURE__ */ jsx2(VectorMaskedNodes, { mask: node.mask, nodes: node.children }) : /* @__PURE__ */ jsx2(VectorSceneNodes, { nodes: node.children }) });
|
|
236
|
+
if (node.layers)
|
|
237
|
+
return (
|
|
238
|
+
// Fill and stroke stacks: each layer in order, bottom to top.
|
|
239
|
+
/* @__PURE__ */ jsx2("g", { "data-vector-id": node.id, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, filter: node.filter, style: blendStyle(node.blendMode), children: node.layers.map((layer) => /* @__PURE__ */ jsx2(VectorPaintPath, { paint: layer, d: node.d, fillRule: node.fillRule, layer: `${layer.kind}-${layer.index}` }, `${layer.kind}-${layer.index}`)) })
|
|
240
|
+
);
|
|
241
|
+
return /* @__PURE__ */ jsx2(VectorPaintPath, { paint: node, d: node.d, fillRule: node.fillRule, id: node.id, transform: node.transform, filter: node.filter, blendMode: node.blendMode });
|
|
242
|
+
});
|
|
272
243
|
function VectorMaskedNodes({ mask, nodes }) {
|
|
273
244
|
const b = mask.bounds;
|
|
274
245
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
@@ -363,7 +334,8 @@ function VectorCanvas({
|
|
|
363
334
|
const editingText = state.textEdit?.nodeId ?? null;
|
|
364
335
|
const fitted = useRef3(!fitOnMount);
|
|
365
336
|
const uid = useId().replace(/:/g, "");
|
|
366
|
-
const
|
|
337
|
+
const [size, setSize] = useState2(null);
|
|
338
|
+
const scene = getVectorSceneRenderData(state, { idPrefix: `ve${uid}-`, ...size ? { viewportSize: size } : {} });
|
|
367
339
|
const overlay = getVectorOverlayRenderData(state);
|
|
368
340
|
const host = getVectorSymbolEditBackground(state, { idPrefix: `ve${uid}-host-` });
|
|
369
341
|
useEffect2(() => {
|
|
@@ -381,6 +353,18 @@ function VectorCanvas({
|
|
|
381
353
|
observer.observe(el);
|
|
382
354
|
return () => observer.disconnect();
|
|
383
355
|
}, [controller]);
|
|
356
|
+
useEffect2(() => {
|
|
357
|
+
const el = svgRef.current;
|
|
358
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
359
|
+
const measure = () => {
|
|
360
|
+
const r = el.getBoundingClientRect();
|
|
361
|
+
if (r.width > 0 && r.height > 0) setSize((s) => s && s.width === r.width && s.height === r.height ? s : { width: r.width, height: r.height });
|
|
362
|
+
};
|
|
363
|
+
measure();
|
|
364
|
+
const observer = new ResizeObserver(measure);
|
|
365
|
+
observer.observe(el);
|
|
366
|
+
return () => observer.disconnect();
|
|
367
|
+
}, []);
|
|
384
368
|
useEffect2(() => {
|
|
385
369
|
if (!editingText) return;
|
|
386
370
|
const t = setTimeout(() => textRef.current?.focus({ preventScroll: true }), 0);
|
|
@@ -516,8 +500,8 @@ function VectorCanvas({
|
|
|
516
500
|
/* @__PURE__ */ jsx2("circle", { cx: h.x, cy: h.y, r: THEME2.handleRadius + (h.hovered || h.active ? 1 : 0), fill: h.active ? accentColor : THEME2.handleFill, stroke: accentColor })
|
|
517
501
|
] }, h.index)),
|
|
518
502
|
overlay.envelope.anchors.map((a) => {
|
|
519
|
-
const
|
|
520
|
-
return /* @__PURE__ */ jsx2("rect", { "data-vector-envelope-anchor": a.index, x: a.x -
|
|
503
|
+
const size2 = as + (a.hovered || a.active ? 2 : 0);
|
|
504
|
+
return /* @__PURE__ */ jsx2("rect", { "data-vector-envelope-anchor": a.index, x: a.x - size2 / 2, y: a.y - size2 / 2, width: size2, height: size2, fill: a.active ? accentColor : THEME2.handleFill, stroke: accentColor }, a.index);
|
|
521
505
|
})
|
|
522
506
|
] }),
|
|
523
507
|
overlay.handles.map((h) => /* @__PURE__ */ jsxs2("g", { "data-vector-handle": h.ref.handle, children: [
|
|
@@ -525,10 +509,10 @@ function VectorCanvas({
|
|
|
525
509
|
/* @__PURE__ */ jsx2("circle", { cx: h.x, cy: h.y, r: THEME2.handleRadius + (h.hovered ? 1 : 0), fill: THEME2.handleFill, stroke: accentColor })
|
|
526
510
|
] }, `${h.ref.nodeId}:${h.ref.subpath}:${h.ref.index}:${h.ref.handle}`)),
|
|
527
511
|
overlay.anchors.map((a) => {
|
|
528
|
-
const
|
|
512
|
+
const size2 = as + (a.hovered ? 2 : 0);
|
|
529
513
|
const fill = a.selected ? accentColor : THEME2.handleFill;
|
|
530
514
|
const key = `${a.ref.nodeId}:${a.ref.subpath}:${a.ref.index}`;
|
|
531
|
-
return a.type === "corner" ? /* @__PURE__ */ jsx2("rect", { "data-vector-anchor": a.ref.index, x: a.x -
|
|
515
|
+
return a.type === "corner" ? /* @__PURE__ */ jsx2("rect", { "data-vector-anchor": a.ref.index, x: a.x - size2 / 2, y: a.y - size2 / 2, width: size2, height: size2, fill, stroke: accentColor }, key) : /* @__PURE__ */ jsx2("circle", { "data-vector-anchor": a.ref.index, cx: a.x, cy: a.y, r: size2 / 2, fill, stroke: accentColor }, key);
|
|
532
516
|
}),
|
|
533
517
|
overlay.cornerWidgets.map((w) => /* @__PURE__ */ jsxs2("g", { "data-vector-corner-widget": w.ref.index, "data-corner-kind": w.kind, children: [
|
|
534
518
|
/* @__PURE__ */ jsx2("circle", { cx: w.x, cy: w.y, r: THEME2.cornerWidgetRadius + (w.hovered ? 1 : 0), fill: THEME2.handleFill, stroke: accentColor }),
|
|
@@ -645,6 +629,10 @@ function VectorCanvas({
|
|
|
645
629
|
/* @__PURE__ */ jsx2("path", { d: "M-3 0H3M0 -3V3", stroke: "#dc2626" })
|
|
646
630
|
] })
|
|
647
631
|
] }),
|
|
632
|
+
overlay.shading.map((sh) => /* @__PURE__ */ jsxs2("g", { "data-vector-shading": sh.kind, children: [
|
|
633
|
+
sh.lines.map((d, i) => /* @__PURE__ */ jsx2("path", { d, stroke: accentColor, strokeWidth: 1, opacity: 0.7 }, i)),
|
|
634
|
+
sh.points.map((p) => /* @__PURE__ */ jsx2("circle", { "data-vector-shading-point": p.index, "data-selected": p.selected || void 0, cx: p.x, cy: p.y, r: p.selected ? 6 : 4.5, fill: p.color, stroke: p.selected ? accentColor : "#ffffff", strokeWidth: p.selected ? 2 : 1.5 }, p.index))
|
|
635
|
+
] }, `shading:${sh.nodeId}`)),
|
|
648
636
|
overlay.trackingPoints.map((t, i) => /* @__PURE__ */ jsx2("path", { "data-vector-tracking-point": "", d: `M${t.x - 5} ${t.y}H${t.x + 5}M${t.x} ${t.y - 5}V${t.y + 5}`, stroke: guideColor, strokeWidth: 1.5 }, `track:${i}`)),
|
|
649
637
|
overlay.typedEntry && /* @__PURE__ */ jsxs2("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
650
638
|
/* @__PURE__ */ jsx2("rect", { x: -3, y: -12, width: overlay.typedEntry.text.length * 7 + 8, height: 17, rx: 3, fill: THEME2.handleFill, stroke: accentColor }),
|
|
@@ -780,7 +768,7 @@ function VectorCanvas({
|
|
|
780
768
|
}
|
|
781
769
|
|
|
782
770
|
// src/vector/VectorToolbar.tsx
|
|
783
|
-
import
|
|
771
|
+
import React9 from "react";
|
|
784
772
|
import {
|
|
785
773
|
VECTOR_TOOLS,
|
|
786
774
|
VECTOR_TOOL_GLYPHS,
|
|
@@ -803,7 +791,7 @@ import {
|
|
|
803
791
|
isVectorMaskGroup,
|
|
804
792
|
widthProfilePreset,
|
|
805
793
|
widthProfilePresetId,
|
|
806
|
-
vectorPaintToHex as
|
|
794
|
+
vectorPaintToHex as vectorPaintToHex5,
|
|
807
795
|
vectorToolLabel,
|
|
808
796
|
vectorPolarAngles,
|
|
809
797
|
vectorPolarIncrementOf
|
|
@@ -1580,7 +1568,7 @@ function VectorTextPanel({ controller, className }) {
|
|
|
1580
1568
|
}
|
|
1581
1569
|
|
|
1582
1570
|
// src/vector/VectorSymbolsPanel.tsx
|
|
1583
|
-
import { useId as useId3, useState as
|
|
1571
|
+
import { useId as useId3, useState as useState3 } from "react";
|
|
1584
1572
|
import { getVectorSymbolsPanel, vectorPaintToHex } from "@pixerate/editor/vector";
|
|
1585
1573
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1586
1574
|
var buttonClass6 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 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";
|
|
@@ -1590,7 +1578,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1590
1578
|
const state = useVectorEditorState(controller);
|
|
1591
1579
|
const uid = useId3().replace(/:/g, "");
|
|
1592
1580
|
const panel = getVectorSymbolsPanel(state, { idPrefix: `vsym${uid}-` });
|
|
1593
|
-
const [error, setError] =
|
|
1581
|
+
const [error, setError] = useState3(null);
|
|
1594
1582
|
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1595
1583
|
const inst = panel.instance;
|
|
1596
1584
|
return /* @__PURE__ */ jsxs8("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symbols-panel": "", "aria-label": "Symbols", children: [
|
|
@@ -1648,7 +1636,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1648
1636
|
}
|
|
1649
1637
|
|
|
1650
1638
|
// src/vector/VectorConstraintsPanel.tsx
|
|
1651
|
-
import { useState as
|
|
1639
|
+
import { useState as useState4 } from "react";
|
|
1652
1640
|
import { getVectorConstraintPanel } from "@pixerate/editor/vector";
|
|
1653
1641
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1654
1642
|
var buttonClass7 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
@@ -1657,8 +1645,8 @@ var labelClass6 = "w-16 text-[11px] font-medium uppercase tracking-wide text-mut
|
|
|
1657
1645
|
function VectorConstraintsPanel({ controller, className }) {
|
|
1658
1646
|
const state = useVectorEditorState(controller);
|
|
1659
1647
|
const panel = getVectorConstraintPanel(state);
|
|
1660
|
-
const [error, setError] =
|
|
1661
|
-
const [param, setParam] =
|
|
1648
|
+
const [error, setError] = useState4(null);
|
|
1649
|
+
const [param, setParam] = useState4({ name: "", value: "" });
|
|
1662
1650
|
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1663
1651
|
const add = (a) => report(controller.addConstraint({ kind: a.kind, refs: a.refs }));
|
|
1664
1652
|
if (!panel.actions.length && !panel.constraints.length && !state.document.constraints?.length && state.tool !== "direct") return null;
|
|
@@ -1925,6 +1913,120 @@ function VectorConnectorPanel({ controller, className }) {
|
|
|
1925
1913
|
] });
|
|
1926
1914
|
}
|
|
1927
1915
|
|
|
1916
|
+
// src/vector/VectorShadingPanel.tsx
|
|
1917
|
+
import { useState as useState5 } from "react";
|
|
1918
|
+
import { isVectorFreeformGradient, isVectorMeshGradient, vectorPaintToHex as vectorPaintToHex3 } from "@pixerate/editor/vector";
|
|
1919
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1920
|
+
var buttonClass10 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
1921
|
+
var numberClass6 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
1922
|
+
function VectorShadingPanel({ controller, className }) {
|
|
1923
|
+
const state = useVectorEditorState(controller);
|
|
1924
|
+
const [rows, setRows] = useState5(2);
|
|
1925
|
+
const [columns, setColumns] = useState5(2);
|
|
1926
|
+
const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path");
|
|
1927
|
+
if (!path) return null;
|
|
1928
|
+
const fill = path.fill;
|
|
1929
|
+
const sel = state.shadingPoint?.nodeId === path.id ? state.shadingPoint : null;
|
|
1930
|
+
const mesh = isVectorMeshGradient(fill) ? fill : null;
|
|
1931
|
+
const free = isVectorFreeformGradient(fill) ? fill : null;
|
|
1932
|
+
const color = sel ? mesh ? mesh.colors[sel.index] : free?.points[sel.index]?.color : void 0;
|
|
1933
|
+
const opacity = sel ? mesh ? mesh.opacities?.[sel.index] ?? 1 : free?.points[sel.index]?.opacity ?? 1 : 1;
|
|
1934
|
+
const spread = sel && free ? free.points[sel.index]?.spread ?? 0 : 0;
|
|
1935
|
+
const edit = (patch, merge) => {
|
|
1936
|
+
if (!sel) return;
|
|
1937
|
+
if (mesh) controller.setMeshPoint(path.id, sel.index, patch, merge ? { merge } : {});
|
|
1938
|
+
else controller.setFreeformPoint(path.id, sel.index, patch, merge ? { merge } : {});
|
|
1939
|
+
};
|
|
1940
|
+
return /* @__PURE__ */ jsxs12("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-shading-panel": path.id, "aria-label": "Mesh and freeform gradient", children: [
|
|
1941
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1942
|
+
/* @__PURE__ */ jsx12("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Shading" }),
|
|
1943
|
+
/* @__PURE__ */ jsx12("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh rows", title: "Mesh rows", className: numberClass6, value: rows, onChange: (e) => setRows(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
|
|
1944
|
+
/* @__PURE__ */ jsx12("span", { className: "text-xs text-muted-foreground", children: "\xD7" }),
|
|
1945
|
+
/* @__PURE__ */ jsx12("input", { type: "number", min: 1, max: 32, "aria-label": "Mesh columns", title: "Mesh columns", className: numberClass6, value: columns, onChange: (e) => setColumns(Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 1))) }),
|
|
1946
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass10, "data-vector-shading-action": "mesh", title: "Create Gradient Mesh: smooth patches whose points blend colours (edit them with the Gradient tool)", onClick: () => controller.setMeshGradient({ rows, columns }, { ids: [path.id] }), children: "Mesh" }),
|
|
1947
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass10, "data-vector-shading-action": "freeform", title: "Freeform Gradient: colour points blended across the shape (click inside with the Gradient tool to add one)", onClick: () => controller.setFreeformGradient({}, { ids: [path.id] }), children: "Freeform" })
|
|
1948
|
+
] }),
|
|
1949
|
+
(mesh || free) && !sel && /* @__PURE__ */ jsxs12("p", { className: "text-[11px] text-muted-foreground", children: [
|
|
1950
|
+
"Gradient tool (G): drag points; ",
|
|
1951
|
+
free ? "click inside to add one, Alt-click to remove." : "pick one to colour it."
|
|
1952
|
+
] }),
|
|
1953
|
+
sel && /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", "data-vector-shading-point": sel.index, children: [
|
|
1954
|
+
/* @__PURE__ */ jsxs12("span", { className: "w-16 text-xs text-foreground", children: [
|
|
1955
|
+
"Point ",
|
|
1956
|
+
sel.index
|
|
1957
|
+
] }),
|
|
1958
|
+
/* @__PURE__ */ jsx12("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: vectorPaintToHex3(color ?? "#000000") ?? "#000000", onChange: (e) => edit({ color: e.target.value }, "shading-color") }),
|
|
1959
|
+
/* @__PURE__ */ jsx12("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point opacity", title: "Opacity", className: "h-4 w-20 accent-primary", value: opacity, onChange: (e) => edit({ opacity: parseFloat(e.target.value) }, "shading-opacity") }),
|
|
1960
|
+
free && /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
1961
|
+
/* @__PURE__ */ jsx12("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point spread", title: "Spread: pure colour round the point", className: "h-4 w-20 accent-primary", value: spread, onChange: (e) => edit({ spread: parseFloat(e.target.value) }, "shading-spread") }),
|
|
1962
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass10, "aria-label": "Remove point", onClick: () => controller.removeFreeformPoint(path.id, sel.index), children: "Remove" })
|
|
1963
|
+
] })
|
|
1964
|
+
] })
|
|
1965
|
+
] });
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
// src/vector/VectorTracePanel.tsx
|
|
1969
|
+
import { useRef as useRef4, useState as useState6 } from "react";
|
|
1970
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1971
|
+
var buttonClass11 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
1972
|
+
var selectClass8 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1973
|
+
var numberClass7 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
1974
|
+
async function filePixels(file, max = 1e6) {
|
|
1975
|
+
const bitmap = await createImageBitmap(file);
|
|
1976
|
+
const k = Math.min(1, Math.sqrt(max / (bitmap.width * bitmap.height)));
|
|
1977
|
+
const width = Math.max(1, Math.round(bitmap.width * k));
|
|
1978
|
+
const height = Math.max(1, Math.round(bitmap.height * k));
|
|
1979
|
+
const canvas = document.createElement("canvas");
|
|
1980
|
+
canvas.width = width;
|
|
1981
|
+
canvas.height = height;
|
|
1982
|
+
const ctx = canvas.getContext("2d");
|
|
1983
|
+
ctx.drawImage(bitmap, 0, 0, width, height);
|
|
1984
|
+
return { width, height, data: ctx.getImageData(0, 0, width, height).data };
|
|
1985
|
+
}
|
|
1986
|
+
function VectorTracePanel({ controller, className }) {
|
|
1987
|
+
const input = useRef4(null);
|
|
1988
|
+
const [mode, setMode] = useState6("threshold");
|
|
1989
|
+
const [colors, setColors] = useState6(6);
|
|
1990
|
+
const [message, setMessage] = useState6(null);
|
|
1991
|
+
const trace = async (file) => {
|
|
1992
|
+
try {
|
|
1993
|
+
const pixels = await filePixels(file);
|
|
1994
|
+
const doc = controller.getState().document;
|
|
1995
|
+
const width = Math.min(doc.width, pixels.width);
|
|
1996
|
+
const r = controller.traceImage(pixels, { mode, colors, width, name: file.name.replace(/\.[^.]+$/, "") || "Image Trace" });
|
|
1997
|
+
setMessage(r.ok ? null : r.message);
|
|
1998
|
+
} catch {
|
|
1999
|
+
setMessage("That file could not be read as an image.");
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
return /* @__PURE__ */ jsxs13("div", { className: `space-y-1 ${className ?? ""}`, "data-vector-trace-panel": "", "aria-label": "Image trace", children: [
|
|
2003
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
|
|
2004
|
+
/* @__PURE__ */ jsx13("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Trace" }),
|
|
2005
|
+
/* @__PURE__ */ jsxs13("select", { "aria-label": "Trace mode", className: selectClass8, value: mode, onChange: (e) => setMode(e.target.value), children: [
|
|
2006
|
+
/* @__PURE__ */ jsx13("option", { value: "threshold", children: "Black & white" }),
|
|
2007
|
+
/* @__PURE__ */ jsx13("option", { value: "color", children: "Colours" })
|
|
2008
|
+
] }),
|
|
2009
|
+
mode === "color" && /* @__PURE__ */ jsx13("input", { type: "number", min: 2, max: 32, "aria-label": "Trace colours", title: "Colours", className: numberClass7, value: colors, onChange: (e) => setColors(Math.max(2, Math.min(32, parseInt(e.target.value, 10) || 2))) }),
|
|
2010
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: buttonClass11, "data-vector-trace-action": "", title: "Image Trace: pick an image to turn into paths", onClick: () => input.current?.click(), children: "Image\u2026" }),
|
|
2011
|
+
/* @__PURE__ */ jsx13(
|
|
2012
|
+
"input",
|
|
2013
|
+
{
|
|
2014
|
+
ref: input,
|
|
2015
|
+
type: "file",
|
|
2016
|
+
accept: "image/*",
|
|
2017
|
+
hidden: true,
|
|
2018
|
+
onChange: (e) => {
|
|
2019
|
+
const file = e.target.files?.[0];
|
|
2020
|
+
e.target.value = "";
|
|
2021
|
+
if (file) void trace(file);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
)
|
|
2025
|
+
] }),
|
|
2026
|
+
message && /* @__PURE__ */ jsx13("p", { className: "text-[11px] text-red-600", children: message })
|
|
2027
|
+
] });
|
|
2028
|
+
}
|
|
2029
|
+
|
|
1928
2030
|
// src/vector/VectorGradientEditor.tsx
|
|
1929
2031
|
import {
|
|
1930
2032
|
VECTOR_GRADIENT_TYPES,
|
|
@@ -1936,12 +2038,12 @@ import {
|
|
|
1936
2038
|
VECTOR_GRADIENT_INTERPOLATION_LABELS,
|
|
1937
2039
|
VECTOR_STROKE_GRADIENT_MODE_LABELS,
|
|
1938
2040
|
getVectorGradientEditor,
|
|
1939
|
-
vectorPaintToHex as
|
|
2041
|
+
vectorPaintToHex as vectorPaintToHex4
|
|
1940
2042
|
} from "@pixerate/editor/vector";
|
|
1941
|
-
import { Fragment as
|
|
1942
|
-
var
|
|
1943
|
-
var
|
|
1944
|
-
var
|
|
2043
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2044
|
+
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2045
|
+
var numberClass8 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
2046
|
+
var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded border border-border bg-background px-1.5 text-xs text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
1945
2047
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
1946
2048
|
function VectorGradientEditor({ controller, className }) {
|
|
1947
2049
|
const state = useVectorEditorState(controller);
|
|
@@ -1953,26 +2055,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1953
2055
|
const setType = (value) => {
|
|
1954
2056
|
if (value === "solid") {
|
|
1955
2057
|
const first = ed.stops[0];
|
|
1956
|
-
controller.setStyle({ [ed.target]:
|
|
2058
|
+
controller.setStyle({ [ed.target]: vectorPaintToHex4(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
1957
2059
|
} else controller.setGradient({ type: value });
|
|
1958
2060
|
};
|
|
1959
|
-
return /* @__PURE__ */
|
|
1960
|
-
/* @__PURE__ */
|
|
1961
|
-
/* @__PURE__ */
|
|
1962
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */
|
|
1963
|
-
ed.mixed && /* @__PURE__ */
|
|
2061
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
2062
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1.5", children: [
|
|
2063
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
2064
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
2065
|
+
ed.mixed && /* @__PURE__ */ jsx14("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1964
2066
|
] }),
|
|
1965
|
-
/* @__PURE__ */
|
|
1966
|
-
/* @__PURE__ */
|
|
1967
|
-
/* @__PURE__ */
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */
|
|
2067
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1.5", children: [
|
|
2068
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2069
|
+
/* @__PURE__ */ jsxs14("select", { "aria-label": "Gradient type", className: selectClass9, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2070
|
+
/* @__PURE__ */ jsx14("option", { value: "solid", children: "Solid" }),
|
|
2071
|
+
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ jsx14("option", { value: t, children: VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
1970
2072
|
] }),
|
|
1971
|
-
/* @__PURE__ */
|
|
2073
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
1972
2074
|
] }),
|
|
1973
|
-
g && /* @__PURE__ */
|
|
1974
|
-
/* @__PURE__ */
|
|
1975
|
-
/* @__PURE__ */
|
|
2075
|
+
g && /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
2076
|
+
/* @__PURE__ */ jsxs14("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
2077
|
+
/* @__PURE__ */ jsx14(
|
|
1976
2078
|
"div",
|
|
1977
2079
|
{
|
|
1978
2080
|
role: "button",
|
|
@@ -1986,7 +2088,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1986
2088
|
}
|
|
1987
2089
|
}
|
|
1988
2090
|
),
|
|
1989
|
-
ed.stops.map((s) => /* @__PURE__ */
|
|
2091
|
+
ed.stops.map((s) => /* @__PURE__ */ jsx14(
|
|
1990
2092
|
"button",
|
|
1991
2093
|
{
|
|
1992
2094
|
type: "button",
|
|
@@ -2000,21 +2102,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2000
2102
|
s.index
|
|
2001
2103
|
))
|
|
2002
2104
|
] }),
|
|
2003
|
-
sel && /* @__PURE__ */
|
|
2004
|
-
/* @__PURE__ */
|
|
2105
|
+
sel && /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
2106
|
+
/* @__PURE__ */ jsx14(
|
|
2005
2107
|
"input",
|
|
2006
2108
|
{
|
|
2007
2109
|
type: "color",
|
|
2008
2110
|
"aria-label": "Stop colour",
|
|
2009
2111
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2010
|
-
value:
|
|
2112
|
+
value: vectorPaintToHex4(sel.color) ?? "#000000",
|
|
2011
2113
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2012
2114
|
onBlur: end
|
|
2013
2115
|
}
|
|
2014
2116
|
),
|
|
2015
|
-
/* @__PURE__ */
|
|
2117
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2016
2118
|
"Opacity",
|
|
2017
|
-
/* @__PURE__ */
|
|
2119
|
+
/* @__PURE__ */ jsx14(
|
|
2018
2120
|
"input",
|
|
2019
2121
|
{
|
|
2020
2122
|
type: "number",
|
|
@@ -2022,7 +2124,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2022
2124
|
max: 100,
|
|
2023
2125
|
step: 5,
|
|
2024
2126
|
"aria-label": "Stop opacity",
|
|
2025
|
-
className:
|
|
2127
|
+
className: numberClass8,
|
|
2026
2128
|
value: percent(sel.opacity ?? 1),
|
|
2027
2129
|
onChange: (e) => {
|
|
2028
2130
|
const n = parseFloat(e.target.value);
|
|
@@ -2031,9 +2133,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2031
2133
|
}
|
|
2032
2134
|
)
|
|
2033
2135
|
] }),
|
|
2034
|
-
/* @__PURE__ */
|
|
2136
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2035
2137
|
"At",
|
|
2036
|
-
/* @__PURE__ */
|
|
2138
|
+
/* @__PURE__ */ jsx14(
|
|
2037
2139
|
"input",
|
|
2038
2140
|
{
|
|
2039
2141
|
type: "number",
|
|
@@ -2041,7 +2143,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2041
2143
|
max: 100,
|
|
2042
2144
|
step: 1,
|
|
2043
2145
|
"aria-label": "Stop position",
|
|
2044
|
-
className:
|
|
2146
|
+
className: numberClass8,
|
|
2045
2147
|
value: percent(sel.offset),
|
|
2046
2148
|
onChange: (e) => {
|
|
2047
2149
|
const n = parseFloat(e.target.value);
|
|
@@ -2050,9 +2152,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2050
2152
|
}
|
|
2051
2153
|
)
|
|
2052
2154
|
] }),
|
|
2053
|
-
!sel.last && /* @__PURE__ */
|
|
2155
|
+
!sel.last && /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2054
2156
|
"Midpoint",
|
|
2055
|
-
/* @__PURE__ */
|
|
2157
|
+
/* @__PURE__ */ jsx14(
|
|
2056
2158
|
"input",
|
|
2057
2159
|
{
|
|
2058
2160
|
type: "number",
|
|
@@ -2060,7 +2162,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2060
2162
|
max: 95,
|
|
2061
2163
|
step: 1,
|
|
2062
2164
|
"aria-label": "Stop midpoint",
|
|
2063
|
-
className:
|
|
2165
|
+
className: numberClass8,
|
|
2064
2166
|
value: percent(sel.midpoint ?? 0.5),
|
|
2065
2167
|
onChange: (e) => {
|
|
2066
2168
|
const n = parseFloat(e.target.value);
|
|
@@ -2069,15 +2171,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2069
2171
|
}
|
|
2070
2172
|
)
|
|
2071
2173
|
] }),
|
|
2072
|
-
/* @__PURE__ */
|
|
2174
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
2073
2175
|
] }),
|
|
2074
|
-
/* @__PURE__ */
|
|
2075
|
-
/* @__PURE__ */
|
|
2076
|
-
/* @__PURE__ */
|
|
2176
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2177
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16", children: "Colours" }),
|
|
2178
|
+
/* @__PURE__ */ jsx14("select", { "aria-label": "Gradient interpolation", className: selectClass9, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx14("option", { value: i, children: VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2077
2179
|
] }),
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */
|
|
2180
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2181
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16", children: "Smooth" }),
|
|
2182
|
+
/* @__PURE__ */ jsx14(
|
|
2081
2183
|
"input",
|
|
2082
2184
|
{
|
|
2083
2185
|
type: "range",
|
|
@@ -2093,23 +2195,23 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2093
2195
|
}
|
|
2094
2196
|
)
|
|
2095
2197
|
] }),
|
|
2096
|
-
/* @__PURE__ */
|
|
2097
|
-
/* @__PURE__ */
|
|
2098
|
-
/* @__PURE__ */
|
|
2198
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2199
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16", children: "Spread" }),
|
|
2200
|
+
/* @__PURE__ */ jsx14("select", { "aria-label": "Gradient spread", className: selectClass9, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ jsx14("option", { value: sp, children: VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2099
2201
|
] }),
|
|
2100
|
-
ed.target === "stroke" && /* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
2102
|
-
/* @__PURE__ */
|
|
2202
|
+
ed.target === "stroke" && /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2203
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16", children: "On stroke" }),
|
|
2204
|
+
/* @__PURE__ */ jsx14("select", { "aria-label": "Gradient on stroke", className: selectClass9, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ jsx14("option", { value: m, children: VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2103
2205
|
] })
|
|
2104
2206
|
] })
|
|
2105
2207
|
] });
|
|
2106
2208
|
}
|
|
2107
2209
|
|
|
2108
2210
|
// src/vector/VectorToolbar.tsx
|
|
2109
|
-
import { Fragment as
|
|
2211
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2110
2212
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
2111
2213
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
2112
|
-
var
|
|
2214
|
+
var buttonClass13 = "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";
|
|
2113
2215
|
function VectorToolbar({
|
|
2114
2216
|
controller,
|
|
2115
2217
|
tools = VECTOR_TOOLS,
|
|
@@ -2127,16 +2229,16 @@ function VectorToolbar({
|
|
|
2127
2229
|
const editing = state.editing;
|
|
2128
2230
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
2129
2231
|
const maskSelected = state.selection.some((id) => isVectorMaskGroup(controller.getNode(id)));
|
|
2130
|
-
const [live, setLive] =
|
|
2232
|
+
const [live, setLive] = React9.useState(false);
|
|
2131
2233
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2132
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */
|
|
2133
|
-
return /* @__PURE__ */
|
|
2134
|
-
/* @__PURE__ */
|
|
2234
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2235
|
+
return /* @__PURE__ */ jsxs15("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2236
|
+
/* @__PURE__ */ jsx15("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ jsx15(
|
|
2135
2237
|
"button",
|
|
2136
2238
|
{
|
|
2137
2239
|
type: "button",
|
|
2138
2240
|
"data-vector-tool": tool,
|
|
2139
|
-
className:
|
|
2241
|
+
className: buttonClass13,
|
|
2140
2242
|
"aria-pressed": state.tool === tool,
|
|
2141
2243
|
title: `${vectorToolLabel(tool)} (${VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2142
2244
|
"aria-label": vectorToolLabel(tool),
|
|
@@ -2145,17 +2247,17 @@ function VectorToolbar({
|
|
|
2145
2247
|
},
|
|
2146
2248
|
tool
|
|
2147
2249
|
)) }),
|
|
2148
|
-
showHistory && /* @__PURE__ */
|
|
2250
|
+
showHistory && /* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
2149
2251
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
2150
2252
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
2151
2253
|
] }),
|
|
2152
|
-
showSnap && /* @__PURE__ */
|
|
2153
|
-
/* @__PURE__ */
|
|
2254
|
+
showSnap && /* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2255
|
+
/* @__PURE__ */ jsx15(
|
|
2154
2256
|
"button",
|
|
2155
2257
|
{
|
|
2156
2258
|
type: "button",
|
|
2157
2259
|
"data-vector-snap": "",
|
|
2158
|
-
className:
|
|
2260
|
+
className: buttonClass13,
|
|
2159
2261
|
"aria-pressed": state.snap.objects,
|
|
2160
2262
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2161
2263
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -2163,7 +2265,7 @@ function VectorToolbar({
|
|
|
2163
2265
|
children: "Snap"
|
|
2164
2266
|
}
|
|
2165
2267
|
),
|
|
2166
|
-
/* @__PURE__ */
|
|
2268
|
+
/* @__PURE__ */ jsxs15(
|
|
2167
2269
|
"select",
|
|
2168
2270
|
{
|
|
2169
2271
|
"data-vector-polar": "",
|
|
@@ -2173,8 +2275,8 @@ function VectorToolbar({
|
|
|
2173
2275
|
value: String(vectorPolarIncrementOf(state.snap.angles) ?? ""),
|
|
2174
2276
|
onChange: (e) => controller.setSnap({ angles: vectorPolarAngles(Number(e.target.value)) }),
|
|
2175
2277
|
children: [
|
|
2176
|
-
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */
|
|
2177
|
-
[90, 45, 30, 15].map((n) => /* @__PURE__ */
|
|
2278
|
+
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */ jsx15("option", { value: "", children: "Custom" }),
|
|
2279
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ jsxs15("option", { value: n, children: [
|
|
2178
2280
|
n,
|
|
2179
2281
|
"\xB0"
|
|
2180
2282
|
] }, n))
|
|
@@ -2182,13 +2284,13 @@ function VectorToolbar({
|
|
|
2182
2284
|
}
|
|
2183
2285
|
)
|
|
2184
2286
|
] }),
|
|
2185
|
-
showPathEdit && /* @__PURE__ */
|
|
2186
|
-
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */
|
|
2287
|
+
showPathEdit && /* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2288
|
+
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ jsx15(
|
|
2187
2289
|
"button",
|
|
2188
2290
|
{
|
|
2189
2291
|
type: "button",
|
|
2190
2292
|
"data-vector-path-action": a.id,
|
|
2191
|
-
className:
|
|
2293
|
+
className: buttonClass13,
|
|
2192
2294
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
2193
2295
|
"aria-label": a.title,
|
|
2194
2296
|
disabled: !a.enabled(count, points),
|
|
@@ -2197,12 +2299,12 @@ function VectorToolbar({
|
|
|
2197
2299
|
},
|
|
2198
2300
|
a.id
|
|
2199
2301
|
)),
|
|
2200
|
-
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */
|
|
2302
|
+
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ jsx15(
|
|
2201
2303
|
"button",
|
|
2202
2304
|
{
|
|
2203
2305
|
type: "button",
|
|
2204
2306
|
"data-vector-edit": t.key,
|
|
2205
|
-
className:
|
|
2307
|
+
className: buttonClass13,
|
|
2206
2308
|
"aria-pressed": editing[t.key],
|
|
2207
2309
|
title: t.title,
|
|
2208
2310
|
"aria-label": t.title,
|
|
@@ -2211,9 +2313,9 @@ function VectorToolbar({
|
|
|
2211
2313
|
},
|
|
2212
2314
|
t.key
|
|
2213
2315
|
)),
|
|
2214
|
-
state.tool === "pencil" && /* @__PURE__ */
|
|
2316
|
+
state.tool === "pencil" && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2215
2317
|
"Smoothing",
|
|
2216
|
-
/* @__PURE__ */
|
|
2318
|
+
/* @__PURE__ */ jsx15(
|
|
2217
2319
|
"input",
|
|
2218
2320
|
{
|
|
2219
2321
|
type: "range",
|
|
@@ -2227,9 +2329,9 @@ function VectorToolbar({
|
|
|
2227
2329
|
}
|
|
2228
2330
|
)
|
|
2229
2331
|
] }),
|
|
2230
|
-
state.tool === "eraser" && /* @__PURE__ */
|
|
2332
|
+
state.tool === "eraser" && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2231
2333
|
"Size",
|
|
2232
|
-
/* @__PURE__ */
|
|
2334
|
+
/* @__PURE__ */ jsx15(
|
|
2233
2335
|
"input",
|
|
2234
2336
|
{
|
|
2235
2337
|
type: "number",
|
|
@@ -2245,12 +2347,12 @@ function VectorToolbar({
|
|
|
2245
2347
|
}
|
|
2246
2348
|
)
|
|
2247
2349
|
] }),
|
|
2248
|
-
state.tool === "paintBucket" && /* @__PURE__ */
|
|
2350
|
+
state.tool === "paintBucket" && /* @__PURE__ */ jsx15(
|
|
2249
2351
|
"button",
|
|
2250
2352
|
{
|
|
2251
2353
|
type: "button",
|
|
2252
2354
|
"data-vector-fill-gap": "",
|
|
2253
|
-
className:
|
|
2355
|
+
className: buttonClass13,
|
|
2254
2356
|
"aria-pressed": editing.fillGap > 0,
|
|
2255
2357
|
title: "Close small gaps between path ends when filling",
|
|
2256
2358
|
"aria-label": "Close gaps",
|
|
@@ -2259,12 +2361,12 @@ function VectorToolbar({
|
|
|
2259
2361
|
}
|
|
2260
2362
|
)
|
|
2261
2363
|
] }),
|
|
2262
|
-
showDistort && /* @__PURE__ */
|
|
2364
|
+
showDistort && /* @__PURE__ */ jsx15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ jsx15(
|
|
2263
2365
|
"button",
|
|
2264
2366
|
{
|
|
2265
2367
|
type: "button",
|
|
2266
2368
|
"data-vector-free-distort": "",
|
|
2267
|
-
className:
|
|
2369
|
+
className: buttonClass13,
|
|
2268
2370
|
"aria-pressed": state.freeDistort,
|
|
2269
2371
|
title: `Free Distort: drag a corner of the selection box to distort in perspective (Shift+Alt+${modKeyLabel()}: symmetric perspective; ${modKeyLabel()}-drag a side to skew)`,
|
|
2270
2372
|
"aria-label": "Free Distort",
|
|
@@ -2272,15 +2374,15 @@ function VectorToolbar({
|
|
|
2272
2374
|
children: "Distort"
|
|
2273
2375
|
}
|
|
2274
2376
|
) }),
|
|
2275
|
-
showBlend && /* @__PURE__ */
|
|
2276
|
-
showArrange && /* @__PURE__ */
|
|
2277
|
-
/* @__PURE__ */
|
|
2278
|
-
/* @__PURE__ */
|
|
2377
|
+
showBlend && /* @__PURE__ */ jsx15(VectorBlendControls, { controller }),
|
|
2378
|
+
showArrange && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
2379
|
+
/* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2380
|
+
/* @__PURE__ */ jsx15(
|
|
2279
2381
|
"button",
|
|
2280
2382
|
{
|
|
2281
2383
|
type: "button",
|
|
2282
2384
|
"data-vector-live-boolean": "",
|
|
2283
|
-
className:
|
|
2385
|
+
className: buttonClass13,
|
|
2284
2386
|
"aria-pressed": live,
|
|
2285
2387
|
title: "Live booleans: keep the shapes editable",
|
|
2286
2388
|
"aria-label": "Live booleans",
|
|
@@ -2297,12 +2399,12 @@ function VectorToolbar({
|
|
|
2297
2399
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2298
2400
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2299
2401
|
] }),
|
|
2300
|
-
/* @__PURE__ */
|
|
2402
|
+
/* @__PURE__ */ jsx15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ jsx15(
|
|
2301
2403
|
"button",
|
|
2302
2404
|
{
|
|
2303
2405
|
type: "button",
|
|
2304
2406
|
"data-vector-pathfinder": a.id,
|
|
2305
|
-
className:
|
|
2407
|
+
className: buttonClass13,
|
|
2306
2408
|
title: a.title,
|
|
2307
2409
|
"aria-label": a.title,
|
|
2308
2410
|
disabled: count < a.min,
|
|
@@ -2311,7 +2413,7 @@ function VectorToolbar({
|
|
|
2311
2413
|
},
|
|
2312
2414
|
a.id
|
|
2313
2415
|
)) }),
|
|
2314
|
-
/* @__PURE__ */
|
|
2416
|
+
/* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
2315
2417
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
2316
2418
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
2317
2419
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -2329,19 +2431,19 @@ function VectorBlendControls({ controller }) {
|
|
|
2329
2431
|
const blend = getVectorBlendControls(state);
|
|
2330
2432
|
const o = blend.options;
|
|
2331
2433
|
const selected = blend.ids.length > 0;
|
|
2332
|
-
return /* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2334
|
-
/* @__PURE__ */
|
|
2434
|
+
return /* @__PURE__ */ jsxs15("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2435
|
+
/* @__PURE__ */ jsx15("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass13, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
2436
|
+
/* @__PURE__ */ jsx15(
|
|
2335
2437
|
"select",
|
|
2336
2438
|
{
|
|
2337
2439
|
"aria-label": "Blend spacing",
|
|
2338
2440
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2339
2441
|
value: o.spacing,
|
|
2340
2442
|
onChange: (e) => applyVectorBlendOptions(controller, { spacing: e.target.value }),
|
|
2341
|
-
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */
|
|
2443
|
+
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ jsx15("option", { value: sp, children: VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2342
2444
|
}
|
|
2343
2445
|
),
|
|
2344
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */
|
|
2446
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ jsx15(
|
|
2345
2447
|
"input",
|
|
2346
2448
|
{
|
|
2347
2449
|
type: "number",
|
|
@@ -2357,12 +2459,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2357
2459
|
}
|
|
2358
2460
|
}
|
|
2359
2461
|
),
|
|
2360
|
-
/* @__PURE__ */
|
|
2462
|
+
/* @__PURE__ */ jsx15(
|
|
2361
2463
|
"button",
|
|
2362
2464
|
{
|
|
2363
2465
|
type: "button",
|
|
2364
2466
|
"data-vector-blend-action": "orient",
|
|
2365
|
-
className:
|
|
2467
|
+
className: buttonClass13,
|
|
2366
2468
|
"aria-pressed": o.orientToSpine,
|
|
2367
2469
|
title: "Orient steps to the spine",
|
|
2368
2470
|
"aria-label": "Orient to spine",
|
|
@@ -2370,12 +2472,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2370
2472
|
children: "\u293F"
|
|
2371
2473
|
}
|
|
2372
2474
|
),
|
|
2373
|
-
/* @__PURE__ */
|
|
2475
|
+
/* @__PURE__ */ jsx15(
|
|
2374
2476
|
"button",
|
|
2375
2477
|
{
|
|
2376
2478
|
type: "button",
|
|
2377
2479
|
"data-vector-blend-action": "spine",
|
|
2378
|
-
className:
|
|
2480
|
+
className: buttonClass13,
|
|
2379
2481
|
title: "Replace Spine (select a blend and a path)",
|
|
2380
2482
|
"aria-label": "Replace Spine",
|
|
2381
2483
|
disabled: !blend.canReplaceSpine,
|
|
@@ -2383,12 +2485,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2383
2485
|
children: "\u2307"
|
|
2384
2486
|
}
|
|
2385
2487
|
),
|
|
2386
|
-
/* @__PURE__ */
|
|
2387
|
-
/* @__PURE__ */
|
|
2488
|
+
/* @__PURE__ */ jsx15("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass13, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2489
|
+
/* @__PURE__ */ jsx15("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass13, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
2388
2490
|
] });
|
|
2389
2491
|
}
|
|
2390
|
-
var
|
|
2391
|
-
var
|
|
2492
|
+
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2493
|
+
var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2392
2494
|
function VectorStylePanel({ controller, className }) {
|
|
2393
2495
|
const state = useVectorEditorState(controller);
|
|
2394
2496
|
const style = getVectorSelectionStyle(state);
|
|
@@ -2420,17 +2522,17 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2420
2522
|
if (style) controller.setWidthProfile(id);
|
|
2421
2523
|
else controller.setDefaults({ strokeWidthProfile: widthProfilePreset(id)?.length ? widthProfilePreset(id) : null });
|
|
2422
2524
|
};
|
|
2423
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */
|
|
2525
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ jsx15("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2424
2526
|
const arrowRow = (end, label) => {
|
|
2425
2527
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
2426
2528
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
2427
|
-
return /* @__PURE__ */
|
|
2428
|
-
/* @__PURE__ */
|
|
2429
|
-
/* @__PURE__ */
|
|
2430
|
-
/* @__PURE__ */
|
|
2431
|
-
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */
|
|
2529
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2530
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2531
|
+
/* @__PURE__ */ jsxs15("select", { "aria-label": `${label} arrowhead`, className: selectClass10, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2532
|
+
/* @__PURE__ */ jsx15("option", { value: "", children: "None" }),
|
|
2533
|
+
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ jsx15("option", { value: h, children: VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2432
2534
|
] }),
|
|
2433
|
-
/* @__PURE__ */
|
|
2535
|
+
/* @__PURE__ */ jsx15(
|
|
2434
2536
|
"input",
|
|
2435
2537
|
{
|
|
2436
2538
|
type: "number",
|
|
@@ -2438,7 +2540,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2438
2540
|
step: 0.25,
|
|
2439
2541
|
"aria-label": `${label} arrowhead scale`,
|
|
2440
2542
|
title: "Scale (\xD7 stroke width)",
|
|
2441
|
-
className:
|
|
2543
|
+
className: numberClass9,
|
|
2442
2544
|
value: source[scaleKey],
|
|
2443
2545
|
onChange: (e) => {
|
|
2444
2546
|
const n = parseFloat(e.target.value);
|
|
@@ -2454,14 +2556,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2454
2556
|
};
|
|
2455
2557
|
const paintRow = (key, label) => {
|
|
2456
2558
|
const paint = source[key];
|
|
2457
|
-
const hex =
|
|
2559
|
+
const hex = vectorPaintToHex5(paint);
|
|
2458
2560
|
const on = paint !== null && paint !== "none";
|
|
2459
|
-
return /* @__PURE__ */
|
|
2460
|
-
/* @__PURE__ */
|
|
2461
|
-
/* @__PURE__ */
|
|
2561
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2562
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2563
|
+
/* @__PURE__ */ jsx15("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
2462
2564
|
label
|
|
2463
2565
|
] }),
|
|
2464
|
-
/* @__PURE__ */
|
|
2566
|
+
/* @__PURE__ */ jsx15(
|
|
2465
2567
|
"input",
|
|
2466
2568
|
{
|
|
2467
2569
|
type: "color",
|
|
@@ -2472,18 +2574,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2472
2574
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
2473
2575
|
}
|
|
2474
2576
|
),
|
|
2475
|
-
on && !hex && /* @__PURE__ */
|
|
2476
|
-
style?.mixed[key] && /* @__PURE__ */
|
|
2577
|
+
on && !hex && /* @__PURE__ */ jsx15("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2578
|
+
style?.mixed[key] && /* @__PURE__ */ jsx15("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2477
2579
|
] });
|
|
2478
2580
|
};
|
|
2479
|
-
return /* @__PURE__ */
|
|
2480
|
-
/* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsxs15("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2582
|
+
/* @__PURE__ */ jsx15("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
2481
2583
|
paintRow("fill", "Fill"),
|
|
2482
2584
|
paintRow("stroke", "Stroke"),
|
|
2483
|
-
style && /* @__PURE__ */
|
|
2484
|
-
/* @__PURE__ */
|
|
2485
|
-
/* @__PURE__ */
|
|
2486
|
-
/* @__PURE__ */
|
|
2585
|
+
style && /* @__PURE__ */ jsx15(VectorGradientEditor, { controller }),
|
|
2586
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2587
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Width" }),
|
|
2588
|
+
/* @__PURE__ */ jsx15(
|
|
2487
2589
|
"input",
|
|
2488
2590
|
{
|
|
2489
2591
|
type: "number",
|
|
@@ -2499,33 +2601,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2499
2601
|
}
|
|
2500
2602
|
)
|
|
2501
2603
|
] }),
|
|
2502
|
-
/* @__PURE__ */
|
|
2503
|
-
/* @__PURE__ */
|
|
2504
|
-
/* @__PURE__ */
|
|
2604
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2605
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Align" }),
|
|
2606
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Stroke alignment", className: selectClass10, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(VECTOR_STROKE_ALIGN_LABELS2).map((a) => /* @__PURE__ */ jsx15("option", { value: a, children: VECTOR_STROKE_ALIGN_LABELS2[a] }, a)) }),
|
|
2505
2607
|
mixed("strokeAlign")
|
|
2506
2608
|
] }),
|
|
2507
|
-
/* @__PURE__ */
|
|
2508
|
-
/* @__PURE__ */
|
|
2509
|
-
/* @__PURE__ */
|
|
2609
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2610
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Profile" }),
|
|
2611
|
+
/* @__PURE__ */ jsxs15(
|
|
2510
2612
|
"select",
|
|
2511
2613
|
{
|
|
2512
2614
|
"aria-label": "Width profile",
|
|
2513
|
-
className:
|
|
2615
|
+
className: selectClass10,
|
|
2514
2616
|
value: source.widthProfile,
|
|
2515
2617
|
onChange: (e) => {
|
|
2516
2618
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2517
2619
|
},
|
|
2518
2620
|
children: [
|
|
2519
|
-
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */
|
|
2520
|
-
source.widthProfile === "custom" && /* @__PURE__ */
|
|
2621
|
+
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ jsx15("option", { value: p.id, children: p.label }, p.id)),
|
|
2622
|
+
source.widthProfile === "custom" && /* @__PURE__ */ jsx15("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2521
2623
|
]
|
|
2522
2624
|
}
|
|
2523
2625
|
),
|
|
2524
|
-
/* @__PURE__ */
|
|
2626
|
+
/* @__PURE__ */ jsx15(
|
|
2525
2627
|
"button",
|
|
2526
2628
|
{
|
|
2527
2629
|
type: "button",
|
|
2528
|
-
className:
|
|
2630
|
+
className: buttonClass13,
|
|
2529
2631
|
title: "Reset to uniform width",
|
|
2530
2632
|
"aria-label": "Reset to uniform width",
|
|
2531
2633
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -2535,27 +2637,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2535
2637
|
),
|
|
2536
2638
|
mixed("widthProfile")
|
|
2537
2639
|
] }),
|
|
2538
|
-
source.hasOpenPath && /* @__PURE__ */
|
|
2640
|
+
source.hasOpenPath && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
2539
2641
|
arrowRow("start", "Start"),
|
|
2540
2642
|
arrowRow("end", "End"),
|
|
2541
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */
|
|
2542
|
-
/* @__PURE__ */
|
|
2543
|
-
/* @__PURE__ */
|
|
2544
|
-
/* @__PURE__ */
|
|
2545
|
-
/* @__PURE__ */
|
|
2643
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2644
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Heads" }),
|
|
2645
|
+
/* @__PURE__ */ jsxs15("select", { "aria-label": "Arrowhead alignment", className: selectClass10, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2646
|
+
/* @__PURE__ */ jsx15("option", { value: "extend", children: "Tip past end" }),
|
|
2647
|
+
/* @__PURE__ */ jsx15("option", { value: "tip", children: "Tip at end" })
|
|
2546
2648
|
] })
|
|
2547
2649
|
] })
|
|
2548
2650
|
] }),
|
|
2549
|
-
source.corners > 0 && /* @__PURE__ */
|
|
2550
|
-
/* @__PURE__ */
|
|
2551
|
-
/* @__PURE__ */
|
|
2651
|
+
source.corners > 0 && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2652
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2653
|
+
/* @__PURE__ */ jsx15(
|
|
2552
2654
|
"input",
|
|
2553
2655
|
{
|
|
2554
2656
|
type: "number",
|
|
2555
2657
|
min: 0,
|
|
2556
2658
|
step: 1,
|
|
2557
2659
|
"aria-label": "Corner radius",
|
|
2558
|
-
className:
|
|
2660
|
+
className: numberClass9,
|
|
2559
2661
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
2560
2662
|
onChange: (e) => {
|
|
2561
2663
|
const n = parseFloat(e.target.value);
|
|
@@ -2563,12 +2665,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2563
2665
|
}
|
|
2564
2666
|
}
|
|
2565
2667
|
),
|
|
2566
|
-
/* @__PURE__ */
|
|
2668
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Corner kind", className: selectClass10, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ jsx15("option", { value: k, children: VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2567
2669
|
mixed("cornerRadius")
|
|
2568
2670
|
] }),
|
|
2569
|
-
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
2671
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "corner-smoothing", title: "Corner smoothing: squircle corners that ease into the curve (0.6 is iOS-like)", children: [
|
|
2672
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Smoothing" }),
|
|
2673
|
+
/* @__PURE__ */ jsx15(
|
|
2572
2674
|
"input",
|
|
2573
2675
|
{
|
|
2574
2676
|
type: "range",
|
|
@@ -2583,9 +2685,9 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2583
2685
|
}
|
|
2584
2686
|
)
|
|
2585
2687
|
] }),
|
|
2586
|
-
style && /* @__PURE__ */
|
|
2587
|
-
/* @__PURE__ */
|
|
2588
|
-
/* @__PURE__ */
|
|
2688
|
+
style && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2689
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Opacity" }),
|
|
2690
|
+
/* @__PURE__ */ jsx15(
|
|
2589
2691
|
"input",
|
|
2590
2692
|
{
|
|
2591
2693
|
type: "range",
|
|
@@ -2599,26 +2701,28 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2599
2701
|
}
|
|
2600
2702
|
)
|
|
2601
2703
|
] }),
|
|
2602
|
-
/* @__PURE__ */
|
|
2603
|
-
style && /* @__PURE__ */
|
|
2604
|
-
style && /* @__PURE__ */
|
|
2605
|
-
style && /* @__PURE__ */
|
|
2606
|
-
style && /* @__PURE__ */
|
|
2607
|
-
/* @__PURE__ */
|
|
2608
|
-
/* @__PURE__ */
|
|
2609
|
-
/* @__PURE__ */
|
|
2610
|
-
/* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ jsx15(VectorTextPanel, { controller }),
|
|
2705
|
+
style && /* @__PURE__ */ jsx15(VectorAppearancePanel, { controller }),
|
|
2706
|
+
style && /* @__PURE__ */ jsx15(VectorEffectsPanel, { controller }),
|
|
2707
|
+
style && /* @__PURE__ */ jsx15(VectorEnvelopePanel, { controller }),
|
|
2708
|
+
style && /* @__PURE__ */ jsx15(VectorMaskPanel, { controller }),
|
|
2709
|
+
/* @__PURE__ */ jsx15(VectorFramePanel, { controller }),
|
|
2710
|
+
/* @__PURE__ */ jsx15(VectorConnectorPanel, { controller }),
|
|
2711
|
+
/* @__PURE__ */ jsx15(VectorShadingPanel, { controller }),
|
|
2712
|
+
/* @__PURE__ */ jsx15(VectorTracePanel, { controller }),
|
|
2713
|
+
/* @__PURE__ */ jsx15(VectorConstraintsPanel, { controller }),
|
|
2714
|
+
/* @__PURE__ */ jsx15(VectorSymbolsPanel, { controller })
|
|
2611
2715
|
] });
|
|
2612
2716
|
}
|
|
2613
2717
|
|
|
2614
2718
|
// src/vector/VectorEditor.tsx
|
|
2615
|
-
import { jsx as
|
|
2719
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2616
2720
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
2617
|
-
return /* @__PURE__ */
|
|
2618
|
-
/* @__PURE__ */
|
|
2619
|
-
/* @__PURE__ */
|
|
2620
|
-
/* @__PURE__ */
|
|
2621
|
-
showStylePanel && /* @__PURE__ */
|
|
2721
|
+
return /* @__PURE__ */ jsxs16("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
2722
|
+
/* @__PURE__ */ jsx16(VectorToolbar, { controller, tools }),
|
|
2723
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
2724
|
+
/* @__PURE__ */ jsx16("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ jsx16(VectorCanvas, { controller, ...canvasProps }) }),
|
|
2725
|
+
showStylePanel && /* @__PURE__ */ jsx16(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
2622
2726
|
] })
|
|
2623
2727
|
] });
|
|
2624
2728
|
}
|
|
@@ -2638,11 +2742,13 @@ export {
|
|
|
2638
2742
|
VectorMaskPanel,
|
|
2639
2743
|
VectorMaskedNodes,
|
|
2640
2744
|
VectorSceneNodes,
|
|
2745
|
+
VectorShadingPanel,
|
|
2641
2746
|
VectorStylePanel,
|
|
2642
2747
|
VectorSymbolsPanel,
|
|
2643
2748
|
VectorTextElement,
|
|
2644
2749
|
VectorTextPanel,
|
|
2645
2750
|
VectorToolbar,
|
|
2751
|
+
VectorTracePanel,
|
|
2646
2752
|
VectorWidthPointEditor,
|
|
2647
2753
|
useVectorCommands,
|
|
2648
2754
|
useVectorEditor,
|