@pixerate/editor-react 0.75.0 → 0.76.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 +254 -220
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +12 -1
- package/dist/vector/index.d.ts +12 -1
- package/dist/vector/index.js +260 -226
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -48,6 +48,7 @@ __export(vector_exports, {
|
|
|
48
48
|
VectorShadingPanel: () => VectorShadingPanel,
|
|
49
49
|
VectorStylePanel: () => VectorStylePanel,
|
|
50
50
|
VectorSymbolsPanel: () => VectorSymbolsPanel,
|
|
51
|
+
VectorSymmetryPanel: () => VectorSymmetryPanel,
|
|
51
52
|
VectorTextElement: () => VectorTextElement,
|
|
52
53
|
VectorTextPanel: () => VectorTextPanel,
|
|
53
54
|
VectorToolbar: () => VectorToolbar,
|
|
@@ -277,48 +278,19 @@ function VectorTextElement({ node }) {
|
|
|
277
278
|
)) });
|
|
278
279
|
}
|
|
279
280
|
function VectorSceneNodes({ nodes }) {
|
|
280
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map(
|
|
281
|
-
(node) => node.kind === "text" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorTextElement, { node }, node.id) : node.kind === "group" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
282
|
-
"g",
|
|
283
|
-
{
|
|
284
|
-
"data-vector-id": node.id,
|
|
285
|
-
"data-vector-mask": node.mask?.type,
|
|
286
|
-
transform: node.transform,
|
|
287
|
-
opacity: node.opacity < 1 ? node.opacity : void 0,
|
|
288
|
-
filter: node.filter,
|
|
289
|
-
style: blendStyle(node.blendMode),
|
|
290
|
-
children: node.mask ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorMaskedNodes, { mask: node.mask, nodes: node.children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: node.children })
|
|
291
|
-
},
|
|
292
|
-
node.id
|
|
293
|
-
) : node.layers ? (
|
|
294
|
-
// Fill and stroke stacks: each layer in order, bottom to top.
|
|
295
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
296
|
-
"g",
|
|
297
|
-
{
|
|
298
|
-
"data-vector-id": node.id,
|
|
299
|
-
transform: node.transform,
|
|
300
|
-
opacity: node.opacity < 1 ? node.opacity : void 0,
|
|
301
|
-
filter: node.filter,
|
|
302
|
-
style: blendStyle(node.blendMode),
|
|
303
|
-
children: node.layers.map((layer) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorPaintPath, { paint: layer, d: node.d, fillRule: node.fillRule, layer: `${layer.kind}-${layer.index}` }, `${layer.kind}-${layer.index}`))
|
|
304
|
-
},
|
|
305
|
-
node.id
|
|
306
|
-
)
|
|
307
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
308
|
-
VectorPaintPath,
|
|
309
|
-
{
|
|
310
|
-
paint: node,
|
|
311
|
-
d: node.d,
|
|
312
|
-
fillRule: node.fillRule,
|
|
313
|
-
id: node.id,
|
|
314
|
-
transform: node.transform,
|
|
315
|
-
filter: node.filter,
|
|
316
|
-
blendMode: node.blendMode
|
|
317
|
-
},
|
|
318
|
-
node.id
|
|
319
|
-
)
|
|
320
|
-
) });
|
|
281
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNode, { node }, node.id)) });
|
|
321
282
|
}
|
|
283
|
+
var VectorSceneNode = import_react3.default.memo(function VectorSceneNode2({ node }) {
|
|
284
|
+
if (node.kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorTextElement, { node });
|
|
285
|
+
if (node.kind === "group")
|
|
286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)(VectorMaskedNodes, { mask: node.mask, nodes: node.children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: node.children }) });
|
|
287
|
+
if (node.layers)
|
|
288
|
+
return (
|
|
289
|
+
// Fill and stroke stacks: each layer in order, bottom to top.
|
|
290
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)(VectorPaintPath, { paint: layer, d: node.d, fillRule: node.fillRule, layer: `${layer.kind}-${layer.index}` }, `${layer.kind}-${layer.index}`)) })
|
|
291
|
+
);
|
|
292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorPaintPath, { paint: node, d: node.d, fillRule: node.fillRule, id: node.id, transform: node.transform, filter: node.filter, blendMode: node.blendMode });
|
|
293
|
+
});
|
|
322
294
|
function VectorMaskedNodes({ mask, nodes }) {
|
|
323
295
|
const b = mask.bounds;
|
|
324
296
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
@@ -413,7 +385,8 @@ function VectorCanvas({
|
|
|
413
385
|
const editingText = state.textEdit?.nodeId ?? null;
|
|
414
386
|
const fitted = (0, import_react3.useRef)(!fitOnMount);
|
|
415
387
|
const uid = (0, import_react3.useId)().replace(/:/g, "");
|
|
416
|
-
const
|
|
388
|
+
const [size, setSize] = (0, import_react3.useState)(null);
|
|
389
|
+
const scene = (0, import_vector3.getVectorSceneRenderData)(state, { idPrefix: `ve${uid}-`, ...size ? { viewportSize: size } : {} });
|
|
417
390
|
const overlay = (0, import_vector3.getVectorOverlayRenderData)(state);
|
|
418
391
|
const host = (0, import_vector3.getVectorSymbolEditBackground)(state, { idPrefix: `ve${uid}-host-` });
|
|
419
392
|
(0, import_react3.useEffect)(() => {
|
|
@@ -431,6 +404,18 @@ function VectorCanvas({
|
|
|
431
404
|
observer.observe(el);
|
|
432
405
|
return () => observer.disconnect();
|
|
433
406
|
}, [controller]);
|
|
407
|
+
(0, import_react3.useEffect)(() => {
|
|
408
|
+
const el = svgRef.current;
|
|
409
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
410
|
+
const measure = () => {
|
|
411
|
+
const r = el.getBoundingClientRect();
|
|
412
|
+
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 });
|
|
413
|
+
};
|
|
414
|
+
measure();
|
|
415
|
+
const observer = new ResizeObserver(measure);
|
|
416
|
+
observer.observe(el);
|
|
417
|
+
return () => observer.disconnect();
|
|
418
|
+
}, []);
|
|
434
419
|
(0, import_react3.useEffect)(() => {
|
|
435
420
|
if (!editingText) return;
|
|
436
421
|
const t = setTimeout(() => textRef.current?.focus({ preventScroll: true }), 0);
|
|
@@ -566,8 +551,8 @@ function VectorCanvas({
|
|
|
566
551
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: h.x, cy: h.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + (h.hovered || h.active ? 1 : 0), fill: h.active ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor })
|
|
567
552
|
] }, h.index)),
|
|
568
553
|
overlay.envelope.anchors.map((a) => {
|
|
569
|
-
const
|
|
570
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { "data-vector-envelope-anchor": a.index, x: a.x -
|
|
554
|
+
const size2 = as + (a.hovered || a.active ? 2 : 0);
|
|
555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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 : import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, a.index);
|
|
571
556
|
})
|
|
572
557
|
] }),
|
|
573
558
|
overlay.handles.map((h) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-handle": h.ref.handle, children: [
|
|
@@ -575,10 +560,10 @@ function VectorCanvas({
|
|
|
575
560
|
/* @__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 })
|
|
576
561
|
] }, `${h.ref.nodeId}:${h.ref.subpath}:${h.ref.index}:${h.ref.handle}`)),
|
|
577
562
|
overlay.anchors.map((a) => {
|
|
578
|
-
const
|
|
563
|
+
const size2 = as + (a.hovered ? 2 : 0);
|
|
579
564
|
const fill = a.selected ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill;
|
|
580
565
|
const key = `${a.ref.nodeId}:${a.ref.subpath}:${a.ref.index}`;
|
|
581
|
-
return a.type === "corner" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { "data-vector-anchor": a.ref.index, x: a.x -
|
|
566
|
+
return a.type === "corner" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-anchor": a.ref.index, cx: a.x, cy: a.y, r: size2 / 2, fill, stroke: accentColor }, key);
|
|
582
567
|
}),
|
|
583
568
|
overlay.cornerWidgets.map((w) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-corner-widget": w.ref.index, "data-corner-kind": w.kind, children: [
|
|
584
569
|
/* @__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 }),
|
|
@@ -699,6 +684,7 @@ function VectorCanvas({
|
|
|
699
684
|
sh.lines.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d, stroke: accentColor, strokeWidth: 1, opacity: 0.7 }, i)),
|
|
700
685
|
sh.points.map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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))
|
|
701
686
|
] }, `shading:${sh.nodeId}`)),
|
|
687
|
+
overlay.symmetry.map((sy) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-symmetry-axes": sy.nodeId, stroke: accentColor, strokeDasharray: sy.drawing ? void 0 : "6 4", opacity: sy.drawing ? 0.9 : 0.6, children: sy.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: l.x1, y1: l.y1, x2: l.x2, y2: l.y2 }, i)) }, `sym:${sy.nodeId}`)),
|
|
702
688
|
overlay.trackingPoints.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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}`)),
|
|
703
689
|
overlay.typedEntry && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
704
690
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: -3, y: -12, width: overlay.typedEntry.text.length * 7 + 8, height: 17, rx: 3, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
@@ -835,7 +821,7 @@ function VectorCanvas({
|
|
|
835
821
|
|
|
836
822
|
// src/vector/VectorToolbar.tsx
|
|
837
823
|
var import_react10 = __toESM(require("react"), 1);
|
|
838
|
-
var
|
|
824
|
+
var import_vector16 = require("@pixerate/editor/vector");
|
|
839
825
|
|
|
840
826
|
// src/vector/VectorEffectsPanel.tsx
|
|
841
827
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -925,6 +911,15 @@ function VectorEffectsPanel({ controller, className }) {
|
|
|
925
911
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "min-w-0 flex-1 truncate", children: spec.label }),
|
|
926
912
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label}`, checked: !!e.params[spec.key], onChange: (ev) => set(e, spec.key, ev.target.checked, false) })
|
|
927
913
|
] }, spec.key);
|
|
914
|
+
if (spec.kind === "color") {
|
|
915
|
+
const c = e.params[spec.key];
|
|
916
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
|
|
917
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClass, children: spec.label }),
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label} on`, checked: c !== null, onChange: (ev) => set(e, spec.key, ev.target.checked ? "#ffffff" : null, false) }),
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "color", "aria-label": `${e.label} ${spec.label}`, className: "h-6 w-8 cursor-pointer rounded border border-border bg-background disabled:opacity-40", disabled: c === null, value: (0, import_vector4.vectorPaintToHex)(c ?? "#ffffff") ?? "#ffffff", onChange: (ev) => set(e, spec.key, ev.target.value, true), onBlur: end })
|
|
920
|
+
] }, spec.key);
|
|
921
|
+
}
|
|
922
|
+
if (spec.kind !== "select") return null;
|
|
928
923
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
|
|
929
924
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClass, children: spec.label }),
|
|
930
925
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": `${e.label} ${spec.label}`, className: selectClass, value: String(e.params[spec.key] ?? ""), onChange: (ev) => set(e, spec.key, ev.target.value, false), children: spec.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: o.value, children: o.label }, o.value)) })
|
|
@@ -2040,16 +2035,53 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2040
2035
|
] });
|
|
2041
2036
|
}
|
|
2042
2037
|
|
|
2043
|
-
// src/vector/
|
|
2038
|
+
// src/vector/VectorSymmetryPanel.tsx
|
|
2044
2039
|
var import_vector14 = require("@pixerate/editor/vector");
|
|
2045
2040
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2041
|
+
var buttonClass12 = "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";
|
|
2046
2042
|
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2047
|
-
var numberClass8 = "h-7 w-
|
|
2048
|
-
|
|
2043
|
+
var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
2044
|
+
function VectorSymmetryPanel({ controller, className }) {
|
|
2045
|
+
const state = useVectorEditorState(controller);
|
|
2046
|
+
const group = state.selection.map((id) => controller.getNode(id)).find(import_vector14.isVectorSymmetryGroup) ?? null;
|
|
2047
|
+
const s = group?.symmetry;
|
|
2048
|
+
const ids = group ? [group.id] : void 0;
|
|
2049
|
+
const drawing = !!group && state.symmetryTarget === group.id;
|
|
2050
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symmetry-panel": "", "aria-label": "Symmetry", children: [
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Symmetry" }),
|
|
2053
|
+
!group && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
|
|
2054
|
+
!group && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
|
|
2055
|
+
group && s && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass9, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector14.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: m, children: import_vector14.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
|
|
2057
|
+
s.mode === "radial" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "checkbox", "aria-label": "Mirror copies", checked: !!s.mirror, onChange: (e) => controller.setSymmetry({ mirror: e.target.checked }, { ids }) }),
|
|
2061
|
+
"Mirror"
|
|
2062
|
+
] })
|
|
2063
|
+
] })
|
|
2064
|
+
] })
|
|
2065
|
+
] }),
|
|
2066
|
+
group && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16" }),
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "aria-pressed": drawing, "data-vector-symmetry-action": "draw", title: "Draw inside: new pen, pencil, shape and text art goes into the group, mirrored as you draw (Escape stops)", onClick: () => drawing ? controller.exitSymmetry() : controller.enterSymmetry(group.id), children: "Draw inside" }),
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, title: "Expand: keep the copies as real objects", onClick: () => controller.releaseSymmetry({ ids, expand: true }), children: "Expand" }),
|
|
2070
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, title: "Release: stop repeating (the copies go)", onClick: () => controller.releaseSymmetry({ ids }), children: "Release" })
|
|
2071
|
+
] })
|
|
2072
|
+
] });
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// src/vector/VectorGradientEditor.tsx
|
|
2076
|
+
var import_vector15 = require("@pixerate/editor/vector");
|
|
2077
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2078
|
+
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2079
|
+
var numberClass9 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
2080
|
+
var buttonClass13 = "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";
|
|
2049
2081
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
2050
2082
|
function VectorGradientEditor({ controller, className }) {
|
|
2051
2083
|
const state = useVectorEditorState(controller);
|
|
2052
|
-
const ed = (0,
|
|
2084
|
+
const ed = (0, import_vector15.getVectorGradientEditor)(state);
|
|
2053
2085
|
if (!ed) return null;
|
|
2054
2086
|
const g = ed.gradient;
|
|
2055
2087
|
const sel = ed.selected;
|
|
@@ -2057,26 +2089,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2057
2089
|
const setType = (value) => {
|
|
2058
2090
|
if (value === "solid") {
|
|
2059
2091
|
const first = ed.stops[0];
|
|
2060
|
-
controller.setStyle({ [ed.target]: (0,
|
|
2092
|
+
controller.setStyle({ [ed.target]: (0, import_vector15.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
2061
2093
|
} else controller.setGradient({ type: value });
|
|
2062
2094
|
};
|
|
2063
|
-
return /* @__PURE__ */ (0,
|
|
2064
|
-
/* @__PURE__ */ (0,
|
|
2065
|
-
/* @__PURE__ */ (0,
|
|
2066
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */ (0,
|
|
2067
|
-
ed.mixed && /* @__PURE__ */ (0,
|
|
2095
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
2098
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
2099
|
+
ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2068
2100
|
] }),
|
|
2069
|
-
/* @__PURE__ */ (0,
|
|
2070
|
-
/* @__PURE__ */ (0,
|
|
2071
|
-
/* @__PURE__ */ (0,
|
|
2072
|
-
/* @__PURE__ */ (0,
|
|
2073
|
-
|
|
2101
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2102
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2103
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("select", { "aria-label": "Gradient type", className: selectClass10, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "solid", children: "Solid" }),
|
|
2105
|
+
import_vector15.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: t, children: import_vector15.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
2074
2106
|
] }),
|
|
2075
|
-
/* @__PURE__ */ (0,
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
2076
2108
|
] }),
|
|
2077
|
-
g && /* @__PURE__ */ (0,
|
|
2078
|
-
/* @__PURE__ */ (0,
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
2109
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2110
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
2111
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2080
2112
|
"div",
|
|
2081
2113
|
{
|
|
2082
2114
|
role: "button",
|
|
@@ -2090,7 +2122,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2090
2122
|
}
|
|
2091
2123
|
}
|
|
2092
2124
|
),
|
|
2093
|
-
ed.stops.map((s) => /* @__PURE__ */ (0,
|
|
2125
|
+
ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2094
2126
|
"button",
|
|
2095
2127
|
{
|
|
2096
2128
|
type: "button",
|
|
@@ -2104,21 +2136,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2104
2136
|
s.index
|
|
2105
2137
|
))
|
|
2106
2138
|
] }),
|
|
2107
|
-
sel && /* @__PURE__ */ (0,
|
|
2108
|
-
/* @__PURE__ */ (0,
|
|
2139
|
+
sel && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2109
2141
|
"input",
|
|
2110
2142
|
{
|
|
2111
2143
|
type: "color",
|
|
2112
2144
|
"aria-label": "Stop colour",
|
|
2113
2145
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2114
|
-
value: (0,
|
|
2146
|
+
value: (0, import_vector15.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
2115
2147
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2116
2148
|
onBlur: end
|
|
2117
2149
|
}
|
|
2118
2150
|
),
|
|
2119
|
-
/* @__PURE__ */ (0,
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2120
2152
|
"Opacity",
|
|
2121
|
-
/* @__PURE__ */ (0,
|
|
2153
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2122
2154
|
"input",
|
|
2123
2155
|
{
|
|
2124
2156
|
type: "number",
|
|
@@ -2126,7 +2158,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2126
2158
|
max: 100,
|
|
2127
2159
|
step: 5,
|
|
2128
2160
|
"aria-label": "Stop opacity",
|
|
2129
|
-
className:
|
|
2161
|
+
className: numberClass9,
|
|
2130
2162
|
value: percent(sel.opacity ?? 1),
|
|
2131
2163
|
onChange: (e) => {
|
|
2132
2164
|
const n = parseFloat(e.target.value);
|
|
@@ -2135,9 +2167,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2135
2167
|
}
|
|
2136
2168
|
)
|
|
2137
2169
|
] }),
|
|
2138
|
-
/* @__PURE__ */ (0,
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2139
2171
|
"At",
|
|
2140
|
-
/* @__PURE__ */ (0,
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2141
2173
|
"input",
|
|
2142
2174
|
{
|
|
2143
2175
|
type: "number",
|
|
@@ -2145,7 +2177,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2145
2177
|
max: 100,
|
|
2146
2178
|
step: 1,
|
|
2147
2179
|
"aria-label": "Stop position",
|
|
2148
|
-
className:
|
|
2180
|
+
className: numberClass9,
|
|
2149
2181
|
value: percent(sel.offset),
|
|
2150
2182
|
onChange: (e) => {
|
|
2151
2183
|
const n = parseFloat(e.target.value);
|
|
@@ -2154,9 +2186,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2154
2186
|
}
|
|
2155
2187
|
)
|
|
2156
2188
|
] }),
|
|
2157
|
-
!sel.last && /* @__PURE__ */ (0,
|
|
2189
|
+
!sel.last && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2158
2190
|
"Midpoint",
|
|
2159
|
-
/* @__PURE__ */ (0,
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2160
2192
|
"input",
|
|
2161
2193
|
{
|
|
2162
2194
|
type: "number",
|
|
@@ -2164,7 +2196,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2164
2196
|
max: 95,
|
|
2165
2197
|
step: 1,
|
|
2166
2198
|
"aria-label": "Stop midpoint",
|
|
2167
|
-
className:
|
|
2199
|
+
className: numberClass9,
|
|
2168
2200
|
value: percent(sel.midpoint ?? 0.5),
|
|
2169
2201
|
onChange: (e) => {
|
|
2170
2202
|
const n = parseFloat(e.target.value);
|
|
@@ -2173,15 +2205,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2173
2205
|
}
|
|
2174
2206
|
)
|
|
2175
2207
|
] }),
|
|
2176
|
-
/* @__PURE__ */ (0,
|
|
2208
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
2177
2209
|
] }),
|
|
2178
|
-
/* @__PURE__ */ (0,
|
|
2179
|
-
/* @__PURE__ */ (0,
|
|
2180
|
-
/* @__PURE__ */ (0,
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass10, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector15.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: i, children: import_vector15.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2181
2213
|
] }),
|
|
2182
|
-
/* @__PURE__ */ (0,
|
|
2183
|
-
/* @__PURE__ */ (0,
|
|
2184
|
-
/* @__PURE__ */ (0,
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2185
2217
|
"input",
|
|
2186
2218
|
{
|
|
2187
2219
|
type: "range",
|
|
@@ -2197,26 +2229,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2197
2229
|
}
|
|
2198
2230
|
)
|
|
2199
2231
|
] }),
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2201
|
-
/* @__PURE__ */ (0,
|
|
2202
|
-
/* @__PURE__ */ (0,
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2233
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient spread", className: selectClass10, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector15.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: sp, children: import_vector15.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2203
2235
|
] }),
|
|
2204
|
-
ed.target === "stroke" && /* @__PURE__ */ (0,
|
|
2205
|
-
/* @__PURE__ */ (0,
|
|
2206
|
-
/* @__PURE__ */ (0,
|
|
2236
|
+
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass10, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector15.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector15.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2207
2239
|
] })
|
|
2208
2240
|
] })
|
|
2209
2241
|
] });
|
|
2210
2242
|
}
|
|
2211
2243
|
|
|
2212
2244
|
// src/vector/VectorToolbar.tsx
|
|
2213
|
-
var
|
|
2245
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2214
2246
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
2215
2247
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
2216
|
-
var
|
|
2248
|
+
var buttonClass14 = "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";
|
|
2217
2249
|
function VectorToolbar({
|
|
2218
2250
|
controller,
|
|
2219
|
-
tools =
|
|
2251
|
+
tools = import_vector16.VECTOR_TOOLS,
|
|
2220
2252
|
showHistory = true,
|
|
2221
2253
|
showArrange = true,
|
|
2222
2254
|
showSnap = true,
|
|
@@ -2230,36 +2262,36 @@ function VectorToolbar({
|
|
|
2230
2262
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
2231
2263
|
const editing = state.editing;
|
|
2232
2264
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
2233
|
-
const maskSelected = state.selection.some((id) => (0,
|
|
2265
|
+
const maskSelected = state.selection.some((id) => (0, import_vector16.isVectorMaskGroup)(controller.getNode(id)));
|
|
2234
2266
|
const [live, setLive] = import_react10.default.useState(false);
|
|
2235
2267
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2236
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
2237
|
-
return /* @__PURE__ */ (0,
|
|
2238
|
-
/* @__PURE__ */ (0,
|
|
2268
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass14, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2239
2271
|
"button",
|
|
2240
2272
|
{
|
|
2241
2273
|
type: "button",
|
|
2242
2274
|
"data-vector-tool": tool,
|
|
2243
|
-
className:
|
|
2275
|
+
className: buttonClass14,
|
|
2244
2276
|
"aria-pressed": state.tool === tool,
|
|
2245
|
-
title: `${(0,
|
|
2246
|
-
"aria-label": (0,
|
|
2277
|
+
title: `${(0, import_vector16.vectorToolLabel)(tool)} (${import_vector16.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2278
|
+
"aria-label": (0, import_vector16.vectorToolLabel)(tool),
|
|
2247
2279
|
onClick: () => controller.setTool(tool),
|
|
2248
|
-
children:
|
|
2280
|
+
children: import_vector16.VECTOR_TOOL_GLYPHS[tool]
|
|
2249
2281
|
},
|
|
2250
2282
|
tool
|
|
2251
2283
|
)) }),
|
|
2252
|
-
showHistory && /* @__PURE__ */ (0,
|
|
2284
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
2253
2285
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
2254
2286
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
2255
2287
|
] }),
|
|
2256
|
-
showSnap && /* @__PURE__ */ (0,
|
|
2257
|
-
/* @__PURE__ */ (0,
|
|
2288
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2289
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2258
2290
|
"button",
|
|
2259
2291
|
{
|
|
2260
2292
|
type: "button",
|
|
2261
2293
|
"data-vector-snap": "",
|
|
2262
|
-
className:
|
|
2294
|
+
className: buttonClass14,
|
|
2263
2295
|
"aria-pressed": state.snap.objects,
|
|
2264
2296
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2265
2297
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -2267,18 +2299,18 @@ function VectorToolbar({
|
|
|
2267
2299
|
children: "Snap"
|
|
2268
2300
|
}
|
|
2269
2301
|
),
|
|
2270
|
-
/* @__PURE__ */ (0,
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2271
2303
|
"select",
|
|
2272
2304
|
{
|
|
2273
2305
|
"data-vector-polar": "",
|
|
2274
2306
|
"aria-label": "Polar tracking increment",
|
|
2275
2307
|
title: "Polar tracking: the angles drawn points snap to from where they leave",
|
|
2276
2308
|
className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
|
|
2277
|
-
value: String((0,
|
|
2278
|
-
onChange: (e) => controller.setSnap({ angles: (0,
|
|
2309
|
+
value: String((0, import_vector16.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
|
|
2310
|
+
onChange: (e) => controller.setSnap({ angles: (0, import_vector16.vectorPolarAngles)(Number(e.target.value)) }),
|
|
2279
2311
|
children: [
|
|
2280
|
-
(0,
|
|
2281
|
-
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0,
|
|
2312
|
+
(0, import_vector16.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "Custom" }),
|
|
2313
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: n, children: [
|
|
2282
2314
|
n,
|
|
2283
2315
|
"\xB0"
|
|
2284
2316
|
] }, n))
|
|
@@ -2286,13 +2318,13 @@ function VectorToolbar({
|
|
|
2286
2318
|
}
|
|
2287
2319
|
)
|
|
2288
2320
|
] }),
|
|
2289
|
-
showPathEdit && /* @__PURE__ */ (0,
|
|
2290
|
-
|
|
2321
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2322
|
+
import_vector16.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2291
2323
|
"button",
|
|
2292
2324
|
{
|
|
2293
2325
|
type: "button",
|
|
2294
2326
|
"data-vector-path-action": a.id,
|
|
2295
|
-
className:
|
|
2327
|
+
className: buttonClass14,
|
|
2296
2328
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
2297
2329
|
"aria-label": a.title,
|
|
2298
2330
|
disabled: !a.enabled(count, points),
|
|
@@ -2301,12 +2333,12 @@ function VectorToolbar({
|
|
|
2301
2333
|
},
|
|
2302
2334
|
a.id
|
|
2303
2335
|
)),
|
|
2304
|
-
|
|
2336
|
+
import_vector16.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2305
2337
|
"button",
|
|
2306
2338
|
{
|
|
2307
2339
|
type: "button",
|
|
2308
2340
|
"data-vector-edit": t.key,
|
|
2309
|
-
className:
|
|
2341
|
+
className: buttonClass14,
|
|
2310
2342
|
"aria-pressed": editing[t.key],
|
|
2311
2343
|
title: t.title,
|
|
2312
2344
|
"aria-label": t.title,
|
|
@@ -2315,9 +2347,9 @@ function VectorToolbar({
|
|
|
2315
2347
|
},
|
|
2316
2348
|
t.key
|
|
2317
2349
|
)),
|
|
2318
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
2350
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2319
2351
|
"Smoothing",
|
|
2320
|
-
/* @__PURE__ */ (0,
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2321
2353
|
"input",
|
|
2322
2354
|
{
|
|
2323
2355
|
type: "range",
|
|
@@ -2331,9 +2363,9 @@ function VectorToolbar({
|
|
|
2331
2363
|
}
|
|
2332
2364
|
)
|
|
2333
2365
|
] }),
|
|
2334
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
2366
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2335
2367
|
"Size",
|
|
2336
|
-
/* @__PURE__ */ (0,
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2337
2369
|
"input",
|
|
2338
2370
|
{
|
|
2339
2371
|
type: "number",
|
|
@@ -2349,26 +2381,26 @@ function VectorToolbar({
|
|
|
2349
2381
|
}
|
|
2350
2382
|
)
|
|
2351
2383
|
] }),
|
|
2352
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
2384
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2353
2385
|
"button",
|
|
2354
2386
|
{
|
|
2355
2387
|
type: "button",
|
|
2356
2388
|
"data-vector-fill-gap": "",
|
|
2357
|
-
className:
|
|
2389
|
+
className: buttonClass14,
|
|
2358
2390
|
"aria-pressed": editing.fillGap > 0,
|
|
2359
2391
|
title: "Close small gaps between path ends when filling",
|
|
2360
2392
|
"aria-label": "Close gaps",
|
|
2361
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
2393
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector16.VECTOR_FILL_GAP }),
|
|
2362
2394
|
children: "Gaps"
|
|
2363
2395
|
}
|
|
2364
2396
|
)
|
|
2365
2397
|
] }),
|
|
2366
|
-
showDistort && /* @__PURE__ */ (0,
|
|
2398
|
+
showDistort && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2367
2399
|
"button",
|
|
2368
2400
|
{
|
|
2369
2401
|
type: "button",
|
|
2370
2402
|
"data-vector-free-distort": "",
|
|
2371
|
-
className:
|
|
2403
|
+
className: buttonClass14,
|
|
2372
2404
|
"aria-pressed": state.freeDistort,
|
|
2373
2405
|
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)`,
|
|
2374
2406
|
"aria-label": "Free Distort",
|
|
@@ -2376,15 +2408,15 @@ function VectorToolbar({
|
|
|
2376
2408
|
children: "Distort"
|
|
2377
2409
|
}
|
|
2378
2410
|
) }),
|
|
2379
|
-
showBlend && /* @__PURE__ */ (0,
|
|
2380
|
-
showArrange && /* @__PURE__ */ (0,
|
|
2381
|
-
/* @__PURE__ */ (0,
|
|
2382
|
-
/* @__PURE__ */ (0,
|
|
2411
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorBlendControls, { controller }),
|
|
2412
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2413
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2414
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2383
2415
|
"button",
|
|
2384
2416
|
{
|
|
2385
2417
|
type: "button",
|
|
2386
2418
|
"data-vector-live-boolean": "",
|
|
2387
|
-
className:
|
|
2419
|
+
className: buttonClass14,
|
|
2388
2420
|
"aria-pressed": live,
|
|
2389
2421
|
title: "Live booleans: keep the shapes editable",
|
|
2390
2422
|
"aria-label": "Live booleans",
|
|
@@ -2401,12 +2433,12 @@ function VectorToolbar({
|
|
|
2401
2433
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2402
2434
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2403
2435
|
] }),
|
|
2404
|
-
/* @__PURE__ */ (0,
|
|
2436
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector16.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2405
2437
|
"button",
|
|
2406
2438
|
{
|
|
2407
2439
|
type: "button",
|
|
2408
2440
|
"data-vector-pathfinder": a.id,
|
|
2409
|
-
className:
|
|
2441
|
+
className: buttonClass14,
|
|
2410
2442
|
title: a.title,
|
|
2411
2443
|
"aria-label": a.title,
|
|
2412
2444
|
disabled: count < a.min,
|
|
@@ -2415,7 +2447,7 @@ function VectorToolbar({
|
|
|
2415
2447
|
},
|
|
2416
2448
|
a.id
|
|
2417
2449
|
)) }),
|
|
2418
|
-
/* @__PURE__ */ (0,
|
|
2450
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
2419
2451
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
2420
2452
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
2421
2453
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -2430,22 +2462,22 @@ function VectorToolbar({
|
|
|
2430
2462
|
}
|
|
2431
2463
|
function VectorBlendControls({ controller }) {
|
|
2432
2464
|
const state = useVectorEditorState(controller);
|
|
2433
|
-
const blend = (0,
|
|
2465
|
+
const blend = (0, import_vector16.getVectorBlendControls)(state);
|
|
2434
2466
|
const o = blend.options;
|
|
2435
2467
|
const selected = blend.ids.length > 0;
|
|
2436
|
-
return /* @__PURE__ */ (0,
|
|
2437
|
-
/* @__PURE__ */ (0,
|
|
2438
|
-
/* @__PURE__ */ (0,
|
|
2468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass14, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2439
2471
|
"select",
|
|
2440
2472
|
{
|
|
2441
2473
|
"aria-label": "Blend spacing",
|
|
2442
2474
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2443
2475
|
value: o.spacing,
|
|
2444
|
-
onChange: (e) => (0,
|
|
2445
|
-
children:
|
|
2476
|
+
onChange: (e) => (0, import_vector16.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
2477
|
+
children: import_vector16.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: sp, children: import_vector16.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2446
2478
|
}
|
|
2447
2479
|
),
|
|
2448
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */ (0,
|
|
2480
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2449
2481
|
"input",
|
|
2450
2482
|
{
|
|
2451
2483
|
type: "number",
|
|
@@ -2457,29 +2489,29 @@ function VectorBlendControls({ controller }) {
|
|
|
2457
2489
|
onChange: (e) => {
|
|
2458
2490
|
const n = parseFloat(e.target.value);
|
|
2459
2491
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
2460
|
-
(0,
|
|
2492
|
+
(0, import_vector16.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
2461
2493
|
}
|
|
2462
2494
|
}
|
|
2463
2495
|
),
|
|
2464
|
-
/* @__PURE__ */ (0,
|
|
2496
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2465
2497
|
"button",
|
|
2466
2498
|
{
|
|
2467
2499
|
type: "button",
|
|
2468
2500
|
"data-vector-blend-action": "orient",
|
|
2469
|
-
className:
|
|
2501
|
+
className: buttonClass14,
|
|
2470
2502
|
"aria-pressed": o.orientToSpine,
|
|
2471
2503
|
title: "Orient steps to the spine",
|
|
2472
2504
|
"aria-label": "Orient to spine",
|
|
2473
|
-
onClick: () => (0,
|
|
2505
|
+
onClick: () => (0, import_vector16.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
2474
2506
|
children: "\u293F"
|
|
2475
2507
|
}
|
|
2476
2508
|
),
|
|
2477
|
-
/* @__PURE__ */ (0,
|
|
2509
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2478
2510
|
"button",
|
|
2479
2511
|
{
|
|
2480
2512
|
type: "button",
|
|
2481
2513
|
"data-vector-blend-action": "spine",
|
|
2482
|
-
className:
|
|
2514
|
+
className: buttonClass14,
|
|
2483
2515
|
title: "Replace Spine (select a blend and a path)",
|
|
2484
2516
|
"aria-label": "Replace Spine",
|
|
2485
2517
|
disabled: !blend.canReplaceSpine,
|
|
@@ -2487,15 +2519,15 @@ function VectorBlendControls({ controller }) {
|
|
|
2487
2519
|
children: "\u2307"
|
|
2488
2520
|
}
|
|
2489
2521
|
),
|
|
2490
|
-
/* @__PURE__ */ (0,
|
|
2491
|
-
/* @__PURE__ */ (0,
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass14, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2523
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass14, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
2492
2524
|
] });
|
|
2493
2525
|
}
|
|
2494
|
-
var
|
|
2495
|
-
var
|
|
2526
|
+
var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2527
|
+
var numberClass10 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2496
2528
|
function VectorStylePanel({ controller, className }) {
|
|
2497
2529
|
const state = useVectorEditorState(controller);
|
|
2498
|
-
const style = (0,
|
|
2530
|
+
const style = (0, import_vector16.getVectorSelectionStyle)(state);
|
|
2499
2531
|
const d = state.defaults;
|
|
2500
2532
|
const source = style ?? {
|
|
2501
2533
|
fill: d.fill ?? null,
|
|
@@ -2508,7 +2540,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2508
2540
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
2509
2541
|
startArrowScale: d.startArrowScale ?? 1,
|
|
2510
2542
|
endArrowScale: d.endArrowScale ?? 1,
|
|
2511
|
-
widthProfile: (0,
|
|
2543
|
+
widthProfile: (0, import_vector16.widthProfilePresetId)(d.strokeWidthProfile),
|
|
2512
2544
|
cornerRadius: d.cornerRadius,
|
|
2513
2545
|
cornerKind: d.cornerKind ?? "round",
|
|
2514
2546
|
cornerSmoothing: 0,
|
|
@@ -2522,19 +2554,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2522
2554
|
};
|
|
2523
2555
|
const setProfile = (id) => {
|
|
2524
2556
|
if (style) controller.setWidthProfile(id);
|
|
2525
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
2557
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector16.widthProfilePreset)(id)?.length ? (0, import_vector16.widthProfilePreset)(id) : null });
|
|
2526
2558
|
};
|
|
2527
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
2559
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2528
2560
|
const arrowRow = (end, label) => {
|
|
2529
2561
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
2530
2562
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
2531
|
-
return /* @__PURE__ */ (0,
|
|
2532
|
-
/* @__PURE__ */ (0,
|
|
2533
|
-
/* @__PURE__ */ (0,
|
|
2534
|
-
/* @__PURE__ */ (0,
|
|
2535
|
-
|
|
2563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass11, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2566
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "None" }),
|
|
2567
|
+
import_vector16.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: h, children: import_vector16.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2536
2568
|
] }),
|
|
2537
|
-
/* @__PURE__ */ (0,
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2538
2570
|
"input",
|
|
2539
2571
|
{
|
|
2540
2572
|
type: "number",
|
|
@@ -2542,7 +2574,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2542
2574
|
step: 0.25,
|
|
2543
2575
|
"aria-label": `${label} arrowhead scale`,
|
|
2544
2576
|
title: "Scale (\xD7 stroke width)",
|
|
2545
|
-
className:
|
|
2577
|
+
className: numberClass10,
|
|
2546
2578
|
value: source[scaleKey],
|
|
2547
2579
|
onChange: (e) => {
|
|
2548
2580
|
const n = parseFloat(e.target.value);
|
|
@@ -2558,14 +2590,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2558
2590
|
};
|
|
2559
2591
|
const paintRow = (key, label) => {
|
|
2560
2592
|
const paint = source[key];
|
|
2561
|
-
const hex = (0,
|
|
2593
|
+
const hex = (0, import_vector16.vectorPaintToHex)(paint);
|
|
2562
2594
|
const on = paint !== null && paint !== "none";
|
|
2563
|
-
return /* @__PURE__ */ (0,
|
|
2564
|
-
/* @__PURE__ */ (0,
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2596
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
2566
2598
|
label
|
|
2567
2599
|
] }),
|
|
2568
|
-
/* @__PURE__ */ (0,
|
|
2600
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2569
2601
|
"input",
|
|
2570
2602
|
{
|
|
2571
2603
|
type: "color",
|
|
@@ -2576,18 +2608,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2576
2608
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
2577
2609
|
}
|
|
2578
2610
|
),
|
|
2579
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
2580
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
2611
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2612
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2581
2613
|
] });
|
|
2582
2614
|
};
|
|
2583
|
-
return /* @__PURE__ */ (0,
|
|
2584
|
-
/* @__PURE__ */ (0,
|
|
2615
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2616
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
2585
2617
|
paintRow("fill", "Fill"),
|
|
2586
2618
|
paintRow("stroke", "Stroke"),
|
|
2587
|
-
style && /* @__PURE__ */ (0,
|
|
2588
|
-
/* @__PURE__ */ (0,
|
|
2589
|
-
/* @__PURE__ */ (0,
|
|
2590
|
-
/* @__PURE__ */ (0,
|
|
2619
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorGradientEditor, { controller }),
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Width" }),
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2591
2623
|
"input",
|
|
2592
2624
|
{
|
|
2593
2625
|
type: "number",
|
|
@@ -2603,33 +2635,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2603
2635
|
}
|
|
2604
2636
|
)
|
|
2605
2637
|
] }),
|
|
2606
|
-
/* @__PURE__ */ (0,
|
|
2607
|
-
/* @__PURE__ */ (0,
|
|
2608
|
-
/* @__PURE__ */ (0,
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Align" }),
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass11, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector16.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: a, children: import_vector16.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
2609
2641
|
mixed("strokeAlign")
|
|
2610
2642
|
] }),
|
|
2611
|
-
/* @__PURE__ */ (0,
|
|
2612
|
-
/* @__PURE__ */ (0,
|
|
2613
|
-
/* @__PURE__ */ (0,
|
|
2643
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2614
2646
|
"select",
|
|
2615
2647
|
{
|
|
2616
2648
|
"aria-label": "Width profile",
|
|
2617
|
-
className:
|
|
2649
|
+
className: selectClass11,
|
|
2618
2650
|
value: source.widthProfile,
|
|
2619
2651
|
onChange: (e) => {
|
|
2620
2652
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2621
2653
|
},
|
|
2622
2654
|
children: [
|
|
2623
|
-
|
|
2624
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
2655
|
+
import_vector16.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
2656
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2625
2657
|
]
|
|
2626
2658
|
}
|
|
2627
2659
|
),
|
|
2628
|
-
/* @__PURE__ */ (0,
|
|
2660
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2629
2661
|
"button",
|
|
2630
2662
|
{
|
|
2631
2663
|
type: "button",
|
|
2632
|
-
className:
|
|
2664
|
+
className: buttonClass14,
|
|
2633
2665
|
title: "Reset to uniform width",
|
|
2634
2666
|
"aria-label": "Reset to uniform width",
|
|
2635
2667
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -2639,27 +2671,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2639
2671
|
),
|
|
2640
2672
|
mixed("widthProfile")
|
|
2641
2673
|
] }),
|
|
2642
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
2674
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2643
2675
|
arrowRow("start", "Start"),
|
|
2644
2676
|
arrowRow("end", "End"),
|
|
2645
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
2646
|
-
/* @__PURE__ */ (0,
|
|
2647
|
-
/* @__PURE__ */ (0,
|
|
2648
|
-
/* @__PURE__ */ (0,
|
|
2649
|
-
/* @__PURE__ */ (0,
|
|
2677
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2678
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass11, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2680
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
2681
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
2650
2682
|
] })
|
|
2651
2683
|
] })
|
|
2652
2684
|
] }),
|
|
2653
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
2654
|
-
/* @__PURE__ */ (0,
|
|
2655
|
-
/* @__PURE__ */ (0,
|
|
2685
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2686
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2656
2688
|
"input",
|
|
2657
2689
|
{
|
|
2658
2690
|
type: "number",
|
|
2659
2691
|
min: 0,
|
|
2660
2692
|
step: 1,
|
|
2661
2693
|
"aria-label": "Corner radius",
|
|
2662
|
-
className:
|
|
2694
|
+
className: numberClass10,
|
|
2663
2695
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
2664
2696
|
onChange: (e) => {
|
|
2665
2697
|
const n = parseFloat(e.target.value);
|
|
@@ -2667,12 +2699,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2667
2699
|
}
|
|
2668
2700
|
}
|
|
2669
2701
|
),
|
|
2670
|
-
/* @__PURE__ */ (0,
|
|
2702
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("select", { "aria-label": "Corner kind", className: selectClass11, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector16.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: k, children: import_vector16.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2671
2703
|
mixed("cornerRadius")
|
|
2672
2704
|
] }),
|
|
2673
|
-
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0,
|
|
2674
|
-
/* @__PURE__ */ (0,
|
|
2675
|
-
/* @__PURE__ */ (0,
|
|
2705
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("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: [
|
|
2706
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Smoothing" }),
|
|
2707
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2676
2708
|
"input",
|
|
2677
2709
|
{
|
|
2678
2710
|
type: "range",
|
|
@@ -2687,9 +2719,9 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2687
2719
|
}
|
|
2688
2720
|
)
|
|
2689
2721
|
] }),
|
|
2690
|
-
style && /* @__PURE__ */ (0,
|
|
2691
|
-
/* @__PURE__ */ (0,
|
|
2692
|
-
/* @__PURE__ */ (0,
|
|
2722
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2723
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2693
2725
|
"input",
|
|
2694
2726
|
{
|
|
2695
2727
|
type: "range",
|
|
@@ -2703,28 +2735,29 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2703
2735
|
}
|
|
2704
2736
|
)
|
|
2705
2737
|
] }),
|
|
2706
|
-
/* @__PURE__ */ (0,
|
|
2707
|
-
style && /* @__PURE__ */ (0,
|
|
2708
|
-
style && /* @__PURE__ */ (0,
|
|
2709
|
-
style && /* @__PURE__ */ (0,
|
|
2710
|
-
style && /* @__PURE__ */ (0,
|
|
2711
|
-
/* @__PURE__ */ (0,
|
|
2712
|
-
/* @__PURE__ */ (0,
|
|
2713
|
-
/* @__PURE__ */ (0,
|
|
2714
|
-
/* @__PURE__ */ (0,
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
2716
|
-
/* @__PURE__ */ (0,
|
|
2738
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorTextPanel, { controller }),
|
|
2739
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorAppearancePanel, { controller }),
|
|
2740
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorEffectsPanel, { controller }),
|
|
2741
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorEnvelopePanel, { controller }),
|
|
2742
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorMaskPanel, { controller }),
|
|
2743
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorFramePanel, { controller }),
|
|
2744
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorConnectorPanel, { controller }),
|
|
2745
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorShadingPanel, { controller }),
|
|
2746
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorSymmetryPanel, { controller }),
|
|
2747
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorTracePanel, { controller }),
|
|
2748
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorConstraintsPanel, { controller }),
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VectorSymbolsPanel, { controller })
|
|
2717
2750
|
] });
|
|
2718
2751
|
}
|
|
2719
2752
|
|
|
2720
2753
|
// src/vector/VectorEditor.tsx
|
|
2721
|
-
var
|
|
2754
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2722
2755
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
2723
|
-
return /* @__PURE__ */ (0,
|
|
2724
|
-
/* @__PURE__ */ (0,
|
|
2725
|
-
/* @__PURE__ */ (0,
|
|
2726
|
-
/* @__PURE__ */ (0,
|
|
2727
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
2756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
2757
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorToolbar, { controller, tools }),
|
|
2758
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
2759
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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_runtime17.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
2760
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
2728
2761
|
] })
|
|
2729
2762
|
] });
|
|
2730
2763
|
}
|
|
@@ -2748,6 +2781,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
2748
2781
|
VectorShadingPanel,
|
|
2749
2782
|
VectorStylePanel,
|
|
2750
2783
|
VectorSymbolsPanel,
|
|
2784
|
+
VectorSymmetryPanel,
|
|
2751
2785
|
VectorTextElement,
|
|
2752
2786
|
VectorTextPanel,
|
|
2753
2787
|
VectorToolbar,
|