@pixerate/editor-react 0.82.0 → 0.84.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 +418 -309
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +23 -1
- package/dist/vector/index.d.ts +23 -1
- package/dist/vector/index.js +287 -180
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -42,8 +42,10 @@ __export(vector_exports, {
|
|
|
42
42
|
VectorGradientAnnotator: () => VectorGradientAnnotator,
|
|
43
43
|
VectorGradientDefs: () => VectorGradientDefs,
|
|
44
44
|
VectorGradientEditor: () => VectorGradientEditor,
|
|
45
|
+
VectorLensPanel: () => VectorLensPanel,
|
|
45
46
|
VectorMaskPanel: () => VectorMaskPanel,
|
|
46
47
|
VectorMaskedNodes: () => VectorMaskedNodes,
|
|
48
|
+
VectorPerspectivePanel: () => VectorPerspectivePanel,
|
|
47
49
|
VectorProviderEffectsPanel: () => VectorProviderEffectsPanel,
|
|
48
50
|
VectorSceneNodes: () => VectorSceneNodes,
|
|
49
51
|
VectorShadingPanel: () => VectorShadingPanel,
|
|
@@ -693,6 +695,11 @@ function VectorCanvas({
|
|
|
693
695
|
sh.lines.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d, stroke: accentColor, strokeWidth: 1, opacity: 0.7 }, i)),
|
|
694
696
|
sh.points.map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-shading-point": p.index, "data-selected": p.selected || void 0, cx: p.x, cy: p.y, r: p.selected ? 6 : 4.5, fill: p.color, stroke: p.selected ? accentColor : "#ffffff", strokeWidth: p.selected ? 2 : 1.5 }, p.index))
|
|
695
697
|
] }, `shading:${sh.nodeId}`)),
|
|
698
|
+
overlay.perspective && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-perspective-grid": "", fill: "none", pointerEvents: "none", children: [
|
|
699
|
+
overlay.perspective.planes.map((pl) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-perspective-plane": pl.plane, "data-active": pl.active || void 0, d: pl.d, stroke: pl.active ? accentColor : guideColor, strokeWidth: pl.active ? 1 : 0.75, opacity: pl.active ? 0.55 : 0.25 }, pl.plane)),
|
|
700
|
+
overlay.perspective.vanishingPoints.map((v, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-vanishing-point": i, cx: v.x, cy: v.y, r: 4, stroke: accentColor, strokeWidth: 1.5 }, i)),
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-perspective-origin": "", cx: overlay.perspective.origin.x, cy: overlay.perspective.origin.y, r: 3, fill: accentColor })
|
|
702
|
+
] }),
|
|
696
703
|
overlay.symmetry.map((sy) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-symmetry-axes": sy.nodeId, stroke: accentColor, strokeDasharray: sy.drawing ? void 0 : "6 4", opacity: sy.drawing ? 0.9 : 0.6, children: sy.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: l.x1, y1: l.y1, x2: l.x2, y2: l.y2 }, i)) }, `sym:${sy.nodeId}`)),
|
|
697
704
|
overlay.trackingPoints.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-tracking-point": "", d: `M${t.x - 5} ${t.y}H${t.x + 5}M${t.x} ${t.y - 5}V${t.y + 5}`, stroke: guideColor, strokeWidth: 1.5 }, `track:${i}`)),
|
|
698
705
|
overlay.typedEntry && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
@@ -829,8 +836,8 @@ function VectorCanvas({
|
|
|
829
836
|
}
|
|
830
837
|
|
|
831
838
|
// src/vector/VectorToolbar.tsx
|
|
832
|
-
var
|
|
833
|
-
var
|
|
839
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
840
|
+
var import_vector18 = require("@pixerate/editor/vector");
|
|
834
841
|
|
|
835
842
|
// src/vector/VectorEffectsPanel.tsx
|
|
836
843
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -2081,16 +2088,114 @@ function VectorSymmetryPanel({ controller, className }) {
|
|
|
2081
2088
|
] });
|
|
2082
2089
|
}
|
|
2083
2090
|
|
|
2084
|
-
// src/vector/
|
|
2091
|
+
// src/vector/VectorPerspectivePanel.tsx
|
|
2092
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
2085
2093
|
var import_vector15 = require("@pixerate/editor/vector");
|
|
2086
2094
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2095
|
+
var buttonClass13 = "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";
|
|
2087
2096
|
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2088
|
-
var
|
|
2089
|
-
|
|
2097
|
+
var PLANE_LABELS = { floor: "Floor", left: "Left wall", right: "Right wall", side: "Side wall", front: "Front" };
|
|
2098
|
+
function VectorPerspectivePanel({ controller, className }) {
|
|
2099
|
+
const state = useVectorEditorState(controller);
|
|
2100
|
+
const grid = state.document.perspective ?? null;
|
|
2101
|
+
const planes = grid ? (0, import_vector15.vectorPerspectivePlanes)(grid) : [];
|
|
2102
|
+
const [attachTo, setAttachTo] = import_react10.default.useState("");
|
|
2103
|
+
const target = (state.perspectivePlane ?? attachTo) || planes[0];
|
|
2104
|
+
const add = (n) => controller.setPerspective((0, import_vector15.vectorPerspectivePreset)(n, state.document.width, state.document.height));
|
|
2105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-perspective-panel": "", "aria-label": "Perspective", children: [
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Perspective" }),
|
|
2108
|
+
[1, 2, 3].map((n) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", className: buttonClass13, "aria-pressed": grid?.vanishingPoints.length === n, "data-vector-perspective-preset": n, title: `A ${n}-point perspective grid for the page`, onClick: () => add(n), children: [
|
|
2109
|
+
n,
|
|
2110
|
+
"-pt"
|
|
2111
|
+
] }, n))
|
|
2112
|
+
] }),
|
|
2113
|
+
grid && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2114
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("select", { "aria-label": "Draw on plane", title: "New rectangles, ellipses, polygons and stars are drawn on this plane", className: selectClass10, value: state.perspectivePlane ?? "", onChange: (e) => controller.setPerspectivePlane(e.target.value || null), children: [
|
|
2116
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: "", children: "Draw flat" }),
|
|
2117
|
+
planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("option", { value: p, children: [
|
|
2118
|
+
"Draw on ",
|
|
2119
|
+
PLANE_LABELS[p].toLowerCase()
|
|
2120
|
+
] }, p))
|
|
2121
|
+
] })
|
|
2122
|
+
] }),
|
|
2123
|
+
grid && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "w-16" }),
|
|
2125
|
+
!state.perspectivePlane && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Attach to plane", className: "h-7 w-24 rounded border border-border bg-background px-1 text-xs", value: attachTo || planes[0], onChange: (e) => setAttachTo(e.target.value), children: planes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: p, children: PLANE_LABELS[p] }, p)) }),
|
|
2126
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, disabled: !state.selection.length, title: "Lay the selection onto the plane (read flat from the grid's origin)", onClick: () => controller.attachToPerspective(target), children: "Attach" }),
|
|
2127
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Show the grid on the canvas", children: [
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", "aria-label": "Show perspective grid", checked: grid.visible !== false, onChange: (e) => controller.setPerspective({ ...grid, visible: e.target.checked }) }),
|
|
2129
|
+
"Show"
|
|
2130
|
+
] }),
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, title: "Remove the grid (art on it stays)", onClick: () => controller.setPerspective(null), children: "Remove" })
|
|
2132
|
+
] })
|
|
2133
|
+
] });
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
// src/vector/VectorLensPanel.tsx
|
|
2137
|
+
var import_vector16 = require("@pixerate/editor/vector");
|
|
2138
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2139
|
+
var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2140
|
+
var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2141
|
+
function VectorLensPanel({ controller, className }) {
|
|
2142
|
+
const state = useVectorEditorState(controller);
|
|
2143
|
+
const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path" && n.subpaths.some((sp) => sp.closed) && !n.connector);
|
|
2144
|
+
if (!path) return null;
|
|
2145
|
+
const lens = path.lens ?? null;
|
|
2146
|
+
const spec = lens ? import_vector16.VECTOR_LENS_SPECS[lens.type] : null;
|
|
2147
|
+
const ids = [path.id];
|
|
2148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
|
|
2149
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Lens" }),
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2152
|
+
"select",
|
|
2153
|
+
{
|
|
2154
|
+
"aria-label": "Lens type",
|
|
2155
|
+
className: selectClass11,
|
|
2156
|
+
value: lens?.type ?? "",
|
|
2157
|
+
onChange: (e) => e.target.value ? controller.setLens({ type: e.target.value }, { ids }) : controller.setLens(null, { ids }),
|
|
2158
|
+
children: [
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "", children: "None" }),
|
|
2160
|
+
import_vector16.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: t, children: import_vector16.VECTOR_LENS_LABELS[t] }, t))
|
|
2161
|
+
]
|
|
2162
|
+
}
|
|
2163
|
+
)
|
|
2164
|
+
] }),
|
|
2165
|
+
lens && spec && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2166
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16" }),
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2168
|
+
"input",
|
|
2169
|
+
{
|
|
2170
|
+
type: "number",
|
|
2171
|
+
"aria-label": "Lens amount",
|
|
2172
|
+
title: `Amount: ${spec.unit} (${spec.min} to ${spec.max})`,
|
|
2173
|
+
className: numberClass9,
|
|
2174
|
+
min: spec.min,
|
|
2175
|
+
max: spec.max,
|
|
2176
|
+
step: lens.type === "magnify" ? 0.1 : 1,
|
|
2177
|
+
value: lens.amount,
|
|
2178
|
+
onChange: (e) => {
|
|
2179
|
+
const v = parseFloat(e.target.value);
|
|
2180
|
+
if (Number.isFinite(v)) controller.setLens({ amount: Math.min(spec.max, Math.max(spec.min, v)) }, { ids, merge: `lens-amount-${path.id}` });
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
),
|
|
2184
|
+
spec.color !== null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "color", "aria-label": "Lens colour", title: "Lens colour", className: "h-7 w-9 rounded border border-border bg-background", value: lens.color ?? spec.color, onChange: (e) => controller.setLens({ color: e.target.value }, { ids, merge: `lens-color-${path.id}` }) })
|
|
2185
|
+
] })
|
|
2186
|
+
] });
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// src/vector/VectorGradientEditor.tsx
|
|
2190
|
+
var import_vector17 = require("@pixerate/editor/vector");
|
|
2191
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2192
|
+
var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2193
|
+
var numberClass10 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
2194
|
+
var buttonClass14 = "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";
|
|
2090
2195
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
2091
2196
|
function VectorGradientEditor({ controller, className }) {
|
|
2092
2197
|
const state = useVectorEditorState(controller);
|
|
2093
|
-
const ed = (0,
|
|
2198
|
+
const ed = (0, import_vector17.getVectorGradientEditor)(state);
|
|
2094
2199
|
if (!ed) return null;
|
|
2095
2200
|
const g = ed.gradient;
|
|
2096
2201
|
const sel = ed.selected;
|
|
@@ -2098,26 +2203,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2098
2203
|
const setType = (value) => {
|
|
2099
2204
|
if (value === "solid") {
|
|
2100
2205
|
const first = ed.stops[0];
|
|
2101
|
-
controller.setStyle({ [ed.target]: (0,
|
|
2206
|
+
controller.setStyle({ [ed.target]: (0, import_vector17.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
2102
2207
|
} else controller.setGradient({ type: value });
|
|
2103
2208
|
};
|
|
2104
|
-
return /* @__PURE__ */ (0,
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2106
|
-
/* @__PURE__ */ (0,
|
|
2107
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */ (0,
|
|
2108
|
-
ed.mixed && /* @__PURE__ */ (0,
|
|
2209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
2212
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
2213
|
+
ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2109
2214
|
] }),
|
|
2110
|
-
/* @__PURE__ */ (0,
|
|
2111
|
-
/* @__PURE__ */ (0,
|
|
2112
|
-
/* @__PURE__ */ (0,
|
|
2113
|
-
/* @__PURE__ */ (0,
|
|
2114
|
-
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2217
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("select", { "aria-label": "Gradient type", className: selectClass12, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "solid", children: "Solid" }),
|
|
2219
|
+
import_vector17.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector17.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
2115
2220
|
] }),
|
|
2116
|
-
/* @__PURE__ */ (0,
|
|
2221
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
2117
2222
|
] }),
|
|
2118
|
-
g && /* @__PURE__ */ (0,
|
|
2119
|
-
/* @__PURE__ */ (0,
|
|
2120
|
-
/* @__PURE__ */ (0,
|
|
2223
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
2224
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
2225
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2121
2226
|
"div",
|
|
2122
2227
|
{
|
|
2123
2228
|
role: "button",
|
|
@@ -2131,7 +2236,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2131
2236
|
}
|
|
2132
2237
|
}
|
|
2133
2238
|
),
|
|
2134
|
-
ed.stops.map((s) => /* @__PURE__ */ (0,
|
|
2239
|
+
ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2135
2240
|
"button",
|
|
2136
2241
|
{
|
|
2137
2242
|
type: "button",
|
|
@@ -2145,21 +2250,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2145
2250
|
s.index
|
|
2146
2251
|
))
|
|
2147
2252
|
] }),
|
|
2148
|
-
sel && /* @__PURE__ */ (0,
|
|
2149
|
-
/* @__PURE__ */ (0,
|
|
2253
|
+
sel && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2150
2255
|
"input",
|
|
2151
2256
|
{
|
|
2152
2257
|
type: "color",
|
|
2153
2258
|
"aria-label": "Stop colour",
|
|
2154
2259
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2155
|
-
value: (0,
|
|
2260
|
+
value: (0, import_vector17.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
2156
2261
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2157
2262
|
onBlur: end
|
|
2158
2263
|
}
|
|
2159
2264
|
),
|
|
2160
|
-
/* @__PURE__ */ (0,
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2161
2266
|
"Opacity",
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2267
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2163
2268
|
"input",
|
|
2164
2269
|
{
|
|
2165
2270
|
type: "number",
|
|
@@ -2167,7 +2272,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2167
2272
|
max: 100,
|
|
2168
2273
|
step: 5,
|
|
2169
2274
|
"aria-label": "Stop opacity",
|
|
2170
|
-
className:
|
|
2275
|
+
className: numberClass10,
|
|
2171
2276
|
value: percent(sel.opacity ?? 1),
|
|
2172
2277
|
onChange: (e) => {
|
|
2173
2278
|
const n = parseFloat(e.target.value);
|
|
@@ -2176,9 +2281,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2176
2281
|
}
|
|
2177
2282
|
)
|
|
2178
2283
|
] }),
|
|
2179
|
-
/* @__PURE__ */ (0,
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2180
2285
|
"At",
|
|
2181
|
-
/* @__PURE__ */ (0,
|
|
2286
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2182
2287
|
"input",
|
|
2183
2288
|
{
|
|
2184
2289
|
type: "number",
|
|
@@ -2186,7 +2291,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2186
2291
|
max: 100,
|
|
2187
2292
|
step: 1,
|
|
2188
2293
|
"aria-label": "Stop position",
|
|
2189
|
-
className:
|
|
2294
|
+
className: numberClass10,
|
|
2190
2295
|
value: percent(sel.offset),
|
|
2191
2296
|
onChange: (e) => {
|
|
2192
2297
|
const n = parseFloat(e.target.value);
|
|
@@ -2195,9 +2300,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2195
2300
|
}
|
|
2196
2301
|
)
|
|
2197
2302
|
] }),
|
|
2198
|
-
!sel.last && /* @__PURE__ */ (0,
|
|
2303
|
+
!sel.last && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2199
2304
|
"Midpoint",
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2305
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2201
2306
|
"input",
|
|
2202
2307
|
{
|
|
2203
2308
|
type: "number",
|
|
@@ -2205,7 +2310,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2205
2310
|
max: 95,
|
|
2206
2311
|
step: 1,
|
|
2207
2312
|
"aria-label": "Stop midpoint",
|
|
2208
|
-
className:
|
|
2313
|
+
className: numberClass10,
|
|
2209
2314
|
value: percent(sel.midpoint ?? 0.5),
|
|
2210
2315
|
onChange: (e) => {
|
|
2211
2316
|
const n = parseFloat(e.target.value);
|
|
@@ -2214,15 +2319,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2214
2319
|
}
|
|
2215
2320
|
)
|
|
2216
2321
|
] }),
|
|
2217
|
-
/* @__PURE__ */ (0,
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass14, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
2218
2323
|
] }),
|
|
2219
|
-
/* @__PURE__ */ (0,
|
|
2220
|
-
/* @__PURE__ */ (0,
|
|
2221
|
-
/* @__PURE__ */ (0,
|
|
2324
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2325
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
2326
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass12, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector17.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: i, children: import_vector17.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2222
2327
|
] }),
|
|
2223
|
-
/* @__PURE__ */ (0,
|
|
2224
|
-
/* @__PURE__ */ (0,
|
|
2225
|
-
/* @__PURE__ */ (0,
|
|
2328
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
2330
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2226
2331
|
"input",
|
|
2227
2332
|
{
|
|
2228
2333
|
type: "range",
|
|
@@ -2238,26 +2343,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2238
2343
|
}
|
|
2239
2344
|
)
|
|
2240
2345
|
] }),
|
|
2241
|
-
/* @__PURE__ */ (0,
|
|
2242
|
-
/* @__PURE__ */ (0,
|
|
2243
|
-
/* @__PURE__ */ (0,
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient spread", className: selectClass12, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector17.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: sp, children: import_vector17.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2244
2349
|
] }),
|
|
2245
|
-
ed.target === "stroke" && /* @__PURE__ */ (0,
|
|
2246
|
-
/* @__PURE__ */ (0,
|
|
2247
|
-
/* @__PURE__ */ (0,
|
|
2350
|
+
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2351
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass12, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector17.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: m, children: import_vector17.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2248
2353
|
] })
|
|
2249
2354
|
] })
|
|
2250
2355
|
] });
|
|
2251
2356
|
}
|
|
2252
2357
|
|
|
2253
2358
|
// src/vector/VectorToolbar.tsx
|
|
2254
|
-
var
|
|
2359
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2255
2360
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
2256
2361
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
2257
|
-
var
|
|
2362
|
+
var buttonClass15 = "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";
|
|
2258
2363
|
function VectorToolbar({
|
|
2259
2364
|
controller,
|
|
2260
|
-
tools =
|
|
2365
|
+
tools = import_vector18.VECTOR_TOOLS,
|
|
2261
2366
|
showHistory = true,
|
|
2262
2367
|
showArrange = true,
|
|
2263
2368
|
showSnap = true,
|
|
@@ -2271,36 +2376,36 @@ function VectorToolbar({
|
|
|
2271
2376
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
2272
2377
|
const editing = state.editing;
|
|
2273
2378
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
2274
|
-
const maskSelected = state.selection.some((id) => (0,
|
|
2275
|
-
const [live, setLive] =
|
|
2379
|
+
const maskSelected = state.selection.some((id) => (0, import_vector18.isVectorMaskGroup)(controller.getNode(id)));
|
|
2380
|
+
const [live, setLive] = import_react11.default.useState(false);
|
|
2276
2381
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2277
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
2278
|
-
return /* @__PURE__ */ (0,
|
|
2279
|
-
/* @__PURE__ */ (0,
|
|
2382
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2280
2385
|
"button",
|
|
2281
2386
|
{
|
|
2282
2387
|
type: "button",
|
|
2283
2388
|
"data-vector-tool": tool,
|
|
2284
|
-
className:
|
|
2389
|
+
className: buttonClass15,
|
|
2285
2390
|
"aria-pressed": state.tool === tool,
|
|
2286
|
-
title: `${(0,
|
|
2287
|
-
"aria-label": (0,
|
|
2391
|
+
title: `${(0, import_vector18.vectorToolLabel)(tool)} (${import_vector18.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2392
|
+
"aria-label": (0, import_vector18.vectorToolLabel)(tool),
|
|
2288
2393
|
onClick: () => controller.setTool(tool),
|
|
2289
|
-
children:
|
|
2394
|
+
children: import_vector18.VECTOR_TOOL_GLYPHS[tool]
|
|
2290
2395
|
},
|
|
2291
2396
|
tool
|
|
2292
2397
|
)) }),
|
|
2293
|
-
showHistory && /* @__PURE__ */ (0,
|
|
2398
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
2294
2399
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
2295
2400
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
2296
2401
|
] }),
|
|
2297
|
-
showSnap && /* @__PURE__ */ (0,
|
|
2298
|
-
/* @__PURE__ */ (0,
|
|
2402
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2403
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2299
2404
|
"button",
|
|
2300
2405
|
{
|
|
2301
2406
|
type: "button",
|
|
2302
2407
|
"data-vector-snap": "",
|
|
2303
|
-
className:
|
|
2408
|
+
className: buttonClass15,
|
|
2304
2409
|
"aria-pressed": state.snap.objects,
|
|
2305
2410
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2306
2411
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -2308,18 +2413,18 @@ function VectorToolbar({
|
|
|
2308
2413
|
children: "Snap"
|
|
2309
2414
|
}
|
|
2310
2415
|
),
|
|
2311
|
-
/* @__PURE__ */ (0,
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2312
2417
|
"select",
|
|
2313
2418
|
{
|
|
2314
2419
|
"data-vector-polar": "",
|
|
2315
2420
|
"aria-label": "Polar tracking increment",
|
|
2316
2421
|
title: "Polar tracking: the angles drawn points snap to from where they leave",
|
|
2317
2422
|
className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
|
|
2318
|
-
value: String((0,
|
|
2319
|
-
onChange: (e) => controller.setSnap({ angles: (0,
|
|
2423
|
+
value: String((0, import_vector18.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
|
|
2424
|
+
onChange: (e) => controller.setSnap({ angles: (0, import_vector18.vectorPolarAngles)(Number(e.target.value)) }),
|
|
2320
2425
|
children: [
|
|
2321
|
-
(0,
|
|
2322
|
-
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0,
|
|
2426
|
+
(0, import_vector18.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "Custom" }),
|
|
2427
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("option", { value: n, children: [
|
|
2323
2428
|
n,
|
|
2324
2429
|
"\xB0"
|
|
2325
2430
|
] }, n))
|
|
@@ -2327,13 +2432,13 @@ function VectorToolbar({
|
|
|
2327
2432
|
}
|
|
2328
2433
|
)
|
|
2329
2434
|
] }),
|
|
2330
|
-
showPathEdit && /* @__PURE__ */ (0,
|
|
2331
|
-
|
|
2435
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2436
|
+
import_vector18.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2332
2437
|
"button",
|
|
2333
2438
|
{
|
|
2334
2439
|
type: "button",
|
|
2335
2440
|
"data-vector-path-action": a.id,
|
|
2336
|
-
className:
|
|
2441
|
+
className: buttonClass15,
|
|
2337
2442
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
2338
2443
|
"aria-label": a.title,
|
|
2339
2444
|
disabled: !a.enabled(count, points),
|
|
@@ -2342,12 +2447,12 @@ function VectorToolbar({
|
|
|
2342
2447
|
},
|
|
2343
2448
|
a.id
|
|
2344
2449
|
)),
|
|
2345
|
-
|
|
2450
|
+
import_vector18.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2346
2451
|
"button",
|
|
2347
2452
|
{
|
|
2348
2453
|
type: "button",
|
|
2349
2454
|
"data-vector-edit": t.key,
|
|
2350
|
-
className:
|
|
2455
|
+
className: buttonClass15,
|
|
2351
2456
|
"aria-pressed": editing[t.key],
|
|
2352
2457
|
title: t.title,
|
|
2353
2458
|
"aria-label": t.title,
|
|
@@ -2356,9 +2461,9 @@ function VectorToolbar({
|
|
|
2356
2461
|
},
|
|
2357
2462
|
t.key
|
|
2358
2463
|
)),
|
|
2359
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
2464
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2360
2465
|
"Smoothing",
|
|
2361
|
-
/* @__PURE__ */ (0,
|
|
2466
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2362
2467
|
"input",
|
|
2363
2468
|
{
|
|
2364
2469
|
type: "range",
|
|
@@ -2372,9 +2477,9 @@ function VectorToolbar({
|
|
|
2372
2477
|
}
|
|
2373
2478
|
)
|
|
2374
2479
|
] }),
|
|
2375
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
2480
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2376
2481
|
"Size",
|
|
2377
|
-
/* @__PURE__ */ (0,
|
|
2482
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2378
2483
|
"input",
|
|
2379
2484
|
{
|
|
2380
2485
|
type: "number",
|
|
@@ -2390,26 +2495,26 @@ function VectorToolbar({
|
|
|
2390
2495
|
}
|
|
2391
2496
|
)
|
|
2392
2497
|
] }),
|
|
2393
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
2498
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2394
2499
|
"button",
|
|
2395
2500
|
{
|
|
2396
2501
|
type: "button",
|
|
2397
2502
|
"data-vector-fill-gap": "",
|
|
2398
|
-
className:
|
|
2503
|
+
className: buttonClass15,
|
|
2399
2504
|
"aria-pressed": editing.fillGap > 0,
|
|
2400
2505
|
title: "Close small gaps between path ends when filling",
|
|
2401
2506
|
"aria-label": "Close gaps",
|
|
2402
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
2507
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector18.VECTOR_FILL_GAP }),
|
|
2403
2508
|
children: "Gaps"
|
|
2404
2509
|
}
|
|
2405
2510
|
)
|
|
2406
2511
|
] }),
|
|
2407
|
-
showDistort && /* @__PURE__ */ (0,
|
|
2512
|
+
showDistort && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2408
2513
|
"button",
|
|
2409
2514
|
{
|
|
2410
2515
|
type: "button",
|
|
2411
2516
|
"data-vector-free-distort": "",
|
|
2412
|
-
className:
|
|
2517
|
+
className: buttonClass15,
|
|
2413
2518
|
"aria-pressed": state.freeDistort,
|
|
2414
2519
|
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)`,
|
|
2415
2520
|
"aria-label": "Free Distort",
|
|
@@ -2417,15 +2522,15 @@ function VectorToolbar({
|
|
|
2417
2522
|
children: "Distort"
|
|
2418
2523
|
}
|
|
2419
2524
|
) }),
|
|
2420
|
-
showBlend && /* @__PURE__ */ (0,
|
|
2421
|
-
showArrange && /* @__PURE__ */ (0,
|
|
2422
|
-
/* @__PURE__ */ (0,
|
|
2423
|
-
/* @__PURE__ */ (0,
|
|
2525
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorBlendControls, { controller }),
|
|
2526
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2424
2529
|
"button",
|
|
2425
2530
|
{
|
|
2426
2531
|
type: "button",
|
|
2427
2532
|
"data-vector-live-boolean": "",
|
|
2428
|
-
className:
|
|
2533
|
+
className: buttonClass15,
|
|
2429
2534
|
"aria-pressed": live,
|
|
2430
2535
|
title: "Live booleans: keep the shapes editable",
|
|
2431
2536
|
"aria-label": "Live booleans",
|
|
@@ -2442,12 +2547,12 @@ function VectorToolbar({
|
|
|
2442
2547
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2443
2548
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2444
2549
|
] }),
|
|
2445
|
-
/* @__PURE__ */ (0,
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector18.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2446
2551
|
"button",
|
|
2447
2552
|
{
|
|
2448
2553
|
type: "button",
|
|
2449
2554
|
"data-vector-pathfinder": a.id,
|
|
2450
|
-
className:
|
|
2555
|
+
className: buttonClass15,
|
|
2451
2556
|
title: a.title,
|
|
2452
2557
|
"aria-label": a.title,
|
|
2453
2558
|
disabled: count < a.min,
|
|
@@ -2456,7 +2561,7 @@ function VectorToolbar({
|
|
|
2456
2561
|
},
|
|
2457
2562
|
a.id
|
|
2458
2563
|
)) }),
|
|
2459
|
-
/* @__PURE__ */ (0,
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
2460
2565
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
2461
2566
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
2462
2567
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -2471,22 +2576,22 @@ function VectorToolbar({
|
|
|
2471
2576
|
}
|
|
2472
2577
|
function VectorBlendControls({ controller }) {
|
|
2473
2578
|
const state = useVectorEditorState(controller);
|
|
2474
|
-
const blend = (0,
|
|
2579
|
+
const blend = (0, import_vector18.getVectorBlendControls)(state);
|
|
2475
2580
|
const o = blend.options;
|
|
2476
2581
|
const selected = blend.ids.length > 0;
|
|
2477
|
-
return /* @__PURE__ */ (0,
|
|
2478
|
-
/* @__PURE__ */ (0,
|
|
2479
|
-
/* @__PURE__ */ (0,
|
|
2582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2583
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass15, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
2584
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2480
2585
|
"select",
|
|
2481
2586
|
{
|
|
2482
2587
|
"aria-label": "Blend spacing",
|
|
2483
2588
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2484
2589
|
value: o.spacing,
|
|
2485
|
-
onChange: (e) => (0,
|
|
2486
|
-
children:
|
|
2590
|
+
onChange: (e) => (0, import_vector18.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
2591
|
+
children: import_vector18.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector18.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2487
2592
|
}
|
|
2488
2593
|
),
|
|
2489
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */ (0,
|
|
2594
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2490
2595
|
"input",
|
|
2491
2596
|
{
|
|
2492
2597
|
type: "number",
|
|
@@ -2498,29 +2603,29 @@ function VectorBlendControls({ controller }) {
|
|
|
2498
2603
|
onChange: (e) => {
|
|
2499
2604
|
const n = parseFloat(e.target.value);
|
|
2500
2605
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
2501
|
-
(0,
|
|
2606
|
+
(0, import_vector18.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
2502
2607
|
}
|
|
2503
2608
|
}
|
|
2504
2609
|
),
|
|
2505
|
-
/* @__PURE__ */ (0,
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2506
2611
|
"button",
|
|
2507
2612
|
{
|
|
2508
2613
|
type: "button",
|
|
2509
2614
|
"data-vector-blend-action": "orient",
|
|
2510
|
-
className:
|
|
2615
|
+
className: buttonClass15,
|
|
2511
2616
|
"aria-pressed": o.orientToSpine,
|
|
2512
2617
|
title: "Orient steps to the spine",
|
|
2513
2618
|
"aria-label": "Orient to spine",
|
|
2514
|
-
onClick: () => (0,
|
|
2619
|
+
onClick: () => (0, import_vector18.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
2515
2620
|
children: "\u293F"
|
|
2516
2621
|
}
|
|
2517
2622
|
),
|
|
2518
|
-
/* @__PURE__ */ (0,
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2519
2624
|
"button",
|
|
2520
2625
|
{
|
|
2521
2626
|
type: "button",
|
|
2522
2627
|
"data-vector-blend-action": "spine",
|
|
2523
|
-
className:
|
|
2628
|
+
className: buttonClass15,
|
|
2524
2629
|
title: "Replace Spine (select a blend and a path)",
|
|
2525
2630
|
"aria-label": "Replace Spine",
|
|
2526
2631
|
disabled: !blend.canReplaceSpine,
|
|
@@ -2528,15 +2633,15 @@ function VectorBlendControls({ controller }) {
|
|
|
2528
2633
|
children: "\u2307"
|
|
2529
2634
|
}
|
|
2530
2635
|
),
|
|
2531
|
-
/* @__PURE__ */ (0,
|
|
2532
|
-
/* @__PURE__ */ (0,
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass15, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass15, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
2533
2638
|
] });
|
|
2534
2639
|
}
|
|
2535
|
-
var
|
|
2536
|
-
var
|
|
2640
|
+
var selectClass13 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2641
|
+
var numberClass11 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2537
2642
|
function VectorStylePanel({ controller, className }) {
|
|
2538
2643
|
const state = useVectorEditorState(controller);
|
|
2539
|
-
const style = (0,
|
|
2644
|
+
const style = (0, import_vector18.getVectorSelectionStyle)(state);
|
|
2540
2645
|
const d = state.defaults;
|
|
2541
2646
|
const source = style ?? {
|
|
2542
2647
|
fill: d.fill ?? null,
|
|
@@ -2549,7 +2654,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2549
2654
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
2550
2655
|
startArrowScale: d.startArrowScale ?? 1,
|
|
2551
2656
|
endArrowScale: d.endArrowScale ?? 1,
|
|
2552
|
-
widthProfile: (0,
|
|
2657
|
+
widthProfile: (0, import_vector18.widthProfilePresetId)(d.strokeWidthProfile),
|
|
2553
2658
|
cornerRadius: d.cornerRadius,
|
|
2554
2659
|
cornerKind: d.cornerKind ?? "round",
|
|
2555
2660
|
cornerSmoothing: 0,
|
|
@@ -2563,19 +2668,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2563
2668
|
};
|
|
2564
2669
|
const setProfile = (id) => {
|
|
2565
2670
|
if (style) controller.setWidthProfile(id);
|
|
2566
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
2671
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector18.widthProfilePreset)(id)?.length ? (0, import_vector18.widthProfilePreset)(id) : null });
|
|
2567
2672
|
};
|
|
2568
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
2673
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2569
2674
|
const arrowRow = (end, label) => {
|
|
2570
2675
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
2571
2676
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
2572
|
-
return /* @__PURE__ */ (0,
|
|
2573
|
-
/* @__PURE__ */ (0,
|
|
2574
|
-
/* @__PURE__ */ (0,
|
|
2575
|
-
/* @__PURE__ */ (0,
|
|
2576
|
-
|
|
2677
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2678
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass13, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2680
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: "None" }),
|
|
2681
|
+
import_vector18.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: h, children: import_vector18.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2577
2682
|
] }),
|
|
2578
|
-
/* @__PURE__ */ (0,
|
|
2683
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2579
2684
|
"input",
|
|
2580
2685
|
{
|
|
2581
2686
|
type: "number",
|
|
@@ -2583,7 +2688,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2583
2688
|
step: 0.25,
|
|
2584
2689
|
"aria-label": `${label} arrowhead scale`,
|
|
2585
2690
|
title: "Scale (\xD7 stroke width)",
|
|
2586
|
-
className:
|
|
2691
|
+
className: numberClass11,
|
|
2587
2692
|
value: source[scaleKey],
|
|
2588
2693
|
onChange: (e) => {
|
|
2589
2694
|
const n = parseFloat(e.target.value);
|
|
@@ -2599,14 +2704,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2599
2704
|
};
|
|
2600
2705
|
const paintRow = (key, label) => {
|
|
2601
2706
|
const paint = source[key];
|
|
2602
|
-
const hex = (0,
|
|
2707
|
+
const hex = (0, import_vector18.vectorPaintToHex)(paint);
|
|
2603
2708
|
const on = paint !== null && paint !== "none";
|
|
2604
|
-
return /* @__PURE__ */ (0,
|
|
2605
|
-
/* @__PURE__ */ (0,
|
|
2606
|
-
/* @__PURE__ */ (0,
|
|
2709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2710
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
2607
2712
|
label
|
|
2608
2713
|
] }),
|
|
2609
|
-
/* @__PURE__ */ (0,
|
|
2714
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2610
2715
|
"input",
|
|
2611
2716
|
{
|
|
2612
2717
|
type: "color",
|
|
@@ -2617,18 +2722,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2617
2722
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
2618
2723
|
}
|
|
2619
2724
|
),
|
|
2620
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
2621
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
2725
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2726
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
2622
2727
|
] });
|
|
2623
2728
|
};
|
|
2624
|
-
return /* @__PURE__ */ (0,
|
|
2625
|
-
/* @__PURE__ */ (0,
|
|
2729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2730
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
2626
2731
|
paintRow("fill", "Fill"),
|
|
2627
2732
|
paintRow("stroke", "Stroke"),
|
|
2628
|
-
style && /* @__PURE__ */ (0,
|
|
2629
|
-
/* @__PURE__ */ (0,
|
|
2630
|
-
/* @__PURE__ */ (0,
|
|
2631
|
-
/* @__PURE__ */ (0,
|
|
2733
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorGradientEditor, { controller }),
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2735
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Width" }),
|
|
2736
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2632
2737
|
"input",
|
|
2633
2738
|
{
|
|
2634
2739
|
type: "number",
|
|
@@ -2644,33 +2749,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2644
2749
|
}
|
|
2645
2750
|
)
|
|
2646
2751
|
] }),
|
|
2647
|
-
/* @__PURE__ */ (0,
|
|
2648
|
-
/* @__PURE__ */ (0,
|
|
2649
|
-
/* @__PURE__ */ (0,
|
|
2752
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2753
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Align" }),
|
|
2754
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass13, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector18.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: a, children: import_vector18.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
2650
2755
|
mixed("strokeAlign")
|
|
2651
2756
|
] }),
|
|
2652
|
-
/* @__PURE__ */ (0,
|
|
2653
|
-
/* @__PURE__ */ (0,
|
|
2654
|
-
/* @__PURE__ */ (0,
|
|
2757
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2758
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
2759
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2655
2760
|
"select",
|
|
2656
2761
|
{
|
|
2657
2762
|
"aria-label": "Width profile",
|
|
2658
|
-
className:
|
|
2763
|
+
className: selectClass13,
|
|
2659
2764
|
value: source.widthProfile,
|
|
2660
2765
|
onChange: (e) => {
|
|
2661
2766
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2662
2767
|
},
|
|
2663
2768
|
children: [
|
|
2664
|
-
|
|
2665
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
2769
|
+
import_vector18.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
2770
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2666
2771
|
]
|
|
2667
2772
|
}
|
|
2668
2773
|
),
|
|
2669
|
-
/* @__PURE__ */ (0,
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2670
2775
|
"button",
|
|
2671
2776
|
{
|
|
2672
2777
|
type: "button",
|
|
2673
|
-
className:
|
|
2778
|
+
className: buttonClass15,
|
|
2674
2779
|
title: "Reset to uniform width",
|
|
2675
2780
|
"aria-label": "Reset to uniform width",
|
|
2676
2781
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -2680,27 +2785,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2680
2785
|
),
|
|
2681
2786
|
mixed("widthProfile")
|
|
2682
2787
|
] }),
|
|
2683
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
2788
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
2684
2789
|
arrowRow("start", "Start"),
|
|
2685
2790
|
arrowRow("end", "End"),
|
|
2686
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
2687
|
-
/* @__PURE__ */ (0,
|
|
2688
|
-
/* @__PURE__ */ (0,
|
|
2689
|
-
/* @__PURE__ */ (0,
|
|
2690
|
-
/* @__PURE__ */ (0,
|
|
2791
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
2793
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass13, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2794
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
2795
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
2691
2796
|
] })
|
|
2692
2797
|
] })
|
|
2693
2798
|
] }),
|
|
2694
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
2695
|
-
/* @__PURE__ */ (0,
|
|
2696
|
-
/* @__PURE__ */ (0,
|
|
2799
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2800
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2801
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2697
2802
|
"input",
|
|
2698
2803
|
{
|
|
2699
2804
|
type: "number",
|
|
2700
2805
|
min: 0,
|
|
2701
2806
|
step: 1,
|
|
2702
2807
|
"aria-label": "Corner radius",
|
|
2703
|
-
className:
|
|
2808
|
+
className: numberClass11,
|
|
2704
2809
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
2705
2810
|
onChange: (e) => {
|
|
2706
2811
|
const n = parseFloat(e.target.value);
|
|
@@ -2708,12 +2813,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2708
2813
|
}
|
|
2709
2814
|
}
|
|
2710
2815
|
),
|
|
2711
|
-
/* @__PURE__ */ (0,
|
|
2816
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Corner kind", className: selectClass13, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector18.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: k, children: import_vector18.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2712
2817
|
mixed("cornerRadius")
|
|
2713
2818
|
] }),
|
|
2714
|
-
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0,
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
2716
|
-
/* @__PURE__ */ (0,
|
|
2819
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "corner-smoothing", title: "Corner smoothing: squircle corners that ease into the curve (0.6 is iOS-like)", children: [
|
|
2820
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Smoothing" }),
|
|
2821
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2717
2822
|
"input",
|
|
2718
2823
|
{
|
|
2719
2824
|
type: "range",
|
|
@@ -2728,9 +2833,9 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2728
2833
|
}
|
|
2729
2834
|
)
|
|
2730
2835
|
] }),
|
|
2731
|
-
style && /* @__PURE__ */ (0,
|
|
2732
|
-
/* @__PURE__ */ (0,
|
|
2733
|
-
/* @__PURE__ */ (0,
|
|
2836
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2734
2839
|
"input",
|
|
2735
2840
|
{
|
|
2736
2841
|
type: "range",
|
|
@@ -2744,33 +2849,35 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2744
2849
|
}
|
|
2745
2850
|
)
|
|
2746
2851
|
] }),
|
|
2747
|
-
/* @__PURE__ */ (0,
|
|
2748
|
-
style && /* @__PURE__ */ (0,
|
|
2749
|
-
style && /* @__PURE__ */ (0,
|
|
2750
|
-
style && /* @__PURE__ */ (0,
|
|
2751
|
-
style && /* @__PURE__ */ (0,
|
|
2752
|
-
/* @__PURE__ */ (0,
|
|
2753
|
-
/* @__PURE__ */ (0,
|
|
2754
|
-
/* @__PURE__ */ (0,
|
|
2755
|
-
/* @__PURE__ */ (0,
|
|
2756
|
-
/* @__PURE__ */ (0,
|
|
2757
|
-
/* @__PURE__ */ (0,
|
|
2758
|
-
/* @__PURE__ */ (0,
|
|
2852
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorTextPanel, { controller }),
|
|
2853
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorAppearancePanel, { controller }),
|
|
2854
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorEffectsPanel, { controller }),
|
|
2855
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorEnvelopePanel, { controller }),
|
|
2856
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorMaskPanel, { controller }),
|
|
2857
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorFramePanel, { controller }),
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorConnectorPanel, { controller }),
|
|
2859
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorShadingPanel, { controller }),
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorSymmetryPanel, { controller }),
|
|
2861
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorPerspectivePanel, { controller }),
|
|
2862
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorLensPanel, { controller }),
|
|
2863
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorTracePanel, { controller }),
|
|
2864
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorConstraintsPanel, { controller }),
|
|
2865
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VectorSymbolsPanel, { controller })
|
|
2759
2866
|
] });
|
|
2760
2867
|
}
|
|
2761
2868
|
|
|
2762
2869
|
// src/effects/useEffects.ts
|
|
2763
|
-
var
|
|
2870
|
+
var import_react12 = require("react");
|
|
2764
2871
|
function useEffects(host, provider) {
|
|
2765
|
-
(0,
|
|
2872
|
+
(0, import_react12.useEffect)(() => {
|
|
2766
2873
|
if (!host || !provider) return;
|
|
2767
2874
|
return host.useEffects(provider);
|
|
2768
2875
|
}, [host, provider]);
|
|
2769
2876
|
}
|
|
2770
2877
|
function useEffectDescription(provider, effect) {
|
|
2771
|
-
const [state, setState] = (0,
|
|
2878
|
+
const [state, setState] = (0, import_react12.useState)({ key: "", description: null, error: null });
|
|
2772
2879
|
const key = provider && effect ? `${provider.id}:${effect}` : "";
|
|
2773
|
-
(0,
|
|
2880
|
+
(0, import_react12.useEffect)(() => {
|
|
2774
2881
|
if (!provider || !effect) return;
|
|
2775
2882
|
let live = true;
|
|
2776
2883
|
Promise.resolve().then(() => provider.describe(effect)).then(
|
|
@@ -2785,13 +2892,13 @@ function useEffectDescription(provider, effect) {
|
|
|
2785
2892
|
}
|
|
2786
2893
|
|
|
2787
2894
|
// src/effects/EffectThumbnail.tsx
|
|
2788
|
-
var
|
|
2895
|
+
var import_react13 = require("react");
|
|
2789
2896
|
var import_effects = require("@pixerate/editor/effects");
|
|
2790
|
-
var
|
|
2897
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2791
2898
|
function EffectThumbnail({ provider, effect, width = 96, height = 54, className = "" }) {
|
|
2792
|
-
const ref = (0,
|
|
2793
|
-
const [failed, setFailed] = (0,
|
|
2794
|
-
(0,
|
|
2899
|
+
const ref = (0, import_react13.useRef)(null);
|
|
2900
|
+
const [failed, setFailed] = (0, import_react13.useState)(effect.kind === "motion");
|
|
2901
|
+
(0, import_react13.useEffect)(() => {
|
|
2795
2902
|
if (effect.kind === "motion") return;
|
|
2796
2903
|
let live = true;
|
|
2797
2904
|
(0, import_effects.renderEffectThumbnail)(provider, effect, { width, height }).then(
|
|
@@ -2806,28 +2913,28 @@ function EffectThumbnail({ provider, effect, width = 96, height = 54, className
|
|
|
2806
2913
|
live = false;
|
|
2807
2914
|
};
|
|
2808
2915
|
}, [provider, effect, width, height]);
|
|
2809
|
-
return /* @__PURE__ */ (0,
|
|
2916
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2810
2917
|
"div",
|
|
2811
2918
|
{
|
|
2812
2919
|
className: `relative overflow-hidden rounded border border-border bg-[repeating-conic-gradient(#8884_0_25%,transparent_0_50%)] bg-[length:12px_12px] ${className}`,
|
|
2813
2920
|
style: { aspectRatio: `${width} / ${height}` },
|
|
2814
2921
|
"data-effect-thumbnail": effect.id,
|
|
2815
|
-
children: failed ? /* @__PURE__ */ (0,
|
|
2922
|
+
children: failed ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "absolute inset-0 flex items-center justify-center text-[10px] text-muted-foreground", children: effect.kind === "motion" ? "Motion" : "No preview" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("canvas", { ref, width, height, className: "h-full w-full", "aria-hidden": "true" })
|
|
2816
2923
|
}
|
|
2817
2924
|
);
|
|
2818
2925
|
}
|
|
2819
2926
|
|
|
2820
2927
|
// src/effects/EffectsBrowser.tsx
|
|
2821
|
-
var
|
|
2928
|
+
var import_react14 = require("react");
|
|
2822
2929
|
var import_effects2 = require("@pixerate/editor/effects");
|
|
2823
|
-
var
|
|
2930
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2824
2931
|
function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, title = "Effects", className = "" }) {
|
|
2825
|
-
const [all, setAll] = (0,
|
|
2826
|
-
const [query, setQuery] = (0,
|
|
2827
|
-
const [category, setCategory] = (0,
|
|
2828
|
-
const [use, setUse] = (0,
|
|
2829
|
-
const [error, setError] = (0,
|
|
2830
|
-
(0,
|
|
2932
|
+
const [all, setAll] = (0, import_react14.useState)([]);
|
|
2933
|
+
const [query, setQuery] = (0, import_react14.useState)("");
|
|
2934
|
+
const [category, setCategory] = (0, import_react14.useState)("");
|
|
2935
|
+
const [use, setUse] = (0, import_react14.useState)("");
|
|
2936
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2937
|
+
(0, import_react14.useEffect)(() => {
|
|
2831
2938
|
if (!provider) return setAll([]);
|
|
2832
2939
|
let live = true;
|
|
2833
2940
|
Promise.resolve().then(() => provider.list()).then(
|
|
@@ -2838,8 +2945,8 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
|
|
|
2838
2945
|
live = false;
|
|
2839
2946
|
};
|
|
2840
2947
|
}, [provider]);
|
|
2841
|
-
const [found, setFound] = (0,
|
|
2842
|
-
(0,
|
|
2948
|
+
const [found, setFound] = (0, import_react14.useState)([]);
|
|
2949
|
+
(0, import_react14.useEffect)(() => {
|
|
2843
2950
|
if (!provider) return setFound([]);
|
|
2844
2951
|
let live = true;
|
|
2845
2952
|
Promise.resolve().then(() => provider.search(query, { ...category ? { category } : {}, ...use ? { use } : {} })).then((list) => live && setFound(list), () => live && setFound([]));
|
|
@@ -2848,14 +2955,14 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
|
|
|
2848
2955
|
};
|
|
2849
2956
|
}, [provider, query, category, use]);
|
|
2850
2957
|
const allowed = (e) => (!kinds || kinds.includes(e.kind)) && (uses ? e.kind !== "motion" || uses.includes("motion") : e.kind !== "motion") && (!uses || e.uses.some((u) => uses.includes(u)));
|
|
2851
|
-
const categories = (0,
|
|
2958
|
+
const categories = (0, import_react14.useMemo)(() => [...new Set(all.filter(allowed).map((e) => e.category))], [all, uses, kinds]);
|
|
2852
2959
|
const shown = found.filter(allowed);
|
|
2853
2960
|
if (!provider)
|
|
2854
|
-
return /* @__PURE__ */ (0,
|
|
2855
|
-
return /* @__PURE__ */ (0,
|
|
2856
|
-
title && /* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
/* @__PURE__ */ (0,
|
|
2961
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: `rounded-md border border-dashed border-border p-3 text-xs text-muted-foreground ${className}`, "data-effects-browser": "", "data-effects-unavailable": "", children: "No effects provider is registered, so effects cannot be added. Effects already in the document are kept." });
|
|
2962
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { className: `flex flex-col gap-2 ${className}`, "data-effects-browser": "", "aria-label": "Effects browser", children: [
|
|
2963
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "text-xs font-semibold", children: title }),
|
|
2964
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
|
|
2965
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2859
2966
|
"input",
|
|
2860
2967
|
{
|
|
2861
2968
|
type: "search",
|
|
@@ -2866,17 +2973,17 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
|
|
|
2866
2973
|
onChange: (e) => setQuery(e.currentTarget.value)
|
|
2867
2974
|
}
|
|
2868
2975
|
),
|
|
2869
|
-
/* @__PURE__ */ (0,
|
|
2870
|
-
/* @__PURE__ */ (0,
|
|
2871
|
-
categories.map((c) => /* @__PURE__ */ (0,
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Category", value: category, onChange: (e) => setCategory(e.currentTarget.value), children: [
|
|
2977
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", children: "All categories" }),
|
|
2978
|
+
categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: c, children: c }, c))
|
|
2872
2979
|
] }),
|
|
2873
|
-
uses && uses.length > 1 && /* @__PURE__ */ (0,
|
|
2874
|
-
/* @__PURE__ */ (0,
|
|
2875
|
-
uses.map((u) => /* @__PURE__ */ (0,
|
|
2980
|
+
uses && uses.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("select", { className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs", "aria-label": "Use", value: use, onChange: (e) => setUse(e.currentTarget.value), children: [
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", children: "Any use" }),
|
|
2982
|
+
uses.map((u) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: u, children: import_effects2.EFFECT_USE_LABELS[u] }, u))
|
|
2876
2983
|
] })
|
|
2877
2984
|
] }),
|
|
2878
|
-
error && /* @__PURE__ */ (0,
|
|
2879
|
-
/* @__PURE__ */ (0,
|
|
2985
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: error }),
|
|
2986
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "grid max-h-96 grid-cols-[repeat(auto-fill,minmax(6.5rem,1fr))] gap-1.5 overflow-y-auto", role: "list", children: shown.map((e) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
2880
2987
|
"button",
|
|
2881
2988
|
{
|
|
2882
2989
|
type: "button",
|
|
@@ -2885,25 +2992,25 @@ function EffectsBrowser({ provider, uses, kinds, onPick, thumbnails = true, titl
|
|
|
2885
2992
|
"data-effect-id": e.id,
|
|
2886
2993
|
onClick: () => onPick(e),
|
|
2887
2994
|
children: [
|
|
2888
|
-
thumbnails && /* @__PURE__ */ (0,
|
|
2889
|
-
/* @__PURE__ */ (0,
|
|
2890
|
-
/* @__PURE__ */ (0,
|
|
2995
|
+
thumbnails && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EffectThumbnail, { provider, effect: e }),
|
|
2996
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-[11px] font-medium", children: e.name }),
|
|
2997
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-[10px] text-muted-foreground", children: e.uses.map((u) => import_effects2.EFFECT_USE_LABELS[u]).join(" \xB7 ") })
|
|
2891
2998
|
]
|
|
2892
2999
|
}
|
|
2893
3000
|
) }, e.id)) }),
|
|
2894
|
-
!shown.length && !error && /* @__PURE__ */ (0,
|
|
3001
|
+
!shown.length && !error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects match." })
|
|
2895
3002
|
] });
|
|
2896
3003
|
}
|
|
2897
3004
|
|
|
2898
3005
|
// src/effects/EffectParameters.tsx
|
|
2899
|
-
var
|
|
3006
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
2900
3007
|
var import_effects3 = require("@pixerate/editor/effects");
|
|
2901
3008
|
var import_parameters2 = require("@pixerate/editor/parameters");
|
|
2902
3009
|
|
|
2903
3010
|
// src/parameters/fields.tsx
|
|
2904
|
-
var
|
|
3011
|
+
var import_react15 = require("react");
|
|
2905
3012
|
var import_parameters = require("@pixerate/editor/parameters");
|
|
2906
|
-
var
|
|
3013
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2907
3014
|
var parameterInputClass = "h-7 w-full min-w-0 rounded-md border border-input bg-background px-2 text-xs text-foreground tabular-nums focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
2908
3015
|
var parameterButtonClass = "inline-flex h-7 items-center justify-center gap-1 rounded-md border border-input bg-background px-2 text-xs text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50";
|
|
2909
3016
|
var rangeClass = "h-4 w-full min-w-0 flex-1 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
@@ -2927,7 +3034,7 @@ function ParameterCommitInput({ value, onCommit, multiline, className, onKeyDown
|
|
|
2927
3034
|
onKeyDown: keyDown,
|
|
2928
3035
|
...rest
|
|
2929
3036
|
};
|
|
2930
|
-
return multiline ? /* @__PURE__ */ (0,
|
|
3037
|
+
return multiline ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "text", ...props }, value);
|
|
2931
3038
|
}
|
|
2932
3039
|
var plainNumber = (field, value) => (0, import_parameters.formatParameterNumber)({ ...field, unit: void 0 }, value);
|
|
2933
3040
|
function ParameterNumberInput({
|
|
@@ -2938,8 +3045,8 @@ function ParameterNumberInput({
|
|
|
2938
3045
|
id,
|
|
2939
3046
|
"aria-label": ariaLabel
|
|
2940
3047
|
}) {
|
|
2941
|
-
return /* @__PURE__ */ (0,
|
|
2942
|
-
/* @__PURE__ */ (0,
|
|
3048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2943
3050
|
ParameterCommitInput,
|
|
2944
3051
|
{
|
|
2945
3052
|
id,
|
|
@@ -2961,21 +3068,21 @@ function ParameterNumberInput({
|
|
|
2961
3068
|
}
|
|
2962
3069
|
}
|
|
2963
3070
|
),
|
|
2964
|
-
field.unit && /* @__PURE__ */ (0,
|
|
3071
|
+
field.unit && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
|
|
2965
3072
|
] });
|
|
2966
3073
|
}
|
|
2967
3074
|
function ParameterSlider(props) {
|
|
2968
3075
|
const { field, value, onChange, onGestureStart, onGestureEnd, disabled } = props;
|
|
2969
|
-
const dragging = (0,
|
|
3076
|
+
const dragging = (0, import_react15.useRef)(false);
|
|
2970
3077
|
const end = () => {
|
|
2971
3078
|
if (!dragging.current) return;
|
|
2972
3079
|
dragging.current = false;
|
|
2973
3080
|
onGestureEnd?.();
|
|
2974
3081
|
};
|
|
2975
|
-
if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0,
|
|
3082
|
+
if (!(0, import_parameters.isSliderField)(field)) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterNumberInput, { ...props });
|
|
2976
3083
|
const step = (0, import_parameters.parameterStep)(field);
|
|
2977
|
-
return /* @__PURE__ */ (0,
|
|
2978
|
-
/* @__PURE__ */ (0,
|
|
3084
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3085
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2979
3086
|
"input",
|
|
2980
3087
|
{
|
|
2981
3088
|
type: "range",
|
|
@@ -2998,11 +3105,11 @@ function ParameterSlider(props) {
|
|
|
2998
3105
|
onChange: (e) => onChange((0, import_parameters.clampParameterNumber)(field, Number(e.target.value)))
|
|
2999
3106
|
}
|
|
3000
3107
|
),
|
|
3001
|
-
/* @__PURE__ */ (0,
|
|
3108
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${(0, import_parameters.parameterLabel)(field)} value` }) })
|
|
3002
3109
|
] });
|
|
3003
3110
|
}
|
|
3004
3111
|
function ParameterToggle({ field, value, onChange, disabled, id }) {
|
|
3005
|
-
return /* @__PURE__ */ (0,
|
|
3112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3006
3113
|
"button",
|
|
3007
3114
|
{
|
|
3008
3115
|
type: "button",
|
|
@@ -3013,7 +3120,7 @@ function ParameterToggle({ field, value, onChange, disabled, id }) {
|
|
|
3013
3120
|
disabled: disabled || field.readOnly,
|
|
3014
3121
|
onClick: () => onChange(!value),
|
|
3015
3122
|
className: `relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:opacity-50 ${value ? "bg-primary" : "bg-muted"}`,
|
|
3016
|
-
children: /* @__PURE__ */ (0,
|
|
3123
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3017
3124
|
"span",
|
|
3018
3125
|
{
|
|
3019
3126
|
className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow transition-transform ${value ? "translate-x-4" : "translate-x-0.5"}`
|
|
@@ -3026,7 +3133,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
|
|
|
3026
3133
|
const options = (0, import_parameters.getChoiceOptions)(field);
|
|
3027
3134
|
const off = disabled || field.readOnly;
|
|
3028
3135
|
if (field.control === "segmented") {
|
|
3029
|
-
return /* @__PURE__ */ (0,
|
|
3136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "radiogroup", "aria-label": (0, import_parameters.parameterLabel)(field), className: "inline-flex flex-wrap rounded-md border border-input bg-muted p-0.5", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3030
3137
|
"button",
|
|
3031
3138
|
{
|
|
3032
3139
|
type: "button",
|
|
@@ -3042,7 +3149,7 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
|
|
|
3042
3149
|
)) });
|
|
3043
3150
|
}
|
|
3044
3151
|
const index = options.findIndex((o) => o.value === value);
|
|
3045
|
-
return /* @__PURE__ */ (0,
|
|
3152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3046
3153
|
"select",
|
|
3047
3154
|
{
|
|
3048
3155
|
id,
|
|
@@ -3054,12 +3161,12 @@ function ParameterSelect({ field, value, onChange, disabled, id }) {
|
|
|
3054
3161
|
if (option) onChange(option.value);
|
|
3055
3162
|
},
|
|
3056
3163
|
className: parameterInputClass,
|
|
3057
|
-
children: options.map((o, i) => /* @__PURE__ */ (0,
|
|
3164
|
+
children: options.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: String(i), title: o.description, children: (0, import_parameters.choiceOptionLabel)(o) }, String(o.value)))
|
|
3058
3165
|
}
|
|
3059
3166
|
);
|
|
3060
3167
|
}
|
|
3061
3168
|
function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd, disabled, id }) {
|
|
3062
|
-
const picking = (0,
|
|
3169
|
+
const picking = (0, import_react15.useRef)(false);
|
|
3063
3170
|
const alpha = !!field.alpha;
|
|
3064
3171
|
const hex = (0, import_parameters.normalizeHexColor)(value, true) ?? "#000000ff";
|
|
3065
3172
|
const rgb = hex.slice(0, 7);
|
|
@@ -3075,11 +3182,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
|
|
|
3075
3182
|
picking.current = false;
|
|
3076
3183
|
onGestureEnd?.();
|
|
3077
3184
|
};
|
|
3078
|
-
return /* @__PURE__ */ (0,
|
|
3079
|
-
/* @__PURE__ */ (0,
|
|
3080
|
-
/* @__PURE__ */ (0,
|
|
3081
|
-
/* @__PURE__ */ (0,
|
|
3082
|
-
/* @__PURE__ */ (0,
|
|
3185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1.5", children: [
|
|
3186
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3187
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "relative h-7 w-9 shrink-0 overflow-hidden rounded-md border border-input bg-[repeating-conic-gradient(#d4d4d8_0_25%,#fff_0_50%)] bg-[length:8px_8px]", children: [
|
|
3188
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
|
|
3189
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3083
3190
|
"input",
|
|
3084
3191
|
{
|
|
3085
3192
|
type: "color",
|
|
@@ -3095,7 +3202,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
|
|
|
3095
3202
|
}
|
|
3096
3203
|
)
|
|
3097
3204
|
] }),
|
|
3098
|
-
/* @__PURE__ */ (0,
|
|
3205
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3099
3206
|
ParameterCommitInput,
|
|
3100
3207
|
{
|
|
3101
3208
|
id,
|
|
@@ -3111,7 +3218,7 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
|
|
|
3111
3218
|
}
|
|
3112
3219
|
)
|
|
3113
3220
|
] }),
|
|
3114
|
-
alpha && /* @__PURE__ */ (0,
|
|
3221
|
+
alpha && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3115
3222
|
"input",
|
|
3116
3223
|
{
|
|
3117
3224
|
type: "range",
|
|
@@ -3129,10 +3236,10 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
|
|
|
3129
3236
|
onChange: (e) => onChange(`${rgb}${Number(e.target.value).toString(16).padStart(2, "0")}`)
|
|
3130
3237
|
}
|
|
3131
3238
|
),
|
|
3132
|
-
field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0,
|
|
3239
|
+
field.swatches && field.swatches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
|
|
3133
3240
|
const swatch = (0, import_parameters.normalizeHexColor)(s, alpha);
|
|
3134
3241
|
if (!swatch) return null;
|
|
3135
|
-
return /* @__PURE__ */ (0,
|
|
3242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3136
3243
|
"button",
|
|
3137
3244
|
{
|
|
3138
3245
|
type: "button",
|
|
@@ -3151,11 +3258,11 @@ function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd,
|
|
|
3151
3258
|
}
|
|
3152
3259
|
function ParameterVector({ field, value, onChange, disabled, id }) {
|
|
3153
3260
|
const size = (0, import_parameters.vectorSize)(field);
|
|
3154
|
-
return /* @__PURE__ */ (0,
|
|
3261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
|
|
3155
3262
|
const component = (0, import_parameters.vectorComponentField)(field, i);
|
|
3156
|
-
return /* @__PURE__ */ (0,
|
|
3157
|
-
/* @__PURE__ */ (0,
|
|
3158
|
-
/* @__PURE__ */ (0,
|
|
3263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex min-w-0 items-center gap-1", children: [
|
|
3264
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
|
|
3265
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3159
3266
|
ParameterNumberInput,
|
|
3160
3267
|
{
|
|
3161
3268
|
field: component,
|
|
@@ -3172,11 +3279,11 @@ function ParameterVector({ field, value, onChange, disabled, id }) {
|
|
|
3172
3279
|
function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
3173
3280
|
const off = disabled || field.readOnly;
|
|
3174
3281
|
const name = (0, import_parameters.parameterLabel)(field);
|
|
3175
|
-
return /* @__PURE__ */ (0,
|
|
3176
|
-
/* @__PURE__ */ (0,
|
|
3177
|
-
/* @__PURE__ */ (0,
|
|
3178
|
-
/* @__PURE__ */ (0,
|
|
3179
|
-
/* @__PURE__ */ (0,
|
|
3282
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "space-y-1.5", children: [
|
|
3283
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3284
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-md border border-input bg-muted", children: value ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
|
|
3285
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
3286
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3180
3287
|
ParameterCommitInput,
|
|
3181
3288
|
{
|
|
3182
3289
|
id,
|
|
@@ -3187,10 +3294,10 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
|
3187
3294
|
onCommit: (text) => onChange(text.trim())
|
|
3188
3295
|
}
|
|
3189
3296
|
),
|
|
3190
|
-
/* @__PURE__ */ (0,
|
|
3191
|
-
resolveFile && /* @__PURE__ */ (0,
|
|
3297
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex gap-1", children: [
|
|
3298
|
+
resolveFile && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
|
|
3192
3299
|
"Choose file\u2026",
|
|
3193
|
-
/* @__PURE__ */ (0,
|
|
3300
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3194
3301
|
"input",
|
|
3195
3302
|
{
|
|
3196
3303
|
type: "file",
|
|
@@ -3206,11 +3313,11 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
|
3206
3313
|
}
|
|
3207
3314
|
)
|
|
3208
3315
|
] }),
|
|
3209
|
-
value && /* @__PURE__ */ (0,
|
|
3316
|
+
value && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
|
|
3210
3317
|
] })
|
|
3211
3318
|
] })
|
|
3212
3319
|
] }),
|
|
3213
|
-
field.options && field.options.length > 0 && /* @__PURE__ */ (0,
|
|
3320
|
+
field.options && field.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3214
3321
|
"button",
|
|
3215
3322
|
{
|
|
3216
3323
|
type: "button",
|
|
@@ -3220,14 +3327,14 @@ function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
|
3220
3327
|
disabled: off,
|
|
3221
3328
|
onClick: () => onChange(o.url),
|
|
3222
3329
|
className: "h-9 w-12 overflow-hidden rounded border border-input aria-pressed:ring-2 aria-pressed:ring-primary",
|
|
3223
|
-
children: /* @__PURE__ */ (0,
|
|
3330
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
|
|
3224
3331
|
},
|
|
3225
3332
|
o.url
|
|
3226
3333
|
)) })
|
|
3227
3334
|
] });
|
|
3228
3335
|
}
|
|
3229
3336
|
function ParameterText({ field, value, onChange, disabled, id }) {
|
|
3230
|
-
return /* @__PURE__ */ (0,
|
|
3337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3231
3338
|
ParameterCommitInput,
|
|
3232
3339
|
{
|
|
3233
3340
|
id,
|
|
@@ -3246,31 +3353,31 @@ function ParameterFieldControl({ field, value, onChange, resolveFile, ...rest })
|
|
|
3246
3353
|
switch (field.type) {
|
|
3247
3354
|
case "number":
|
|
3248
3355
|
case "int":
|
|
3249
|
-
return /* @__PURE__ */ (0,
|
|
3356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterSlider, { field, value, onChange: set, ...rest });
|
|
3250
3357
|
case "boolean":
|
|
3251
|
-
return /* @__PURE__ */ (0,
|
|
3358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterToggle, { field, value, onChange: set, ...rest });
|
|
3252
3359
|
case "choice":
|
|
3253
|
-
return /* @__PURE__ */ (0,
|
|
3360
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterSelect, { field, value, onChange: set, ...rest });
|
|
3254
3361
|
case "color":
|
|
3255
|
-
return /* @__PURE__ */ (0,
|
|
3362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterColor, { field, value, onChange: set, ...rest });
|
|
3256
3363
|
case "vector":
|
|
3257
|
-
return /* @__PURE__ */ (0,
|
|
3364
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterVector, { field, value, onChange: set, ...rest });
|
|
3258
3365
|
case "image":
|
|
3259
|
-
return /* @__PURE__ */ (0,
|
|
3366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
|
|
3260
3367
|
case "text":
|
|
3261
|
-
return /* @__PURE__ */ (0,
|
|
3368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ParameterText, { field, value, onChange: set, ...rest });
|
|
3262
3369
|
}
|
|
3263
3370
|
}
|
|
3264
3371
|
|
|
3265
3372
|
// src/effects/EffectParameters.tsx
|
|
3266
|
-
var
|
|
3373
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3267
3374
|
function EffectParameters({ description, values, onChange, onReset, keyframed, onPreset, disabled = false, className = "" }) {
|
|
3268
|
-
const fields = (0,
|
|
3269
|
-
const idBase = (0,
|
|
3270
|
-
const gesture =
|
|
3271
|
-
const count =
|
|
3272
|
-
return /* @__PURE__ */ (0,
|
|
3273
|
-
onPreset && description.presets.length > 0 && /* @__PURE__ */ (0,
|
|
3375
|
+
const fields = (0, import_react16.useMemo)(() => (0, import_effects3.effectParameterFields)(description), [description]);
|
|
3376
|
+
const idBase = (0, import_react16.useId)();
|
|
3377
|
+
const gesture = import_react16.default.useRef(null);
|
|
3378
|
+
const count = import_react16.default.useRef(0);
|
|
3379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `space-y-2 ${className}`, "data-effect-parameters": description.id, children: [
|
|
3380
|
+
onPreset && description.presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3274
3381
|
"select",
|
|
3275
3382
|
{
|
|
3276
3383
|
className: "w-full rounded border border-border bg-transparent px-1 py-0.5 text-xs",
|
|
@@ -3282,8 +3389,8 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
|
|
|
3282
3389
|
if (preset) onPreset({ ...description.defaults, ...preset.values });
|
|
3283
3390
|
},
|
|
3284
3391
|
children: [
|
|
3285
|
-
/* @__PURE__ */ (0,
|
|
3286
|
-
description.presets.map((p) => /* @__PURE__ */ (0,
|
|
3392
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", children: "Presets\u2026" }),
|
|
3393
|
+
description.presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: p.name, children: p.name }, p.name))
|
|
3287
3394
|
]
|
|
3288
3395
|
}
|
|
3289
3396
|
),
|
|
@@ -3293,13 +3400,13 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
|
|
|
3293
3400
|
const keyed = keyframed?.has(field.id) ?? false;
|
|
3294
3401
|
const value = (0, import_effects3.effectFieldValue)(field, values[field.id]);
|
|
3295
3402
|
const changed = !keyed && !(0, import_parameters2.parameterValuesEqual)(value, field.default);
|
|
3296
|
-
return /* @__PURE__ */ (0,
|
|
3297
|
-
/* @__PURE__ */ (0,
|
|
3298
|
-
/* @__PURE__ */ (0,
|
|
3299
|
-
keyed && /* @__PURE__ */ (0,
|
|
3300
|
-
onReset && changed && !disabled && /* @__PURE__ */ (0,
|
|
3403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "space-y-1", "data-effect-control": field.id, children: [
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
3405
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium", title: field.description, children: label }),
|
|
3406
|
+
keyed && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-[10px] text-muted-foreground", children: "keyframed" }),
|
|
3407
|
+
onReset && changed && !disabled && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: "rounded px-1 text-[11px] text-muted-foreground hover:text-foreground", "aria-label": `Reset ${label}`, onClick: () => onReset(field.id), children: "\u21BA" })
|
|
3301
3408
|
] }),
|
|
3302
|
-
/* @__PURE__ */ (0,
|
|
3409
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3303
3410
|
ParameterFieldControl,
|
|
3304
3411
|
{
|
|
3305
3412
|
field,
|
|
@@ -3313,25 +3420,25 @@ function EffectParameters({ description, values, onChange, onReset, keyframed, o
|
|
|
3313
3420
|
)
|
|
3314
3421
|
] }, field.id);
|
|
3315
3422
|
}),
|
|
3316
|
-
!fields.length && /* @__PURE__ */ (0,
|
|
3423
|
+
!fields.length && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No controls." })
|
|
3317
3424
|
] });
|
|
3318
3425
|
}
|
|
3319
3426
|
|
|
3320
3427
|
// src/vector/VectorProviderEffectsPanel.tsx
|
|
3321
|
-
var
|
|
3322
|
-
var
|
|
3428
|
+
var import_react17 = require("react");
|
|
3429
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3323
3430
|
var btn = "rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40";
|
|
3324
3431
|
function Controls({ controller, group }) {
|
|
3325
3432
|
const provider = controller.effectsProvider;
|
|
3326
3433
|
const tag = group.providerEffect;
|
|
3327
3434
|
const { description, error } = useEffectDescription(provider, tag.effect);
|
|
3328
|
-
const [message, setMessage] = (0,
|
|
3435
|
+
const [message, setMessage] = (0, import_react17.useState)(null);
|
|
3329
3436
|
const run = (work) => void work.then(() => setMessage(null), (e) => setMessage(e instanceof Error ? e.message : String(e)));
|
|
3330
|
-
if (!provider) return /* @__PURE__ */ (0,
|
|
3331
|
-
if (error) return /* @__PURE__ */ (0,
|
|
3332
|
-
if (!description) return /* @__PURE__ */ (0,
|
|
3333
|
-
return /* @__PURE__ */ (0,
|
|
3334
|
-
/* @__PURE__ */ (0,
|
|
3437
|
+
if (!provider) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider: the shapes are kept as they are." });
|
|
3438
|
+
if (error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-amber-500", children: error });
|
|
3439
|
+
if (!description) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
|
|
3440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
3441
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3335
3442
|
EffectParameters,
|
|
3336
3443
|
{
|
|
3337
3444
|
description,
|
|
@@ -3341,18 +3448,18 @@ function Controls({ controller, group }) {
|
|
|
3341
3448
|
onPreset: (v) => run(controller.updateVectorEffect(group.id, v))
|
|
3342
3449
|
}
|
|
3343
3450
|
),
|
|
3344
|
-
message && /* @__PURE__ */ (0,
|
|
3451
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
|
|
3345
3452
|
] });
|
|
3346
3453
|
}
|
|
3347
3454
|
function VectorProviderEffectsPanel({ controller, className = "" }) {
|
|
3348
3455
|
const state = useVectorEditorState(controller);
|
|
3349
|
-
const provider = (0,
|
|
3456
|
+
const provider = (0, import_react17.useSyncExternalStore)(
|
|
3350
3457
|
(cb) => controller.effects.subscribe(cb),
|
|
3351
3458
|
() => controller.effects.provider,
|
|
3352
3459
|
() => controller.effects.provider
|
|
3353
3460
|
);
|
|
3354
|
-
const [browse, setBrowse] = (0,
|
|
3355
|
-
const [message, setMessage] = (0,
|
|
3461
|
+
const [browse, setBrowse] = (0, import_react17.useState)(false);
|
|
3462
|
+
const [message, setMessage] = (0, import_react17.useState)(null);
|
|
3356
3463
|
void state;
|
|
3357
3464
|
const groups = controller.vectorEffectGroups();
|
|
3358
3465
|
const selected = groups.filter((g) => state.selection.includes(g.id));
|
|
@@ -3360,41 +3467,41 @@ function VectorProviderEffectsPanel({ controller, className = "" }) {
|
|
|
3360
3467
|
setMessage(null);
|
|
3361
3468
|
Promise.resolve().then(work).catch((e) => setMessage(e instanceof Error ? e.message : String(e)));
|
|
3362
3469
|
};
|
|
3363
|
-
return /* @__PURE__ */ (0,
|
|
3364
|
-
/* @__PURE__ */ (0,
|
|
3365
|
-
/* @__PURE__ */ (0,
|
|
3366
|
-
/* @__PURE__ */ (0,
|
|
3470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Vector effects", "data-vector-provider-effects": "", children: [
|
|
3471
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3472
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "flex-1 font-semibold", children: "Effects" }),
|
|
3473
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn, disabled: !provider, "aria-pressed": browse, onClick: () => setBrowse(!browse), children: "Add effect\u2026" })
|
|
3367
3474
|
] }),
|
|
3368
|
-
!provider && /* @__PURE__ */ (0,
|
|
3369
|
-
browse && /* @__PURE__ */ (0,
|
|
3370
|
-
selected.map((g) => /* @__PURE__ */ (0,
|
|
3371
|
-
/* @__PURE__ */ (0,
|
|
3372
|
-
/* @__PURE__ */ (0,
|
|
3373
|
-
/* @__PURE__ */ (0,
|
|
3475
|
+
!provider && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effect groups are kept as shapes." }),
|
|
3476
|
+
browse && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EffectsBrowser, { provider, kinds: ["vector"], title: "Vector effects", onPick: (e) => (setBrowse(false), run(() => controller.addVectorEffect(e.id))) }),
|
|
3477
|
+
selected.map((g) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-effect-group": g.id, children: [
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3479
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: g.providerEffect.name ?? g.providerEffect.effect }),
|
|
3480
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn, title: "Keep the shapes as a plain group", onClick: () => run(() => controller.detachVectorEffect(g.id)), children: "Detach" })
|
|
3374
3481
|
] }),
|
|
3375
|
-
/* @__PURE__ */ (0,
|
|
3482
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Controls, { controller, group: g })
|
|
3376
3483
|
] }, g.id)),
|
|
3377
|
-
groups.length > 0 && !selected.length && /* @__PURE__ */ (0,
|
|
3484
|
+
groups.length > 0 && !selected.length && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
|
|
3378
3485
|
"Select an effect group (",
|
|
3379
3486
|
groups.length,
|
|
3380
3487
|
" in the drawing) to change it."
|
|
3381
3488
|
] }),
|
|
3382
|
-
message && /* @__PURE__ */ (0,
|
|
3489
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
|
|
3383
3490
|
] });
|
|
3384
3491
|
}
|
|
3385
3492
|
|
|
3386
3493
|
// src/vector/VectorEditor.tsx
|
|
3387
|
-
var
|
|
3494
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3388
3495
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, effects, className }) {
|
|
3389
3496
|
useEffects(controller, effects);
|
|
3390
3497
|
const effectsShown = !!effects || controller.vectorEffectGroups().length > 0;
|
|
3391
|
-
return /* @__PURE__ */ (0,
|
|
3392
|
-
/* @__PURE__ */ (0,
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
/* @__PURE__ */ (0,
|
|
3395
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
3396
|
-
/* @__PURE__ */ (0,
|
|
3397
|
-
effectsShown && /* @__PURE__ */ (0,
|
|
3498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
3499
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorToolbar, { controller, tools }),
|
|
3500
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
3501
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
3502
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex w-full shrink-0 flex-col gap-2 md:w-56", children: [
|
|
3503
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorStylePanel, { controller, className: "rounded-md border border-border p-3" }),
|
|
3504
|
+
effectsShown && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(VectorProviderEffectsPanel, { controller, className: "rounded-md border border-border p-3" })
|
|
3398
3505
|
] })
|
|
3399
3506
|
] })
|
|
3400
3507
|
] });
|
|
@@ -3413,8 +3520,10 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
3413
3520
|
VectorGradientAnnotator,
|
|
3414
3521
|
VectorGradientDefs,
|
|
3415
3522
|
VectorGradientEditor,
|
|
3523
|
+
VectorLensPanel,
|
|
3416
3524
|
VectorMaskPanel,
|
|
3417
3525
|
VectorMaskedNodes,
|
|
3526
|
+
VectorPerspectivePanel,
|
|
3418
3527
|
VectorProviderEffectsPanel,
|
|
3419
3528
|
VectorSceneNodes,
|
|
3420
3529
|
VectorShadingPanel,
|