@pixerate/editor-react 0.32.0 → 0.33.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 +323 -110
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +24 -5
- package/dist/vector/index.d.ts +24 -5
- package/dist/vector/index.js +320 -98
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -33,7 +33,9 @@ __export(vector_exports, {
|
|
|
33
33
|
VectorCanvas: () => VectorCanvas,
|
|
34
34
|
VectorEditor: () => VectorEditor,
|
|
35
35
|
VectorEffectsPanel: () => VectorEffectsPanel,
|
|
36
|
+
VectorGradientAnnotator: () => VectorGradientAnnotator,
|
|
36
37
|
VectorGradientDefs: () => VectorGradientDefs,
|
|
38
|
+
VectorGradientEditor: () => VectorGradientEditor,
|
|
37
39
|
VectorSceneNodes: () => VectorSceneNodes,
|
|
38
40
|
VectorStylePanel: () => VectorStylePanel,
|
|
39
41
|
VectorToolbar: () => VectorToolbar,
|
|
@@ -176,12 +178,50 @@ function VectorWidthPointEditor({ controller, edit, accentColor = import_vector2
|
|
|
176
178
|
|
|
177
179
|
// src/vector/VectorCanvas.tsx
|
|
178
180
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
181
|
+
function GradientElement({ def }) {
|
|
182
|
+
const stops = def.stops.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: s.offset, stopColor: s.stopColor, stopOpacity: s.stopOpacity }, i));
|
|
183
|
+
return def.type === "radial" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("radialGradient", { id: def.id, ...def.attrs, children: stops }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("linearGradient", { id: def.id, ...def.attrs, children: stops });
|
|
184
|
+
}
|
|
179
185
|
function VectorGradientDefs({ defs }) {
|
|
180
186
|
if (!defs.length) return null;
|
|
181
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: defs.map(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: defs.map(
|
|
188
|
+
(def) => def.type === "pattern" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("pattern", { id: def.id, ...def.attrs, children: [
|
|
189
|
+
def.gradients.map((g) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GradientElement, { def: g }, g.id)),
|
|
190
|
+
def.tiles.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: t.d, fill: t.fill }, i))
|
|
191
|
+
] }, def.id) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GradientElement, { def }, def.id)
|
|
192
|
+
) });
|
|
193
|
+
}
|
|
194
|
+
function VectorGradientAnnotator({ annotator: g, accentColor = import_vector3.VECTOR_OVERLAY_THEME.accent }) {
|
|
195
|
+
const r = import_vector3.VECTOR_OVERLAY_THEME.handleRadius + 1.5;
|
|
196
|
+
const ring = (p, part, size = r) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-gradient-handle": part, cx: p.x, cy: p.y, r: size + (p.hovered ? 1 : 0), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor, strokeWidth: p.hovered ? 2 : 1 });
|
|
197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-gradient-annotator": g.type, children: [
|
|
198
|
+
g.extent && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-gradient-extent": "", d: g.extent, fill: "none", stroke: accentColor, strokeDasharray: "4 3" }),
|
|
199
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: g.start.x, y1: g.start.y, x2: g.end.x, y2: g.end.y, stroke: "#ffffff", strokeWidth: 3 }),
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { "data-vector-gradient-bar": "", x1: g.start.x, y1: g.start.y, x2: g.end.x, y2: g.end.y, stroke: accentColor }),
|
|
201
|
+
g.aspect && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: g.start.x, y1: g.start.y, x2: g.aspect.x, y2: g.aspect.y, stroke: accentColor, strokeDasharray: "2 2" }),
|
|
202
|
+
ring(g.start, "start"),
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
204
|
+
"rect",
|
|
205
|
+
{
|
|
206
|
+
"data-vector-gradient-handle": g.end.handle,
|
|
207
|
+
x: g.end.x - r,
|
|
208
|
+
y: g.end.y - r,
|
|
209
|
+
width: 2 * r,
|
|
210
|
+
height: 2 * r,
|
|
211
|
+
fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill,
|
|
212
|
+
stroke: accentColor,
|
|
213
|
+
strokeWidth: g.end.hovered ? 2 : 1
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
g.aspect && ring(g.aspect, "aspect", import_vector3.VECTOR_OVERLAY_THEME.handleRadius),
|
|
217
|
+
g.focal && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-gradient-handle": "focal", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: g.focal.x, cy: g.focal.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius - 1 + (g.focal.hovered ? 1 : 0), fill: accentColor, stroke: import_vector3.VECTOR_OVERLAY_THEME.handleFill }) }),
|
|
218
|
+
g.midpoints.map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-gradient-midpoint": m.index, d: (0, import_vector3.vectorDiamondPath)(m.x, m.y, 4 + (m.hovered ? 1 : 0)), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, m.index)),
|
|
219
|
+
g.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-gradient-stop": s.index, "data-selected": s.selected || void 0, opacity: g.removing && s.selected ? 0.35 : 1, children: [
|
|
220
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: s.barX, y1: s.barY, x2: s.x, y2: s.y, stroke: accentColor }),
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: s.x - 5, y: s.y - 5, width: 10, height: 10, rx: 2, fill: s.color, fillOpacity: s.opacity, stroke: s.selected ? accentColor : "#ffffff", strokeWidth: s.selected || s.hovered ? 2 : 1 }),
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: s.x - 6.5, y: s.y - 6.5, width: 13, height: 13, rx: 3, fill: "none", stroke: s.selected ? "#ffffff" : accentColor })
|
|
223
|
+
] }, s.index))
|
|
224
|
+
] });
|
|
185
225
|
}
|
|
186
226
|
function VectorSceneNodes({ nodes }) {
|
|
187
227
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map(
|
|
@@ -405,6 +445,7 @@ function VectorCanvas({
|
|
|
405
445
|
},
|
|
406
446
|
`blend-anchor:${i}`
|
|
407
447
|
)),
|
|
448
|
+
overlay.gradient && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorGradientAnnotator, { annotator: overlay.gradient, accentColor }),
|
|
408
449
|
overlay.widthSpot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-width-spot": "", children: [
|
|
409
450
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: overlay.widthSpot.left.x, y1: overlay.widthSpot.left.y, x2: overlay.widthSpot.right.x, y2: overlay.widthSpot.right.y, stroke: accentColor, strokeDasharray: "3 2" }),
|
|
410
451
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: (0, import_vector3.vectorDiamondPath)(overlay.widthSpot.x, overlay.widthSpot.y), fill: "none", stroke: accentColor })
|
|
@@ -511,7 +552,7 @@ function VectorCanvas({
|
|
|
511
552
|
|
|
512
553
|
// src/vector/VectorToolbar.tsx
|
|
513
554
|
var import_react4 = __toESM(require("react"), 1);
|
|
514
|
-
var
|
|
555
|
+
var import_vector6 = require("@pixerate/editor/vector");
|
|
515
556
|
|
|
516
557
|
// src/vector/VectorEffectsPanel.tsx
|
|
517
558
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -653,14 +694,183 @@ function VectorEffectsPanel({ controller, className }) {
|
|
|
653
694
|
] });
|
|
654
695
|
}
|
|
655
696
|
|
|
656
|
-
// src/vector/
|
|
697
|
+
// src/vector/VectorGradientEditor.tsx
|
|
698
|
+
var import_vector5 = require("@pixerate/editor/vector");
|
|
657
699
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
700
|
+
var selectClass2 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
701
|
+
var numberClass2 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
702
|
+
var buttonClass2 = "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";
|
|
703
|
+
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
704
|
+
function VectorGradientEditor({ controller, className }) {
|
|
705
|
+
const state = useVectorEditorState(controller);
|
|
706
|
+
const ed = (0, import_vector5.getVectorGradientEditor)(state);
|
|
707
|
+
if (!ed) return null;
|
|
708
|
+
const g = ed.gradient;
|
|
709
|
+
const sel = ed.selected;
|
|
710
|
+
const end = () => controller.endMergedEdit();
|
|
711
|
+
const setType = (value) => {
|
|
712
|
+
if (value === "solid") {
|
|
713
|
+
const first = ed.stops[0];
|
|
714
|
+
controller.setStyle({ [ed.target]: (0, import_vector5.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
715
|
+
} else controller.setGradient({ type: value });
|
|
716
|
+
};
|
|
717
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
718
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
719
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
720
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
721
|
+
ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
722
|
+
] }),
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
724
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { "aria-label": "Gradient type", className: selectClass2, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "solid", children: "Solid" }),
|
|
727
|
+
import_vector5.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: t, children: import_vector5.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
728
|
+
] }),
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
730
|
+
] }),
|
|
731
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
732
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
734
|
+
"div",
|
|
735
|
+
{
|
|
736
|
+
role: "button",
|
|
737
|
+
tabIndex: -1,
|
|
738
|
+
"aria-label": "Add gradient stop",
|
|
739
|
+
className: "absolute inset-x-1.5 top-0 h-4 cursor-copy rounded border border-border",
|
|
740
|
+
style: { backgroundImage: `${ed.preview}, repeating-conic-gradient(#ddd 0% 25%, #fff 0% 50%)`, backgroundSize: "auto, 8px 8px" },
|
|
741
|
+
onClick: (e) => {
|
|
742
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
743
|
+
controller.addGradientStop(r.width > 0 ? Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) : 0.5);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
),
|
|
747
|
+
ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
748
|
+
"button",
|
|
749
|
+
{
|
|
750
|
+
type: "button",
|
|
751
|
+
"data-vector-gradient-stop": s.index,
|
|
752
|
+
"aria-label": `Gradient stop ${s.index + 1} at ${percent(s.offset)}%`,
|
|
753
|
+
"aria-pressed": s.selected,
|
|
754
|
+
className: "absolute top-4 h-3.5 w-3 -translate-x-1/2 rounded-sm border border-border aria-pressed:ring-2 aria-pressed:ring-primary",
|
|
755
|
+
style: { left: `calc(6px + (100% - 12px) * ${s.offset})`, background: s.color, opacity: 0.4 + 0.6 * (s.opacity ?? 1) },
|
|
756
|
+
onClick: () => controller.selectGradientStop(s.selected ? null : s.index)
|
|
757
|
+
},
|
|
758
|
+
s.index
|
|
759
|
+
))
|
|
760
|
+
] }),
|
|
761
|
+
sel && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
762
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
763
|
+
"input",
|
|
764
|
+
{
|
|
765
|
+
type: "color",
|
|
766
|
+
"aria-label": "Stop colour",
|
|
767
|
+
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
768
|
+
value: (0, import_vector5.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
769
|
+
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
770
|
+
onBlur: end
|
|
771
|
+
}
|
|
772
|
+
),
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
774
|
+
"Opacity",
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
776
|
+
"input",
|
|
777
|
+
{
|
|
778
|
+
type: "number",
|
|
779
|
+
min: 0,
|
|
780
|
+
max: 100,
|
|
781
|
+
step: 5,
|
|
782
|
+
"aria-label": "Stop opacity",
|
|
783
|
+
className: numberClass2,
|
|
784
|
+
value: percent(sel.opacity ?? 1),
|
|
785
|
+
onChange: (e) => {
|
|
786
|
+
const n = parseFloat(e.target.value);
|
|
787
|
+
if (Number.isFinite(n)) controller.setGradientStop(sel.index, { opacity: n / 100 });
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
)
|
|
791
|
+
] }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
793
|
+
"At",
|
|
794
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
795
|
+
"input",
|
|
796
|
+
{
|
|
797
|
+
type: "number",
|
|
798
|
+
min: 0,
|
|
799
|
+
max: 100,
|
|
800
|
+
step: 1,
|
|
801
|
+
"aria-label": "Stop position",
|
|
802
|
+
className: numberClass2,
|
|
803
|
+
value: percent(sel.offset),
|
|
804
|
+
onChange: (e) => {
|
|
805
|
+
const n = parseFloat(e.target.value);
|
|
806
|
+
if (Number.isFinite(n)) controller.setGradientStop(sel.index, { offset: n / 100 });
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
] }),
|
|
811
|
+
!sel.last && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
812
|
+
"Midpoint",
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
814
|
+
"input",
|
|
815
|
+
{
|
|
816
|
+
type: "number",
|
|
817
|
+
min: 5,
|
|
818
|
+
max: 95,
|
|
819
|
+
step: 1,
|
|
820
|
+
"aria-label": "Stop midpoint",
|
|
821
|
+
className: numberClass2,
|
|
822
|
+
value: percent(sel.midpoint ?? 0.5),
|
|
823
|
+
onChange: (e) => {
|
|
824
|
+
const n = parseFloat(e.target.value);
|
|
825
|
+
if (Number.isFinite(n)) controller.setGradientStop(sel.index, { midpoint: n / 100 });
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
)
|
|
829
|
+
] }),
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
831
|
+
] }),
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass2, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector5.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: i, children: import_vector5.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
835
|
+
] }),
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
837
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
838
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
839
|
+
"input",
|
|
840
|
+
{
|
|
841
|
+
type: "range",
|
|
842
|
+
min: 0,
|
|
843
|
+
max: 1,
|
|
844
|
+
step: 0.05,
|
|
845
|
+
"aria-label": "Gradient smoothness",
|
|
846
|
+
className: "h-4 flex-1 accent-primary",
|
|
847
|
+
value: ed.smoothness,
|
|
848
|
+
onChange: (e) => controller.setGradient({ smoothness: parseFloat(e.target.value) }, { merge: "gradient-smoothness" }),
|
|
849
|
+
onPointerUp: end,
|
|
850
|
+
onBlur: end
|
|
851
|
+
}
|
|
852
|
+
)
|
|
853
|
+
] }),
|
|
854
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
855
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Gradient spread", className: selectClass2, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector5.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: sp, children: import_vector5.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
857
|
+
] }),
|
|
858
|
+
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass2, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector5.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: m, children: import_vector5.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
861
|
+
] })
|
|
862
|
+
] })
|
|
863
|
+
] });
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/vector/VectorToolbar.tsx
|
|
867
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
658
868
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
659
869
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
660
|
-
var
|
|
870
|
+
var buttonClass3 = "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";
|
|
661
871
|
function VectorToolbar({
|
|
662
872
|
controller,
|
|
663
|
-
tools =
|
|
873
|
+
tools = import_vector6.VECTOR_TOOLS,
|
|
664
874
|
showHistory = true,
|
|
665
875
|
showArrange = true,
|
|
666
876
|
showSnap = true,
|
|
@@ -675,32 +885,32 @@ function VectorToolbar({
|
|
|
675
885
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
676
886
|
const [live, setLive] = import_react4.default.useState(false);
|
|
677
887
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
678
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
679
|
-
return /* @__PURE__ */ (0,
|
|
680
|
-
/* @__PURE__ */ (0,
|
|
888
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: buttonClass3, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
681
891
|
"button",
|
|
682
892
|
{
|
|
683
893
|
type: "button",
|
|
684
894
|
"data-vector-tool": tool,
|
|
685
|
-
className:
|
|
895
|
+
className: buttonClass3,
|
|
686
896
|
"aria-pressed": state.tool === tool,
|
|
687
|
-
title: `${(0,
|
|
688
|
-
"aria-label": (0,
|
|
897
|
+
title: `${(0, import_vector6.vectorToolLabel)(tool)} (${import_vector6.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
898
|
+
"aria-label": (0, import_vector6.vectorToolLabel)(tool),
|
|
689
899
|
onClick: () => controller.setTool(tool),
|
|
690
|
-
children:
|
|
900
|
+
children: import_vector6.VECTOR_TOOL_GLYPHS[tool]
|
|
691
901
|
},
|
|
692
902
|
tool
|
|
693
903
|
)) }),
|
|
694
|
-
showHistory && /* @__PURE__ */ (0,
|
|
904
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
695
905
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
696
906
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
697
907
|
] }),
|
|
698
|
-
showSnap && /* @__PURE__ */ (0,
|
|
908
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
699
909
|
"button",
|
|
700
910
|
{
|
|
701
911
|
type: "button",
|
|
702
912
|
"data-vector-snap": "",
|
|
703
|
-
className:
|
|
913
|
+
className: buttonClass3,
|
|
704
914
|
"aria-pressed": state.snap.objects,
|
|
705
915
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
706
916
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -708,13 +918,13 @@ function VectorToolbar({
|
|
|
708
918
|
children: "Snap"
|
|
709
919
|
}
|
|
710
920
|
) }),
|
|
711
|
-
showPathEdit && /* @__PURE__ */ (0,
|
|
712
|
-
|
|
921
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
922
|
+
import_vector6.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
713
923
|
"button",
|
|
714
924
|
{
|
|
715
925
|
type: "button",
|
|
716
926
|
"data-vector-path-action": a.id,
|
|
717
|
-
className:
|
|
927
|
+
className: buttonClass3,
|
|
718
928
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
719
929
|
"aria-label": a.title,
|
|
720
930
|
disabled: !a.enabled(count, points),
|
|
@@ -723,12 +933,12 @@ function VectorToolbar({
|
|
|
723
933
|
},
|
|
724
934
|
a.id
|
|
725
935
|
)),
|
|
726
|
-
|
|
936
|
+
import_vector6.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
727
937
|
"button",
|
|
728
938
|
{
|
|
729
939
|
type: "button",
|
|
730
940
|
"data-vector-edit": t.key,
|
|
731
|
-
className:
|
|
941
|
+
className: buttonClass3,
|
|
732
942
|
"aria-pressed": editing[t.key],
|
|
733
943
|
title: t.title,
|
|
734
944
|
"aria-label": t.title,
|
|
@@ -737,9 +947,9 @@ function VectorToolbar({
|
|
|
737
947
|
},
|
|
738
948
|
t.key
|
|
739
949
|
)),
|
|
740
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
950
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
741
951
|
"Smoothing",
|
|
742
|
-
/* @__PURE__ */ (0,
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
743
953
|
"input",
|
|
744
954
|
{
|
|
745
955
|
type: "range",
|
|
@@ -753,9 +963,9 @@ function VectorToolbar({
|
|
|
753
963
|
}
|
|
754
964
|
)
|
|
755
965
|
] }),
|
|
756
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
966
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
757
967
|
"Size",
|
|
758
|
-
/* @__PURE__ */ (0,
|
|
968
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
759
969
|
"input",
|
|
760
970
|
{
|
|
761
971
|
type: "number",
|
|
@@ -771,29 +981,29 @@ function VectorToolbar({
|
|
|
771
981
|
}
|
|
772
982
|
)
|
|
773
983
|
] }),
|
|
774
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
984
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
775
985
|
"button",
|
|
776
986
|
{
|
|
777
987
|
type: "button",
|
|
778
988
|
"data-vector-fill-gap": "",
|
|
779
|
-
className:
|
|
989
|
+
className: buttonClass3,
|
|
780
990
|
"aria-pressed": editing.fillGap > 0,
|
|
781
991
|
title: "Close small gaps between path ends when filling",
|
|
782
992
|
"aria-label": "Close gaps",
|
|
783
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
993
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector6.VECTOR_FILL_GAP }),
|
|
784
994
|
children: "Gaps"
|
|
785
995
|
}
|
|
786
996
|
)
|
|
787
997
|
] }),
|
|
788
|
-
showBlend && /* @__PURE__ */ (0,
|
|
789
|
-
showArrange && /* @__PURE__ */ (0,
|
|
790
|
-
/* @__PURE__ */ (0,
|
|
791
|
-
/* @__PURE__ */ (0,
|
|
998
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VectorBlendControls, { controller }),
|
|
999
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
1001
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
792
1002
|
"button",
|
|
793
1003
|
{
|
|
794
1004
|
type: "button",
|
|
795
1005
|
"data-vector-live-boolean": "",
|
|
796
|
-
className:
|
|
1006
|
+
className: buttonClass3,
|
|
797
1007
|
"aria-pressed": live,
|
|
798
1008
|
title: "Live booleans: keep the shapes editable",
|
|
799
1009
|
"aria-label": "Live booleans",
|
|
@@ -808,12 +1018,12 @@ function VectorToolbar({
|
|
|
808
1018
|
act("G", "Group", () => controller.group(), count < 1),
|
|
809
1019
|
act("U", "Ungroup", () => controller.ungroup(), !groupSelected)
|
|
810
1020
|
] }),
|
|
811
|
-
/* @__PURE__ */ (0,
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector6.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
812
1022
|
"button",
|
|
813
1023
|
{
|
|
814
1024
|
type: "button",
|
|
815
1025
|
"data-vector-pathfinder": a.id,
|
|
816
|
-
className:
|
|
1026
|
+
className: buttonClass3,
|
|
817
1027
|
title: a.title,
|
|
818
1028
|
"aria-label": a.title,
|
|
819
1029
|
disabled: count < a.min,
|
|
@@ -822,7 +1032,7 @@ function VectorToolbar({
|
|
|
822
1032
|
},
|
|
823
1033
|
a.id
|
|
824
1034
|
)) }),
|
|
825
|
-
/* @__PURE__ */ (0,
|
|
1035
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
826
1036
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
827
1037
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
828
1038
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -837,22 +1047,22 @@ function VectorToolbar({
|
|
|
837
1047
|
}
|
|
838
1048
|
function VectorBlendControls({ controller }) {
|
|
839
1049
|
const state = useVectorEditorState(controller);
|
|
840
|
-
const blend = (0,
|
|
1050
|
+
const blend = (0, import_vector6.getVectorBlendControls)(state);
|
|
841
1051
|
const o = blend.options;
|
|
842
1052
|
const selected = blend.ids.length > 0;
|
|
843
|
-
return /* @__PURE__ */ (0,
|
|
844
|
-
/* @__PURE__ */ (0,
|
|
845
|
-
/* @__PURE__ */ (0,
|
|
1053
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
1054
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass3, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
1055
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
846
1056
|
"select",
|
|
847
1057
|
{
|
|
848
1058
|
"aria-label": "Blend spacing",
|
|
849
1059
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
850
1060
|
value: o.spacing,
|
|
851
|
-
onChange: (e) => (0,
|
|
852
|
-
children:
|
|
1061
|
+
onChange: (e) => (0, import_vector6.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
1062
|
+
children: import_vector6.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: sp, children: import_vector6.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
853
1063
|
}
|
|
854
1064
|
),
|
|
855
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */ (0,
|
|
1065
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
856
1066
|
"input",
|
|
857
1067
|
{
|
|
858
1068
|
type: "number",
|
|
@@ -864,29 +1074,29 @@ function VectorBlendControls({ controller }) {
|
|
|
864
1074
|
onChange: (e) => {
|
|
865
1075
|
const n = parseFloat(e.target.value);
|
|
866
1076
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
867
|
-
(0,
|
|
1077
|
+
(0, import_vector6.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
868
1078
|
}
|
|
869
1079
|
}
|
|
870
1080
|
),
|
|
871
|
-
/* @__PURE__ */ (0,
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
872
1082
|
"button",
|
|
873
1083
|
{
|
|
874
1084
|
type: "button",
|
|
875
1085
|
"data-vector-blend-action": "orient",
|
|
876
|
-
className:
|
|
1086
|
+
className: buttonClass3,
|
|
877
1087
|
"aria-pressed": o.orientToSpine,
|
|
878
1088
|
title: "Orient steps to the spine",
|
|
879
1089
|
"aria-label": "Orient to spine",
|
|
880
|
-
onClick: () => (0,
|
|
1090
|
+
onClick: () => (0, import_vector6.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
881
1091
|
children: "\u293F"
|
|
882
1092
|
}
|
|
883
1093
|
),
|
|
884
|
-
/* @__PURE__ */ (0,
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
885
1095
|
"button",
|
|
886
1096
|
{
|
|
887
1097
|
type: "button",
|
|
888
1098
|
"data-vector-blend-action": "spine",
|
|
889
|
-
className:
|
|
1099
|
+
className: buttonClass3,
|
|
890
1100
|
title: "Replace Spine (select a blend and a path)",
|
|
891
1101
|
"aria-label": "Replace Spine",
|
|
892
1102
|
disabled: !blend.canReplaceSpine,
|
|
@@ -894,15 +1104,15 @@ function VectorBlendControls({ controller }) {
|
|
|
894
1104
|
children: "\u2307"
|
|
895
1105
|
}
|
|
896
1106
|
),
|
|
897
|
-
/* @__PURE__ */ (0,
|
|
898
|
-
/* @__PURE__ */ (0,
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass3, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass3, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
899
1109
|
] });
|
|
900
1110
|
}
|
|
901
|
-
var
|
|
902
|
-
var
|
|
1111
|
+
var selectClass3 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1112
|
+
var numberClass3 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
903
1113
|
function VectorStylePanel({ controller, className }) {
|
|
904
1114
|
const state = useVectorEditorState(controller);
|
|
905
|
-
const style = (0,
|
|
1115
|
+
const style = (0, import_vector6.getVectorSelectionStyle)(state);
|
|
906
1116
|
const d = state.defaults;
|
|
907
1117
|
const source = style ?? {
|
|
908
1118
|
fill: d.fill ?? null,
|
|
@@ -915,7 +1125,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
915
1125
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
916
1126
|
startArrowScale: d.startArrowScale ?? 1,
|
|
917
1127
|
endArrowScale: d.endArrowScale ?? 1,
|
|
918
|
-
widthProfile: (0,
|
|
1128
|
+
widthProfile: (0, import_vector6.widthProfilePresetId)(d.strokeWidthProfile),
|
|
919
1129
|
cornerRadius: d.cornerRadius,
|
|
920
1130
|
cornerKind: d.cornerKind ?? "round",
|
|
921
1131
|
corners: 1,
|
|
@@ -928,19 +1138,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
928
1138
|
};
|
|
929
1139
|
const setProfile = (id) => {
|
|
930
1140
|
if (style) controller.setWidthProfile(id);
|
|
931
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
1141
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector6.widthProfilePreset)(id)?.length ? (0, import_vector6.widthProfilePreset)(id) : null });
|
|
932
1142
|
};
|
|
933
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
1143
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
934
1144
|
const arrowRow = (end, label) => {
|
|
935
1145
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
936
1146
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
937
|
-
return /* @__PURE__ */ (0,
|
|
938
|
-
/* @__PURE__ */ (0,
|
|
939
|
-
/* @__PURE__ */ (0,
|
|
940
|
-
/* @__PURE__ */ (0,
|
|
941
|
-
|
|
1147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass3, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: "None" }),
|
|
1151
|
+
import_vector6.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: h, children: import_vector6.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
942
1152
|
] }),
|
|
943
|
-
/* @__PURE__ */ (0,
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
944
1154
|
"input",
|
|
945
1155
|
{
|
|
946
1156
|
type: "number",
|
|
@@ -948,7 +1158,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
948
1158
|
step: 0.25,
|
|
949
1159
|
"aria-label": `${label} arrowhead scale`,
|
|
950
1160
|
title: "Scale (\xD7 stroke width)",
|
|
951
|
-
className:
|
|
1161
|
+
className: numberClass3,
|
|
952
1162
|
value: source[scaleKey],
|
|
953
1163
|
onChange: (e) => {
|
|
954
1164
|
const n = parseFloat(e.target.value);
|
|
@@ -964,14 +1174,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
964
1174
|
};
|
|
965
1175
|
const paintRow = (key, label) => {
|
|
966
1176
|
const paint = source[key];
|
|
967
|
-
const hex = (0,
|
|
1177
|
+
const hex = (0, import_vector6.vectorPaintToHex)(paint);
|
|
968
1178
|
const on = paint !== null && paint !== "none";
|
|
969
|
-
return /* @__PURE__ */ (0,
|
|
970
|
-
/* @__PURE__ */ (0,
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
1179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1180
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
1181
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
972
1182
|
label
|
|
973
1183
|
] }),
|
|
974
|
-
/* @__PURE__ */ (0,
|
|
1184
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
975
1185
|
"input",
|
|
976
1186
|
{
|
|
977
1187
|
type: "color",
|
|
@@ -982,17 +1192,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
982
1192
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
983
1193
|
}
|
|
984
1194
|
),
|
|
985
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
986
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
1195
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
1196
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
987
1197
|
] });
|
|
988
1198
|
};
|
|
989
|
-
return /* @__PURE__ */ (0,
|
|
990
|
-
/* @__PURE__ */ (0,
|
|
1199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
991
1201
|
paintRow("fill", "Fill"),
|
|
992
1202
|
paintRow("stroke", "Stroke"),
|
|
993
|
-
/* @__PURE__ */ (0,
|
|
994
|
-
|
|
995
|
-
/* @__PURE__ */ (0,
|
|
1203
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VectorGradientEditor, { controller }),
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1205
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16", children: "Width" }),
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
996
1207
|
"input",
|
|
997
1208
|
{
|
|
998
1209
|
type: "number",
|
|
@@ -1008,33 +1219,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1008
1219
|
}
|
|
1009
1220
|
)
|
|
1010
1221
|
] }),
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1012
|
-
/* @__PURE__ */ (0,
|
|
1013
|
-
/* @__PURE__ */ (0,
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
1223
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16", children: "Align" }),
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass3, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector6.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: a, children: import_vector6.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
1014
1225
|
mixed("strokeAlign")
|
|
1015
1226
|
] }),
|
|
1016
|
-
/* @__PURE__ */ (0,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1227
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
1229
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1019
1230
|
"select",
|
|
1020
1231
|
{
|
|
1021
1232
|
"aria-label": "Width profile",
|
|
1022
|
-
className:
|
|
1233
|
+
className: selectClass3,
|
|
1023
1234
|
value: source.widthProfile,
|
|
1024
1235
|
onChange: (e) => {
|
|
1025
1236
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
1026
1237
|
},
|
|
1027
1238
|
children: [
|
|
1028
|
-
|
|
1029
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
1239
|
+
import_vector6.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
1240
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
1030
1241
|
]
|
|
1031
1242
|
}
|
|
1032
1243
|
),
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1034
1245
|
"button",
|
|
1035
1246
|
{
|
|
1036
1247
|
type: "button",
|
|
1037
|
-
className:
|
|
1248
|
+
className: buttonClass3,
|
|
1038
1249
|
title: "Reset to uniform width",
|
|
1039
1250
|
"aria-label": "Reset to uniform width",
|
|
1040
1251
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -1044,27 +1255,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1044
1255
|
),
|
|
1045
1256
|
mixed("widthProfile")
|
|
1046
1257
|
] }),
|
|
1047
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
1258
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1048
1259
|
arrowRow("start", "Start"),
|
|
1049
1260
|
arrowRow("end", "End"),
|
|
1050
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
1051
|
-
/* @__PURE__ */ (0,
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1053
|
-
/* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1261
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass3, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
1055
1266
|
] })
|
|
1056
1267
|
] })
|
|
1057
1268
|
] }),
|
|
1058
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1269
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1061
1272
|
"input",
|
|
1062
1273
|
{
|
|
1063
1274
|
type: "number",
|
|
1064
1275
|
min: 0,
|
|
1065
1276
|
step: 1,
|
|
1066
1277
|
"aria-label": "Corner radius",
|
|
1067
|
-
className:
|
|
1278
|
+
className: numberClass3,
|
|
1068
1279
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
1069
1280
|
onChange: (e) => {
|
|
1070
1281
|
const n = parseFloat(e.target.value);
|
|
@@ -1072,12 +1283,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1072
1283
|
}
|
|
1073
1284
|
}
|
|
1074
1285
|
),
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("select", { "aria-label": "Corner kind", className: selectClass3, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector6.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: k, children: import_vector6.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
1076
1287
|
mixed("cornerRadius")
|
|
1077
1288
|
] }),
|
|
1078
|
-
style && /* @__PURE__ */ (0,
|
|
1079
|
-
/* @__PURE__ */ (0,
|
|
1080
|
-
/* @__PURE__ */ (0,
|
|
1289
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1081
1292
|
"input",
|
|
1082
1293
|
{
|
|
1083
1294
|
type: "range",
|
|
@@ -1091,18 +1302,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1091
1302
|
}
|
|
1092
1303
|
)
|
|
1093
1304
|
] }),
|
|
1094
|
-
style && /* @__PURE__ */ (0,
|
|
1305
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VectorEffectsPanel, { controller })
|
|
1095
1306
|
] });
|
|
1096
1307
|
}
|
|
1097
1308
|
|
|
1098
1309
|
// src/vector/VectorEditor.tsx
|
|
1099
|
-
var
|
|
1310
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1100
1311
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
1101
|
-
return /* @__PURE__ */ (0,
|
|
1102
|
-
/* @__PURE__ */ (0,
|
|
1103
|
-
/* @__PURE__ */ (0,
|
|
1104
|
-
/* @__PURE__ */ (0,
|
|
1105
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
1312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VectorToolbar, { controller, tools }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
1316
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
1106
1317
|
] })
|
|
1107
1318
|
] });
|
|
1108
1319
|
}
|
|
@@ -1111,7 +1322,9 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
1111
1322
|
VectorCanvas,
|
|
1112
1323
|
VectorEditor,
|
|
1113
1324
|
VectorEffectsPanel,
|
|
1325
|
+
VectorGradientAnnotator,
|
|
1114
1326
|
VectorGradientDefs,
|
|
1327
|
+
VectorGradientEditor,
|
|
1115
1328
|
VectorSceneNodes,
|
|
1116
1329
|
VectorStylePanel,
|
|
1117
1330
|
VectorToolbar,
|