@pixerate/editor-react 0.86.0 → 0.88.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 +163 -49
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +25 -4
- package/dist/vector/index.d.ts +25 -4
- package/dist/vector/index.js +122 -7
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __export(vector_exports, {
|
|
|
39
39
|
VectorEnvelopePanel: () => VectorEnvelopePanel,
|
|
40
40
|
VectorFilterDefs: () => VectorFilterDefs,
|
|
41
41
|
VectorFramePanel: () => VectorFramePanel,
|
|
42
|
+
VectorGeneratePanel: () => VectorGeneratePanel,
|
|
42
43
|
VectorGradientAnnotator: () => VectorGradientAnnotator,
|
|
43
44
|
VectorGradientDefs: () => VectorGradientDefs,
|
|
44
45
|
VectorGradientEditor: () => VectorGradientEditor,
|
|
@@ -62,7 +63,8 @@ __export(vector_exports, {
|
|
|
62
63
|
useVectorEditor: () => useVectorEditor,
|
|
63
64
|
useVectorEditorController: () => useVectorEditorController,
|
|
64
65
|
useVectorEditorState: () => useVectorEditorState,
|
|
65
|
-
useVectorEffectsTools: () => useVectorEffectsTools
|
|
66
|
+
useVectorEffectsTools: () => useVectorEffectsTools,
|
|
67
|
+
useVectorGenerationTools: () => useVectorGenerationTools
|
|
66
68
|
});
|
|
67
69
|
module.exports = __toCommonJS(vector_exports);
|
|
68
70
|
|
|
@@ -114,6 +116,30 @@ function useVectorEffectsTools(registry, controller, options = {}) {
|
|
|
114
116
|
return registry.register((0, import_vector.createVectorEffectsToolProvider)(controller, { id, namespace, readOnly }));
|
|
115
117
|
}, [registry, controller, id, namespace, readOnly]);
|
|
116
118
|
}
|
|
119
|
+
function useVectorGenerationTools(registry, controller, options) {
|
|
120
|
+
const latest = (0, import_react.useRef)(options);
|
|
121
|
+
latest.current = options;
|
|
122
|
+
const { id, namespace } = options;
|
|
123
|
+
(0, import_react.useEffect)(() => {
|
|
124
|
+
if (!registry) return;
|
|
125
|
+
const models = () => {
|
|
126
|
+
const m = latest.current.models;
|
|
127
|
+
return typeof m === "function" ? m() : m;
|
|
128
|
+
};
|
|
129
|
+
return registry.register(
|
|
130
|
+
(0, import_vector.createVectorGenerationToolProvider)(controller, {
|
|
131
|
+
id,
|
|
132
|
+
namespace,
|
|
133
|
+
models,
|
|
134
|
+
generate: (request, context) => latest.current.generate(request, context),
|
|
135
|
+
readOnly: () => {
|
|
136
|
+
const r = latest.current.readOnly;
|
|
137
|
+
return (typeof r === "function" ? r() : r) ?? false;
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
);
|
|
141
|
+
}, [registry, controller, id, namespace]);
|
|
142
|
+
}
|
|
117
143
|
|
|
118
144
|
// src/vector/VectorCanvas.tsx
|
|
119
145
|
var import_react3 = __toESM(require("react"), 1);
|
|
@@ -299,7 +325,12 @@ var VectorSceneNode = import_react3.default.memo(function VectorSceneNode2({ nod
|
|
|
299
325
|
if (node.layers)
|
|
300
326
|
return (
|
|
301
327
|
// Fill and stroke stacks: each layer in order, bottom to top.
|
|
302
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-id": node.id, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, filter: node.filter, style: blendStyle(node.blendMode), children: node.layers.map(
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-id": node.id, transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, filter: node.filter, style: blendStyle(node.blendMode), children: node.layers.map(
|
|
329
|
+
(layer) => layer.kind === "brushstroke" ? (
|
|
330
|
+
// A brushstroke: its rendered brush images over their boxes.
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-layer": `brushstroke-${layer.index}`, opacity: layer.opacity < 1 ? layer.opacity : void 0, style: blendStyle(layer.blendMode), children: (layer.images ?? []).map((im, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("image", { href: im.href, x: im.x, y: im.y, width: im.width, height: im.height, preserveAspectRatio: "none" }, i)) }, `${layer.kind}-${layer.index}`)
|
|
332
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorPaintPath, { paint: layer, d: node.d, fillRule: node.fillRule, layer: `${layer.kind}-${layer.index}` }, `${layer.kind}-${layer.index}`)
|
|
333
|
+
) })
|
|
303
334
|
);
|
|
304
335
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorPaintPath, { paint: node, d: node.d, fillRule: node.fillRule, id: node.id, transform: node.transform, filter: node.filter, blendMode: node.blendMode });
|
|
305
336
|
});
|
|
@@ -658,6 +689,7 @@ function VectorCanvas({
|
|
|
658
689
|
overlay.builder.lines.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-line": "", d, fill: "none", stroke: import_vector3.VECTOR_OVERLAY_THEME.builderErase, strokeWidth: 3, strokeLinecap: "round" }, `l${i}`)),
|
|
659
690
|
overlay.builder.trail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-builder-trail": "", d: overlay.builder.trail, fill: "none", stroke: overlay.builder.mode === "erase" ? import_vector3.VECTOR_OVERLAY_THEME.builderErase : accentColor, strokeWidth: 1 })
|
|
660
691
|
] }),
|
|
692
|
+
overlay.brush && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-brush": "", cx: overlay.brush.x, cy: overlay.brush.y, r: overlay.brush.r, fill: "none", stroke: accentColor, strokeWidth: 1, strokeDasharray: "4 3", pointerEvents: "none" }),
|
|
661
693
|
overlay.toolStroke && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
662
694
|
"path",
|
|
663
695
|
{
|
|
@@ -838,7 +870,7 @@ function VectorCanvas({
|
|
|
838
870
|
|
|
839
871
|
// src/vector/VectorToolbar.tsx
|
|
840
872
|
var import_react11 = __toESM(require("react"), 1);
|
|
841
|
-
var
|
|
873
|
+
var import_vector20 = require("@pixerate/editor/vector");
|
|
842
874
|
|
|
843
875
|
// src/vector/VectorEffectsPanel.tsx
|
|
844
876
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -1006,6 +1038,30 @@ function VectorAppearancePanel({ controller, className }) {
|
|
|
1006
1038
|
const update = (l, patch, merge = false) => controller.updatePaintLayer(l.kind, l.index, patch, { ids, merge });
|
|
1007
1039
|
const layerRow = (l, count) => {
|
|
1008
1040
|
const name = `${l.kind === "fill" ? "Fill" : "Stroke"} ${l.index + 1}`;
|
|
1041
|
+
if (l.brushstroke)
|
|
1042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "space-y-1 rounded border border-border p-1", "data-vector-layer": `${l.kind}-${l.index}`, "data-vector-brushstroke": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1043
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", "aria-label": `${name} visible`, title: "Show", checked: l.visible, onChange: (e) => update(l, { visible: e.target.checked }) }),
|
|
1044
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "color", "aria-label": `${name} colour`, className: "h-7 w-10 cursor-pointer rounded border border-border bg-background", value: l.color ?? "#000000", onChange: (e) => controller.setBrushstroke(l.index, { color: e.target.value }, { ids, merge: true }), onBlur: end }),
|
|
1045
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": `${name} brush`, className: selectClass2, value: l.brushstroke.brushId, onChange: (e) => controller.setBrushstroke(l.index, { brushId: e.target.value }, { ids }), children: (0, import_vector5.vectorBrushstrokeBrushes)().map((b) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: b.id, children: b.name }, b.id)) }),
|
|
1046
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1047
|
+
"input",
|
|
1048
|
+
{
|
|
1049
|
+
type: "number",
|
|
1050
|
+
min: 0.5,
|
|
1051
|
+
step: 0.5,
|
|
1052
|
+
"aria-label": `${name} brush size`,
|
|
1053
|
+
title: "Brush size",
|
|
1054
|
+
className: numberClass2,
|
|
1055
|
+
value: l.brushstroke.size,
|
|
1056
|
+
onChange: (e) => {
|
|
1057
|
+
const n = parseFloat(e.target.value);
|
|
1058
|
+
if (Number.isFinite(n) && n > 0) controller.setBrushstroke(l.index, { size: Math.min(500, n) }, { ids, merge: true });
|
|
1059
|
+
},
|
|
1060
|
+
onBlur: end
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, title: "Remove", "aria-label": `Remove ${name}`, onClick: () => controller.removePaintLayer("stroke", l.index, { ids }), children: "\xD7" })
|
|
1064
|
+
] }) }, `${l.kind}-${l.index}`);
|
|
1009
1065
|
if (l.unknownKind)
|
|
1010
1066
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-[11px] text-muted-foreground", "data-vector-layer": `${l.kind}-${l.index}`, children: [
|
|
1011
1067
|
name,
|
|
@@ -1101,7 +1157,8 @@ function VectorAppearancePanel({ controller, className }) {
|
|
|
1101
1157
|
onClick: () => controller.addPaintLayer(kind, {}, { ids }),
|
|
1102
1158
|
children: "+"
|
|
1103
1159
|
}
|
|
1104
|
-
)
|
|
1160
|
+
),
|
|
1161
|
+
kind === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, title: "Add a brushstroke (a natural-media brush along the path)", "aria-label": "Add brushstroke", "data-vector-add-brushstroke": "", disabled: !ids.length, onClick: () => controller.addBrushstroke({ brushId: (0, import_vector5.vectorBrushstrokeBrushes)()[0].id }, { ids }), children: "\u270E+" })
|
|
1105
1162
|
] }),
|
|
1106
1163
|
[...layers].reverse().map((l) => layerRow(l, layers.length))
|
|
1107
1164
|
] });
|
|
@@ -2021,6 +2078,7 @@ function VectorShadingPanel({ controller, className }) {
|
|
|
2021
2078
|
|
|
2022
2079
|
// src/vector/VectorTracePanel.tsx
|
|
2023
2080
|
var import_react9 = require("react");
|
|
2081
|
+
var import_vector15 = require("@pixerate/editor/vector");
|
|
2024
2082
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2025
2083
|
var buttonClass12 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
2026
2084
|
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
@@ -2047,7 +2105,8 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2047
2105
|
const pixels = await filePixels(file);
|
|
2048
2106
|
const doc = controller.getState().document;
|
|
2049
2107
|
const width = Math.min(doc.width, pixels.width);
|
|
2050
|
-
const
|
|
2108
|
+
const name = file.name.replace(/\.[^.]+$/, "") || void 0;
|
|
2109
|
+
const r = mode === "threshold" || mode === "color" ? controller.traceImage(pixels, { mode, colors, width, name: name ?? "Image Trace" }) : controller.stylizeImage(pixels, mode, { width, ...name ? { name } : {} });
|
|
2051
2110
|
setMessage(r.ok ? null : r.message);
|
|
2052
2111
|
} catch {
|
|
2053
2112
|
setMessage("That file could not be read as an image.");
|
|
@@ -2058,7 +2117,8 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2058
2117
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Trace" }),
|
|
2059
2118
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("select", { "aria-label": "Trace mode", className: selectClass9, value: mode, onChange: (e) => setMode(e.target.value), children: [
|
|
2060
2119
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "threshold", children: "Black & white" }),
|
|
2061
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "color", children: "Colours" })
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "color", children: "Colours" }),
|
|
2121
|
+
import_vector15.VECTOR_STYLIZE_STYLES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: s, children: import_vector15.VECTOR_STYLIZE_LABELS[s] }, s))
|
|
2062
2122
|
] }),
|
|
2063
2123
|
mode === "color" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("input", { type: "number", min: 2, max: 32, "aria-label": "Trace colours", title: "Colours", className: numberClass7, value: colors, onChange: (e) => setColors(Math.max(2, Math.min(32, parseInt(e.target.value, 10) || 2))) }),
|
|
2064
2124
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: buttonClass12, "data-vector-trace-action": "", title: "Image Trace: pick an image to turn into paths", onClick: () => input.current?.click(), children: "Image\u2026" }),
|
|
@@ -2082,14 +2142,14 @@ function VectorTracePanel({ controller, className }) {
|
|
|
2082
2142
|
}
|
|
2083
2143
|
|
|
2084
2144
|
// src/vector/VectorSymmetryPanel.tsx
|
|
2085
|
-
var
|
|
2145
|
+
var import_vector16 = require("@pixerate/editor/vector");
|
|
2086
2146
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2087
2147
|
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";
|
|
2088
2148
|
var selectClass10 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2089
2149
|
var numberClass8 = "h-7 w-12 rounded border border-border bg-background px-1.5 text-xs";
|
|
2090
2150
|
function VectorSymmetryPanel({ controller, className }) {
|
|
2091
2151
|
const state = useVectorEditorState(controller);
|
|
2092
|
-
const group = state.selection.map((id) => controller.getNode(id)).find(
|
|
2152
|
+
const group = state.selection.map((id) => controller.getNode(id)).find(import_vector16.isVectorSymmetryGroup) ?? null;
|
|
2093
2153
|
const s = group?.symmetry;
|
|
2094
2154
|
const ids = group ? [group.id] : void 0;
|
|
2095
2155
|
const drawing = !!group && state.symmetryTarget === group.id;
|
|
@@ -2099,7 +2159,7 @@ function VectorSymmetryPanel({ controller, className }) {
|
|
|
2099
2159
|
!group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "make", title: "Make Symmetry: the selection (or nothing yet) mirrored live across a vertical axis", onClick: () => controller.makeSymmetry({ mode: "vertical" }), children: "Mirror" }),
|
|
2100
2160
|
!group && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: buttonClass13, "data-vector-symmetry-action": "radial", title: "Make Symmetry: the selection repeated round its centre", onClick: () => controller.makeSymmetry({ mode: "radial", copies: 6 }), children: "Radial" }),
|
|
2101
2161
|
group && s && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2102
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass10, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children:
|
|
2162
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("select", { "aria-label": "Symmetry mode", className: selectClass10, value: s.mode, onChange: (e) => controller.setSymmetry({ mode: e.target.value }, { ids }), children: import_vector16.VECTOR_SYMMETRY_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { value: m, children: import_vector16.VECTOR_SYMMETRY_MODE_LABELS[m] }, m)) }),
|
|
2103
2163
|
s.mode === "radial" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2104
2164
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "number", min: 2, max: 64, "aria-label": "Symmetry copies", title: "Copies round the circle", className: numberClass8, value: s.copies ?? 6, onChange: (e) => controller.setSymmetry({ copies: Math.max(2, Math.min(64, parseInt(e.target.value, 10) || 2)) }, { ids }) }),
|
|
2105
2165
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Mirror each copy too (kaleidoscope)", children: [
|
|
@@ -2120,7 +2180,7 @@ function VectorSymmetryPanel({ controller, className }) {
|
|
|
2120
2180
|
|
|
2121
2181
|
// src/vector/VectorPerspectivePanel.tsx
|
|
2122
2182
|
var import_react10 = __toESM(require("react"), 1);
|
|
2123
|
-
var
|
|
2183
|
+
var import_vector17 = require("@pixerate/editor/vector");
|
|
2124
2184
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2125
2185
|
var buttonClass14 = "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";
|
|
2126
2186
|
var selectClass11 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
@@ -2128,10 +2188,10 @@ var PLANE_LABELS = { floor: "Floor", left: "Left wall", right: "Right wall", sid
|
|
|
2128
2188
|
function VectorPerspectivePanel({ controller, className }) {
|
|
2129
2189
|
const state = useVectorEditorState(controller);
|
|
2130
2190
|
const grid = state.document.perspective ?? null;
|
|
2131
|
-
const planes = grid ? (0,
|
|
2191
|
+
const planes = grid ? (0, import_vector17.vectorPerspectivePlanes)(grid) : [];
|
|
2132
2192
|
const [attachTo, setAttachTo] = import_react10.default.useState("");
|
|
2133
2193
|
const target = (state.perspectivePlane ?? attachTo) || planes[0];
|
|
2134
|
-
const add = (n) => controller.setPerspective((0,
|
|
2194
|
+
const add = (n) => controller.setPerspective((0, import_vector17.vectorPerspectivePreset)(n, state.document.width, state.document.height));
|
|
2135
2195
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-perspective-panel": "", "aria-label": "Perspective", children: [
|
|
2136
2196
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
2137
2197
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Perspective" }),
|
|
@@ -2164,7 +2224,7 @@ function VectorPerspectivePanel({ controller, className }) {
|
|
|
2164
2224
|
}
|
|
2165
2225
|
|
|
2166
2226
|
// src/vector/VectorLensPanel.tsx
|
|
2167
|
-
var
|
|
2227
|
+
var import_vector18 = require("@pixerate/editor/vector");
|
|
2168
2228
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2169
2229
|
var selectClass12 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2170
2230
|
var numberClass9 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
@@ -2173,7 +2233,7 @@ function VectorLensPanel({ controller, className }) {
|
|
|
2173
2233
|
const path = state.selection.map((id) => controller.getNode(id)).find((n) => n?.type === "path" && n.subpaths.some((sp) => sp.closed) && !n.connector);
|
|
2174
2234
|
if (!path) return null;
|
|
2175
2235
|
const lens = path.lens ?? null;
|
|
2176
|
-
const spec = lens ?
|
|
2236
|
+
const spec = lens ? import_vector18.VECTOR_LENS_SPECS[lens.type] : null;
|
|
2177
2237
|
const ids = [path.id];
|
|
2178
2238
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-lens-panel": "", "aria-label": "Lens", children: [
|
|
2179
2239
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
@@ -2187,7 +2247,7 @@ function VectorLensPanel({ controller, className }) {
|
|
|
2187
2247
|
onChange: (e) => e.target.value ? controller.setLens({ type: e.target.value }, { ids }) : controller.setLens(null, { ids }),
|
|
2188
2248
|
children: [
|
|
2189
2249
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: "None" }),
|
|
2190
|
-
|
|
2250
|
+
import_vector18.VECTOR_LENS_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: t, children: import_vector18.VECTOR_LENS_LABELS[t] }, t))
|
|
2191
2251
|
]
|
|
2192
2252
|
}
|
|
2193
2253
|
)
|
|
@@ -2217,7 +2277,7 @@ function VectorLensPanel({ controller, className }) {
|
|
|
2217
2277
|
}
|
|
2218
2278
|
|
|
2219
2279
|
// src/vector/VectorGradientEditor.tsx
|
|
2220
|
-
var
|
|
2280
|
+
var import_vector19 = require("@pixerate/editor/vector");
|
|
2221
2281
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2222
2282
|
var selectClass13 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2223
2283
|
var numberClass10 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
@@ -2225,7 +2285,7 @@ var buttonClass15 = "inline-flex h-7 min-w-7 items-center justify-center rounded
|
|
|
2225
2285
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
2226
2286
|
function VectorGradientEditor({ controller, className }) {
|
|
2227
2287
|
const state = useVectorEditorState(controller);
|
|
2228
|
-
const ed = (0,
|
|
2288
|
+
const ed = (0, import_vector19.getVectorGradientEditor)(state);
|
|
2229
2289
|
if (!ed) return null;
|
|
2230
2290
|
const g = ed.gradient;
|
|
2231
2291
|
const sel = ed.selected;
|
|
@@ -2233,7 +2293,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2233
2293
|
const setType = (value) => {
|
|
2234
2294
|
if (value === "solid") {
|
|
2235
2295
|
const first = ed.stops[0];
|
|
2236
|
-
controller.setStyle({ [ed.target]: (0,
|
|
2296
|
+
controller.setStyle({ [ed.target]: (0, import_vector19.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
2237
2297
|
} else controller.setGradient({ type: value });
|
|
2238
2298
|
};
|
|
2239
2299
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
@@ -2246,7 +2306,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2246
2306
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
2247
2307
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { "aria-label": "Gradient type", className: selectClass13, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
2248
2308
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "solid", children: "Solid" }),
|
|
2249
|
-
|
|
2309
|
+
import_vector19.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: t, children: import_vector19.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
2250
2310
|
] }),
|
|
2251
2311
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: buttonClass15, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
2252
2312
|
] }),
|
|
@@ -2287,7 +2347,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2287
2347
|
type: "color",
|
|
2288
2348
|
"aria-label": "Stop colour",
|
|
2289
2349
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
2290
|
-
value: (0,
|
|
2350
|
+
value: (0, import_vector19.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
2291
2351
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
2292
2352
|
onBlur: end
|
|
2293
2353
|
}
|
|
@@ -2353,7 +2413,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2353
2413
|
] }),
|
|
2354
2414
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2355
2415
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
2356
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass13, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children:
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass13, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector19.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: i, children: import_vector19.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
2357
2417
|
] }),
|
|
2358
2418
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2359
2419
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
@@ -2375,11 +2435,11 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
2375
2435
|
] }),
|
|
2376
2436
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2377
2437
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
2378
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient spread", className: selectClass13, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children:
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient spread", className: selectClass13, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector19.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: sp, children: import_vector19.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
2379
2439
|
] }),
|
|
2380
2440
|
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2381
2441
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
2382
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass13, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children:
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass13, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector19.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: m, children: import_vector19.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
2383
2443
|
] })
|
|
2384
2444
|
] })
|
|
2385
2445
|
] });
|
|
@@ -2392,7 +2452,7 @@ var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.te
|
|
|
2392
2452
|
var buttonClass16 = "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";
|
|
2393
2453
|
function VectorToolbar({
|
|
2394
2454
|
controller,
|
|
2395
|
-
tools =
|
|
2455
|
+
tools = import_vector20.VECTOR_TOOLS,
|
|
2396
2456
|
showHistory = true,
|
|
2397
2457
|
showArrange = true,
|
|
2398
2458
|
showSnap = true,
|
|
@@ -2406,7 +2466,7 @@ function VectorToolbar({
|
|
|
2406
2466
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
2407
2467
|
const editing = state.editing;
|
|
2408
2468
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
2409
|
-
const maskSelected = state.selection.some((id) => (0,
|
|
2469
|
+
const maskSelected = state.selection.some((id) => (0, import_vector20.isVectorMaskGroup)(controller.getNode(id)));
|
|
2410
2470
|
const [live, setLive] = import_react11.default.useState(false);
|
|
2411
2471
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
2412
2472
|
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: buttonClass16, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
@@ -2418,10 +2478,10 @@ function VectorToolbar({
|
|
|
2418
2478
|
"data-vector-tool": tool,
|
|
2419
2479
|
className: buttonClass16,
|
|
2420
2480
|
"aria-pressed": state.tool === tool,
|
|
2421
|
-
title: `${(0,
|
|
2422
|
-
"aria-label": (0,
|
|
2481
|
+
title: `${(0, import_vector20.vectorToolLabel)(tool)} (${import_vector20.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2482
|
+
"aria-label": (0, import_vector20.vectorToolLabel)(tool),
|
|
2423
2483
|
onClick: () => controller.setTool(tool),
|
|
2424
|
-
children:
|
|
2484
|
+
children: import_vector20.VECTOR_TOOL_GLYPHS[tool]
|
|
2425
2485
|
},
|
|
2426
2486
|
tool
|
|
2427
2487
|
)) }),
|
|
@@ -2450,10 +2510,10 @@ function VectorToolbar({
|
|
|
2450
2510
|
"aria-label": "Polar tracking increment",
|
|
2451
2511
|
title: "Polar tracking: the angles drawn points snap to from where they leave",
|
|
2452
2512
|
className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
|
|
2453
|
-
value: String((0,
|
|
2454
|
-
onChange: (e) => controller.setSnap({ angles: (0,
|
|
2513
|
+
value: String((0, import_vector20.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
|
|
2514
|
+
onChange: (e) => controller.setSnap({ angles: (0, import_vector20.vectorPolarAngles)(Number(e.target.value)) }),
|
|
2455
2515
|
children: [
|
|
2456
|
-
(0,
|
|
2516
|
+
(0, import_vector20.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "Custom" }),
|
|
2457
2517
|
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("option", { value: n, children: [
|
|
2458
2518
|
n,
|
|
2459
2519
|
"\xB0"
|
|
@@ -2463,7 +2523,7 @@ function VectorToolbar({
|
|
|
2463
2523
|
)
|
|
2464
2524
|
] }),
|
|
2465
2525
|
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2466
|
-
|
|
2526
|
+
import_vector20.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2467
2527
|
"button",
|
|
2468
2528
|
{
|
|
2469
2529
|
type: "button",
|
|
@@ -2477,7 +2537,7 @@ function VectorToolbar({
|
|
|
2477
2537
|
},
|
|
2478
2538
|
a.id
|
|
2479
2539
|
)),
|
|
2480
|
-
|
|
2540
|
+
import_vector20.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2481
2541
|
"button",
|
|
2482
2542
|
{
|
|
2483
2543
|
type: "button",
|
|
@@ -2525,6 +2585,20 @@ function VectorToolbar({
|
|
|
2525
2585
|
}
|
|
2526
2586
|
)
|
|
2527
2587
|
] }),
|
|
2588
|
+
state.tool === "distort" && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex flex-wrap items-center gap-1", "data-vector-distort-options": "", children: [
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Distort brush", title: "What the brush does to the outlines it passes over", className: "h-7 rounded border border-border bg-background px-1 text-xs", value: editing.distortMode, onChange: (e) => controller.setEditing({ distortMode: e.target.value }), children: import_vector20.VECTOR_DISTORT_BRUSH_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: m, children: m[0].toUpperCase() + m.slice(1) }, m)) }),
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2591
|
+
"Size",
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "number", min: 1, step: 1, "aria-label": "Distort brush size", className: "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs", value: editing.distortSize, onChange: (e) => {
|
|
2593
|
+
const n = parseFloat(e.target.value);
|
|
2594
|
+
if (Number.isFinite(n) && n > 0) controller.setEditing({ distortSize: n });
|
|
2595
|
+
} })
|
|
2596
|
+
] }),
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
2598
|
+
"Strength",
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "range", min: 0, max: 1, step: 0.05, "aria-label": "Distort brush strength", className: "h-4 w-20 accent-primary", value: editing.distortStrength, onChange: (e) => controller.setEditing({ distortStrength: parseFloat(e.target.value) }) })
|
|
2600
|
+
] })
|
|
2601
|
+
] }),
|
|
2528
2602
|
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2529
2603
|
"button",
|
|
2530
2604
|
{
|
|
@@ -2534,7 +2608,7 @@ function VectorToolbar({
|
|
|
2534
2608
|
"aria-pressed": editing.fillGap > 0,
|
|
2535
2609
|
title: "Close small gaps between path ends when filling",
|
|
2536
2610
|
"aria-label": "Close gaps",
|
|
2537
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
2611
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector20.VECTOR_FILL_GAP }),
|
|
2538
2612
|
children: "Gaps"
|
|
2539
2613
|
}
|
|
2540
2614
|
)
|
|
@@ -2577,7 +2651,7 @@ function VectorToolbar({
|
|
|
2577
2651
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
2578
2652
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
2579
2653
|
] }),
|
|
2580
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children:
|
|
2654
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector20.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2581
2655
|
"button",
|
|
2582
2656
|
{
|
|
2583
2657
|
type: "button",
|
|
@@ -2606,7 +2680,7 @@ function VectorToolbar({
|
|
|
2606
2680
|
}
|
|
2607
2681
|
function VectorBlendControls({ controller }) {
|
|
2608
2682
|
const state = useVectorEditorState(controller);
|
|
2609
|
-
const blend = (0,
|
|
2683
|
+
const blend = (0, import_vector20.getVectorBlendControls)(state);
|
|
2610
2684
|
const o = blend.options;
|
|
2611
2685
|
const selected = blend.ids.length > 0;
|
|
2612
2686
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
@@ -2617,8 +2691,8 @@ function VectorBlendControls({ controller }) {
|
|
|
2617
2691
|
"aria-label": "Blend spacing",
|
|
2618
2692
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
2619
2693
|
value: o.spacing,
|
|
2620
|
-
onChange: (e) => (0,
|
|
2621
|
-
children:
|
|
2694
|
+
onChange: (e) => (0, import_vector20.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
2695
|
+
children: import_vector20.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: sp, children: import_vector20.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
2622
2696
|
}
|
|
2623
2697
|
),
|
|
2624
2698
|
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
@@ -2633,7 +2707,7 @@ function VectorBlendControls({ controller }) {
|
|
|
2633
2707
|
onChange: (e) => {
|
|
2634
2708
|
const n = parseFloat(e.target.value);
|
|
2635
2709
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
2636
|
-
(0,
|
|
2710
|
+
(0, import_vector20.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
2637
2711
|
}
|
|
2638
2712
|
}
|
|
2639
2713
|
),
|
|
@@ -2646,7 +2720,7 @@ function VectorBlendControls({ controller }) {
|
|
|
2646
2720
|
"aria-pressed": o.orientToSpine,
|
|
2647
2721
|
title: "Orient steps to the spine",
|
|
2648
2722
|
"aria-label": "Orient to spine",
|
|
2649
|
-
onClick: () => (0,
|
|
2723
|
+
onClick: () => (0, import_vector20.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
2650
2724
|
children: "\u293F"
|
|
2651
2725
|
}
|
|
2652
2726
|
),
|
|
@@ -2671,7 +2745,7 @@ var selectClass14 = "h-7 min-w-0 flex-1 rounded border border-border bg-backgrou
|
|
|
2671
2745
|
var numberClass11 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
2672
2746
|
function VectorStylePanel({ controller, className }) {
|
|
2673
2747
|
const state = useVectorEditorState(controller);
|
|
2674
|
-
const style = (0,
|
|
2748
|
+
const style = (0, import_vector20.getVectorSelectionStyle)(state);
|
|
2675
2749
|
const d = state.defaults;
|
|
2676
2750
|
const source = style ?? {
|
|
2677
2751
|
fill: d.fill ?? null,
|
|
@@ -2684,7 +2758,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2684
2758
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
2685
2759
|
startArrowScale: d.startArrowScale ?? 1,
|
|
2686
2760
|
endArrowScale: d.endArrowScale ?? 1,
|
|
2687
|
-
widthProfile: (0,
|
|
2761
|
+
widthProfile: (0, import_vector20.widthProfilePresetId)(d.strokeWidthProfile),
|
|
2688
2762
|
cornerRadius: d.cornerRadius,
|
|
2689
2763
|
cornerKind: d.cornerKind ?? "round",
|
|
2690
2764
|
cornerSmoothing: 0,
|
|
@@ -2698,7 +2772,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2698
2772
|
};
|
|
2699
2773
|
const setProfile = (id) => {
|
|
2700
2774
|
if (style) controller.setWidthProfile(id);
|
|
2701
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
2775
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector20.widthProfilePreset)(id)?.length ? (0, import_vector20.widthProfilePreset)(id) : null });
|
|
2702
2776
|
};
|
|
2703
2777
|
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
2704
2778
|
const arrowRow = (end, label) => {
|
|
@@ -2708,7 +2782,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2708
2782
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2709
2783
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass14, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2710
2784
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "None" }),
|
|
2711
|
-
|
|
2785
|
+
import_vector20.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: h, children: import_vector20.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
2712
2786
|
] }),
|
|
2713
2787
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2714
2788
|
"input",
|
|
@@ -2734,7 +2808,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2734
2808
|
};
|
|
2735
2809
|
const paintRow = (key, label) => {
|
|
2736
2810
|
const paint = source[key];
|
|
2737
|
-
const hex = (0,
|
|
2811
|
+
const hex = (0, import_vector20.vectorPaintToHex)(paint);
|
|
2738
2812
|
const on = paint !== null && paint !== "none";
|
|
2739
2813
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2740
2814
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
@@ -2781,7 +2855,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2781
2855
|
] }),
|
|
2782
2856
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2783
2857
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16", children: "Align" }),
|
|
2784
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass14, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass14, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector20.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: a, children: import_vector20.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
2785
2859
|
mixed("strokeAlign")
|
|
2786
2860
|
] }),
|
|
2787
2861
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
@@ -2796,7 +2870,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2796
2870
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
2797
2871
|
},
|
|
2798
2872
|
children: [
|
|
2799
|
-
|
|
2873
|
+
import_vector20.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
2800
2874
|
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
2801
2875
|
]
|
|
2802
2876
|
}
|
|
@@ -2843,7 +2917,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
2843
2917
|
}
|
|
2844
2918
|
}
|
|
2845
2919
|
),
|
|
2846
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Corner kind", className: selectClass14, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children:
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("select", { "aria-label": "Corner kind", className: selectClass14, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector20.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: k, children: import_vector20.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
2847
2921
|
mixed("cornerRadius")
|
|
2848
2922
|
] }),
|
|
2849
2923
|
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.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: [
|
|
@@ -3537,6 +3611,44 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
3537
3611
|
] })
|
|
3538
3612
|
] });
|
|
3539
3613
|
}
|
|
3614
|
+
|
|
3615
|
+
// src/vector/VectorGeneratePanel.tsx
|
|
3616
|
+
var import_react18 = require("react");
|
|
3617
|
+
var import_vector21 = require("@pixerate/editor/vector");
|
|
3618
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
3619
|
+
var buttonClass17 = "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";
|
|
3620
|
+
var selectClass15 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
3621
|
+
var AS_LABELS = { color: "Traced in colour", threshold: "Traced in one colour", mosaic: "Mosaic", halftone: "Halftone", lowPoly: "Low poly", hatch: "Engraving" };
|
|
3622
|
+
function VectorGeneratePanel({ controller, models, generate, className }) {
|
|
3623
|
+
const usable = (0, import_vector21.vectorArtModels)(models);
|
|
3624
|
+
const [prompt, setPrompt] = (0, import_react18.useState)("");
|
|
3625
|
+
const [model, setModel] = (0, import_react18.useState)("");
|
|
3626
|
+
const [as, setAs] = (0, import_react18.useState)("color");
|
|
3627
|
+
const [busy, setBusy] = (0, import_react18.useState)(false);
|
|
3628
|
+
const [message, setMessage] = (0, import_react18.useState)(null);
|
|
3629
|
+
const chosen = usable.find((m) => m.id === model) ?? usable[0];
|
|
3630
|
+
if (!usable.length) return null;
|
|
3631
|
+
const run = async () => {
|
|
3632
|
+
setBusy(true);
|
|
3633
|
+
setMessage(null);
|
|
3634
|
+
const r = await (0, import_vector21.generateVectorArt)(controller, { prompt, model: chosen.id, as, idempotencyKey: `${Date.now()}-${Math.random().toString(36).slice(2)}` }, { models, generate });
|
|
3635
|
+
setBusy(false);
|
|
3636
|
+
setMessage(r.ok ? null : r.message ?? "Generation failed.");
|
|
3637
|
+
};
|
|
3638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: `space-y-1 ${className ?? ""}`, "data-vector-generate-panel": "", "aria-label": "Generate", children: [
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3640
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Generate" }),
|
|
3641
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("select", { "aria-label": "Generation model", className: selectClass15, value: chosen.id, onChange: (e) => setModel(e.target.value), children: usable.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: m.id, children: m.name ?? m.id }, m.id)) }),
|
|
3642
|
+
chosen.media === "image" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("select", { "aria-label": "Image to vectors", className: selectClass15, value: as, onChange: (e) => setAs(e.target.value), children: import_vector21.VECTOR_GENERATED_IMAGE_AS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: a, children: AS_LABELS[a] }, a)) })
|
|
3643
|
+
] }),
|
|
3644
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
3645
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "w-16" }),
|
|
3646
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("input", { type: "text", "aria-label": "Prompt", placeholder: "Describe the art\u2026", className: "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1.5 text-xs", value: prompt, onChange: (e) => setPrompt(e.target.value), onKeyDown: (e) => e.key === "Enter" && prompt.trim() && !busy && void run() }),
|
|
3647
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass17, "data-vector-generate-action": "", disabled: !prompt.trim() || busy, onClick: () => void run(), children: busy ? "Generating\u2026" : "Generate" })
|
|
3648
|
+
] }),
|
|
3649
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-[11px] text-red-600", children: message })
|
|
3650
|
+
] });
|
|
3651
|
+
}
|
|
3540
3652
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3541
3653
|
0 && (module.exports = {
|
|
3542
3654
|
VectorAppearancePanel,
|
|
@@ -3548,6 +3660,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
3548
3660
|
VectorEnvelopePanel,
|
|
3549
3661
|
VectorFilterDefs,
|
|
3550
3662
|
VectorFramePanel,
|
|
3663
|
+
VectorGeneratePanel,
|
|
3551
3664
|
VectorGradientAnnotator,
|
|
3552
3665
|
VectorGradientDefs,
|
|
3553
3666
|
VectorGradientEditor,
|
|
@@ -3571,6 +3684,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
3571
3684
|
useVectorEditor,
|
|
3572
3685
|
useVectorEditorController,
|
|
3573
3686
|
useVectorEditorState,
|
|
3574
|
-
useVectorEffectsTools
|
|
3687
|
+
useVectorEffectsTools,
|
|
3688
|
+
useVectorGenerationTools
|
|
3575
3689
|
});
|
|
3576
3690
|
//# sourceMappingURL=index.cjs.map
|