@pixerate/editor-react 0.33.0 → 0.35.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/README.md +1 -0
- package/dist/chart/index.cjs +562 -0
- package/dist/chart/index.cjs.map +1 -0
- package/dist/chart/index.d.cts +118 -0
- package/dist/chart/index.d.ts +118 -0
- package/dist/chart/index.js +544 -0
- package/dist/chart/index.js.map +1 -0
- package/dist/vector/index.cjs +298 -155
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +17 -3
- package/dist/vector/index.d.ts +17 -3
- package/dist/vector/index.js +281 -139
- package/dist/vector/index.js.map +1 -1
- package/package.json +11 -3
package/dist/vector/index.js
CHANGED
|
@@ -365,13 +365,28 @@ function VectorCanvas({
|
|
|
365
365
|
/* @__PURE__ */ jsxs2("g", { "data-vector-overlay": "", pointerEvents: "none", fill: "none", children: [
|
|
366
366
|
overlay.outlines.map((o) => /* @__PURE__ */ jsx2("path", { d: o.d, stroke: accentColor, strokeWidth: o.selected ? 1 : 1.5, opacity: o.selected ? 1 : 0.7 }, o.id)),
|
|
367
367
|
overlay.penPreview && /* @__PURE__ */ jsx2("path", { d: overlay.penPreview, stroke: accentColor, strokeDasharray: "4 3" }),
|
|
368
|
-
box && /* @__PURE__ */ jsxs2("g", { "data-vector-selection": "", transform: box.transform || void 0, children: [
|
|
368
|
+
box && /* @__PURE__ */ jsxs2("g", { "data-vector-selection": "", "data-free-distort": box.freeDistort || void 0, transform: box.transform || void 0, children: [
|
|
369
369
|
/* @__PURE__ */ jsx2("rect", { x: box.x, y: box.y, width: box.width, height: box.height, stroke: accentColor }),
|
|
370
370
|
/* @__PURE__ */ jsx2("line", { x1: box.x + box.width / 2, y1: box.y, x2: box.x + box.width / 2, y2: box.y - 24, stroke: accentColor }),
|
|
371
371
|
box.handles.map(
|
|
372
372
|
(h) => h.handle === "rotate" ? /* @__PURE__ */ jsx2("circle", { "data-handle": h.handle, cx: h.x, cy: h.y, r: hs / 2 + 1, fill: THEME2.handleFill, stroke: accentColor }, h.handle) : /* @__PURE__ */ jsx2("rect", { "data-handle": h.handle, x: h.x - hs / 2, y: h.y - hs / 2, width: hs, height: hs, fill: THEME2.handleFill, stroke: accentColor }, h.handle)
|
|
373
373
|
)
|
|
374
374
|
] }),
|
|
375
|
+
overlay.distort && /* @__PURE__ */ jsxs2("g", { "data-vector-distort": overlay.distort.mode, children: [
|
|
376
|
+
/* @__PURE__ */ jsx2("path", { d: overlay.distort.d, stroke: accentColor }),
|
|
377
|
+
overlay.distort.corners.map((c, i) => /* @__PURE__ */ jsx2("rect", { x: c.x - hs / 2, y: c.y - hs / 2, width: hs, height: hs, fill: THEME2.handleFill, stroke: accentColor }, i))
|
|
378
|
+
] }),
|
|
379
|
+
overlay.envelope && /* @__PURE__ */ jsxs2("g", { "data-vector-envelope-mesh": overlay.envelope.nodeId, children: [
|
|
380
|
+
/* @__PURE__ */ jsx2("path", { "data-vector-envelope-grid": "", d: overlay.envelope.grid, stroke: accentColor, strokeOpacity: 0.8 }),
|
|
381
|
+
overlay.envelope.handles.map((h) => /* @__PURE__ */ jsxs2("g", { "data-vector-envelope-handle": h.index, children: [
|
|
382
|
+
/* @__PURE__ */ jsx2("line", { x1: h.anchorX, y1: h.anchorY, x2: h.x, y2: h.y, stroke: accentColor, strokeOpacity: 0.6 }),
|
|
383
|
+
/* @__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 })
|
|
384
|
+
] }, h.index)),
|
|
385
|
+
overlay.envelope.anchors.map((a) => {
|
|
386
|
+
const size = as + (a.hovered || a.active ? 2 : 0);
|
|
387
|
+
return /* @__PURE__ */ jsx2("rect", { "data-vector-envelope-anchor": a.index, x: a.x - size / 2, y: a.y - size / 2, width: size, height: size, fill: a.active ? accentColor : THEME2.handleFill, stroke: accentColor }, a.index);
|
|
388
|
+
})
|
|
389
|
+
] }),
|
|
375
390
|
overlay.handles.map((h) => /* @__PURE__ */ jsxs2("g", { "data-vector-handle": h.ref.handle, children: [
|
|
376
391
|
/* @__PURE__ */ jsx2("line", { x1: h.anchorX, y1: h.anchorY, x2: h.x, y2: h.y, stroke: accentColor }),
|
|
377
392
|
/* @__PURE__ */ jsx2("circle", { cx: h.x, cy: h.y, r: THEME2.handleRadius + (h.hovered ? 1 : 0), fill: THEME2.handleFill, stroke: accentColor })
|
|
@@ -513,7 +528,7 @@ function VectorCanvas({
|
|
|
513
528
|
}
|
|
514
529
|
|
|
515
530
|
// src/vector/VectorToolbar.tsx
|
|
516
|
-
import
|
|
531
|
+
import React4 from "react";
|
|
517
532
|
import {
|
|
518
533
|
VECTOR_TOOLS,
|
|
519
534
|
VECTOR_TOOL_GLYPHS,
|
|
@@ -682,6 +697,117 @@ function VectorEffectsPanel({ controller, className }) {
|
|
|
682
697
|
] });
|
|
683
698
|
}
|
|
684
699
|
|
|
700
|
+
// src/vector/VectorEnvelopePanel.tsx
|
|
701
|
+
import React3 from "react";
|
|
702
|
+
import { VECTOR_ENVELOPE_STYLE_OPTIONS, getVectorEnvelopePanel } from "@pixerate/editor/vector";
|
|
703
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
704
|
+
var buttonClass2 = "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";
|
|
705
|
+
var numberClass2 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
706
|
+
var selectClass2 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
707
|
+
var labelClass2 = "w-full truncate text-[11px] text-muted-foreground";
|
|
708
|
+
var SLIDERS = [
|
|
709
|
+
{ key: "bend", label: "Bend %" },
|
|
710
|
+
{ key: "horizontal", label: "Horizontal distortion %" },
|
|
711
|
+
{ key: "vertical", label: "Vertical distortion %" }
|
|
712
|
+
];
|
|
713
|
+
function VectorEnvelopePanel({ controller, className }) {
|
|
714
|
+
const state = useVectorEditorState(controller);
|
|
715
|
+
const panel = getVectorEnvelopePanel(state);
|
|
716
|
+
const [size, setSize] = React3.useState({ rows: 2, columns: 2 });
|
|
717
|
+
if (!panel) return null;
|
|
718
|
+
const env = panel.envelope;
|
|
719
|
+
const ids = panel.nodeId ? [panel.nodeId] : void 0;
|
|
720
|
+
const end = () => controller.endMergedEdit();
|
|
721
|
+
const set = (patch, merge = false) => controller.envelope(patch, { ids, merge });
|
|
722
|
+
const rows = env?.params.rows ?? size.rows;
|
|
723
|
+
const columns = env?.params.columns ?? size.columns;
|
|
724
|
+
const setCount = (key, raw) => {
|
|
725
|
+
const n = Math.round(parseFloat(raw));
|
|
726
|
+
if (!Number.isFinite(n) || n < 1 || n > 16) return;
|
|
727
|
+
if (env) set({ [key]: n });
|
|
728
|
+
else setSize({ ...size, [key]: n });
|
|
729
|
+
};
|
|
730
|
+
return /* @__PURE__ */ jsxs4("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-envelope": "", "aria-label": "Envelope", children: [
|
|
731
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
732
|
+
/* @__PURE__ */ jsx4("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Envelope" }),
|
|
733
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "data-vector-envelope-action": "warp", className: buttonClass2, title: "Make with Warp", "aria-label": "Make with Warp", disabled: !panel.canMake || !!env, onClick: () => set({ style: "arc", bend: 50 }), children: "Warp" }),
|
|
734
|
+
/* @__PURE__ */ jsx4(
|
|
735
|
+
"button",
|
|
736
|
+
{
|
|
737
|
+
type: "button",
|
|
738
|
+
"data-vector-envelope-action": "mesh",
|
|
739
|
+
className: buttonClass2,
|
|
740
|
+
title: "Make with Mesh",
|
|
741
|
+
"aria-label": "Make with Mesh",
|
|
742
|
+
disabled: !panel.canMake || !!env,
|
|
743
|
+
onClick: () => set({ style: "mesh", rows: size.rows, columns: size.columns }),
|
|
744
|
+
children: "Mesh"
|
|
745
|
+
}
|
|
746
|
+
),
|
|
747
|
+
/* @__PURE__ */ jsx4(
|
|
748
|
+
"button",
|
|
749
|
+
{
|
|
750
|
+
type: "button",
|
|
751
|
+
"data-vector-envelope-action": "top",
|
|
752
|
+
className: buttonClass2,
|
|
753
|
+
title: "Make with Top Object",
|
|
754
|
+
"aria-label": "Make with Top Object",
|
|
755
|
+
disabled: !panel.canMakeWithTopObject,
|
|
756
|
+
onClick: () => controller.makeEnvelopeWithTopObject({ rows: size.rows, columns: size.columns }),
|
|
757
|
+
children: "Top"
|
|
758
|
+
}
|
|
759
|
+
),
|
|
760
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "data-vector-envelope-action": "release", className: buttonClass2, title: "Release Envelope", "aria-label": "Release Envelope", disabled: !panel.canRelease, onClick: () => controller.releaseEnvelope(), children: "Release" }),
|
|
761
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "data-vector-envelope-action": "expand", className: buttonClass2, title: "Expand Envelope", "aria-label": "Expand Envelope", disabled: !panel.canRelease, onClick: () => controller.expandAppearance(), children: "Expand" })
|
|
762
|
+
] }),
|
|
763
|
+
env && /* @__PURE__ */ jsxs4("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-envelope-param": "style", children: [
|
|
764
|
+
/* @__PURE__ */ jsx4("span", { className: labelClass2, children: "Warp" }),
|
|
765
|
+
/* @__PURE__ */ jsx4("select", { "aria-label": "Envelope warp", className: selectClass2, value: env.params.style, onChange: (e) => set({ style: e.target.value }), children: VECTOR_ENVELOPE_STYLE_OPTIONS.map((o) => /* @__PURE__ */ jsx4("option", { value: o.value, children: o.label }, o.value)) })
|
|
766
|
+
] }),
|
|
767
|
+
env && env.params.style !== "mesh" && SLIDERS.map((s) => {
|
|
768
|
+
const value = env.params[s.key];
|
|
769
|
+
const onChange = (ev) => {
|
|
770
|
+
const n = parseFloat(ev.target.value);
|
|
771
|
+
if (Number.isFinite(n)) set({ [s.key]: n }, true);
|
|
772
|
+
};
|
|
773
|
+
return /* @__PURE__ */ jsxs4("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-envelope-param": s.key, children: [
|
|
774
|
+
/* @__PURE__ */ jsx4("span", { className: labelClass2, children: s.label }),
|
|
775
|
+
/* @__PURE__ */ jsx4(
|
|
776
|
+
"input",
|
|
777
|
+
{
|
|
778
|
+
type: "range",
|
|
779
|
+
min: -100,
|
|
780
|
+
max: 100,
|
|
781
|
+
step: 1,
|
|
782
|
+
"aria-label": `Envelope ${s.label} slider`,
|
|
783
|
+
className: "h-4 min-w-0 flex-1 accent-primary",
|
|
784
|
+
value,
|
|
785
|
+
onChange,
|
|
786
|
+
onPointerUp: end,
|
|
787
|
+
onKeyUp: end,
|
|
788
|
+
onBlur: end
|
|
789
|
+
}
|
|
790
|
+
),
|
|
791
|
+
/* @__PURE__ */ jsx4("input", { type: "number", min: -100, max: 100, step: 1, "aria-label": `Envelope ${s.label}`, className: numberClass2, value, onChange, onBlur: end })
|
|
792
|
+
] }, s.key);
|
|
793
|
+
}),
|
|
794
|
+
env && env.params.style !== "mesh" && /* @__PURE__ */ jsxs4("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-envelope-param": "orientation", children: [
|
|
795
|
+
/* @__PURE__ */ jsx4("span", { className: labelClass2, children: "Orientation" }),
|
|
796
|
+
/* @__PURE__ */ jsxs4("select", { "aria-label": "Envelope orientation", className: selectClass2, value: env.params.orientation, onChange: (e) => set({ orientation: e.target.value }), children: [
|
|
797
|
+
/* @__PURE__ */ jsx4("option", { value: "horizontal", children: "Horizontal" }),
|
|
798
|
+
/* @__PURE__ */ jsx4("option", { value: "vertical", children: "Vertical" })
|
|
799
|
+
] })
|
|
800
|
+
] }),
|
|
801
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-envelope-param": "mesh", children: [
|
|
802
|
+
/* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate text-[11px] text-muted-foreground", children: "Mesh rows \xD7 columns" }),
|
|
803
|
+
/* @__PURE__ */ jsx4("input", { type: "number", min: 1, max: 16, step: 1, "aria-label": "Envelope mesh rows", className: numberClass2, value: rows, onChange: (e) => setCount("rows", e.target.value) }),
|
|
804
|
+
/* @__PURE__ */ jsx4("input", { type: "number", min: 1, max: 16, step: 1, "aria-label": "Envelope mesh columns", className: numberClass2, value: columns, onChange: (e) => setCount("columns", e.target.value) })
|
|
805
|
+
] }),
|
|
806
|
+
panel.count > 1 && !panel.canMakeWithTopObject && /* @__PURE__ */ jsx4("p", { className: "text-[11px] text-muted-foreground", children: "Select one object to edit its envelope." }),
|
|
807
|
+
env && /* @__PURE__ */ jsx4("p", { className: "text-[11px] text-muted-foreground", children: "Edit the mesh with the Envelope tool (U)." })
|
|
808
|
+
] });
|
|
809
|
+
}
|
|
810
|
+
|
|
685
811
|
// src/vector/VectorGradientEditor.tsx
|
|
686
812
|
import {
|
|
687
813
|
VECTOR_GRADIENT_TYPES,
|
|
@@ -695,10 +821,10 @@ import {
|
|
|
695
821
|
getVectorGradientEditor,
|
|
696
822
|
vectorPaintToHex
|
|
697
823
|
} from "@pixerate/editor/vector";
|
|
698
|
-
import { Fragment as Fragment2, jsx as
|
|
699
|
-
var
|
|
700
|
-
var
|
|
701
|
-
var
|
|
824
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
825
|
+
var selectClass3 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
826
|
+
var numberClass3 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
827
|
+
var buttonClass3 = "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";
|
|
702
828
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
703
829
|
function VectorGradientEditor({ controller, className }) {
|
|
704
830
|
const state = useVectorEditorState(controller);
|
|
@@ -713,23 +839,23 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
713
839
|
controller.setStyle({ [ed.target]: vectorPaintToHex(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
714
840
|
} else controller.setGradient({ type: value });
|
|
715
841
|
};
|
|
716
|
-
return /* @__PURE__ */
|
|
717
|
-
/* @__PURE__ */
|
|
718
|
-
/* @__PURE__ */
|
|
719
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */
|
|
720
|
-
ed.mixed && /* @__PURE__ */
|
|
842
|
+
return /* @__PURE__ */ jsxs5("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
843
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5", children: [
|
|
844
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
845
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ jsx5("button", { type: "button", className: buttonClass3, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
846
|
+
ed.mixed && /* @__PURE__ */ jsx5("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
721
847
|
] }),
|
|
722
|
-
/* @__PURE__ */
|
|
723
|
-
/* @__PURE__ */
|
|
724
|
-
/* @__PURE__ */
|
|
725
|
-
/* @__PURE__ */
|
|
726
|
-
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */
|
|
848
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5", children: [
|
|
849
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
850
|
+
/* @__PURE__ */ jsxs5("select", { "aria-label": "Gradient type", className: selectClass3, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
851
|
+
/* @__PURE__ */ jsx5("option", { value: "solid", children: "Solid" }),
|
|
852
|
+
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ jsx5("option", { value: t, children: VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
727
853
|
] }),
|
|
728
|
-
/* @__PURE__ */
|
|
854
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: buttonClass3, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
729
855
|
] }),
|
|
730
|
-
g && /* @__PURE__ */
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
/* @__PURE__ */
|
|
856
|
+
g && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
857
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
858
|
+
/* @__PURE__ */ jsx5(
|
|
733
859
|
"div",
|
|
734
860
|
{
|
|
735
861
|
role: "button",
|
|
@@ -743,7 +869,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
743
869
|
}
|
|
744
870
|
}
|
|
745
871
|
),
|
|
746
|
-
ed.stops.map((s) => /* @__PURE__ */
|
|
872
|
+
ed.stops.map((s) => /* @__PURE__ */ jsx5(
|
|
747
873
|
"button",
|
|
748
874
|
{
|
|
749
875
|
type: "button",
|
|
@@ -757,8 +883,8 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
757
883
|
s.index
|
|
758
884
|
))
|
|
759
885
|
] }),
|
|
760
|
-
sel && /* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
886
|
+
sel && /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
887
|
+
/* @__PURE__ */ jsx5(
|
|
762
888
|
"input",
|
|
763
889
|
{
|
|
764
890
|
type: "color",
|
|
@@ -769,9 +895,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
769
895
|
onBlur: end
|
|
770
896
|
}
|
|
771
897
|
),
|
|
772
|
-
/* @__PURE__ */
|
|
898
|
+
/* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
773
899
|
"Opacity",
|
|
774
|
-
/* @__PURE__ */
|
|
900
|
+
/* @__PURE__ */ jsx5(
|
|
775
901
|
"input",
|
|
776
902
|
{
|
|
777
903
|
type: "number",
|
|
@@ -779,7 +905,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
779
905
|
max: 100,
|
|
780
906
|
step: 5,
|
|
781
907
|
"aria-label": "Stop opacity",
|
|
782
|
-
className:
|
|
908
|
+
className: numberClass3,
|
|
783
909
|
value: percent(sel.opacity ?? 1),
|
|
784
910
|
onChange: (e) => {
|
|
785
911
|
const n = parseFloat(e.target.value);
|
|
@@ -788,9 +914,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
788
914
|
}
|
|
789
915
|
)
|
|
790
916
|
] }),
|
|
791
|
-
/* @__PURE__ */
|
|
917
|
+
/* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
792
918
|
"At",
|
|
793
|
-
/* @__PURE__ */
|
|
919
|
+
/* @__PURE__ */ jsx5(
|
|
794
920
|
"input",
|
|
795
921
|
{
|
|
796
922
|
type: "number",
|
|
@@ -798,7 +924,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
798
924
|
max: 100,
|
|
799
925
|
step: 1,
|
|
800
926
|
"aria-label": "Stop position",
|
|
801
|
-
className:
|
|
927
|
+
className: numberClass3,
|
|
802
928
|
value: percent(sel.offset),
|
|
803
929
|
onChange: (e) => {
|
|
804
930
|
const n = parseFloat(e.target.value);
|
|
@@ -807,9 +933,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
807
933
|
}
|
|
808
934
|
)
|
|
809
935
|
] }),
|
|
810
|
-
!sel.last && /* @__PURE__ */
|
|
936
|
+
!sel.last && /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
811
937
|
"Midpoint",
|
|
812
|
-
/* @__PURE__ */
|
|
938
|
+
/* @__PURE__ */ jsx5(
|
|
813
939
|
"input",
|
|
814
940
|
{
|
|
815
941
|
type: "number",
|
|
@@ -817,7 +943,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
817
943
|
max: 95,
|
|
818
944
|
step: 1,
|
|
819
945
|
"aria-label": "Stop midpoint",
|
|
820
|
-
className:
|
|
946
|
+
className: numberClass3,
|
|
821
947
|
value: percent(sel.midpoint ?? 0.5),
|
|
822
948
|
onChange: (e) => {
|
|
823
949
|
const n = parseFloat(e.target.value);
|
|
@@ -826,15 +952,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
826
952
|
}
|
|
827
953
|
)
|
|
828
954
|
] }),
|
|
829
|
-
/* @__PURE__ */
|
|
955
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: buttonClass3, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
830
956
|
] }),
|
|
831
|
-
/* @__PURE__ */
|
|
832
|
-
/* @__PURE__ */
|
|
833
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
958
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16", children: "Colours" }),
|
|
959
|
+
/* @__PURE__ */ jsx5("select", { "aria-label": "Gradient interpolation", className: selectClass3, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx5("option", { value: i, children: VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
834
960
|
] }),
|
|
835
|
-
/* @__PURE__ */
|
|
836
|
-
/* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
961
|
+
/* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
962
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16", children: "Smooth" }),
|
|
963
|
+
/* @__PURE__ */ jsx5(
|
|
838
964
|
"input",
|
|
839
965
|
{
|
|
840
966
|
type: "range",
|
|
@@ -850,23 +976,23 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
850
976
|
}
|
|
851
977
|
)
|
|
852
978
|
] }),
|
|
853
|
-
/* @__PURE__ */
|
|
854
|
-
/* @__PURE__ */
|
|
855
|
-
/* @__PURE__ */
|
|
979
|
+
/* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
980
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16", children: "Spread" }),
|
|
981
|
+
/* @__PURE__ */ jsx5("select", { "aria-label": "Gradient spread", className: selectClass3, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ jsx5("option", { value: sp, children: VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
856
982
|
] }),
|
|
857
|
-
ed.target === "stroke" && /* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
859
|
-
/* @__PURE__ */
|
|
983
|
+
ed.target === "stroke" && /* @__PURE__ */ jsxs5("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
984
|
+
/* @__PURE__ */ jsx5("span", { className: "w-16", children: "On stroke" }),
|
|
985
|
+
/* @__PURE__ */ jsx5("select", { "aria-label": "Gradient on stroke", className: selectClass3, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ jsx5("option", { value: m, children: VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
860
986
|
] })
|
|
861
987
|
] })
|
|
862
988
|
] });
|
|
863
989
|
}
|
|
864
990
|
|
|
865
991
|
// src/vector/VectorToolbar.tsx
|
|
866
|
-
import { Fragment as Fragment3, jsx as
|
|
992
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
867
993
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
868
994
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
869
|
-
var
|
|
995
|
+
var buttonClass4 = "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";
|
|
870
996
|
function VectorToolbar({
|
|
871
997
|
controller,
|
|
872
998
|
tools = VECTOR_TOOLS,
|
|
@@ -875,6 +1001,7 @@ function VectorToolbar({
|
|
|
875
1001
|
showSnap = true,
|
|
876
1002
|
showPathEdit = true,
|
|
877
1003
|
showBlend = true,
|
|
1004
|
+
showDistort = true,
|
|
878
1005
|
className
|
|
879
1006
|
}) {
|
|
880
1007
|
const state = useVectorEditorState(controller);
|
|
@@ -882,16 +1009,16 @@ function VectorToolbar({
|
|
|
882
1009
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
883
1010
|
const editing = state.editing;
|
|
884
1011
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
885
|
-
const [live, setLive] =
|
|
1012
|
+
const [live, setLive] = React4.useState(false);
|
|
886
1013
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
887
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */
|
|
888
|
-
return /* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
1014
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ jsx6("button", { type: "button", className: buttonClass4, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
1015
|
+
return /* @__PURE__ */ jsxs6("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
1016
|
+
/* @__PURE__ */ jsx6("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ jsx6(
|
|
890
1017
|
"button",
|
|
891
1018
|
{
|
|
892
1019
|
type: "button",
|
|
893
1020
|
"data-vector-tool": tool,
|
|
894
|
-
className:
|
|
1021
|
+
className: buttonClass4,
|
|
895
1022
|
"aria-pressed": state.tool === tool,
|
|
896
1023
|
title: `${vectorToolLabel(tool)} (${VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
897
1024
|
"aria-label": vectorToolLabel(tool),
|
|
@@ -900,16 +1027,16 @@ function VectorToolbar({
|
|
|
900
1027
|
},
|
|
901
1028
|
tool
|
|
902
1029
|
)) }),
|
|
903
|
-
showHistory && /* @__PURE__ */
|
|
1030
|
+
showHistory && /* @__PURE__ */ jsxs6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
904
1031
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
905
1032
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
906
1033
|
] }),
|
|
907
|
-
showSnap && /* @__PURE__ */
|
|
1034
|
+
showSnap && /* @__PURE__ */ jsx6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ jsx6(
|
|
908
1035
|
"button",
|
|
909
1036
|
{
|
|
910
1037
|
type: "button",
|
|
911
1038
|
"data-vector-snap": "",
|
|
912
|
-
className:
|
|
1039
|
+
className: buttonClass4,
|
|
913
1040
|
"aria-pressed": state.snap.objects,
|
|
914
1041
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
915
1042
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -917,13 +1044,13 @@ function VectorToolbar({
|
|
|
917
1044
|
children: "Snap"
|
|
918
1045
|
}
|
|
919
1046
|
) }),
|
|
920
|
-
showPathEdit && /* @__PURE__ */
|
|
921
|
-
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */
|
|
1047
|
+
showPathEdit && /* @__PURE__ */ jsxs6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
1048
|
+
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ jsx6(
|
|
922
1049
|
"button",
|
|
923
1050
|
{
|
|
924
1051
|
type: "button",
|
|
925
1052
|
"data-vector-path-action": a.id,
|
|
926
|
-
className:
|
|
1053
|
+
className: buttonClass4,
|
|
927
1054
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
928
1055
|
"aria-label": a.title,
|
|
929
1056
|
disabled: !a.enabled(count, points),
|
|
@@ -932,12 +1059,12 @@ function VectorToolbar({
|
|
|
932
1059
|
},
|
|
933
1060
|
a.id
|
|
934
1061
|
)),
|
|
935
|
-
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */
|
|
1062
|
+
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ jsx6(
|
|
936
1063
|
"button",
|
|
937
1064
|
{
|
|
938
1065
|
type: "button",
|
|
939
1066
|
"data-vector-edit": t.key,
|
|
940
|
-
className:
|
|
1067
|
+
className: buttonClass4,
|
|
941
1068
|
"aria-pressed": editing[t.key],
|
|
942
1069
|
title: t.title,
|
|
943
1070
|
"aria-label": t.title,
|
|
@@ -946,9 +1073,9 @@ function VectorToolbar({
|
|
|
946
1073
|
},
|
|
947
1074
|
t.key
|
|
948
1075
|
)),
|
|
949
|
-
state.tool === "pencil" && /* @__PURE__ */
|
|
1076
|
+
state.tool === "pencil" && /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
950
1077
|
"Smoothing",
|
|
951
|
-
/* @__PURE__ */
|
|
1078
|
+
/* @__PURE__ */ jsx6(
|
|
952
1079
|
"input",
|
|
953
1080
|
{
|
|
954
1081
|
type: "range",
|
|
@@ -962,9 +1089,9 @@ function VectorToolbar({
|
|
|
962
1089
|
}
|
|
963
1090
|
)
|
|
964
1091
|
] }),
|
|
965
|
-
state.tool === "eraser" && /* @__PURE__ */
|
|
1092
|
+
state.tool === "eraser" && /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
966
1093
|
"Size",
|
|
967
|
-
/* @__PURE__ */
|
|
1094
|
+
/* @__PURE__ */ jsx6(
|
|
968
1095
|
"input",
|
|
969
1096
|
{
|
|
970
1097
|
type: "number",
|
|
@@ -980,12 +1107,12 @@ function VectorToolbar({
|
|
|
980
1107
|
}
|
|
981
1108
|
)
|
|
982
1109
|
] }),
|
|
983
|
-
state.tool === "paintBucket" && /* @__PURE__ */
|
|
1110
|
+
state.tool === "paintBucket" && /* @__PURE__ */ jsx6(
|
|
984
1111
|
"button",
|
|
985
1112
|
{
|
|
986
1113
|
type: "button",
|
|
987
1114
|
"data-vector-fill-gap": "",
|
|
988
|
-
className:
|
|
1115
|
+
className: buttonClass4,
|
|
989
1116
|
"aria-pressed": editing.fillGap > 0,
|
|
990
1117
|
title: "Close small gaps between path ends when filling",
|
|
991
1118
|
"aria-label": "Close gaps",
|
|
@@ -994,15 +1121,28 @@ function VectorToolbar({
|
|
|
994
1121
|
}
|
|
995
1122
|
)
|
|
996
1123
|
] }),
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1124
|
+
showDistort && /* @__PURE__ */ jsx6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ jsx6(
|
|
1125
|
+
"button",
|
|
1126
|
+
{
|
|
1127
|
+
type: "button",
|
|
1128
|
+
"data-vector-free-distort": "",
|
|
1129
|
+
className: buttonClass4,
|
|
1130
|
+
"aria-pressed": state.freeDistort,
|
|
1131
|
+
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)`,
|
|
1132
|
+
"aria-label": "Free Distort",
|
|
1133
|
+
onClick: () => controller.setFreeDistort(!state.freeDistort),
|
|
1134
|
+
children: "Distort"
|
|
1135
|
+
}
|
|
1136
|
+
) }),
|
|
1137
|
+
showBlend && /* @__PURE__ */ jsx6(VectorBlendControls, { controller }),
|
|
1138
|
+
showArrange && /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1139
|
+
/* @__PURE__ */ jsxs6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
1140
|
+
/* @__PURE__ */ jsx6(
|
|
1001
1141
|
"button",
|
|
1002
1142
|
{
|
|
1003
1143
|
type: "button",
|
|
1004
1144
|
"data-vector-live-boolean": "",
|
|
1005
|
-
className:
|
|
1145
|
+
className: buttonClass4,
|
|
1006
1146
|
"aria-pressed": live,
|
|
1007
1147
|
title: "Live booleans: keep the shapes editable",
|
|
1008
1148
|
"aria-label": "Live booleans",
|
|
@@ -1017,12 +1157,12 @@ function VectorToolbar({
|
|
|
1017
1157
|
act("G", "Group", () => controller.group(), count < 1),
|
|
1018
1158
|
act("U", "Ungroup", () => controller.ungroup(), !groupSelected)
|
|
1019
1159
|
] }),
|
|
1020
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsx6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ jsx6(
|
|
1021
1161
|
"button",
|
|
1022
1162
|
{
|
|
1023
1163
|
type: "button",
|
|
1024
1164
|
"data-vector-pathfinder": a.id,
|
|
1025
|
-
className:
|
|
1165
|
+
className: buttonClass4,
|
|
1026
1166
|
title: a.title,
|
|
1027
1167
|
"aria-label": a.title,
|
|
1028
1168
|
disabled: count < a.min,
|
|
@@ -1031,7 +1171,7 @@ function VectorToolbar({
|
|
|
1031
1171
|
},
|
|
1032
1172
|
a.id
|
|
1033
1173
|
)) }),
|
|
1034
|
-
/* @__PURE__ */
|
|
1174
|
+
/* @__PURE__ */ jsxs6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
1035
1175
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
1036
1176
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
1037
1177
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -1049,19 +1189,19 @@ function VectorBlendControls({ controller }) {
|
|
|
1049
1189
|
const blend = getVectorBlendControls(state);
|
|
1050
1190
|
const o = blend.options;
|
|
1051
1191
|
const selected = blend.ids.length > 0;
|
|
1052
|
-
return /* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1192
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
1193
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass4, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
1194
|
+
/* @__PURE__ */ jsx6(
|
|
1055
1195
|
"select",
|
|
1056
1196
|
{
|
|
1057
1197
|
"aria-label": "Blend spacing",
|
|
1058
1198
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
1059
1199
|
value: o.spacing,
|
|
1060
1200
|
onChange: (e) => applyVectorBlendOptions(controller, { spacing: e.target.value }),
|
|
1061
|
-
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */
|
|
1201
|
+
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ jsx6("option", { value: sp, children: VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
1062
1202
|
}
|
|
1063
1203
|
),
|
|
1064
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */
|
|
1204
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ jsx6(
|
|
1065
1205
|
"input",
|
|
1066
1206
|
{
|
|
1067
1207
|
type: "number",
|
|
@@ -1077,12 +1217,12 @@ function VectorBlendControls({ controller }) {
|
|
|
1077
1217
|
}
|
|
1078
1218
|
}
|
|
1079
1219
|
),
|
|
1080
|
-
/* @__PURE__ */
|
|
1220
|
+
/* @__PURE__ */ jsx6(
|
|
1081
1221
|
"button",
|
|
1082
1222
|
{
|
|
1083
1223
|
type: "button",
|
|
1084
1224
|
"data-vector-blend-action": "orient",
|
|
1085
|
-
className:
|
|
1225
|
+
className: buttonClass4,
|
|
1086
1226
|
"aria-pressed": o.orientToSpine,
|
|
1087
1227
|
title: "Orient steps to the spine",
|
|
1088
1228
|
"aria-label": "Orient to spine",
|
|
@@ -1090,12 +1230,12 @@ function VectorBlendControls({ controller }) {
|
|
|
1090
1230
|
children: "\u293F"
|
|
1091
1231
|
}
|
|
1092
1232
|
),
|
|
1093
|
-
/* @__PURE__ */
|
|
1233
|
+
/* @__PURE__ */ jsx6(
|
|
1094
1234
|
"button",
|
|
1095
1235
|
{
|
|
1096
1236
|
type: "button",
|
|
1097
1237
|
"data-vector-blend-action": "spine",
|
|
1098
|
-
className:
|
|
1238
|
+
className: buttonClass4,
|
|
1099
1239
|
title: "Replace Spine (select a blend and a path)",
|
|
1100
1240
|
"aria-label": "Replace Spine",
|
|
1101
1241
|
disabled: !blend.canReplaceSpine,
|
|
@@ -1103,12 +1243,12 @@ function VectorBlendControls({ controller }) {
|
|
|
1103
1243
|
children: "\u2307"
|
|
1104
1244
|
}
|
|
1105
1245
|
),
|
|
1106
|
-
/* @__PURE__ */
|
|
1107
|
-
/* @__PURE__ */
|
|
1246
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass4, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
1247
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass4, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
1108
1248
|
] });
|
|
1109
1249
|
}
|
|
1110
|
-
var
|
|
1111
|
-
var
|
|
1250
|
+
var selectClass4 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1251
|
+
var numberClass4 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
1112
1252
|
function VectorStylePanel({ controller, className }) {
|
|
1113
1253
|
const state = useVectorEditorState(controller);
|
|
1114
1254
|
const style = getVectorSelectionStyle(state);
|
|
@@ -1139,17 +1279,17 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1139
1279
|
if (style) controller.setWidthProfile(id);
|
|
1140
1280
|
else controller.setDefaults({ strokeWidthProfile: widthProfilePreset(id)?.length ? widthProfilePreset(id) : null });
|
|
1141
1281
|
};
|
|
1142
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */
|
|
1282
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
1143
1283
|
const arrowRow = (end, label) => {
|
|
1144
1284
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
1145
1285
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
1146
|
-
return /* @__PURE__ */
|
|
1147
|
-
/* @__PURE__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
1149
|
-
/* @__PURE__ */
|
|
1150
|
-
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */
|
|
1286
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
1288
|
+
/* @__PURE__ */ jsxs6("select", { "aria-label": `${label} arrowhead`, className: selectClass4, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
1289
|
+
/* @__PURE__ */ jsx6("option", { value: "", children: "None" }),
|
|
1290
|
+
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ jsx6("option", { value: h, children: VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
1151
1291
|
] }),
|
|
1152
|
-
/* @__PURE__ */
|
|
1292
|
+
/* @__PURE__ */ jsx6(
|
|
1153
1293
|
"input",
|
|
1154
1294
|
{
|
|
1155
1295
|
type: "number",
|
|
@@ -1157,7 +1297,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1157
1297
|
step: 0.25,
|
|
1158
1298
|
"aria-label": `${label} arrowhead scale`,
|
|
1159
1299
|
title: "Scale (\xD7 stroke width)",
|
|
1160
|
-
className:
|
|
1300
|
+
className: numberClass4,
|
|
1161
1301
|
value: source[scaleKey],
|
|
1162
1302
|
onChange: (e) => {
|
|
1163
1303
|
const n = parseFloat(e.target.value);
|
|
@@ -1175,12 +1315,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1175
1315
|
const paint = source[key];
|
|
1176
1316
|
const hex = vectorPaintToHex2(paint);
|
|
1177
1317
|
const on = paint !== null && paint !== "none";
|
|
1178
|
-
return /* @__PURE__ */
|
|
1179
|
-
/* @__PURE__ */
|
|
1180
|
-
/* @__PURE__ */
|
|
1318
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1319
|
+
/* @__PURE__ */ jsxs6("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
1320
|
+
/* @__PURE__ */ jsx6("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
1181
1321
|
label
|
|
1182
1322
|
] }),
|
|
1183
|
-
/* @__PURE__ */
|
|
1323
|
+
/* @__PURE__ */ jsx6(
|
|
1184
1324
|
"input",
|
|
1185
1325
|
{
|
|
1186
1326
|
type: "color",
|
|
@@ -1191,18 +1331,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1191
1331
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
1192
1332
|
}
|
|
1193
1333
|
),
|
|
1194
|
-
on && !hex && /* @__PURE__ */
|
|
1195
|
-
style?.mixed[key] && /* @__PURE__ */
|
|
1334
|
+
on && !hex && /* @__PURE__ */ jsx6("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
1335
|
+
style?.mixed[key] && /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1196
1336
|
] });
|
|
1197
1337
|
};
|
|
1198
|
-
return /* @__PURE__ */
|
|
1199
|
-
/* @__PURE__ */
|
|
1338
|
+
return /* @__PURE__ */ jsxs6("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
1339
|
+
/* @__PURE__ */ jsx6("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
1200
1340
|
paintRow("fill", "Fill"),
|
|
1201
1341
|
paintRow("stroke", "Stroke"),
|
|
1202
|
-
style && /* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */
|
|
1204
|
-
/* @__PURE__ */
|
|
1205
|
-
/* @__PURE__ */
|
|
1342
|
+
style && /* @__PURE__ */ jsx6(VectorGradientEditor, { controller }),
|
|
1343
|
+
/* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16", children: "Width" }),
|
|
1345
|
+
/* @__PURE__ */ jsx6(
|
|
1206
1346
|
"input",
|
|
1207
1347
|
{
|
|
1208
1348
|
type: "number",
|
|
@@ -1218,33 +1358,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1218
1358
|
}
|
|
1219
1359
|
)
|
|
1220
1360
|
] }),
|
|
1221
|
-
/* @__PURE__ */
|
|
1222
|
-
/* @__PURE__ */
|
|
1223
|
-
/* @__PURE__ */
|
|
1361
|
+
/* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
1362
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16", children: "Align" }),
|
|
1363
|
+
/* @__PURE__ */ jsx6("select", { "aria-label": "Stroke alignment", className: selectClass4, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ jsx6("option", { value: a, children: VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
1224
1364
|
mixed("strokeAlign")
|
|
1225
1365
|
] }),
|
|
1226
|
-
/* @__PURE__ */
|
|
1227
|
-
/* @__PURE__ */
|
|
1228
|
-
/* @__PURE__ */
|
|
1366
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
1367
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16", children: "Profile" }),
|
|
1368
|
+
/* @__PURE__ */ jsxs6(
|
|
1229
1369
|
"select",
|
|
1230
1370
|
{
|
|
1231
1371
|
"aria-label": "Width profile",
|
|
1232
|
-
className:
|
|
1372
|
+
className: selectClass4,
|
|
1233
1373
|
value: source.widthProfile,
|
|
1234
1374
|
onChange: (e) => {
|
|
1235
1375
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
1236
1376
|
},
|
|
1237
1377
|
children: [
|
|
1238
|
-
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */
|
|
1239
|
-
source.widthProfile === "custom" && /* @__PURE__ */
|
|
1378
|
+
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ jsx6("option", { value: p.id, children: p.label }, p.id)),
|
|
1379
|
+
source.widthProfile === "custom" && /* @__PURE__ */ jsx6("option", { value: "custom", disabled: true, children: "Custom" })
|
|
1240
1380
|
]
|
|
1241
1381
|
}
|
|
1242
1382
|
),
|
|
1243
|
-
/* @__PURE__ */
|
|
1383
|
+
/* @__PURE__ */ jsx6(
|
|
1244
1384
|
"button",
|
|
1245
1385
|
{
|
|
1246
1386
|
type: "button",
|
|
1247
|
-
className:
|
|
1387
|
+
className: buttonClass4,
|
|
1248
1388
|
title: "Reset to uniform width",
|
|
1249
1389
|
"aria-label": "Reset to uniform width",
|
|
1250
1390
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -1254,27 +1394,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1254
1394
|
),
|
|
1255
1395
|
mixed("widthProfile")
|
|
1256
1396
|
] }),
|
|
1257
|
-
source.hasOpenPath && /* @__PURE__ */
|
|
1397
|
+
source.hasOpenPath && /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1258
1398
|
arrowRow("start", "Start"),
|
|
1259
1399
|
arrowRow("end", "End"),
|
|
1260
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */
|
|
1261
|
-
/* @__PURE__ */
|
|
1262
|
-
/* @__PURE__ */
|
|
1263
|
-
/* @__PURE__ */
|
|
1264
|
-
/* @__PURE__ */
|
|
1400
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
1401
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16", children: "Heads" }),
|
|
1402
|
+
/* @__PURE__ */ jsxs6("select", { "aria-label": "Arrowhead alignment", className: selectClass4, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
1403
|
+
/* @__PURE__ */ jsx6("option", { value: "extend", children: "Tip past end" }),
|
|
1404
|
+
/* @__PURE__ */ jsx6("option", { value: "tip", children: "Tip at end" })
|
|
1265
1405
|
] })
|
|
1266
1406
|
] })
|
|
1267
1407
|
] }),
|
|
1268
|
-
source.corners > 0 && /* @__PURE__ */
|
|
1269
|
-
/* @__PURE__ */
|
|
1270
|
-
/* @__PURE__ */
|
|
1408
|
+
source.corners > 0 && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
1409
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
1410
|
+
/* @__PURE__ */ jsx6(
|
|
1271
1411
|
"input",
|
|
1272
1412
|
{
|
|
1273
1413
|
type: "number",
|
|
1274
1414
|
min: 0,
|
|
1275
1415
|
step: 1,
|
|
1276
1416
|
"aria-label": "Corner radius",
|
|
1277
|
-
className:
|
|
1417
|
+
className: numberClass4,
|
|
1278
1418
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
1279
1419
|
onChange: (e) => {
|
|
1280
1420
|
const n = parseFloat(e.target.value);
|
|
@@ -1282,12 +1422,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1282
1422
|
}
|
|
1283
1423
|
}
|
|
1284
1424
|
),
|
|
1285
|
-
/* @__PURE__ */
|
|
1425
|
+
/* @__PURE__ */ jsx6("select", { "aria-label": "Corner kind", className: selectClass4, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ jsx6("option", { value: k, children: VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
1286
1426
|
mixed("cornerRadius")
|
|
1287
1427
|
] }),
|
|
1288
|
-
style && /* @__PURE__ */
|
|
1289
|
-
/* @__PURE__ */
|
|
1290
|
-
/* @__PURE__ */
|
|
1428
|
+
style && /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1429
|
+
/* @__PURE__ */ jsx6("span", { className: "w-16", children: "Opacity" }),
|
|
1430
|
+
/* @__PURE__ */ jsx6(
|
|
1291
1431
|
"input",
|
|
1292
1432
|
{
|
|
1293
1433
|
type: "range",
|
|
@@ -1301,18 +1441,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1301
1441
|
}
|
|
1302
1442
|
)
|
|
1303
1443
|
] }),
|
|
1304
|
-
style && /* @__PURE__ */
|
|
1444
|
+
style && /* @__PURE__ */ jsx6(VectorEffectsPanel, { controller }),
|
|
1445
|
+
style && /* @__PURE__ */ jsx6(VectorEnvelopePanel, { controller })
|
|
1305
1446
|
] });
|
|
1306
1447
|
}
|
|
1307
1448
|
|
|
1308
1449
|
// src/vector/VectorEditor.tsx
|
|
1309
|
-
import { jsx as
|
|
1450
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1310
1451
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
1311
|
-
return /* @__PURE__ */
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
/* @__PURE__ */
|
|
1314
|
-
/* @__PURE__ */
|
|
1315
|
-
showStylePanel && /* @__PURE__ */
|
|
1452
|
+
return /* @__PURE__ */ jsxs7("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
1453
|
+
/* @__PURE__ */ jsx7(VectorToolbar, { controller, tools }),
|
|
1454
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
1455
|
+
/* @__PURE__ */ jsx7("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ jsx7(VectorCanvas, { controller, ...canvasProps }) }),
|
|
1456
|
+
showStylePanel && /* @__PURE__ */ jsx7(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
1316
1457
|
] })
|
|
1317
1458
|
] });
|
|
1318
1459
|
}
|
|
@@ -1320,6 +1461,7 @@ export {
|
|
|
1320
1461
|
VectorCanvas,
|
|
1321
1462
|
VectorEditor,
|
|
1322
1463
|
VectorEffectsPanel,
|
|
1464
|
+
VectorEnvelopePanel,
|
|
1323
1465
|
VectorGradientAnnotator,
|
|
1324
1466
|
VectorGradientDefs,
|
|
1325
1467
|
VectorGradientEditor,
|