@pixerate/editor-react 0.75.1 → 0.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vector/index.cjs +224 -174
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +12 -1
- package/dist/vector/index.d.ts +12 -1
- package/dist/vector/index.js +217 -167
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.js
CHANGED
|
@@ -633,6 +633,7 @@ function VectorCanvas({
|
|
|
633
633
|
sh.lines.map((d, i) => /* @__PURE__ */ jsx2("path", { d, stroke: accentColor, strokeWidth: 1, opacity: 0.7 }, i)),
|
|
634
634
|
sh.points.map((p) => /* @__PURE__ */ jsx2("circle", { "data-vector-shading-point": p.index, "data-selected": p.selected || void 0, cx: p.x, cy: p.y, r: p.selected ? 6 : 4.5, fill: p.color, stroke: p.selected ? accentColor : "#ffffff", strokeWidth: p.selected ? 2 : 1.5 }, p.index))
|
|
635
635
|
] }, `shading:${sh.nodeId}`)),
|
|
636
|
+
overlay.symmetry.map((sy) => /* @__PURE__ */ jsx2("g", { "data-vector-symmetry-axes": sy.nodeId, stroke: accentColor, strokeDasharray: sy.drawing ? void 0 : "6 4", opacity: sy.drawing ? 0.9 : 0.6, children: sy.lines.map((l, i) => /* @__PURE__ */ jsx2("line", { x1: l.x1, y1: l.y1, x2: l.x2, y2: l.y2 }, i)) }, `sym:${sy.nodeId}`)),
|
|
636
637
|
overlay.trackingPoints.map((t, i) => /* @__PURE__ */ jsx2("path", { "data-vector-tracking-point": "", d: `M${t.x - 5} ${t.y}H${t.x + 5}M${t.x} ${t.y - 5}V${t.y + 5}`, stroke: guideColor, strokeWidth: 1.5 }, `track:${i}`)),
|
|
637
638
|
overlay.typedEntry && /* @__PURE__ */ jsxs2("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
638
639
|
/* @__PURE__ */ jsx2("rect", { x: -3, y: -12, width: overlay.typedEntry.text.length * 7 + 8, height: 17, rx: 3, fill: THEME2.handleFill, stroke: accentColor }),
|
|
@@ -791,7 +792,7 @@ import {
|
|
|
791
792
|
isVectorMaskGroup,
|
|
792
793
|
widthProfilePreset,
|
|
793
794
|
widthProfilePresetId,
|
|
794
|
-
vectorPaintToHex as
|
|
795
|
+
vectorPaintToHex as vectorPaintToHex6,
|
|
795
796
|
vectorToolLabel,
|
|
796
797
|
vectorPolarAngles,
|
|
797
798
|
vectorPolarIncrementOf
|
|
@@ -800,7 +801,8 @@ import {
|
|
|
800
801
|
// src/vector/VectorEffectsPanel.tsx
|
|
801
802
|
import {
|
|
802
803
|
VECTOR_EFFECT_MENU,
|
|
803
|
-
getVectorEffectsPanel
|
|
804
|
+
getVectorEffectsPanel,
|
|
805
|
+
vectorPaintToHex
|
|
804
806
|
} from "@pixerate/editor/vector";
|
|
805
807
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
806
808
|
var buttonClass = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
@@ -888,6 +890,15 @@ function VectorEffectsPanel({ controller, className }) {
|
|
|
888
890
|
/* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate", children: spec.label }),
|
|
889
891
|
/* @__PURE__ */ jsx3("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label}`, checked: !!e.params[spec.key], onChange: (ev) => set(e, spec.key, ev.target.checked, false) })
|
|
890
892
|
] }, spec.key);
|
|
893
|
+
if (spec.kind === "color") {
|
|
894
|
+
const c = e.params[spec.key];
|
|
895
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
|
|
896
|
+
/* @__PURE__ */ jsx3("span", { className: labelClass, children: spec.label }),
|
|
897
|
+
/* @__PURE__ */ jsx3("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label} on`, checked: c !== null, onChange: (ev) => set(e, spec.key, ev.target.checked ? "#ffffff" : null, false) }),
|
|
898
|
+
/* @__PURE__ */ jsx3("input", { type: "color", "aria-label": `${e.label} ${spec.label}`, className: "h-6 w-8 cursor-pointer rounded border border-border bg-background disabled:opacity-40", disabled: c === null, value: vectorPaintToHex(c ?? "#ffffff") ?? "#ffffff", onChange: (ev) => set(e, spec.key, ev.target.value, true), onBlur: end })
|
|
899
|
+
] }, spec.key);
|
|
900
|
+
}
|
|
901
|
+
if (spec.kind !== "select") return null;
|
|
891
902
|
return /* @__PURE__ */ jsxs3("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
|
|
892
903
|
/* @__PURE__ */ jsx3("span", { className: labelClass, children: spec.label }),
|
|
893
904
|
/* @__PURE__ */ jsx3("select", { "aria-label": `${e.label} ${spec.label}`, className: selectClass, value: String(e.params[spec.key] ?? ""), onChange: (ev) => set(e, spec.key, ev.target.value, false), children: spec.options.map((o) => /* @__PURE__ */ jsx3("option", { value: o.value, children: o.label }, o.value)) })
|
|
@@ -1569,7 +1580,7 @@ function VectorTextPanel({ controller, className }) {
|
|
|
1569
1580
|
|
|
1570
1581
|
// src/vector/VectorSymbolsPanel.tsx
|
|
1571
1582
|
import { useId as useId3, useState as useState3 } from "react";
|
|
1572
|
-
import { getVectorSymbolsPanel, vectorPaintToHex } from "@pixerate/editor/vector";
|
|
1583
|
+
import { getVectorSymbolsPanel, vectorPaintToHex as vectorPaintToHex2 } from "@pixerate/editor/vector";
|
|
1573
1584
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1574
1585
|
var buttonClass6 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
1575
1586
|
var selectClass5 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
@@ -1623,7 +1634,7 @@ function VectorSymbolsPanel({ controller, className }) {
|
|
|
1623
1634
|
type: "color",
|
|
1624
1635
|
"aria-label": "Instance fill",
|
|
1625
1636
|
className: "h-6 w-8 rounded border border-border",
|
|
1626
|
-
value:
|
|
1637
|
+
value: vectorPaintToHex2(inst.fill ?? void 0) ?? "#000000",
|
|
1627
1638
|
onChange: (e) => report(controller.setInstanceOptions({ fill: e.target.value }, { ids: [inst.id] }))
|
|
1628
1639
|
}
|
|
1629
1640
|
)
|
|
@@ -1729,7 +1740,7 @@ import {
|
|
|
1729
1740
|
VECTOR_VERTICAL_RESIZING,
|
|
1730
1741
|
VECTOR_VERTICAL_RESIZING_LABELS,
|
|
1731
1742
|
getVectorFramePanel,
|
|
1732
|
-
vectorPaintToHex as
|
|
1743
|
+
vectorPaintToHex as vectorPaintToHex3
|
|
1733
1744
|
} from "@pixerate/editor/vector";
|
|
1734
1745
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1735
1746
|
var buttonClass8 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
@@ -1740,7 +1751,7 @@ function VectorFramePanel({ controller, className }) {
|
|
|
1740
1751
|
const panel = getVectorFramePanel(state);
|
|
1741
1752
|
const f = panel.frame;
|
|
1742
1753
|
const ids = f ? [f.id] : void 0;
|
|
1743
|
-
const fillHex = f ?
|
|
1754
|
+
const fillHex = f ? vectorPaintToHex3(f.frame.fill ?? null) : null;
|
|
1744
1755
|
const number = (key, label) => /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1745
1756
|
/* @__PURE__ */ jsx10("span", { className: "w-4 text-muted-foreground", children: label }),
|
|
1746
1757
|
/* @__PURE__ */ jsx10(
|
|
@@ -1915,7 +1926,7 @@ function VectorConnectorPanel({ controller, className }) {
|
|
|
1915
1926
|
|
|
1916
1927
|
// src/vector/VectorShadingPanel.tsx
|
|
1917
1928
|
import { useState as useState5 } from "react";
|
|
1918
|
-
import { isVectorFreeformGradient, isVectorMeshGradient, vectorPaintToHex as
|
|
1929
|
+
import { isVectorFreeformGradient, isVectorMeshGradient, vectorPaintToHex as vectorPaintToHex4 } from "@pixerate/editor/vector";
|
|
1919
1930
|
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1920
1931
|
var buttonClass10 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
1921
1932
|
var numberClass6 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
@@ -1955,7 +1966,7 @@ function VectorShadingPanel({ controller, className }) {
|
|
|
1955
1966
|
"Point ",
|
|
1956
1967
|
sel.index
|
|
1957
1968
|
] }),
|
|
1958
|
-
/* @__PURE__ */ jsx12("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value:
|
|
1969
|
+
/* @__PURE__ */ jsx12("input", { type: "color", "aria-label": "Point colour", className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: vectorPaintToHex4(color ?? "#000000") ?? "#000000", onChange: (e) => edit({ color: e.target.value }, "shading-color") }),
|
|
1959
1970
|
/* @__PURE__ */ jsx12("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point opacity", title: "Opacity", className: "h-4 w-20 accent-primary", value: opacity, onChange: (e) => edit({ opacity: parseFloat(e.target.value) }, "shading-opacity") }),
|
|
1960
1971
|
free && /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
1961
1972
|
/* @__PURE__ */ jsx12("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Point spread", title: "Spread: pure colour round the point", className: "h-4 w-20 accent-primary", value: spread, onChange: (e) => edit({ spread: parseFloat(e.target.value) }, "shading-spread") }),
|
|
@@ -2027,6 +2038,43 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2027
2038
|
] });
|
|
2028
2039
|
}
|
|
2029
2040
|
|
|
2041
|
+
// src/vector/VectorSymmetryPanel.tsx
|
|
2042
|
+
import { VECTOR_SYMMETRY_MODES, VECTOR_SYMMETRY_MODE_LABELS, isVectorSymmetryGroup } from "@pixerate/editor/vector";
|
|
2043
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2044
|
+
var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
2045
|
+
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2046
|
+
var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
2047
|
+
function VectorSymmetryPanel({ controller, className }) {
|
|
2048
|
+
const state = useVectorEditorState(controller);
|
|
2049
|
+
const group = state.selection.map((id) => controller.getNode(id)).find(isVectorSymmetryGroup) ?? null;
|
|
2050
|
+
const s = group?.symmetry;
|
|
2051
|
+
const ids = group ? [group.id] : void 0;
|
|
2052
|
+
const drawing = !!group && state.symmetryTarget === group.id;
|
|
2053
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symmetry-panel": "", "aria-label": "Symmetry", children: [
|
|
2054
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2055
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Symmetry" }),
|
|
2056
|
+
!group && /* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
|
|
2057
|
+
!group && /* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
|
|
2058
|
+
group && s && /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
2059
|
+
/* @__PURE__ */ jsx14("select", { "aria-label": "Symmetry mode", className: selectClass9, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ jsx14("option", { value: m, children: VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
|
|
2060
|
+
s.mode === "radial" && /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
2061
|
+
/* @__PURE__ */ jsx14("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
|
|
2062
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
|
|
2063
|
+
/* @__PURE__ */ jsx14("input", { type: "checkbox", "aria-label": "Mirror copies", checked: !!s.mirror, onChange: (e) => controller.setSymmetry({ mirror: e.target.checked }, { ids }) }),
|
|
2064
|
+
"Mirror"
|
|
2065
|
+
] })
|
|
2066
|
+
] })
|
|
2067
|
+
] })
|
|
2068
|
+
] }),
|
|
2069
|
+
group && /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2070
|
+
/* @__PURE__ */ jsx14("span", { className: "w-16" }),
|
|
2071
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, "aria-pressed": drawing, "data-vector-symmetry-action": "draw", title: "Draw inside: new pen, pencil, shape and text art goes into the group, mirrored as you draw (Escape stops)", onClick: () => drawing ? controller.exitSymmetry() : controller.enterSymmetry(group.id), children: "Draw inside" }),
|
|
2072
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, title: "Expand: keep the copies as real objects", onClick: () => controller.releaseSymmetry({ ids, expand: true }), children: "Expand" }),
|
|
2073
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: buttonClass12, title: "Release: stop repeating (the copies go)", onClick: () => controller.releaseSymmetry({ ids }), children: "Release" })
|
|
2074
|
+
] })
|
|
2075
|
+
] });
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2030
2078
|
// src/vector/VectorGradientEditor.tsx
|
|
2031
2079
|
import {
|
|
2032
2080
|
VECTOR_GRADIENT_TYPES,
|
|
@@ -2038,12 +2086,12 @@ import {
|
|
|
2038
2086
|
VECTOR_GRADIENT_INTERPOLATION_LABELS,
|
|
2039
2087
|
VECTOR_STROKE_GRADIENT_MODE_LABELS,
|
|
2040
2088
|
getVectorGradientEditor,
|
|
2041
|
-
vectorPaintToHex as
|
|
2089
|
+
vectorPaintToHex as vectorPaintToHex5
|
|
2042
2090
|
} from "@pixerate/editor/vector";
|
|
2043
|
-
import { Fragment as
|
|
2044
|
-
var
|
|
2045
|
-
var
|
|
2046
|
-
var
|
|
2091
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2092
|
+
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2093
|
+
var numberClass9 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
2094
|
+
var buttonClass13 = "inline-flex h-7 min-w-7 items-center justify-center rounded border border-border bg-background px-1.5 text-xs text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
2047
2095
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
2048
2096
|
function VectorGradientEditor({ controller, className }) {
|
|
2049
2097
|
const state = useVectorEditorState(controller);
|
|
@@ -2055,26 +2103,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2055
2103
|
const setType = (value) => {
|
|
2056
2104
|
if (value === "solid") {
|
|
2057
2105
|
const first = ed.stops[0];
|
|
2058
|
-
controller.setStyle({ [ed.target]:
|
|
2106
|
+
controller.setStyle({ [ed.target]: vectorPaintToHex5(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
2059
2107
|
} else controller.setGradient({ type: value });
|
|
2060
2108
|
};
|
|
2061
|
-
return /* @__PURE__ */
|
|
2062
|
-
/* @__PURE__ */
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */
|
|
2065
|
-
ed.mixed && /* @__PURE__ */
|
|
2109
|
+
return /* @__PURE__ */ jsxs15("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
2110
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
2111
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
2112
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
2113
|
+
ed.mixed && /* @__PURE__ */ jsx15("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2066
2114
|
] }),
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
2070
|
-
/* @__PURE__ */
|
|
2071
|
-
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */
|
|
2115
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5", children: [
|
|
2116
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2117
|
+
/* @__PURE__ */ jsxs15("select", { "aria-label": "Gradient type", className: selectClass10, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2118
|
+
/* @__PURE__ */ jsx15("option", { value: "solid", children: "Solid" }),
|
|
2119
|
+
VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ jsx15("option", { value: t, children: VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
2072
2120
|
] }),
|
|
2073
|
-
/* @__PURE__ */
|
|
2121
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
2074
2122
|
] }),
|
|
2075
|
-
g && /* @__PURE__ */
|
|
2076
|
-
/* @__PURE__ */
|
|
2077
|
-
/* @__PURE__ */
|
|
2123
|
+
g && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
2124
|
+
/* @__PURE__ */ jsxs15("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
2125
|
+
/* @__PURE__ */ jsx15(
|
|
2078
2126
|
"div",
|
|
2079
2127
|
{
|
|
2080
2128
|
role: "button",
|
|
@@ -2088,7 +2136,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2088
2136
|
}
|
|
2089
2137
|
}
|
|
2090
2138
|
),
|
|
2091
|
-
ed.stops.map((s) => /* @__PURE__ */
|
|
2139
|
+
ed.stops.map((s) => /* @__PURE__ */ jsx15(
|
|
2092
2140
|
"button",
|
|
2093
2141
|
{
|
|
2094
2142
|
type: "button",
|
|
@@ -2102,21 +2150,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2102
2150
|
s.index
|
|
2103
2151
|
))
|
|
2104
2152
|
] }),
|
|
2105
|
-
sel && /* @__PURE__ */
|
|
2106
|
-
/* @__PURE__ */
|
|
2153
|
+
sel && /* @__PURE__ */ jsxs15("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
2154
|
+
/* @__PURE__ */ jsx15(
|
|
2107
2155
|
"input",
|
|
2108
2156
|
{
|
|
2109
2157
|
type: "color",
|
|
2110
2158
|
"aria-label": "Stop colour",
|
|
2111
2159
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2112
|
-
value:
|
|
2160
|
+
value: vectorPaintToHex5(sel.color) ?? "#000000",
|
|
2113
2161
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2114
2162
|
onBlur: end
|
|
2115
2163
|
}
|
|
2116
2164
|
),
|
|
2117
|
-
/* @__PURE__ */
|
|
2165
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2118
2166
|
"Opacity",
|
|
2119
|
-
/* @__PURE__ */
|
|
2167
|
+
/* @__PURE__ */ jsx15(
|
|
2120
2168
|
"input",
|
|
2121
2169
|
{
|
|
2122
2170
|
type: "number",
|
|
@@ -2124,7 +2172,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2124
2172
|
max: 100,
|
|
2125
2173
|
step: 5,
|
|
2126
2174
|
"aria-label": "Stop opacity",
|
|
2127
|
-
className:
|
|
2175
|
+
className: numberClass9,
|
|
2128
2176
|
value: percent(sel.opacity ?? 1),
|
|
2129
2177
|
onChange: (e) => {
|
|
2130
2178
|
const n = parseFloat(e.target.value);
|
|
@@ -2133,9 +2181,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2133
2181
|
}
|
|
2134
2182
|
)
|
|
2135
2183
|
] }),
|
|
2136
|
-
/* @__PURE__ */
|
|
2184
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2137
2185
|
"At",
|
|
2138
|
-
/* @__PURE__ */
|
|
2186
|
+
/* @__PURE__ */ jsx15(
|
|
2139
2187
|
"input",
|
|
2140
2188
|
{
|
|
2141
2189
|
type: "number",
|
|
@@ -2143,7 +2191,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2143
2191
|
max: 100,
|
|
2144
2192
|
step: 1,
|
|
2145
2193
|
"aria-label": "Stop position",
|
|
2146
|
-
className:
|
|
2194
|
+
className: numberClass9,
|
|
2147
2195
|
value: percent(sel.offset),
|
|
2148
2196
|
onChange: (e) => {
|
|
2149
2197
|
const n = parseFloat(e.target.value);
|
|
@@ -2152,9 +2200,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2152
2200
|
}
|
|
2153
2201
|
)
|
|
2154
2202
|
] }),
|
|
2155
|
-
!sel.last && /* @__PURE__ */
|
|
2203
|
+
!sel.last && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2156
2204
|
"Midpoint",
|
|
2157
|
-
/* @__PURE__ */
|
|
2205
|
+
/* @__PURE__ */ jsx15(
|
|
2158
2206
|
"input",
|
|
2159
2207
|
{
|
|
2160
2208
|
type: "number",
|
|
@@ -2162,7 +2210,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2162
2210
|
max: 95,
|
|
2163
2211
|
step: 1,
|
|
2164
2212
|
"aria-label": "Stop midpoint",
|
|
2165
|
-
className:
|
|
2213
|
+
className: numberClass9,
|
|
2166
2214
|
value: percent(sel.midpoint ?? 0.5),
|
|
2167
2215
|
onChange: (e) => {
|
|
2168
2216
|
const n = parseFloat(e.target.value);
|
|
@@ -2171,15 +2219,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2171
2219
|
}
|
|
2172
2220
|
)
|
|
2173
2221
|
] }),
|
|
2174
|
-
/* @__PURE__ */
|
|
2222
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: buttonClass13, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
2175
2223
|
] }),
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2224
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2225
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Colours" }),
|
|
2226
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient interpolation", className: selectClass10, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ jsx15("option", { value: i, children: VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2179
2227
|
] }),
|
|
2180
|
-
/* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
2228
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2229
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Smooth" }),
|
|
2230
|
+
/* @__PURE__ */ jsx15(
|
|
2183
2231
|
"input",
|
|
2184
2232
|
{
|
|
2185
2233
|
type: "range",
|
|
@@ -2195,23 +2243,23 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2195
2243
|
}
|
|
2196
2244
|
)
|
|
2197
2245
|
] }),
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2200
|
-
/* @__PURE__ */
|
|
2246
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2247
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "Spread" }),
|
|
2248
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient spread", className: selectClass10, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ jsx15("option", { value: sp, children: VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2201
2249
|
] }),
|
|
2202
|
-
ed.target === "stroke" && /* @__PURE__ */
|
|
2203
|
-
/* @__PURE__ */
|
|
2204
|
-
/* @__PURE__ */
|
|
2250
|
+
ed.target === "stroke" && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2251
|
+
/* @__PURE__ */ jsx15("span", { className: "w-16", children: "On stroke" }),
|
|
2252
|
+
/* @__PURE__ */ jsx15("select", { "aria-label": "Gradient on stroke", className: selectClass10, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ jsx15("option", { value: m, children: VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2205
2253
|
] })
|
|
2206
2254
|
] })
|
|
2207
2255
|
] });
|
|
2208
2256
|
}
|
|
2209
2257
|
|
|
2210
2258
|
// src/vector/VectorToolbar.tsx
|
|
2211
|
-
import { Fragment as
|
|
2259
|
+
import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2212
2260
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
2213
2261
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
2214
|
-
var
|
|
2262
|
+
var buttonClass14 = "inline-flex h-8 min-w-8 items-center justify-center rounded-md border border-border bg-background px-2 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
2215
2263
|
function VectorToolbar({
|
|
2216
2264
|
controller,
|
|
2217
2265
|
tools = VECTOR_TOOLS,
|
|
@@ -2231,14 +2279,14 @@ function VectorToolbar({
|
|
|
2231
2279
|
const maskSelected = state.selection.some((id) => isVectorMaskGroup(controller.getNode(id)));
|
|
2232
2280
|
const [live, setLive] = React9.useState(false);
|
|
2233
2281
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2234
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */
|
|
2235
|
-
return /* @__PURE__ */
|
|
2236
|
-
/* @__PURE__ */
|
|
2282
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ jsx16("button", { type: "button", className: buttonClass14, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2283
|
+
return /* @__PURE__ */ jsxs16("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2284
|
+
/* @__PURE__ */ jsx16("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ jsx16(
|
|
2237
2285
|
"button",
|
|
2238
2286
|
{
|
|
2239
2287
|
type: "button",
|
|
2240
2288
|
"data-vector-tool": tool,
|
|
2241
|
-
className:
|
|
2289
|
+
className: buttonClass14,
|
|
2242
2290
|
"aria-pressed": state.tool === tool,
|
|
2243
2291
|
title: `${vectorToolLabel(tool)} (${VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2244
2292
|
"aria-label": vectorToolLabel(tool),
|
|
@@ -2247,17 +2295,17 @@ function VectorToolbar({
|
|
|
2247
2295
|
},
|
|
2248
2296
|
tool
|
|
2249
2297
|
)) }),
|
|
2250
|
-
showHistory && /* @__PURE__ */
|
|
2298
|
+
showHistory && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
2251
2299
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
2252
2300
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
2253
2301
|
] }),
|
|
2254
|
-
showSnap && /* @__PURE__ */
|
|
2255
|
-
/* @__PURE__ */
|
|
2302
|
+
showSnap && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2303
|
+
/* @__PURE__ */ jsx16(
|
|
2256
2304
|
"button",
|
|
2257
2305
|
{
|
|
2258
2306
|
type: "button",
|
|
2259
2307
|
"data-vector-snap": "",
|
|
2260
|
-
className:
|
|
2308
|
+
className: buttonClass14,
|
|
2261
2309
|
"aria-pressed": state.snap.objects,
|
|
2262
2310
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2263
2311
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -2265,7 +2313,7 @@ function VectorToolbar({
|
|
|
2265
2313
|
children: "Snap"
|
|
2266
2314
|
}
|
|
2267
2315
|
),
|
|
2268
|
-
/* @__PURE__ */
|
|
2316
|
+
/* @__PURE__ */ jsxs16(
|
|
2269
2317
|
"select",
|
|
2270
2318
|
{
|
|
2271
2319
|
"data-vector-polar": "",
|
|
@@ -2275,8 +2323,8 @@ function VectorToolbar({
|
|
|
2275
2323
|
value: String(vectorPolarIncrementOf(state.snap.angles) ?? ""),
|
|
2276
2324
|
onChange: (e) => controller.setSnap({ angles: vectorPolarAngles(Number(e.target.value)) }),
|
|
2277
2325
|
children: [
|
|
2278
|
-
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */
|
|
2279
|
-
[90, 45, 30, 15].map((n) => /* @__PURE__ */
|
|
2326
|
+
vectorPolarIncrementOf(state.snap.angles) === null && /* @__PURE__ */ jsx16("option", { value: "", children: "Custom" }),
|
|
2327
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ jsxs16("option", { value: n, children: [
|
|
2280
2328
|
n,
|
|
2281
2329
|
"\xB0"
|
|
2282
2330
|
] }, n))
|
|
@@ -2284,13 +2332,13 @@ function VectorToolbar({
|
|
|
2284
2332
|
}
|
|
2285
2333
|
)
|
|
2286
2334
|
] }),
|
|
2287
|
-
showPathEdit && /* @__PURE__ */
|
|
2288
|
-
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */
|
|
2335
|
+
showPathEdit && /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2336
|
+
VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ jsx16(
|
|
2289
2337
|
"button",
|
|
2290
2338
|
{
|
|
2291
2339
|
type: "button",
|
|
2292
2340
|
"data-vector-path-action": a.id,
|
|
2293
|
-
className:
|
|
2341
|
+
className: buttonClass14,
|
|
2294
2342
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
2295
2343
|
"aria-label": a.title,
|
|
2296
2344
|
disabled: !a.enabled(count, points),
|
|
@@ -2299,12 +2347,12 @@ function VectorToolbar({
|
|
|
2299
2347
|
},
|
|
2300
2348
|
a.id
|
|
2301
2349
|
)),
|
|
2302
|
-
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */
|
|
2350
|
+
VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ jsx16(
|
|
2303
2351
|
"button",
|
|
2304
2352
|
{
|
|
2305
2353
|
type: "button",
|
|
2306
2354
|
"data-vector-edit": t.key,
|
|
2307
|
-
className:
|
|
2355
|
+
className: buttonClass14,
|
|
2308
2356
|
"aria-pressed": editing[t.key],
|
|
2309
2357
|
title: t.title,
|
|
2310
2358
|
"aria-label": t.title,
|
|
@@ -2313,9 +2361,9 @@ function VectorToolbar({
|
|
|
2313
2361
|
},
|
|
2314
2362
|
t.key
|
|
2315
2363
|
)),
|
|
2316
|
-
state.tool === "pencil" && /* @__PURE__ */
|
|
2364
|
+
state.tool === "pencil" && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2317
2365
|
"Smoothing",
|
|
2318
|
-
/* @__PURE__ */
|
|
2366
|
+
/* @__PURE__ */ jsx16(
|
|
2319
2367
|
"input",
|
|
2320
2368
|
{
|
|
2321
2369
|
type: "range",
|
|
@@ -2329,9 +2377,9 @@ function VectorToolbar({
|
|
|
2329
2377
|
}
|
|
2330
2378
|
)
|
|
2331
2379
|
] }),
|
|
2332
|
-
state.tool === "eraser" && /* @__PURE__ */
|
|
2380
|
+
state.tool === "eraser" && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2333
2381
|
"Size",
|
|
2334
|
-
/* @__PURE__ */
|
|
2382
|
+
/* @__PURE__ */ jsx16(
|
|
2335
2383
|
"input",
|
|
2336
2384
|
{
|
|
2337
2385
|
type: "number",
|
|
@@ -2347,12 +2395,12 @@ function VectorToolbar({
|
|
|
2347
2395
|
}
|
|
2348
2396
|
)
|
|
2349
2397
|
] }),
|
|
2350
|
-
state.tool === "paintBucket" && /* @__PURE__ */
|
|
2398
|
+
state.tool === "paintBucket" && /* @__PURE__ */ jsx16(
|
|
2351
2399
|
"button",
|
|
2352
2400
|
{
|
|
2353
2401
|
type: "button",
|
|
2354
2402
|
"data-vector-fill-gap": "",
|
|
2355
|
-
className:
|
|
2403
|
+
className: buttonClass14,
|
|
2356
2404
|
"aria-pressed": editing.fillGap > 0,
|
|
2357
2405
|
title: "Close small gaps between path ends when filling",
|
|
2358
2406
|
"aria-label": "Close gaps",
|
|
@@ -2361,12 +2409,12 @@ function VectorToolbar({
|
|
|
2361
2409
|
}
|
|
2362
2410
|
)
|
|
2363
2411
|
] }),
|
|
2364
|
-
showDistort && /* @__PURE__ */
|
|
2412
|
+
showDistort && /* @__PURE__ */ jsx16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ jsx16(
|
|
2365
2413
|
"button",
|
|
2366
2414
|
{
|
|
2367
2415
|
type: "button",
|
|
2368
2416
|
"data-vector-free-distort": "",
|
|
2369
|
-
className:
|
|
2417
|
+
className: buttonClass14,
|
|
2370
2418
|
"aria-pressed": state.freeDistort,
|
|
2371
2419
|
title: `Free Distort: drag a corner of the selection box to distort in perspective (Shift+Alt+${modKeyLabel()}: symmetric perspective; ${modKeyLabel()}-drag a side to skew)`,
|
|
2372
2420
|
"aria-label": "Free Distort",
|
|
@@ -2374,15 +2422,15 @@ function VectorToolbar({
|
|
|
2374
2422
|
children: "Distort"
|
|
2375
2423
|
}
|
|
2376
2424
|
) }),
|
|
2377
|
-
showBlend && /* @__PURE__ */
|
|
2378
|
-
showArrange && /* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2380
|
-
/* @__PURE__ */
|
|
2425
|
+
showBlend && /* @__PURE__ */ jsx16(VectorBlendControls, { controller }),
|
|
2426
|
+
showArrange && /* @__PURE__ */ jsxs16(Fragment6, { children: [
|
|
2427
|
+
/* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2428
|
+
/* @__PURE__ */ jsx16(
|
|
2381
2429
|
"button",
|
|
2382
2430
|
{
|
|
2383
2431
|
type: "button",
|
|
2384
2432
|
"data-vector-live-boolean": "",
|
|
2385
|
-
className:
|
|
2433
|
+
className: buttonClass14,
|
|
2386
2434
|
"aria-pressed": live,
|
|
2387
2435
|
title: "Live booleans: keep the shapes editable",
|
|
2388
2436
|
"aria-label": "Live booleans",
|
|
@@ -2399,12 +2447,12 @@ function VectorToolbar({
|
|
|
2399
2447
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2400
2448
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2401
2449
|
] }),
|
|
2402
|
-
/* @__PURE__ */
|
|
2450
|
+
/* @__PURE__ */ jsx16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ jsx16(
|
|
2403
2451
|
"button",
|
|
2404
2452
|
{
|
|
2405
2453
|
type: "button",
|
|
2406
2454
|
"data-vector-pathfinder": a.id,
|
|
2407
|
-
className:
|
|
2455
|
+
className: buttonClass14,
|
|
2408
2456
|
title: a.title,
|
|
2409
2457
|
"aria-label": a.title,
|
|
2410
2458
|
disabled: count < a.min,
|
|
@@ -2413,7 +2461,7 @@ function VectorToolbar({
|
|
|
2413
2461
|
},
|
|
2414
2462
|
a.id
|
|
2415
2463
|
)) }),
|
|
2416
|
-
/* @__PURE__ */
|
|
2464
|
+
/* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
2417
2465
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
2418
2466
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
2419
2467
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -2431,19 +2479,19 @@ function VectorBlendControls({ controller }) {
|
|
|
2431
2479
|
const blend = getVectorBlendControls(state);
|
|
2432
2480
|
const o = blend.options;
|
|
2433
2481
|
const selected = blend.ids.length > 0;
|
|
2434
|
-
return /* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2436
|
-
/* @__PURE__ */
|
|
2482
|
+
return /* @__PURE__ */ jsxs16("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2483
|
+
/* @__PURE__ */ jsx16("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass14, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
2484
|
+
/* @__PURE__ */ jsx16(
|
|
2437
2485
|
"select",
|
|
2438
2486
|
{
|
|
2439
2487
|
"aria-label": "Blend spacing",
|
|
2440
2488
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2441
2489
|
value: o.spacing,
|
|
2442
2490
|
onChange: (e) => applyVectorBlendOptions(controller, { spacing: e.target.value }),
|
|
2443
|
-
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */
|
|
2491
|
+
children: VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ jsx16("option", { value: sp, children: VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2444
2492
|
}
|
|
2445
2493
|
),
|
|
2446
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */
|
|
2494
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ jsx16(
|
|
2447
2495
|
"input",
|
|
2448
2496
|
{
|
|
2449
2497
|
type: "number",
|
|
@@ -2459,12 +2507,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2459
2507
|
}
|
|
2460
2508
|
}
|
|
2461
2509
|
),
|
|
2462
|
-
/* @__PURE__ */
|
|
2510
|
+
/* @__PURE__ */ jsx16(
|
|
2463
2511
|
"button",
|
|
2464
2512
|
{
|
|
2465
2513
|
type: "button",
|
|
2466
2514
|
"data-vector-blend-action": "orient",
|
|
2467
|
-
className:
|
|
2515
|
+
className: buttonClass14,
|
|
2468
2516
|
"aria-pressed": o.orientToSpine,
|
|
2469
2517
|
title: "Orient steps to the spine",
|
|
2470
2518
|
"aria-label": "Orient to spine",
|
|
@@ -2472,12 +2520,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2472
2520
|
children: "\u293F"
|
|
2473
2521
|
}
|
|
2474
2522
|
),
|
|
2475
|
-
/* @__PURE__ */
|
|
2523
|
+
/* @__PURE__ */ jsx16(
|
|
2476
2524
|
"button",
|
|
2477
2525
|
{
|
|
2478
2526
|
type: "button",
|
|
2479
2527
|
"data-vector-blend-action": "spine",
|
|
2480
|
-
className:
|
|
2528
|
+
className: buttonClass14,
|
|
2481
2529
|
title: "Replace Spine (select a blend and a path)",
|
|
2482
2530
|
"aria-label": "Replace Spine",
|
|
2483
2531
|
disabled: !blend.canReplaceSpine,
|
|
@@ -2485,12 +2533,12 @@ function VectorBlendControls({ controller }) {
|
|
|
2485
2533
|
children: "\u2307"
|
|
2486
2534
|
}
|
|
2487
2535
|
),
|
|
2488
|
-
/* @__PURE__ */
|
|
2489
|
-
/* @__PURE__ */
|
|
2536
|
+
/* @__PURE__ */ jsx16("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass14, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2537
|
+
/* @__PURE__ */ jsx16("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass14, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
2490
2538
|
] });
|
|
2491
2539
|
}
|
|
2492
|
-
var
|
|
2493
|
-
var
|
|
2540
|
+
var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2541
|
+
var numberClass10 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2494
2542
|
function VectorStylePanel({ controller, className }) {
|
|
2495
2543
|
const state = useVectorEditorState(controller);
|
|
2496
2544
|
const style = getVectorSelectionStyle(state);
|
|
@@ -2522,17 +2570,17 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2522
2570
|
if (style) controller.setWidthProfile(id);
|
|
2523
2571
|
else controller.setDefaults({ strokeWidthProfile: widthProfilePreset(id)?.length ? widthProfilePreset(id) : null });
|
|
2524
2572
|
};
|
|
2525
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */
|
|
2573
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ jsx16("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2526
2574
|
const arrowRow = (end, label) => {
|
|
2527
2575
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
2528
2576
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
2529
|
-
return /* @__PURE__ */
|
|
2530
|
-
/* @__PURE__ */
|
|
2531
|
-
/* @__PURE__ */
|
|
2532
|
-
/* @__PURE__ */
|
|
2533
|
-
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */
|
|
2577
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2578
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2579
|
+
/* @__PURE__ */ jsxs16("select", { "aria-label": `${label} arrowhead`, className: selectClass11, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2580
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "None" }),
|
|
2581
|
+
VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ jsx16("option", { value: h, children: VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2534
2582
|
] }),
|
|
2535
|
-
/* @__PURE__ */
|
|
2583
|
+
/* @__PURE__ */ jsx16(
|
|
2536
2584
|
"input",
|
|
2537
2585
|
{
|
|
2538
2586
|
type: "number",
|
|
@@ -2540,7 +2588,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2540
2588
|
step: 0.25,
|
|
2541
2589
|
"aria-label": `${label} arrowhead scale`,
|
|
2542
2590
|
title: "Scale (\xD7 stroke width)",
|
|
2543
|
-
className:
|
|
2591
|
+
className: numberClass10,
|
|
2544
2592
|
value: source[scaleKey],
|
|
2545
2593
|
onChange: (e) => {
|
|
2546
2594
|
const n = parseFloat(e.target.value);
|
|
@@ -2556,14 +2604,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2556
2604
|
};
|
|
2557
2605
|
const paintRow = (key, label) => {
|
|
2558
2606
|
const paint = source[key];
|
|
2559
|
-
const hex =
|
|
2607
|
+
const hex = vectorPaintToHex6(paint);
|
|
2560
2608
|
const on = paint !== null && paint !== "none";
|
|
2561
|
-
return /* @__PURE__ */
|
|
2562
|
-
/* @__PURE__ */
|
|
2563
|
-
/* @__PURE__ */
|
|
2609
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2610
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2611
|
+
/* @__PURE__ */ jsx16("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
2564
2612
|
label
|
|
2565
2613
|
] }),
|
|
2566
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsx16(
|
|
2567
2615
|
"input",
|
|
2568
2616
|
{
|
|
2569
2617
|
type: "color",
|
|
@@ -2574,18 +2622,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2574
2622
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
2575
2623
|
}
|
|
2576
2624
|
),
|
|
2577
|
-
on && !hex && /* @__PURE__ */
|
|
2578
|
-
style?.mixed[key] && /* @__PURE__ */
|
|
2625
|
+
on && !hex && /* @__PURE__ */ jsx16("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2626
|
+
style?.mixed[key] && /* @__PURE__ */ jsx16("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2579
2627
|
] });
|
|
2580
2628
|
};
|
|
2581
|
-
return /* @__PURE__ */
|
|
2582
|
-
/* @__PURE__ */
|
|
2629
|
+
return /* @__PURE__ */ jsxs16("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2630
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
2583
2631
|
paintRow("fill", "Fill"),
|
|
2584
2632
|
paintRow("stroke", "Stroke"),
|
|
2585
|
-
style && /* @__PURE__ */
|
|
2586
|
-
/* @__PURE__ */
|
|
2587
|
-
/* @__PURE__ */
|
|
2588
|
-
/* @__PURE__ */
|
|
2633
|
+
style && /* @__PURE__ */ jsx16(VectorGradientEditor, { controller }),
|
|
2634
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2635
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Width" }),
|
|
2636
|
+
/* @__PURE__ */ jsx16(
|
|
2589
2637
|
"input",
|
|
2590
2638
|
{
|
|
2591
2639
|
type: "number",
|
|
@@ -2601,33 +2649,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2601
2649
|
}
|
|
2602
2650
|
)
|
|
2603
2651
|
] }),
|
|
2604
|
-
/* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2653
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Align" }),
|
|
2654
|
+
/* @__PURE__ */ jsx16("select", { "aria-label": "Stroke alignment", className: selectClass11, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(VECTOR_STROKE_ALIGN_LABELS2).map((a) => /* @__PURE__ */ jsx16("option", { value: a, children: VECTOR_STROKE_ALIGN_LABELS2[a] }, a)) }),
|
|
2607
2655
|
mixed("strokeAlign")
|
|
2608
2656
|
] }),
|
|
2609
|
-
/* @__PURE__ */
|
|
2610
|
-
/* @__PURE__ */
|
|
2611
|
-
/* @__PURE__ */
|
|
2657
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2658
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Profile" }),
|
|
2659
|
+
/* @__PURE__ */ jsxs16(
|
|
2612
2660
|
"select",
|
|
2613
2661
|
{
|
|
2614
2662
|
"aria-label": "Width profile",
|
|
2615
|
-
className:
|
|
2663
|
+
className: selectClass11,
|
|
2616
2664
|
value: source.widthProfile,
|
|
2617
2665
|
onChange: (e) => {
|
|
2618
2666
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2619
2667
|
},
|
|
2620
2668
|
children: [
|
|
2621
|
-
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */
|
|
2622
|
-
source.widthProfile === "custom" && /* @__PURE__ */
|
|
2669
|
+
VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ jsx16("option", { value: p.id, children: p.label }, p.id)),
|
|
2670
|
+
source.widthProfile === "custom" && /* @__PURE__ */ jsx16("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2623
2671
|
]
|
|
2624
2672
|
}
|
|
2625
2673
|
),
|
|
2626
|
-
/* @__PURE__ */
|
|
2674
|
+
/* @__PURE__ */ jsx16(
|
|
2627
2675
|
"button",
|
|
2628
2676
|
{
|
|
2629
2677
|
type: "button",
|
|
2630
|
-
className:
|
|
2678
|
+
className: buttonClass14,
|
|
2631
2679
|
title: "Reset to uniform width",
|
|
2632
2680
|
"aria-label": "Reset to uniform width",
|
|
2633
2681
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -2637,27 +2685,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2637
2685
|
),
|
|
2638
2686
|
mixed("widthProfile")
|
|
2639
2687
|
] }),
|
|
2640
|
-
source.hasOpenPath && /* @__PURE__ */
|
|
2688
|
+
source.hasOpenPath && /* @__PURE__ */ jsxs16(Fragment6, { children: [
|
|
2641
2689
|
arrowRow("start", "Start"),
|
|
2642
2690
|
arrowRow("end", "End"),
|
|
2643
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */
|
|
2644
|
-
/* @__PURE__ */
|
|
2645
|
-
/* @__PURE__ */
|
|
2646
|
-
/* @__PURE__ */
|
|
2647
|
-
/* @__PURE__ */
|
|
2691
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2692
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Heads" }),
|
|
2693
|
+
/* @__PURE__ */ jsxs16("select", { "aria-label": "Arrowhead alignment", className: selectClass11, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2694
|
+
/* @__PURE__ */ jsx16("option", { value: "extend", children: "Tip past end" }),
|
|
2695
|
+
/* @__PURE__ */ jsx16("option", { value: "tip", children: "Tip at end" })
|
|
2648
2696
|
] })
|
|
2649
2697
|
] })
|
|
2650
2698
|
] }),
|
|
2651
|
-
source.corners > 0 && /* @__PURE__ */
|
|
2652
|
-
/* @__PURE__ */
|
|
2653
|
-
/* @__PURE__ */
|
|
2699
|
+
source.corners > 0 && /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2700
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2701
|
+
/* @__PURE__ */ jsx16(
|
|
2654
2702
|
"input",
|
|
2655
2703
|
{
|
|
2656
2704
|
type: "number",
|
|
2657
2705
|
min: 0,
|
|
2658
2706
|
step: 1,
|
|
2659
2707
|
"aria-label": "Corner radius",
|
|
2660
|
-
className:
|
|
2708
|
+
className: numberClass10,
|
|
2661
2709
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
2662
2710
|
onChange: (e) => {
|
|
2663
2711
|
const n = parseFloat(e.target.value);
|
|
@@ -2665,12 +2713,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2665
2713
|
}
|
|
2666
2714
|
}
|
|
2667
2715
|
),
|
|
2668
|
-
/* @__PURE__ */
|
|
2716
|
+
/* @__PURE__ */ jsx16("select", { "aria-label": "Corner kind", className: selectClass11, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ jsx16("option", { value: k, children: VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2669
2717
|
mixed("cornerRadius")
|
|
2670
2718
|
] }),
|
|
2671
|
-
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2719
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "corner-smoothing", title: "Corner smoothing: squircle corners that ease into the curve (0.6 is iOS-like)", children: [
|
|
2720
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Smoothing" }),
|
|
2721
|
+
/* @__PURE__ */ jsx16(
|
|
2674
2722
|
"input",
|
|
2675
2723
|
{
|
|
2676
2724
|
type: "range",
|
|
@@ -2685,9 +2733,9 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2685
2733
|
}
|
|
2686
2734
|
)
|
|
2687
2735
|
] }),
|
|
2688
|
-
style && /* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
2690
|
-
/* @__PURE__ */
|
|
2736
|
+
style && /* @__PURE__ */ jsxs16("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2737
|
+
/* @__PURE__ */ jsx16("span", { className: "w-16", children: "Opacity" }),
|
|
2738
|
+
/* @__PURE__ */ jsx16(
|
|
2691
2739
|
"input",
|
|
2692
2740
|
{
|
|
2693
2741
|
type: "range",
|
|
@@ -2701,28 +2749,29 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2701
2749
|
}
|
|
2702
2750
|
)
|
|
2703
2751
|
] }),
|
|
2704
|
-
/* @__PURE__ */
|
|
2705
|
-
style && /* @__PURE__ */
|
|
2706
|
-
style && /* @__PURE__ */
|
|
2707
|
-
style && /* @__PURE__ */
|
|
2708
|
-
style && /* @__PURE__ */
|
|
2709
|
-
/* @__PURE__ */
|
|
2710
|
-
/* @__PURE__ */
|
|
2711
|
-
/* @__PURE__ */
|
|
2712
|
-
/* @__PURE__ */
|
|
2713
|
-
/* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */
|
|
2752
|
+
/* @__PURE__ */ jsx16(VectorTextPanel, { controller }),
|
|
2753
|
+
style && /* @__PURE__ */ jsx16(VectorAppearancePanel, { controller }),
|
|
2754
|
+
style && /* @__PURE__ */ jsx16(VectorEffectsPanel, { controller }),
|
|
2755
|
+
style && /* @__PURE__ */ jsx16(VectorEnvelopePanel, { controller }),
|
|
2756
|
+
style && /* @__PURE__ */ jsx16(VectorMaskPanel, { controller }),
|
|
2757
|
+
/* @__PURE__ */ jsx16(VectorFramePanel, { controller }),
|
|
2758
|
+
/* @__PURE__ */ jsx16(VectorConnectorPanel, { controller }),
|
|
2759
|
+
/* @__PURE__ */ jsx16(VectorShadingPanel, { controller }),
|
|
2760
|
+
/* @__PURE__ */ jsx16(VectorSymmetryPanel, { controller }),
|
|
2761
|
+
/* @__PURE__ */ jsx16(VectorTracePanel, { controller }),
|
|
2762
|
+
/* @__PURE__ */ jsx16(VectorConstraintsPanel, { controller }),
|
|
2763
|
+
/* @__PURE__ */ jsx16(VectorSymbolsPanel, { controller })
|
|
2715
2764
|
] });
|
|
2716
2765
|
}
|
|
2717
2766
|
|
|
2718
2767
|
// src/vector/VectorEditor.tsx
|
|
2719
|
-
import { jsx as
|
|
2768
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2720
2769
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
2721
|
-
return /* @__PURE__ */
|
|
2722
|
-
/* @__PURE__ */
|
|
2723
|
-
/* @__PURE__ */
|
|
2724
|
-
/* @__PURE__ */
|
|
2725
|
-
showStylePanel && /* @__PURE__ */
|
|
2770
|
+
return /* @__PURE__ */ jsxs17("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
2771
|
+
/* @__PURE__ */ jsx17(VectorToolbar, { controller, tools }),
|
|
2772
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
2773
|
+
/* @__PURE__ */ jsx17("div", { className: "relative min-h-[320px] flex-1 overflow-hidden rounded-md border border-border bg-muted/40", style: { height }, children: /* @__PURE__ */ jsx17(VectorCanvas, { controller, ...canvasProps }) }),
|
|
2774
|
+
showStylePanel && /* @__PURE__ */ jsx17(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
2726
2775
|
] })
|
|
2727
2776
|
] });
|
|
2728
2777
|
}
|
|
@@ -2745,6 +2794,7 @@ export {
|
|
|
2745
2794
|
VectorShadingPanel,
|
|
2746
2795
|
VectorStylePanel,
|
|
2747
2796
|
VectorSymbolsPanel,
|
|
2797
|
+
VectorSymmetryPanel,
|
|
2748
2798
|
VectorTextElement,
|
|
2749
2799
|
VectorTextPanel,
|
|
2750
2800
|
VectorToolbar,
|