@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.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 }),
|
|
@@ -649,6 +633,7 @@ function VectorCanvas({
|
|
|
649
633
|
sh.lines.map((d, i) => /* @__PURE__ */ jsx2("path", { d, stroke: accentColor, strokeWidth: 1, opacity: 0.7 }, i)),
|
|
650
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))
|
|
651
635
|
] }, `shading:${sh.nodeId}`)),
|
|
636
|
+
overlay.symmetry.map((sy) => /* @__PURE__ */ jsx2("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__ */ jsx2("line", { x1: l.x1, y1: l.y1, x2: l.x2, y2: l.y2 }, i)) }, `sym:${sy.nodeId}`)),
|
|
652
637
|
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}`)),
|
|
653
638
|
overlay.typedEntry && /* @__PURE__ */ jsxs2("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
654
639
|
/* @__PURE__ */ jsx2("rect", { x: -3, y: -12, width: overlay.typedEntry.text.length * 7 + 8, height: 17, rx: 3, fill: THEME2.handleFill, stroke: accentColor }),
|
|
@@ -807,7 +792,7 @@ import {
|
|
|
807
792
|
isVectorMaskGroup,
|
|
808
793
|
widthProfilePreset,
|
|
809
794
|
widthProfilePresetId,
|
|
810
|
-
vectorPaintToHex as
|
|
795
|
+
vectorPaintToHex as vectorPaintToHex6,
|
|
811
796
|
vectorToolLabel,
|
|
812
797
|
vectorPolarAngles,
|
|
813
798
|
vectorPolarIncrementOf
|
|
@@ -816,7 +801,8 @@ import {
|
|
|
816
801
|
// src/vector/VectorEffectsPanel.tsx
|
|
817
802
|
import {
|
|
818
803
|
VECTOR_EFFECT_MENU,
|
|
819
|
-
getVectorEffectsPanel
|
|
804
|
+
getVectorEffectsPanel,
|
|
805
|
+
vectorPaintToHex
|
|
820
806
|
} from "@pixerate/editor/vector";
|
|
821
807
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
822
808
|
var buttonClass = "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";
|
|
@@ -904,6 +890,15 @@ function VectorEffectsPanel({ controller, className }) {
|
|
|
904
890
|
/* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate", children: spec.label }),
|
|
905
891
|
/* @__PURE__ */ jsx3("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label}`, checked: !!e.params[spec.key], onChange: (ev) => set(e, spec.key, ev.target.checked, false) })
|
|
906
892
|
] }, spec.key);
|
|
893
|
+
if (spec.kind === "color") {
|
|
894
|
+
const c = e.params[spec.key];
|
|
895
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
|
|
896
|
+
/* @__PURE__ */ jsx3("span", { className: labelClass, children: spec.label }),
|
|
897
|
+
/* @__PURE__ */ jsx3("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) }),
|
|
898
|
+
/* @__PURE__ */ jsx3("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: vectorPaintToHex(c ?? "#ffffff") ?? "#ffffff", onChange: (ev) => set(e, spec.key, ev.target.value, true), onBlur: end })
|
|
899
|
+
] }, spec.key);
|
|
900
|
+
}
|
|
901
|
+
if (spec.kind !== "select") return null;
|
|
907
902
|
return /* @__PURE__ */ jsxs3("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: [
|
|
908
903
|
/* @__PURE__ */ jsx3("span", { className: labelClass, children: spec.label }),
|
|
909
904
|
/* @__PURE__ */ jsx3("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__ */ jsx3("option", { value: o.value, children: o.label }, o.value)) })
|
|
@@ -1584,8 +1579,8 @@ function VectorTextPanel({ controller, className }) {
|
|
|
1584
1579
|
}
|
|
1585
1580
|
|
|
1586
1581
|
// src/vector/VectorSymbolsPanel.tsx
|
|
1587
|
-
import { useId as useId3, useState as
|
|
1588
|
-
import { getVectorSymbolsPanel, vectorPaintToHex } from "@pixerate/editor/vector";
|
|
1582
|
+
import { useId as useId3, useState as useState3 } from "react";
|
|
1583
|
+
import { getVectorSymbolsPanel, vectorPaintToHex as vectorPaintToHex2 } from "@pixerate/editor/vector";
|
|
1589
1584
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1590
1585
|
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";
|
|
1591
1586
|
var selectClass5 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
@@ -1594,7 +1589,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1594
1589
|
const state = useVectorEditorState(controller);
|
|
1595
1590
|
const uid = useId3().replace(/:/g, "");
|
|
1596
1591
|
const panel = getVectorSymbolsPanel(state, { idPrefix: `vsym${uid}-` });
|
|
1597
|
-
const [error, setError] =
|
|
1592
|
+
const [error, setError] = useState3(null);
|
|
1598
1593
|
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1599
1594
|
const inst = panel.instance;
|
|
1600
1595
|
return /* @__PURE__ */ jsxs8("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symbols-panel": "", "aria-label": "Symbols", children: [
|
|
@@ -1639,7 +1634,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1639
1634
|
type: "color",
|
|
1640
1635
|
"aria-label": "Instance fill",
|
|
1641
1636
|
className: "h-6 w-8 rounded border border-border",
|
|
1642
|
-
value:
|
|
1637
|
+
value: vectorPaintToHex2(inst.fill ?? void 0) ?? "#000000",
|
|
1643
1638
|
onChange: (e) => report(controller.setInstanceOptions({ fill: e.target.value }, { ids: [inst.id] }))
|
|
1644
1639
|
}
|
|
1645
1640
|
)
|
|
@@ -1652,7 +1647,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1652
1647
|
}
|
|
1653
1648
|
|
|
1654
1649
|
// src/vector/VectorConstraintsPanel.tsx
|
|
1655
|
-
import { useState as
|
|
1650
|
+
import { useState as useState4 } from "react";
|
|
1656
1651
|
import { getVectorConstraintPanel } from "@pixerate/editor/vector";
|
|
1657
1652
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1658
1653
|
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";
|
|
@@ -1661,8 +1656,8 @@ var labelClass6 = "w-16 text-[11px] font-medium uppercase tracking-wide text-mut
|
|
|
1661
1656
|
function VectorConstraintsPanel({ controller, className }) {
|
|
1662
1657
|
const state = useVectorEditorState(controller);
|
|
1663
1658
|
const panel = getVectorConstraintPanel(state);
|
|
1664
|
-
const [error, setError] =
|
|
1665
|
-
const [param, setParam] =
|
|
1659
|
+
const [error, setError] = useState4(null);
|
|
1660
|
+
const [param, setParam] = useState4({ name: "", value: "" });
|
|
1666
1661
|
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1667
1662
|
const add = (a) => report(controller.addConstraint({ kind: a.kind, refs: a.refs }));
|
|
1668
1663
|
if (!panel.actions.length && !panel.constraints.length && !state.document.constraints?.length && state.tool !== "direct") return null;
|
|
@@ -1745,7 +1740,7 @@ import {
|
|
|
1745
1740
|
VECTOR_VERTICAL_RESIZING,
|
|
1746
1741
|
VECTOR_VERTICAL_RESIZING_LABELS,
|
|
1747
1742
|
getVectorFramePanel,
|
|
1748
|
-
vectorPaintToHex as
|
|
1743
|
+
vectorPaintToHex as vectorPaintToHex3
|
|
1749
1744
|
} from "@pixerate/editor/vector";
|
|
1750
1745
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1751
1746
|
var buttonClass8 = "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";
|
|
@@ -1756,7 +1751,7 @@ function VectorFramePanel({ controller, className }) {
|
|
|
1756
1751
|
const panel = getVectorFramePanel(state);
|
|
1757
1752
|
const f = panel.frame;
|
|
1758
1753
|
const ids = f ? [f.id] : void 0;
|
|
1759
|
-
const fillHex = f ?
|
|
1754
|
+
const fillHex = f ? vectorPaintToHex3(f.frame.fill ?? null) : null;
|
|
1760
1755
|
const number = (key, label) => /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1761
1756
|
/* @__PURE__ */ jsx10("span", { className: "w-4 text-muted-foreground", children: label }),
|
|
1762
1757
|
/* @__PURE__ */ jsx10(
|
|
@@ -1930,15 +1925,15 @@ function VectorConnectorPanel({ controller, className }) {
|
|
|
1930
1925
|
}
|
|
1931
1926
|
|
|
1932
1927
|
// src/vector/VectorShadingPanel.tsx
|
|
1933
|
-
import { useState as
|
|
1934
|
-
import { isVectorFreeformGradient, isVectorMeshGradient, vectorPaintToHex as
|
|
1928
|
+
import { useState as useState5 } from "react";
|
|
1929
|
+
import { isVectorFreeformGradient, isVectorMeshGradient, vectorPaintToHex as vectorPaintToHex4 } from "@pixerate/editor/vector";
|
|
1935
1930
|
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1936
1931
|
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";
|
|
1937
1932
|
var numberClass6 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
1938
1933
|
function VectorShadingPanel({ controller, className }) {
|
|
1939
1934
|
const state = useVectorEditorState(controller);
|
|
1940
|
-
const [rows, setRows] =
|
|
1941
|
-
const [columns, setColumns] =
|
|
1935
|
+
const [rows, setRows] = useState5(2);
|
|
1936
|
+
const [columns, setColumns] = useState5(2);
|
|
1942
1937
|
const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path");
|
|
1943
1938
|
if (!path) return null;
|
|
1944
1939
|
const fill = path.fill;
|
|
@@ -1971,7 +1966,7 @@ function VectorShadingPanel({ controller, className }) {
|
|
|
1971
1966
|
"Point ",
|
|
1972
1967
|
sel.index
|
|
1973
1968
|
] }),
|
|
1974
|
-
/* @__PURE__ */ jsx12("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value:
|
|
1969
|
+
/* @__PURE__ */ jsx12("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: vectorPaintToHex4(color ?? "#000000") ?? "#000000", onChange: (e) => edit({ color: e.target.value }, "shading-color") }),
|
|
1975
1970
|
/* @__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") }),
|
|
1976
1971
|
free && /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
1977
1972
|
/* @__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") }),
|
|
@@ -1982,7 +1977,7 @@ function VectorShadingPanel({ controller, className }) {
|
|
|
1982
1977
|
}
|
|
1983
1978
|
|
|
1984
1979
|
// src/vector/VectorTracePanel.tsx
|
|
1985
|
-
import { useRef as useRef4, useState as
|
|
1980
|
+
import { useRef as useRef4, useState as useState6 } from "react";
|
|
1986
1981
|
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1987
1982
|
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";
|
|
1988
1983
|
var selectClass8 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
@@ -2001,9 +1996,9 @@ async function filePixels(file, max = 1e6) {
|
|
|
2001
1996
|
}
|
|
2002
1997
|
function VectorTracePanel({ controller, className }) {
|
|
2003
1998
|
const input = useRef4(null);
|
|
2004
|
-
const [mode, setMode] =
|
|
2005
|
-
const [colors, setColors] =
|
|
2006
|
-
const [message, setMessage] =
|
|
1999
|
+
const [mode, setMode] = useState6("threshold");
|
|
2000
|
+
const [colors, setColors] = useState6(6);
|
|
2001
|
+
const [message, setMessage] = useState6(null);
|
|
2007
2002
|
const trace = async (file) => {
|
|
2008
2003
|
try {
|
|
2009
2004
|
const pixels = await filePixels(file);
|
|
@@ -2043,6 +2038,43 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2043
2038
|
] });
|
|
2044
2039
|
}
|
|
2045
2040
|
|
|
2041
|
+
// src/vector/VectorSymmetryPanel.tsx
|
|
2042
|
+
import { VECTOR_SYMMETRY_MODES, VECTOR_SYMMETRY_MODE_LABELS, isVectorSymmetryGroup } from "@pixerate/editor/vector";
|
|
2043
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2044
|
+
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";
|
|
2045
|
+
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2046
|
+
var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
2047
|
+
function VectorSymmetryPanel({ controller, className }) {
|
|
2048
|
+
const state = useVectorEditorState(controller);
|
|
2049
|
+
const group = state.selection.map((id) => controller.getNode(id)).find(isVectorSymmetryGroup) ?? null;
|
|
2050
|
+
const s = group?.symmetry;
|
|
2051
|
+
const ids = group ? [group.id] : void 0;
|
|
2052
|
+
const drawing = !!group && state.symmetryTarget === group.id;
|
|
2053
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symmetry-panel": "", "aria-label": "Symmetry", children: [
|
|
2054
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2055
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Symmetry" }),
|
|
2056
|
+
!group && /* @__PURE__ */ jsx14("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" }),
|
|
2057
|
+
!group && /* @__PURE__ */ jsx14("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" }),
|
|
2058
|
+
group && s && /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
2059
|
+
/* @__PURE__ */ jsx14("select", { "aria-label": "Symmetry mode", className: selectClass9, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ jsx14("option", { value: m, children: VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
|
|
2060
|
+
s.mode === "radial" && /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
2061
|
+
/* @__PURE__ */ jsx14("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 }) }),
|
|
2062
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
|
|
2063
|
+
/* @__PURE__ */ jsx14("input", { type: "checkbox", "aria-label": "Mirror copies", checked: !!s.mirror, onChange: (e) => controller.setSymmetry({ mirror: e.target.checked }, { ids }) }),
|
|
2064
|
+
"Mirror"
|
|
2065
|
+
] })
|
|
2066
|
+
] })
|
|
2067
|
+
] })
|
|
2068
|
+
] }),
|
|
2069
|
+
group && /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2070
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16" }),
|
|
2071
|
+
/* @__PURE__ */ jsx14("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" }),
|
|
2072
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, title: "Expand: keep the copies as real objects", onClick: () => controller.releaseSymmetry({ ids, expand: true }), children: "Expand" }),
|
|
2073
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, title: "Release: stop repeating (the copies go)", onClick: () => controller.releaseSymmetry({ ids }), children: "Release" })
|
|
2074
|
+
] })
|
|
2075
|
+
] });
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2046
2078
|
// src/vector/VectorGradientEditor.tsx
|
|
2047
2079
|
import {
|
|
2048
2080
|
VECTOR_GRADIENT_TYPES,
|
|
@@ -2054,12 +2086,12 @@ import {
|
|
|
2054
2086
|
VECTOR_GRADIENT_INTERPOLATION_LABELS,
|
|
2055
2087
|
VECTOR_STROKE_GRADIENT_MODE_LABELS,
|
|
2056
2088
|
getVectorGradientEditor,
|
|
2057
|
-
vectorPaintToHex as
|
|
2089
|
+
vectorPaintToHex as vectorPaintToHex5
|
|
2058
2090
|
} from "@pixerate/editor/vector";
|
|
2059
|
-
import { Fragment as
|
|
2060
|
-
var
|
|
2061
|
-
var
|
|
2062
|
-
var
|
|
2091
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2092
|
+
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2093
|
+
var numberClass9 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
2094
|
+
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";
|
|
2063
2095
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
2064
2096
|
function VectorGradientEditor({ controller, className }) {
|
|
2065
2097
|
const state = useVectorEditorState(controller);
|
|
@@ -2071,26 +2103,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2071
2103
|
const setType = (value) => {
|
|
2072
2104
|
if (value === "solid") {
|
|
2073
2105
|
const first = ed.stops[0];
|
|
2074
|
-
controller.setStyle({ [ed.target]:
|
|
2106
|
+
controller.setStyle({ [ed.target]: vectorPaintToHex5(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
2075
2107
|
} else controller.setGradient({ type: value });
|
|
2076
2108
|
};
|
|
2077
|
-
return /* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */
|
|
2081
|
-
ed.mixed && /* @__PURE__ */
|
|
2109
|
+
return /* @__PURE__ */ jsxs15("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
2110
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
2111
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
2112
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
2113
|
+
ed.mixed && /* @__PURE__ */ jsx15("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2082
2114
|
] }),
|
|
2083
|
-
/* @__PURE__ */
|
|
2084
|
-
/* @__PURE__ */
|
|
2085
|
-
/* @__PURE__ */
|
|
2086
|
-
/* @__PURE__ */
|
|
2087
|
-
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */
|
|
2115
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
2116
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2117
|
+
/* @__PURE__ */ jsxs15("select", { "aria-label": "Gradient type", className: selectClass10, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2118
|
+
/* @__PURE__ */ jsx15("option", { value: "solid", children: "Solid" }),
|
|
2119
|
+
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ jsx15("option", { value: t, children: VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
2088
2120
|
] }),
|
|
2089
|
-
/* @__PURE__ */
|
|
2121
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
2090
2122
|
] }),
|
|
2091
|
-
g && /* @__PURE__ */
|
|
2092
|
-
/* @__PURE__ */
|
|
2093
|
-
/* @__PURE__ */
|
|
2123
|
+
g && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
2124
|
+
/* @__PURE__ */ jsxs15("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
2125
|
+
/* @__PURE__ */ jsx15(
|
|
2094
2126
|
"div",
|
|
2095
2127
|
{
|
|
2096
2128
|
role: "button",
|
|
@@ -2104,7 +2136,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2104
2136
|
}
|
|
2105
2137
|
}
|
|
2106
2138
|
),
|
|
2107
|
-
ed.stops.map((s) => /* @__PURE__ */
|
|
2139
|
+
ed.stops.map((s) => /* @__PURE__ */ jsx15(
|
|
2108
2140
|
"button",
|
|
2109
2141
|
{
|
|
2110
2142
|
type: "button",
|
|
@@ -2118,21 +2150,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2118
2150
|
s.index
|
|
2119
2151
|
))
|
|
2120
2152
|
] }),
|
|
2121
|
-
sel && /* @__PURE__ */
|
|
2122
|
-
/* @__PURE__ */
|
|
2153
|
+
sel && /* @__PURE__ */ jsxs15("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
2154
|
+
/* @__PURE__ */ jsx15(
|
|
2123
2155
|
"input",
|
|
2124
2156
|
{
|
|
2125
2157
|
type: "color",
|
|
2126
2158
|
"aria-label": "Stop colour",
|
|
2127
2159
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2128
|
-
value:
|
|
2160
|
+
value: vectorPaintToHex5(sel.color) ?? "#000000",
|
|
2129
2161
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2130
2162
|
onBlur: end
|
|
2131
2163
|
}
|
|
2132
2164
|
),
|
|
2133
|
-
/* @__PURE__ */
|
|
2165
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2134
2166
|
"Opacity",
|
|
2135
|
-
/* @__PURE__ */
|
|
2167
|
+
/* @__PURE__ */ jsx15(
|
|
2136
2168
|
"input",
|
|
2137
2169
|
{
|
|
2138
2170
|
type: "number",
|
|
@@ -2140,7 +2172,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2140
2172
|
max: 100,
|
|
2141
2173
|
step: 5,
|
|
2142
2174
|
"aria-label": "Stop opacity",
|
|
2143
|
-
className:
|
|
2175
|
+
className: numberClass9,
|
|
2144
2176
|
value: percent(sel.opacity ?? 1),
|
|
2145
2177
|
onChange: (e) => {
|
|
2146
2178
|
const n = parseFloat(e.target.value);
|
|
@@ -2149,9 +2181,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2149
2181
|
}
|
|
2150
2182
|
)
|
|
2151
2183
|
] }),
|
|
2152
|
-
/* @__PURE__ */
|
|
2184
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2153
2185
|
"At",
|
|
2154
|
-
/* @__PURE__ */
|
|
2186
|
+
/* @__PURE__ */ jsx15(
|
|
2155
2187
|
"input",
|
|
2156
2188
|
{
|
|
2157
2189
|
type: "number",
|
|
@@ -2159,7 +2191,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2159
2191
|
max: 100,
|
|
2160
2192
|
step: 1,
|
|
2161
2193
|
"aria-label": "Stop position",
|
|
2162
|
-
className:
|
|
2194
|
+
className: numberClass9,
|
|
2163
2195
|
value: percent(sel.offset),
|
|
2164
2196
|
onChange: (e) => {
|
|
2165
2197
|
const n = parseFloat(e.target.value);
|
|
@@ -2168,9 +2200,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2168
2200
|
}
|
|
2169
2201
|
)
|
|
2170
2202
|
] }),
|
|
2171
|
-
!sel.last && /* @__PURE__ */
|
|
2203
|
+
!sel.last && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2172
2204
|
"Midpoint",
|
|
2173
|
-
/* @__PURE__ */
|
|
2205
|
+
/* @__PURE__ */ jsx15(
|
|
2174
2206
|
"input",
|
|
2175
2207
|
{
|
|
2176
2208
|
type: "number",
|
|
@@ -2178,7 +2210,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2178
2210
|
max: 95,
|
|
2179
2211
|
step: 1,
|
|
2180
2212
|
"aria-label": "Stop midpoint",
|
|
2181
|
-
className:
|
|
2213
|
+
className: numberClass9,
|
|
2182
2214
|
value: percent(sel.midpoint ?? 0.5),
|
|
2183
2215
|
onChange: (e) => {
|
|
2184
2216
|
const n = parseFloat(e.target.value);
|
|
@@ -2187,15 +2219,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2187
2219
|
}
|
|
2188
2220
|
)
|
|
2189
2221
|
] }),
|
|
2190
|
-
/* @__PURE__ */
|
|
2222
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
2191
2223
|
] }),
|
|
2192
|
-
/* @__PURE__ */
|
|
2193
|
-
/* @__PURE__ */
|
|
2194
|
-
/* @__PURE__ */
|
|
2224
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2225
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Colours" }),
|
|
2226
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient interpolation", className: selectClass10, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx15("option", { value: i, children: VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2195
2227
|
] }),
|
|
2196
|
-
/* @__PURE__ */
|
|
2197
|
-
/* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2228
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2229
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Smooth" }),
|
|
2230
|
+
/* @__PURE__ */ jsx15(
|
|
2199
2231
|
"input",
|
|
2200
2232
|
{
|
|
2201
2233
|
type: "range",
|
|
@@ -2211,23 +2243,23 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2211
2243
|
}
|
|
2212
2244
|
)
|
|
2213
2245
|
] }),
|
|
2214
|
-
/* @__PURE__ */
|
|
2215
|
-
/* @__PURE__ */
|
|
2216
|
-
/* @__PURE__ */
|
|
2246
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2247
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Spread" }),
|
|
2248
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient spread", className: selectClass10, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ jsx15("option", { value: sp, children: VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2217
2249
|
] }),
|
|
2218
|
-
ed.target === "stroke" && /* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2220
|
-
/* @__PURE__ */
|
|
2250
|
+
ed.target === "stroke" && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2251
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "On stroke" }),
|
|
2252
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient on stroke", className: selectClass10, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ jsx15("option", { value: m, children: VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2221
2253
|
] })
|
|
2222
2254
|
] })
|
|
2223
2255
|
] });
|
|
2224
2256
|
}
|
|
2225
2257
|
|
|
2226
2258
|
// src/vector/VectorToolbar.tsx
|
|
2227
|
-
import { Fragment as
|
|
2259
|
+
import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2228
2260
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
2229
2261
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
2230
|
-
var
|
|
2262
|
+
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";
|
|
2231
2263
|
function VectorToolbar({
|
|
2232
2264
|
controller,
|
|
2233
2265
|
tools = VECTOR_TOOLS,
|
|
@@ -2247,14 +2279,14 @@ function VectorToolbar({
|
|
|
2247
2279
|
const maskSelected = state.selection.some((id) => isVectorMaskGroup(controller.getNode(id)));
|
|
2248
2280
|
const [live, setLive] = React9.useState(false);
|
|
2249
2281
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2250
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */
|
|
2251
|
-
return /* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2282
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ jsx16("button", { type: "button", className: buttonClass14, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2283
|
+
return /* @__PURE__ */ jsxs16("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2284
|
+
/* @__PURE__ */ jsx16("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ jsx16(
|
|
2253
2285
|
"button",
|
|
2254
2286
|
{
|
|
2255
2287
|
type: "button",
|
|
2256
2288
|
"data-vector-tool": tool,
|
|
2257
|
-
className:
|
|
2289
|
+
className: buttonClass14,
|
|
2258
2290
|
"aria-pressed": state.tool === tool,
|
|
2259
2291
|
title: `${vectorToolLabel(tool)} (${VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2260
2292
|
"aria-label": vectorToolLabel(tool),
|
|
@@ -2263,17 +2295,17 @@ function VectorToolbar({
|
|
|
2263
2295
|
},
|
|
2264
2296
|
tool
|
|
2265
2297
|
)) }),
|
|
2266
|
-
showHistory && /* @__PURE__ */
|
|
2298
|
+
showHistory && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
2267
2299
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
2268
2300
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
2269
2301
|
] }),
|
|
2270
|
-
showSnap && /* @__PURE__ */
|
|
2271
|
-
/* @__PURE__ */
|
|
2302
|
+
showSnap && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2303
|
+
/* @__PURE__ */ jsx16(
|
|
2272
2304
|
"button",
|
|
2273
2305
|
{
|
|
2274
2306
|
type: "button",
|
|
2275
2307
|
"data-vector-snap": "",
|
|
2276
|
-
className:
|
|
2308
|
+
className: buttonClass14,
|
|
2277
2309
|
"aria-pressed": state.snap.objects,
|
|
2278
2310
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2279
2311
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -2281,7 +2313,7 @@ function VectorToolbar({
|
|
|
2281
2313
|
children: "Snap"
|
|
2282
2314
|
}
|
|
2283
2315
|
),
|
|
2284
|
-
/* @__PURE__ */
|
|
2316
|
+
/* @__PURE__ */ jsxs16(
|
|
2285
2317
|
"select",
|
|
2286
2318
|
{
|
|
2287
2319
|
"data-vector-polar": "",
|
|
@@ -2291,8 +2323,8 @@ function VectorToolbar({
|
|
|
2291
2323
|
value: String(vectorPolarIncrementOf(state.snap.angles) ?? ""),
|
|
2292
2324
|
onChange: (e) => controller.setSnap({ angles: vectorPolarAngles(Number(e.target.value)) }),
|
|
2293
2325
|
children: [
|
|
2294
|
-
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */
|
|
2295
|
-
[90, 45, 30, 15].map((n) => /* @__PURE__ */
|
|
2326
|
+
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */ jsx16("option", { value: "", children: "Custom" }),
|
|
2327
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ jsxs16("option", { value: n, children: [
|
|
2296
2328
|
n,
|
|
2297
2329
|
"\xB0"
|
|
2298
2330
|
] }, n))
|
|
@@ -2300,13 +2332,13 @@ function VectorToolbar({
|
|
|
2300
2332
|
}
|
|
2301
2333
|
)
|
|
2302
2334
|
] }),
|
|
2303
|
-
showPathEdit && /* @__PURE__ */
|
|
2304
|
-
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */
|
|
2335
|
+
showPathEdit && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2336
|
+
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ jsx16(
|
|
2305
2337
|
"button",
|
|
2306
2338
|
{
|
|
2307
2339
|
type: "button",
|
|
2308
2340
|
"data-vector-path-action": a.id,
|
|
2309
|
-
className:
|
|
2341
|
+
className: buttonClass14,
|
|
2310
2342
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
2311
2343
|
"aria-label": a.title,
|
|
2312
2344
|
disabled: !a.enabled(count, points),
|
|
@@ -2315,12 +2347,12 @@ function VectorToolbar({
|
|
|
2315
2347
|
},
|
|
2316
2348
|
a.id
|
|
2317
2349
|
)),
|
|
2318
|
-
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */
|
|
2350
|
+
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ jsx16(
|
|
2319
2351
|
"button",
|
|
2320
2352
|
{
|
|
2321
2353
|
type: "button",
|
|
2322
2354
|
"data-vector-edit": t.key,
|
|
2323
|
-
className:
|
|
2355
|
+
className: buttonClass14,
|
|
2324
2356
|
"aria-pressed": editing[t.key],
|
|
2325
2357
|
title: t.title,
|
|
2326
2358
|
"aria-label": t.title,
|
|
@@ -2329,9 +2361,9 @@ function VectorToolbar({
|
|
|
2329
2361
|
},
|
|
2330
2362
|
t.key
|
|
2331
2363
|
)),
|
|
2332
|
-
state.tool === "pencil" && /* @__PURE__ */
|
|
2364
|
+
state.tool === "pencil" && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2333
2365
|
"Smoothing",
|
|
2334
|
-
/* @__PURE__ */
|
|
2366
|
+
/* @__PURE__ */ jsx16(
|
|
2335
2367
|
"input",
|
|
2336
2368
|
{
|
|
2337
2369
|
type: "range",
|
|
@@ -2345,9 +2377,9 @@ function VectorToolbar({
|
|
|
2345
2377
|
}
|
|
2346
2378
|
)
|
|
2347
2379
|
] }),
|
|
2348
|
-
state.tool === "eraser" && /* @__PURE__ */
|
|
2380
|
+
state.tool === "eraser" && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2349
2381
|
"Size",
|
|
2350
|
-
/* @__PURE__ */
|
|
2382
|
+
/* @__PURE__ */ jsx16(
|
|
2351
2383
|
"input",
|
|
2352
2384
|
{
|
|
2353
2385
|
type: "number",
|
|
@@ -2363,12 +2395,12 @@ function VectorToolbar({
|
|
|
2363
2395
|
}
|
|
2364
2396
|
)
|
|
2365
2397
|
] }),
|
|
2366
|
-
state.tool === "paintBucket" && /* @__PURE__ */
|
|
2398
|
+
state.tool === "paintBucket" && /* @__PURE__ */ jsx16(
|
|
2367
2399
|
"button",
|
|
2368
2400
|
{
|
|
2369
2401
|
type: "button",
|
|
2370
2402
|
"data-vector-fill-gap": "",
|
|
2371
|
-
className:
|
|
2403
|
+
className: buttonClass14,
|
|
2372
2404
|
"aria-pressed": editing.fillGap > 0,
|
|
2373
2405
|
title: "Close small gaps between path ends when filling",
|
|
2374
2406
|
"aria-label": "Close gaps",
|
|
@@ -2377,12 +2409,12 @@ function VectorToolbar({
|
|
|
2377
2409
|
}
|
|
2378
2410
|
)
|
|
2379
2411
|
] }),
|
|
2380
|
-
showDistort && /* @__PURE__ */
|
|
2412
|
+
showDistort && /* @__PURE__ */ jsx16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ jsx16(
|
|
2381
2413
|
"button",
|
|
2382
2414
|
{
|
|
2383
2415
|
type: "button",
|
|
2384
2416
|
"data-vector-free-distort": "",
|
|
2385
|
-
className:
|
|
2417
|
+
className: buttonClass14,
|
|
2386
2418
|
"aria-pressed": state.freeDistort,
|
|
2387
2419
|
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)`,
|
|
2388
2420
|
"aria-label": "Free Distort",
|
|
@@ -2390,15 +2422,15 @@ function VectorToolbar({
|
|
|
2390
2422
|
children: "Distort"
|
|
2391
2423
|
}
|
|
2392
2424
|
) }),
|
|
2393
|
-
showBlend && /* @__PURE__ */
|
|
2394
|
-
showArrange && /* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2425
|
+
showBlend && /* @__PURE__ */ jsx16(VectorBlendControls, { controller }),
|
|
2426
|
+
showArrange && /* @__PURE__ */ jsxs16(Fragment6, { children: [
|
|
2427
|
+
/* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2428
|
+
/* @__PURE__ */ jsx16(
|
|
2397
2429
|
"button",
|
|
2398
2430
|
{
|
|
2399
2431
|
type: "button",
|
|
2400
2432
|
"data-vector-live-boolean": "",
|
|
2401
|
-
className:
|
|
2433
|
+
className: buttonClass14,
|
|
2402
2434
|
"aria-pressed": live,
|
|
2403
2435
|
title: "Live booleans: keep the shapes editable",
|
|
2404
2436
|
"aria-label": "Live booleans",
|
|
@@ -2415,12 +2447,12 @@ function VectorToolbar({
|
|
|
2415
2447
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2416
2448
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2417
2449
|
] }),
|
|
2418
|
-
/* @__PURE__ */
|
|
2450
|
+
/* @__PURE__ */ jsx16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ jsx16(
|
|
2419
2451
|
"button",
|
|
2420
2452
|
{
|
|
2421
2453
|
type: "button",
|
|
2422
2454
|
"data-vector-pathfinder": a.id,
|
|
2423
|
-
className:
|
|
2455
|
+
className: buttonClass14,
|
|
2424
2456
|
title: a.title,
|
|
2425
2457
|
"aria-label": a.title,
|
|
2426
2458
|
disabled: count < a.min,
|
|
@@ -2429,7 +2461,7 @@ function VectorToolbar({
|
|
|
2429
2461
|
},
|
|
2430
2462
|
a.id
|
|
2431
2463
|
)) }),
|
|
2432
|
-
/* @__PURE__ */
|
|
2464
|
+
/* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
2433
2465
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
2434
2466
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
2435
2467
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -2447,19 +2479,19 @@ function VectorBlendControls({ controller }) {
|
|
|
2447
2479
|
const blend = getVectorBlendControls(state);
|
|
2448
2480
|
const o = blend.options;
|
|
2449
2481
|
const selected = blend.ids.length > 0;
|
|
2450
|
-
return /* @__PURE__ */
|
|
2451
|
-
/* @__PURE__ */
|
|
2452
|
-
/* @__PURE__ */
|
|
2482
|
+
return /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2483
|
+
/* @__PURE__ */ jsx16("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" }),
|
|
2484
|
+
/* @__PURE__ */ jsx16(
|
|
2453
2485
|
"select",
|
|
2454
2486
|
{
|
|
2455
2487
|
"aria-label": "Blend spacing",
|
|
2456
2488
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2457
2489
|
value: o.spacing,
|
|
2458
2490
|
onChange: (e) => applyVectorBlendOptions(controller, { spacing: e.target.value }),
|
|
2459
|
-
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */
|
|
2491
|
+
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ jsx16("option", { value: sp, children: VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2460
2492
|
}
|
|
2461
2493
|
),
|
|
2462
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */
|
|
2494
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ jsx16(
|
|
2463
2495
|
"input",
|
|
2464
2496
|
{
|
|
2465
2497
|
type: "number",
|
|
@@ -2475,12 +2507,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2475
2507
|
}
|
|
2476
2508
|
}
|
|
2477
2509
|
),
|
|
2478
|
-
/* @__PURE__ */
|
|
2510
|
+
/* @__PURE__ */ jsx16(
|
|
2479
2511
|
"button",
|
|
2480
2512
|
{
|
|
2481
2513
|
type: "button",
|
|
2482
2514
|
"data-vector-blend-action": "orient",
|
|
2483
|
-
className:
|
|
2515
|
+
className: buttonClass14,
|
|
2484
2516
|
"aria-pressed": o.orientToSpine,
|
|
2485
2517
|
title: "Orient steps to the spine",
|
|
2486
2518
|
"aria-label": "Orient to spine",
|
|
@@ -2488,12 +2520,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2488
2520
|
children: "\u293F"
|
|
2489
2521
|
}
|
|
2490
2522
|
),
|
|
2491
|
-
/* @__PURE__ */
|
|
2523
|
+
/* @__PURE__ */ jsx16(
|
|
2492
2524
|
"button",
|
|
2493
2525
|
{
|
|
2494
2526
|
type: "button",
|
|
2495
2527
|
"data-vector-blend-action": "spine",
|
|
2496
|
-
className:
|
|
2528
|
+
className: buttonClass14,
|
|
2497
2529
|
title: "Replace Spine (select a blend and a path)",
|
|
2498
2530
|
"aria-label": "Replace Spine",
|
|
2499
2531
|
disabled: !blend.canReplaceSpine,
|
|
@@ -2501,12 +2533,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2501
2533
|
children: "\u2307"
|
|
2502
2534
|
}
|
|
2503
2535
|
),
|
|
2504
|
-
/* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2536
|
+
/* @__PURE__ */ jsx16("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass14, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2537
|
+
/* @__PURE__ */ jsx16("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass14, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
2506
2538
|
] });
|
|
2507
2539
|
}
|
|
2508
|
-
var
|
|
2509
|
-
var
|
|
2540
|
+
var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2541
|
+
var numberClass10 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2510
2542
|
function VectorStylePanel({ controller, className }) {
|
|
2511
2543
|
const state = useVectorEditorState(controller);
|
|
2512
2544
|
const style = getVectorSelectionStyle(state);
|
|
@@ -2538,17 +2570,17 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2538
2570
|
if (style) controller.setWidthProfile(id);
|
|
2539
2571
|
else controller.setDefaults({ strokeWidthProfile: widthProfilePreset(id)?.length ? widthProfilePreset(id) : null });
|
|
2540
2572
|
};
|
|
2541
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */
|
|
2573
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ jsx16("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2542
2574
|
const arrowRow = (end, label) => {
|
|
2543
2575
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
2544
2576
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
2545
|
-
return /* @__PURE__ */
|
|
2546
|
-
/* @__PURE__ */
|
|
2547
|
-
/* @__PURE__ */
|
|
2548
|
-
/* @__PURE__ */
|
|
2549
|
-
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */
|
|
2577
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2578
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2579
|
+
/* @__PURE__ */ jsxs16("select", { "aria-label": `${label} arrowhead`, className: selectClass11, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2580
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "None" }),
|
|
2581
|
+
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ jsx16("option", { value: h, children: VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2550
2582
|
] }),
|
|
2551
|
-
/* @__PURE__ */
|
|
2583
|
+
/* @__PURE__ */ jsx16(
|
|
2552
2584
|
"input",
|
|
2553
2585
|
{
|
|
2554
2586
|
type: "number",
|
|
@@ -2556,7 +2588,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2556
2588
|
step: 0.25,
|
|
2557
2589
|
"aria-label": `${label} arrowhead scale`,
|
|
2558
2590
|
title: "Scale (\xD7 stroke width)",
|
|
2559
|
-
className:
|
|
2591
|
+
className: numberClass10,
|
|
2560
2592
|
value: source[scaleKey],
|
|
2561
2593
|
onChange: (e) => {
|
|
2562
2594
|
const n = parseFloat(e.target.value);
|
|
@@ -2572,14 +2604,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2572
2604
|
};
|
|
2573
2605
|
const paintRow = (key, label) => {
|
|
2574
2606
|
const paint = source[key];
|
|
2575
|
-
const hex =
|
|
2607
|
+
const hex = vectorPaintToHex6(paint);
|
|
2576
2608
|
const on = paint !== null && paint !== "none";
|
|
2577
|
-
return /* @__PURE__ */
|
|
2578
|
-
/* @__PURE__ */
|
|
2579
|
-
/* @__PURE__ */
|
|
2609
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2610
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2611
|
+
/* @__PURE__ */ jsx16("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
2580
2612
|
label
|
|
2581
2613
|
] }),
|
|
2582
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsx16(
|
|
2583
2615
|
"input",
|
|
2584
2616
|
{
|
|
2585
2617
|
type: "color",
|
|
@@ -2590,18 +2622,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2590
2622
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
2591
2623
|
}
|
|
2592
2624
|
),
|
|
2593
|
-
on && !hex && /* @__PURE__ */
|
|
2594
|
-
style?.mixed[key] && /* @__PURE__ */
|
|
2625
|
+
on && !hex && /* @__PURE__ */ jsx16("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2626
|
+
style?.mixed[key] && /* @__PURE__ */ jsx16("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2595
2627
|
] });
|
|
2596
2628
|
};
|
|
2597
|
-
return /* @__PURE__ */
|
|
2598
|
-
/* @__PURE__ */
|
|
2629
|
+
return /* @__PURE__ */ jsxs16("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2630
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
2599
2631
|
paintRow("fill", "Fill"),
|
|
2600
2632
|
paintRow("stroke", "Stroke"),
|
|
2601
|
-
style && /* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
2603
|
-
/* @__PURE__ */
|
|
2604
|
-
/* @__PURE__ */
|
|
2633
|
+
style && /* @__PURE__ */ jsx16(VectorGradientEditor, { controller }),
|
|
2634
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2635
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Width" }),
|
|
2636
|
+
/* @__PURE__ */ jsx16(
|
|
2605
2637
|
"input",
|
|
2606
2638
|
{
|
|
2607
2639
|
type: "number",
|
|
@@ -2617,33 +2649,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2617
2649
|
}
|
|
2618
2650
|
)
|
|
2619
2651
|
] }),
|
|
2620
|
-
/* @__PURE__ */
|
|
2621
|
-
/* @__PURE__ */
|
|
2622
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2653
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Align" }),
|
|
2654
|
+
/* @__PURE__ */ jsx16("select", { "aria-label": "Stroke alignment", className: selectClass11, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(VECTOR_STROKE_ALIGN_LABELS2).map((a) => /* @__PURE__ */ jsx16("option", { value: a, children: VECTOR_STROKE_ALIGN_LABELS2[a] }, a)) }),
|
|
2623
2655
|
mixed("strokeAlign")
|
|
2624
2656
|
] }),
|
|
2625
|
-
/* @__PURE__ */
|
|
2626
|
-
/* @__PURE__ */
|
|
2627
|
-
/* @__PURE__ */
|
|
2657
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2658
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Profile" }),
|
|
2659
|
+
/* @__PURE__ */ jsxs16(
|
|
2628
2660
|
"select",
|
|
2629
2661
|
{
|
|
2630
2662
|
"aria-label": "Width profile",
|
|
2631
|
-
className:
|
|
2663
|
+
className: selectClass11,
|
|
2632
2664
|
value: source.widthProfile,
|
|
2633
2665
|
onChange: (e) => {
|
|
2634
2666
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2635
2667
|
},
|
|
2636
2668
|
children: [
|
|
2637
|
-
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */
|
|
2638
|
-
source.widthProfile === "custom" && /* @__PURE__ */
|
|
2669
|
+
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ jsx16("option", { value: p.id, children: p.label }, p.id)),
|
|
2670
|
+
source.widthProfile === "custom" && /* @__PURE__ */ jsx16("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2639
2671
|
]
|
|
2640
2672
|
}
|
|
2641
2673
|
),
|
|
2642
|
-
/* @__PURE__ */
|
|
2674
|
+
/* @__PURE__ */ jsx16(
|
|
2643
2675
|
"button",
|
|
2644
2676
|
{
|
|
2645
2677
|
type: "button",
|
|
2646
|
-
className:
|
|
2678
|
+
className: buttonClass14,
|
|
2647
2679
|
title: "Reset to uniform width",
|
|
2648
2680
|
"aria-label": "Reset to uniform width",
|
|
2649
2681
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -2653,27 +2685,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2653
2685
|
),
|
|
2654
2686
|
mixed("widthProfile")
|
|
2655
2687
|
] }),
|
|
2656
|
-
source.hasOpenPath && /* @__PURE__ */
|
|
2688
|
+
source.hasOpenPath && /* @__PURE__ */ jsxs16(Fragment6, { children: [
|
|
2657
2689
|
arrowRow("start", "Start"),
|
|
2658
2690
|
arrowRow("end", "End"),
|
|
2659
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */
|
|
2660
|
-
/* @__PURE__ */
|
|
2661
|
-
/* @__PURE__ */
|
|
2662
|
-
/* @__PURE__ */
|
|
2663
|
-
/* @__PURE__ */
|
|
2691
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2692
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Heads" }),
|
|
2693
|
+
/* @__PURE__ */ jsxs16("select", { "aria-label": "Arrowhead alignment", className: selectClass11, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2694
|
+
/* @__PURE__ */ jsx16("option", { value: "extend", children: "Tip past end" }),
|
|
2695
|
+
/* @__PURE__ */ jsx16("option", { value: "tip", children: "Tip at end" })
|
|
2664
2696
|
] })
|
|
2665
2697
|
] })
|
|
2666
2698
|
] }),
|
|
2667
|
-
source.corners > 0 && /* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2699
|
+
source.corners > 0 && /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2700
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2701
|
+
/* @__PURE__ */ jsx16(
|
|
2670
2702
|
"input",
|
|
2671
2703
|
{
|
|
2672
2704
|
type: "number",
|
|
2673
2705
|
min: 0,
|
|
2674
2706
|
step: 1,
|
|
2675
2707
|
"aria-label": "Corner radius",
|
|
2676
|
-
className:
|
|
2708
|
+
className: numberClass10,
|
|
2677
2709
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
2678
2710
|
onChange: (e) => {
|
|
2679
2711
|
const n = parseFloat(e.target.value);
|
|
@@ -2681,12 +2713,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2681
2713
|
}
|
|
2682
2714
|
}
|
|
2683
2715
|
),
|
|
2684
|
-
/* @__PURE__ */
|
|
2716
|
+
/* @__PURE__ */ jsx16("select", { "aria-label": "Corner kind", className: selectClass11, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ jsx16("option", { value: k, children: VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2685
2717
|
mixed("cornerRadius")
|
|
2686
2718
|
] }),
|
|
2687
|
-
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */
|
|
2688
|
-
/* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
2719
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ jsxs16("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: [
|
|
2720
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Smoothing" }),
|
|
2721
|
+
/* @__PURE__ */ jsx16(
|
|
2690
2722
|
"input",
|
|
2691
2723
|
{
|
|
2692
2724
|
type: "range",
|
|
@@ -2701,9 +2733,9 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2701
2733
|
}
|
|
2702
2734
|
)
|
|
2703
2735
|
] }),
|
|
2704
|
-
style && /* @__PURE__ */
|
|
2705
|
-
/* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2736
|
+
style && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2737
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Opacity" }),
|
|
2738
|
+
/* @__PURE__ */ jsx16(
|
|
2707
2739
|
"input",
|
|
2708
2740
|
{
|
|
2709
2741
|
type: "range",
|
|
@@ -2717,28 +2749,29 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2717
2749
|
}
|
|
2718
2750
|
)
|
|
2719
2751
|
] }),
|
|
2720
|
-
/* @__PURE__ */
|
|
2721
|
-
style && /* @__PURE__ */
|
|
2722
|
-
style && /* @__PURE__ */
|
|
2723
|
-
style && /* @__PURE__ */
|
|
2724
|
-
style && /* @__PURE__ */
|
|
2725
|
-
/* @__PURE__ */
|
|
2726
|
-
/* @__PURE__ */
|
|
2727
|
-
/* @__PURE__ */
|
|
2728
|
-
/* @__PURE__ */
|
|
2729
|
-
/* @__PURE__ */
|
|
2730
|
-
/* @__PURE__ */
|
|
2752
|
+
/* @__PURE__ */ jsx16(VectorTextPanel, { controller }),
|
|
2753
|
+
style && /* @__PURE__ */ jsx16(VectorAppearancePanel, { controller }),
|
|
2754
|
+
style && /* @__PURE__ */ jsx16(VectorEffectsPanel, { controller }),
|
|
2755
|
+
style && /* @__PURE__ */ jsx16(VectorEnvelopePanel, { controller }),
|
|
2756
|
+
style && /* @__PURE__ */ jsx16(VectorMaskPanel, { controller }),
|
|
2757
|
+
/* @__PURE__ */ jsx16(VectorFramePanel, { controller }),
|
|
2758
|
+
/* @__PURE__ */ jsx16(VectorConnectorPanel, { controller }),
|
|
2759
|
+
/* @__PURE__ */ jsx16(VectorShadingPanel, { controller }),
|
|
2760
|
+
/* @__PURE__ */ jsx16(VectorSymmetryPanel, { controller }),
|
|
2761
|
+
/* @__PURE__ */ jsx16(VectorTracePanel, { controller }),
|
|
2762
|
+
/* @__PURE__ */ jsx16(VectorConstraintsPanel, { controller }),
|
|
2763
|
+
/* @__PURE__ */ jsx16(VectorSymbolsPanel, { controller })
|
|
2731
2764
|
] });
|
|
2732
2765
|
}
|
|
2733
2766
|
|
|
2734
2767
|
// src/vector/VectorEditor.tsx
|
|
2735
|
-
import { jsx as
|
|
2768
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2736
2769
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
2737
|
-
return /* @__PURE__ */
|
|
2738
|
-
/* @__PURE__ */
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
showStylePanel && /* @__PURE__ */
|
|
2770
|
+
return /* @__PURE__ */ jsxs17("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
2771
|
+
/* @__PURE__ */ jsx17(VectorToolbar, { controller, tools }),
|
|
2772
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
2773
|
+
/* @__PURE__ */ jsx17("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ jsx17(VectorCanvas, { controller, ...canvasProps }) }),
|
|
2774
|
+
showStylePanel && /* @__PURE__ */ jsx17(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
2742
2775
|
] })
|
|
2743
2776
|
] });
|
|
2744
2777
|
}
|
|
@@ -2761,6 +2794,7 @@ export {
|
|
|
2761
2794
|
VectorShadingPanel,
|
|
2762
2795
|
VectorStylePanel,
|
|
2763
2796
|
VectorSymbolsPanel,
|
|
2797
|
+
VectorSymmetryPanel,
|
|
2764
2798
|
VectorTextElement,
|
|
2765
2799
|
VectorTextPanel,
|
|
2766
2800
|
VectorToolbar,
|