@pixerate/editor-react 0.68.1 → 0.70.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/paint-editor/index.cjs +133 -5
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +37 -5
- package/dist/paint-editor/index.d.ts +37 -5
- package/dist/paint-editor/index.js +151 -11
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/vector/index.cjs +302 -152
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +23 -2
- package/dist/vector/index.d.ts +23 -2
- package/dist/vector/index.js +285 -136
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
package/dist/vector/index.cjs
CHANGED
|
@@ -39,6 +39,8 @@ __export(vector_exports, {
|
|
|
39
39
|
VectorGradientAnnotator: () => VectorGradientAnnotator,
|
|
40
40
|
VectorGradientDefs: () => VectorGradientDefs,
|
|
41
41
|
VectorGradientEditor: () => VectorGradientEditor,
|
|
42
|
+
VectorMaskPanel: () => VectorMaskPanel,
|
|
43
|
+
VectorMaskedNodes: () => VectorMaskedNodes,
|
|
42
44
|
VectorSceneNodes: () => VectorSceneNodes,
|
|
43
45
|
VectorStylePanel: () => VectorStylePanel,
|
|
44
46
|
VectorToolbar: () => VectorToolbar,
|
|
@@ -228,7 +230,8 @@ function VectorGradientAnnotator({ annotator: g, accentColor = import_vector3.VE
|
|
|
228
230
|
}
|
|
229
231
|
function VectorFilterDefs({ filters }) {
|
|
230
232
|
if (!filters.length) return null;
|
|
231
|
-
const
|
|
233
|
+
const props = (attrs) => Object.fromEntries(Object.entries(attrs).map(([k, v]) => [k.replace(/-([a-z])/g, (_, c) => c.toUpperCase()), v]));
|
|
234
|
+
const primitive = (p, key) => import_react3.default.createElement(p.tag, { key, ...props(p.attrs) }, p.children?.map(primitive));
|
|
232
235
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: filters.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("filter", { id: f.id, filterUnits: "userSpaceOnUse", x: f.x, y: f.y, width: f.width, height: f.height, colorInterpolationFilters: "sRGB", children: f.primitives.map(primitive) }, f.id)) });
|
|
233
236
|
}
|
|
234
237
|
var blendStyle = (blendMode) => blendMode ? { mixBlendMode: blendMode } : void 0;
|
|
@@ -238,11 +241,12 @@ function VectorSceneNodes({ nodes }) {
|
|
|
238
241
|
"g",
|
|
239
242
|
{
|
|
240
243
|
"data-vector-id": node.id,
|
|
244
|
+
"data-vector-mask": node.mask?.type,
|
|
241
245
|
transform: node.transform,
|
|
242
246
|
opacity: node.opacity < 1 ? node.opacity : void 0,
|
|
243
247
|
filter: node.filter,
|
|
244
248
|
style: blendStyle(node.blendMode),
|
|
245
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: node.children })
|
|
249
|
+
children: node.mask ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorMaskedNodes, { mask: node.mask, nodes: node.children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: node.children })
|
|
246
250
|
},
|
|
247
251
|
node.id
|
|
248
252
|
) : node.layers ? (
|
|
@@ -274,6 +278,13 @@ function VectorSceneNodes({ nodes }) {
|
|
|
274
278
|
)
|
|
275
279
|
) });
|
|
276
280
|
}
|
|
281
|
+
function VectorMaskedNodes({ mask, nodes }) {
|
|
282
|
+
const b = mask.bounds;
|
|
283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
284
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: mask.clip ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("clipPath", { id: mask.id, children: mask.clip.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: c.d, clipRule: c.clipRule }, i)) }) : b && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("mask", { id: mask.id, maskUnits: "userSpaceOnUse", x: b.x, y: b.y, width: b.width, height: b.height, style: mask.type === "alpha" ? { maskType: "alpha" } : void 0, children: mask.filter ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { filter: mask.filter, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: mask.nodes ?? [] }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: mask.nodes ?? [] }) }) }),
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-masked": "", clipPath: mask.clip ? `url(#${mask.id})` : void 0, mask: mask.clip ? void 0 : `url(#${mask.id})`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes }) })
|
|
286
|
+
] });
|
|
287
|
+
}
|
|
277
288
|
function VectorPaintPath({
|
|
278
289
|
paint,
|
|
279
290
|
d,
|
|
@@ -501,6 +512,21 @@ function VectorCanvas({
|
|
|
501
512
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: w.x, cy: w.y, r: import_vector3.VECTOR_OVERLAY_THEME.cornerWidgetRadius + (w.hovered ? 1 : 0), fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
502
513
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: w.x, cy: w.y, r: 1.5, fill: accentColor })
|
|
503
514
|
] }, `corner:${w.ref.nodeId}:${w.ref.subpath}:${w.ref.index}`)),
|
|
515
|
+
overlay.masks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
516
|
+
"path",
|
|
517
|
+
{
|
|
518
|
+
"data-vector-mask-indicator": m.id,
|
|
519
|
+
"data-mask-type": m.type,
|
|
520
|
+
"data-inverted": m.invert || void 0,
|
|
521
|
+
d: m.d,
|
|
522
|
+
fill: "none",
|
|
523
|
+
stroke: import_vector3.VECTOR_OVERLAY_THEME.mask,
|
|
524
|
+
strokeWidth: m.editing ? 1.5 : 1,
|
|
525
|
+
strokeDasharray: m.editing ? void 0 : import_vector3.VECTOR_OVERLAY_THEME.maskDash,
|
|
526
|
+
opacity: m.enabled ? 1 : 0.5
|
|
527
|
+
},
|
|
528
|
+
`mask:${m.id}`
|
|
529
|
+
)),
|
|
504
530
|
overlay.blend.spines.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-blend-spine": sp.id, "data-replaced": sp.replaced || void 0, children: [
|
|
505
531
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: sp.d, fill: "none", stroke: accentColor, strokeDasharray: "4 3" }),
|
|
506
532
|
sp.keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: k.x, cy: k.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }, i))
|
|
@@ -629,7 +655,7 @@ function VectorCanvas({
|
|
|
629
655
|
|
|
630
656
|
// src/vector/VectorToolbar.tsx
|
|
631
657
|
var import_react5 = __toESM(require("react"), 1);
|
|
632
|
-
var
|
|
658
|
+
var import_vector9 = require("@pixerate/editor/vector");
|
|
633
659
|
|
|
634
660
|
// src/vector/VectorEffectsPanel.tsx
|
|
635
661
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -1090,16 +1116,134 @@ function VectorEnvelopePanel({ controller, className }) {
|
|
|
1090
1116
|
] });
|
|
1091
1117
|
}
|
|
1092
1118
|
|
|
1093
|
-
// src/vector/
|
|
1119
|
+
// src/vector/VectorMaskPanel.tsx
|
|
1094
1120
|
var import_vector7 = require("@pixerate/editor/vector");
|
|
1095
1121
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1122
|
+
var buttonClass4 = "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";
|
|
1096
1123
|
var selectClass4 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1124
|
+
function VectorMaskPanel({ controller, className }) {
|
|
1125
|
+
const state = useVectorEditorState(controller);
|
|
1126
|
+
const panel = (0, import_vector7.getVectorMaskPanel)(state);
|
|
1127
|
+
if (!panel) return null;
|
|
1128
|
+
const g = panel.group;
|
|
1129
|
+
const ids = g ? [g.id] : void 0;
|
|
1130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-mask-panel": "", "aria-label": "Mask", children: [
|
|
1131
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Mask" }),
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1134
|
+
"button",
|
|
1135
|
+
{
|
|
1136
|
+
type: "button",
|
|
1137
|
+
"data-vector-mask-action": "clip",
|
|
1138
|
+
className: buttonClass4,
|
|
1139
|
+
title: panel.makeHint ?? "Make Clipping Mask: the topmost object clips the others",
|
|
1140
|
+
"aria-label": "Make Clipping Mask",
|
|
1141
|
+
disabled: !panel.canMake,
|
|
1142
|
+
onClick: () => controller.makeMask("clip"),
|
|
1143
|
+
children: "Clip"
|
|
1144
|
+
}
|
|
1145
|
+
),
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1147
|
+
"button",
|
|
1148
|
+
{
|
|
1149
|
+
type: "button",
|
|
1150
|
+
"data-vector-mask-action": "opacity",
|
|
1151
|
+
className: buttonClass4,
|
|
1152
|
+
title: panel.makeHint ?? "Make Opacity Mask: the topmost object fades the others by its brightness",
|
|
1153
|
+
"aria-label": "Make Opacity Mask",
|
|
1154
|
+
disabled: !panel.canMake,
|
|
1155
|
+
onClick: () => controller.makeMask("luminance"),
|
|
1156
|
+
children: "Opacity"
|
|
1157
|
+
}
|
|
1158
|
+
),
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1160
|
+
"button",
|
|
1161
|
+
{
|
|
1162
|
+
type: "button",
|
|
1163
|
+
"data-vector-mask-action": "release",
|
|
1164
|
+
className: buttonClass4,
|
|
1165
|
+
title: "Release: the mask goes back on top and draws as itself",
|
|
1166
|
+
"aria-label": "Release Mask",
|
|
1167
|
+
disabled: !g,
|
|
1168
|
+
onClick: () => controller.releaseMask({ ids }),
|
|
1169
|
+
children: "Release"
|
|
1170
|
+
}
|
|
1171
|
+
)
|
|
1172
|
+
] }),
|
|
1173
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", "data-vector-mask-group": g.id, "data-mask-type": g.type, children: [
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1176
|
+
"select",
|
|
1177
|
+
{
|
|
1178
|
+
"aria-label": "Mask type",
|
|
1179
|
+
className: selectClass4,
|
|
1180
|
+
value: g.type,
|
|
1181
|
+
title: import_vector7.VECTOR_MASK_TYPE_OPTIONS.find((o) => o.value === g.type)?.title,
|
|
1182
|
+
onChange: (e) => controller.setMaskOptions({ type: e.target.value }, { ids }),
|
|
1183
|
+
children: import_vector7.VECTOR_MASK_TYPE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: o.value, title: o.title, children: o.label }, o.value))
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Show the contents where the mask hides them", children: [
|
|
1187
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "checkbox", "aria-label": "Invert mask", checked: g.invert, onChange: (e) => controller.setMaskOptions({ invert: e.target.checked }, { ids }) }),
|
|
1188
|
+
"Invert"
|
|
1189
|
+
] })
|
|
1190
|
+
] }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1193
|
+
"button",
|
|
1194
|
+
{
|
|
1195
|
+
type: "button",
|
|
1196
|
+
"data-vector-mask-action": "edit-mask",
|
|
1197
|
+
className: buttonClass4,
|
|
1198
|
+
"aria-pressed": g.editing === "mask",
|
|
1199
|
+
title: "Edit Mask: select the mask (a path opens for anchor editing)",
|
|
1200
|
+
"aria-label": "Edit Mask",
|
|
1201
|
+
onClick: () => controller.editMask({ id: g.id }),
|
|
1202
|
+
children: "Edit mask"
|
|
1203
|
+
}
|
|
1204
|
+
),
|
|
1205
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1206
|
+
"button",
|
|
1207
|
+
{
|
|
1208
|
+
type: "button",
|
|
1209
|
+
"data-vector-mask-action": "edit-contents",
|
|
1210
|
+
className: buttonClass4,
|
|
1211
|
+
"aria-pressed": g.editing === "contents",
|
|
1212
|
+
title: "Edit Contents: select what the mask masks",
|
|
1213
|
+
"aria-label": "Edit Contents",
|
|
1214
|
+
disabled: !g.contents.length,
|
|
1215
|
+
onClick: () => controller.editMaskContents({ id: g.id }),
|
|
1216
|
+
children: "Contents"
|
|
1217
|
+
}
|
|
1218
|
+
),
|
|
1219
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1220
|
+
"button",
|
|
1221
|
+
{
|
|
1222
|
+
type: "button",
|
|
1223
|
+
"data-vector-mask-action": "toggle",
|
|
1224
|
+
className: buttonClass4,
|
|
1225
|
+
"aria-pressed": g.enabled,
|
|
1226
|
+
title: g.enabled ? "Turn the mask off (hide it): the contents draw whole" : "Turn the mask on",
|
|
1227
|
+
"aria-label": "Mask on",
|
|
1228
|
+
onClick: () => controller.setMaskOptions({ enabled: !g.enabled }, { ids }),
|
|
1229
|
+
children: g.enabled ? "On" : "Off"
|
|
1230
|
+
}
|
|
1231
|
+
)
|
|
1232
|
+
] })
|
|
1233
|
+
] })
|
|
1234
|
+
] });
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// src/vector/VectorGradientEditor.tsx
|
|
1238
|
+
var import_vector8 = require("@pixerate/editor/vector");
|
|
1239
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1240
|
+
var selectClass5 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1097
1241
|
var numberClass4 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
1098
|
-
var
|
|
1242
|
+
var buttonClass5 = "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";
|
|
1099
1243
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
1100
1244
|
function VectorGradientEditor({ controller, className }) {
|
|
1101
1245
|
const state = useVectorEditorState(controller);
|
|
1102
|
-
const ed = (0,
|
|
1246
|
+
const ed = (0, import_vector8.getVectorGradientEditor)(state);
|
|
1103
1247
|
if (!ed) return null;
|
|
1104
1248
|
const g = ed.gradient;
|
|
1105
1249
|
const sel = ed.selected;
|
|
@@ -1107,26 +1251,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1107
1251
|
const setType = (value) => {
|
|
1108
1252
|
if (value === "solid") {
|
|
1109
1253
|
const first = ed.stops[0];
|
|
1110
|
-
controller.setStyle({ [ed.target]: (0,
|
|
1254
|
+
controller.setStyle({ [ed.target]: (0, import_vector8.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
1111
1255
|
} else controller.setGradient({ type: value });
|
|
1112
1256
|
};
|
|
1113
|
-
return /* @__PURE__ */ (0,
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1115
|
-
/* @__PURE__ */ (0,
|
|
1116
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */ (0,
|
|
1117
|
-
ed.mixed && /* @__PURE__ */ (0,
|
|
1257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1259
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
1260
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
1261
|
+
ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1118
1262
|
] }),
|
|
1119
|
-
/* @__PURE__ */ (0,
|
|
1120
|
-
/* @__PURE__ */ (0,
|
|
1121
|
-
/* @__PURE__ */ (0,
|
|
1122
|
-
/* @__PURE__ */ (0,
|
|
1123
|
-
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { "aria-label": "Gradient type", className: selectClass5, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "solid", children: "Solid" }),
|
|
1267
|
+
import_vector8.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: t, children: import_vector8.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
1124
1268
|
] }),
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
1126
1270
|
] }),
|
|
1127
|
-
g && /* @__PURE__ */ (0,
|
|
1128
|
-
/* @__PURE__ */ (0,
|
|
1129
|
-
/* @__PURE__ */ (0,
|
|
1271
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1130
1274
|
"div",
|
|
1131
1275
|
{
|
|
1132
1276
|
role: "button",
|
|
@@ -1140,7 +1284,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1140
1284
|
}
|
|
1141
1285
|
}
|
|
1142
1286
|
),
|
|
1143
|
-
ed.stops.map((s) => /* @__PURE__ */ (0,
|
|
1287
|
+
ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1144
1288
|
"button",
|
|
1145
1289
|
{
|
|
1146
1290
|
type: "button",
|
|
@@ -1154,21 +1298,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1154
1298
|
s.index
|
|
1155
1299
|
))
|
|
1156
1300
|
] }),
|
|
1157
|
-
sel && /* @__PURE__ */ (0,
|
|
1158
|
-
/* @__PURE__ */ (0,
|
|
1301
|
+
sel && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1159
1303
|
"input",
|
|
1160
1304
|
{
|
|
1161
1305
|
type: "color",
|
|
1162
1306
|
"aria-label": "Stop colour",
|
|
1163
1307
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
1164
|
-
value: (0,
|
|
1308
|
+
value: (0, import_vector8.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
1165
1309
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
1166
1310
|
onBlur: end
|
|
1167
1311
|
}
|
|
1168
1312
|
),
|
|
1169
|
-
/* @__PURE__ */ (0,
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1170
1314
|
"Opacity",
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1172
1316
|
"input",
|
|
1173
1317
|
{
|
|
1174
1318
|
type: "number",
|
|
@@ -1185,9 +1329,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1185
1329
|
}
|
|
1186
1330
|
)
|
|
1187
1331
|
] }),
|
|
1188
|
-
/* @__PURE__ */ (0,
|
|
1332
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1189
1333
|
"At",
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1191
1335
|
"input",
|
|
1192
1336
|
{
|
|
1193
1337
|
type: "number",
|
|
@@ -1204,9 +1348,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1204
1348
|
}
|
|
1205
1349
|
)
|
|
1206
1350
|
] }),
|
|
1207
|
-
!sel.last && /* @__PURE__ */ (0,
|
|
1351
|
+
!sel.last && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1208
1352
|
"Midpoint",
|
|
1209
|
-
/* @__PURE__ */ (0,
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1210
1354
|
"input",
|
|
1211
1355
|
{
|
|
1212
1356
|
type: "number",
|
|
@@ -1223,15 +1367,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1223
1367
|
}
|
|
1224
1368
|
)
|
|
1225
1369
|
] }),
|
|
1226
|
-
/* @__PURE__ */ (0,
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
1227
1371
|
] }),
|
|
1228
|
-
/* @__PURE__ */ (0,
|
|
1229
|
-
/* @__PURE__ */ (0,
|
|
1230
|
-
/* @__PURE__ */ (0,
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass5, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector8.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: i, children: import_vector8.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
1231
1375
|
] }),
|
|
1232
|
-
/* @__PURE__ */ (0,
|
|
1233
|
-
/* @__PURE__ */ (0,
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1235
1379
|
"input",
|
|
1236
1380
|
{
|
|
1237
1381
|
type: "range",
|
|
@@ -1247,26 +1391,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1247
1391
|
}
|
|
1248
1392
|
)
|
|
1249
1393
|
] }),
|
|
1250
|
-
/* @__PURE__ */ (0,
|
|
1251
|
-
/* @__PURE__ */ (0,
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("select", { "aria-label": "Gradient spread", className: selectClass5, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector8.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: sp, children: import_vector8.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
1253
1397
|
] }),
|
|
1254
|
-
ed.target === "stroke" && /* @__PURE__ */ (0,
|
|
1255
|
-
/* @__PURE__ */ (0,
|
|
1256
|
-
/* @__PURE__ */ (0,
|
|
1398
|
+
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass5, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector8.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: m, children: import_vector8.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
1257
1401
|
] })
|
|
1258
1402
|
] })
|
|
1259
1403
|
] });
|
|
1260
1404
|
}
|
|
1261
1405
|
|
|
1262
1406
|
// src/vector/VectorToolbar.tsx
|
|
1263
|
-
var
|
|
1407
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1264
1408
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
1265
1409
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
1266
|
-
var
|
|
1410
|
+
var buttonClass6 = "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";
|
|
1267
1411
|
function VectorToolbar({
|
|
1268
1412
|
controller,
|
|
1269
|
-
tools =
|
|
1413
|
+
tools = import_vector9.VECTOR_TOOLS,
|
|
1270
1414
|
showHistory = true,
|
|
1271
1415
|
showArrange = true,
|
|
1272
1416
|
showSnap = true,
|
|
@@ -1280,34 +1424,35 @@ function VectorToolbar({
|
|
|
1280
1424
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
1281
1425
|
const editing = state.editing;
|
|
1282
1426
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
1427
|
+
const maskSelected = state.selection.some((id) => (0, import_vector9.isVectorMaskGroup)(controller.getNode(id)));
|
|
1283
1428
|
const [live, setLive] = import_react5.default.useState(false);
|
|
1284
1429
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
1285
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
1286
|
-
return /* @__PURE__ */ (0,
|
|
1287
|
-
/* @__PURE__ */ (0,
|
|
1430
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
1431
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1288
1433
|
"button",
|
|
1289
1434
|
{
|
|
1290
1435
|
type: "button",
|
|
1291
1436
|
"data-vector-tool": tool,
|
|
1292
|
-
className:
|
|
1437
|
+
className: buttonClass6,
|
|
1293
1438
|
"aria-pressed": state.tool === tool,
|
|
1294
|
-
title: `${(0,
|
|
1295
|
-
"aria-label": (0,
|
|
1439
|
+
title: `${(0, import_vector9.vectorToolLabel)(tool)} (${import_vector9.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
1440
|
+
"aria-label": (0, import_vector9.vectorToolLabel)(tool),
|
|
1296
1441
|
onClick: () => controller.setTool(tool),
|
|
1297
|
-
children:
|
|
1442
|
+
children: import_vector9.VECTOR_TOOL_GLYPHS[tool]
|
|
1298
1443
|
},
|
|
1299
1444
|
tool
|
|
1300
1445
|
)) }),
|
|
1301
|
-
showHistory && /* @__PURE__ */ (0,
|
|
1446
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
1302
1447
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
1303
1448
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
1304
1449
|
] }),
|
|
1305
|
-
showSnap && /* @__PURE__ */ (0,
|
|
1450
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1306
1451
|
"button",
|
|
1307
1452
|
{
|
|
1308
1453
|
type: "button",
|
|
1309
1454
|
"data-vector-snap": "",
|
|
1310
|
-
className:
|
|
1455
|
+
className: buttonClass6,
|
|
1311
1456
|
"aria-pressed": state.snap.objects,
|
|
1312
1457
|
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
1313
1458
|
"aria-label": VECTOR_SNAP_TITLE,
|
|
@@ -1315,13 +1460,13 @@ function VectorToolbar({
|
|
|
1315
1460
|
children: "Snap"
|
|
1316
1461
|
}
|
|
1317
1462
|
) }),
|
|
1318
|
-
showPathEdit && /* @__PURE__ */ (0,
|
|
1319
|
-
|
|
1463
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
1464
|
+
import_vector9.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1320
1465
|
"button",
|
|
1321
1466
|
{
|
|
1322
1467
|
type: "button",
|
|
1323
1468
|
"data-vector-path-action": a.id,
|
|
1324
|
-
className:
|
|
1469
|
+
className: buttonClass6,
|
|
1325
1470
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
1326
1471
|
"aria-label": a.title,
|
|
1327
1472
|
disabled: !a.enabled(count, points),
|
|
@@ -1330,12 +1475,12 @@ function VectorToolbar({
|
|
|
1330
1475
|
},
|
|
1331
1476
|
a.id
|
|
1332
1477
|
)),
|
|
1333
|
-
|
|
1478
|
+
import_vector9.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1334
1479
|
"button",
|
|
1335
1480
|
{
|
|
1336
1481
|
type: "button",
|
|
1337
1482
|
"data-vector-edit": t.key,
|
|
1338
|
-
className:
|
|
1483
|
+
className: buttonClass6,
|
|
1339
1484
|
"aria-pressed": editing[t.key],
|
|
1340
1485
|
title: t.title,
|
|
1341
1486
|
"aria-label": t.title,
|
|
@@ -1344,9 +1489,9 @@ function VectorToolbar({
|
|
|
1344
1489
|
},
|
|
1345
1490
|
t.key
|
|
1346
1491
|
)),
|
|
1347
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
1492
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1348
1493
|
"Smoothing",
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1350
1495
|
"input",
|
|
1351
1496
|
{
|
|
1352
1497
|
type: "range",
|
|
@@ -1360,9 +1505,9 @@ function VectorToolbar({
|
|
|
1360
1505
|
}
|
|
1361
1506
|
)
|
|
1362
1507
|
] }),
|
|
1363
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
1508
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1364
1509
|
"Size",
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1510
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1366
1511
|
"input",
|
|
1367
1512
|
{
|
|
1368
1513
|
type: "number",
|
|
@@ -1378,26 +1523,26 @@ function VectorToolbar({
|
|
|
1378
1523
|
}
|
|
1379
1524
|
)
|
|
1380
1525
|
] }),
|
|
1381
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
1526
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1382
1527
|
"button",
|
|
1383
1528
|
{
|
|
1384
1529
|
type: "button",
|
|
1385
1530
|
"data-vector-fill-gap": "",
|
|
1386
|
-
className:
|
|
1531
|
+
className: buttonClass6,
|
|
1387
1532
|
"aria-pressed": editing.fillGap > 0,
|
|
1388
1533
|
title: "Close small gaps between path ends when filling",
|
|
1389
1534
|
"aria-label": "Close gaps",
|
|
1390
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
1535
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector9.VECTOR_FILL_GAP }),
|
|
1391
1536
|
children: "Gaps"
|
|
1392
1537
|
}
|
|
1393
1538
|
)
|
|
1394
1539
|
] }),
|
|
1395
|
-
showDistort && /* @__PURE__ */ (0,
|
|
1540
|
+
showDistort && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1396
1541
|
"button",
|
|
1397
1542
|
{
|
|
1398
1543
|
type: "button",
|
|
1399
1544
|
"data-vector-free-distort": "",
|
|
1400
|
-
className:
|
|
1545
|
+
className: buttonClass6,
|
|
1401
1546
|
"aria-pressed": state.freeDistort,
|
|
1402
1547
|
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)`,
|
|
1403
1548
|
"aria-label": "Free Distort",
|
|
@@ -1405,15 +1550,15 @@ function VectorToolbar({
|
|
|
1405
1550
|
children: "Distort"
|
|
1406
1551
|
}
|
|
1407
1552
|
) }),
|
|
1408
|
-
showBlend && /* @__PURE__ */ (0,
|
|
1409
|
-
showArrange && /* @__PURE__ */ (0,
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1411
|
-
/* @__PURE__ */ (0,
|
|
1553
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorBlendControls, { controller }),
|
|
1554
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1412
1557
|
"button",
|
|
1413
1558
|
{
|
|
1414
1559
|
type: "button",
|
|
1415
1560
|
"data-vector-live-boolean": "",
|
|
1416
|
-
className:
|
|
1561
|
+
className: buttonClass6,
|
|
1417
1562
|
"aria-pressed": live,
|
|
1418
1563
|
title: "Live booleans: keep the shapes editable",
|
|
1419
1564
|
"aria-label": "Live booleans",
|
|
@@ -1426,14 +1571,16 @@ function VectorToolbar({
|
|
|
1426
1571
|
act("\u2229", "Intersect", () => controller.booleanOp("intersect", { live }), booleanDisabled),
|
|
1427
1572
|
act("\u22BB", "Exclude", () => controller.booleanOp("exclude", { live }), booleanDisabled),
|
|
1428
1573
|
act("G", "Group", () => controller.group(), count < 1),
|
|
1429
|
-
act("U", "Ungroup", () => controller.ungroup(), !groupSelected)
|
|
1574
|
+
act("U", "Ungroup", () => controller.ungroup(), !groupSelected),
|
|
1575
|
+
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
1576
|
+
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
1430
1577
|
] }),
|
|
1431
|
-
/* @__PURE__ */ (0,
|
|
1578
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector9.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1432
1579
|
"button",
|
|
1433
1580
|
{
|
|
1434
1581
|
type: "button",
|
|
1435
1582
|
"data-vector-pathfinder": a.id,
|
|
1436
|
-
className:
|
|
1583
|
+
className: buttonClass6,
|
|
1437
1584
|
title: a.title,
|
|
1438
1585
|
"aria-label": a.title,
|
|
1439
1586
|
disabled: count < a.min,
|
|
@@ -1442,7 +1589,7 @@ function VectorToolbar({
|
|
|
1442
1589
|
},
|
|
1443
1590
|
a.id
|
|
1444
1591
|
)) }),
|
|
1445
|
-
/* @__PURE__ */ (0,
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
1446
1593
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
1447
1594
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
1448
1595
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -1457,22 +1604,22 @@ function VectorToolbar({
|
|
|
1457
1604
|
}
|
|
1458
1605
|
function VectorBlendControls({ controller }) {
|
|
1459
1606
|
const state = useVectorEditorState(controller);
|
|
1460
|
-
const blend = (0,
|
|
1607
|
+
const blend = (0, import_vector9.getVectorBlendControls)(state);
|
|
1461
1608
|
const o = blend.options;
|
|
1462
1609
|
const selected = blend.ids.length > 0;
|
|
1463
|
-
return /* @__PURE__ */ (0,
|
|
1464
|
-
/* @__PURE__ */ (0,
|
|
1465
|
-
/* @__PURE__ */ (0,
|
|
1610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass6, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1466
1613
|
"select",
|
|
1467
1614
|
{
|
|
1468
1615
|
"aria-label": "Blend spacing",
|
|
1469
1616
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
1470
1617
|
value: o.spacing,
|
|
1471
|
-
onChange: (e) => (0,
|
|
1472
|
-
children:
|
|
1618
|
+
onChange: (e) => (0, import_vector9.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
1619
|
+
children: import_vector9.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: sp, children: import_vector9.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
1473
1620
|
}
|
|
1474
1621
|
),
|
|
1475
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */ (0,
|
|
1622
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1476
1623
|
"input",
|
|
1477
1624
|
{
|
|
1478
1625
|
type: "number",
|
|
@@ -1484,29 +1631,29 @@ function VectorBlendControls({ controller }) {
|
|
|
1484
1631
|
onChange: (e) => {
|
|
1485
1632
|
const n = parseFloat(e.target.value);
|
|
1486
1633
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
1487
|
-
(0,
|
|
1634
|
+
(0, import_vector9.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
1488
1635
|
}
|
|
1489
1636
|
}
|
|
1490
1637
|
),
|
|
1491
|
-
/* @__PURE__ */ (0,
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1492
1639
|
"button",
|
|
1493
1640
|
{
|
|
1494
1641
|
type: "button",
|
|
1495
1642
|
"data-vector-blend-action": "orient",
|
|
1496
|
-
className:
|
|
1643
|
+
className: buttonClass6,
|
|
1497
1644
|
"aria-pressed": o.orientToSpine,
|
|
1498
1645
|
title: "Orient steps to the spine",
|
|
1499
1646
|
"aria-label": "Orient to spine",
|
|
1500
|
-
onClick: () => (0,
|
|
1647
|
+
onClick: () => (0, import_vector9.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
1501
1648
|
children: "\u293F"
|
|
1502
1649
|
}
|
|
1503
1650
|
),
|
|
1504
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1505
1652
|
"button",
|
|
1506
1653
|
{
|
|
1507
1654
|
type: "button",
|
|
1508
1655
|
"data-vector-blend-action": "spine",
|
|
1509
|
-
className:
|
|
1656
|
+
className: buttonClass6,
|
|
1510
1657
|
title: "Replace Spine (select a blend and a path)",
|
|
1511
1658
|
"aria-label": "Replace Spine",
|
|
1512
1659
|
disabled: !blend.canReplaceSpine,
|
|
@@ -1514,15 +1661,15 @@ function VectorBlendControls({ controller }) {
|
|
|
1514
1661
|
children: "\u2307"
|
|
1515
1662
|
}
|
|
1516
1663
|
),
|
|
1517
|
-
/* @__PURE__ */ (0,
|
|
1518
|
-
/* @__PURE__ */ (0,
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass6, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass6, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
1519
1666
|
] });
|
|
1520
1667
|
}
|
|
1521
|
-
var
|
|
1668
|
+
var selectClass6 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1522
1669
|
var numberClass5 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
1523
1670
|
function VectorStylePanel({ controller, className }) {
|
|
1524
1671
|
const state = useVectorEditorState(controller);
|
|
1525
|
-
const style = (0,
|
|
1672
|
+
const style = (0, import_vector9.getVectorSelectionStyle)(state);
|
|
1526
1673
|
const d = state.defaults;
|
|
1527
1674
|
const source = style ?? {
|
|
1528
1675
|
fill: d.fill ?? null,
|
|
@@ -1535,7 +1682,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1535
1682
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
1536
1683
|
startArrowScale: d.startArrowScale ?? 1,
|
|
1537
1684
|
endArrowScale: d.endArrowScale ?? 1,
|
|
1538
|
-
widthProfile: (0,
|
|
1685
|
+
widthProfile: (0, import_vector9.widthProfilePresetId)(d.strokeWidthProfile),
|
|
1539
1686
|
cornerRadius: d.cornerRadius,
|
|
1540
1687
|
cornerKind: d.cornerKind ?? "round",
|
|
1541
1688
|
corners: 1,
|
|
@@ -1548,19 +1695,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1548
1695
|
};
|
|
1549
1696
|
const setProfile = (id) => {
|
|
1550
1697
|
if (style) controller.setWidthProfile(id);
|
|
1551
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
1698
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector9.widthProfilePreset)(id)?.length ? (0, import_vector9.widthProfilePreset)(id) : null });
|
|
1552
1699
|
};
|
|
1553
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
1700
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
1554
1701
|
const arrowRow = (end, label) => {
|
|
1555
1702
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
1556
1703
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
1557
|
-
return /* @__PURE__ */ (0,
|
|
1558
|
-
/* @__PURE__ */ (0,
|
|
1559
|
-
/* @__PURE__ */ (0,
|
|
1560
|
-
/* @__PURE__ */ (0,
|
|
1561
|
-
|
|
1704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass6, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "None" }),
|
|
1708
|
+
import_vector9.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: h, children: import_vector9.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
1562
1709
|
] }),
|
|
1563
|
-
/* @__PURE__ */ (0,
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1564
1711
|
"input",
|
|
1565
1712
|
{
|
|
1566
1713
|
type: "number",
|
|
@@ -1584,14 +1731,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1584
1731
|
};
|
|
1585
1732
|
const paintRow = (key, label) => {
|
|
1586
1733
|
const paint = source[key];
|
|
1587
|
-
const hex = (0,
|
|
1734
|
+
const hex = (0, import_vector9.vectorPaintToHex)(paint);
|
|
1588
1735
|
const on = paint !== null && paint !== "none";
|
|
1589
|
-
return /* @__PURE__ */ (0,
|
|
1590
|
-
/* @__PURE__ */ (0,
|
|
1591
|
-
/* @__PURE__ */ (0,
|
|
1736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
1738
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
1592
1739
|
label
|
|
1593
1740
|
] }),
|
|
1594
|
-
/* @__PURE__ */ (0,
|
|
1741
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1595
1742
|
"input",
|
|
1596
1743
|
{
|
|
1597
1744
|
type: "color",
|
|
@@ -1602,18 +1749,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1602
1749
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
1603
1750
|
}
|
|
1604
1751
|
),
|
|
1605
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
1606
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
1752
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
1753
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1607
1754
|
] });
|
|
1608
1755
|
};
|
|
1609
|
-
return /* @__PURE__ */ (0,
|
|
1610
|
-
/* @__PURE__ */ (0,
|
|
1756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
1611
1758
|
paintRow("fill", "Fill"),
|
|
1612
1759
|
paintRow("stroke", "Stroke"),
|
|
1613
|
-
style && /* @__PURE__ */ (0,
|
|
1614
|
-
/* @__PURE__ */ (0,
|
|
1615
|
-
/* @__PURE__ */ (0,
|
|
1616
|
-
/* @__PURE__ */ (0,
|
|
1760
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorGradientEditor, { controller }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16", children: "Width" }),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1617
1764
|
"input",
|
|
1618
1765
|
{
|
|
1619
1766
|
type: "number",
|
|
@@ -1629,33 +1776,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1629
1776
|
}
|
|
1630
1777
|
)
|
|
1631
1778
|
] }),
|
|
1632
|
-
/* @__PURE__ */ (0,
|
|
1633
|
-
/* @__PURE__ */ (0,
|
|
1634
|
-
/* @__PURE__ */ (0,
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16", children: "Align" }),
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass6, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector9.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: a, children: import_vector9.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
1635
1782
|
mixed("strokeAlign")
|
|
1636
1783
|
] }),
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1639
|
-
/* @__PURE__ */ (0,
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
1785
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1640
1787
|
"select",
|
|
1641
1788
|
{
|
|
1642
1789
|
"aria-label": "Width profile",
|
|
1643
|
-
className:
|
|
1790
|
+
className: selectClass6,
|
|
1644
1791
|
value: source.widthProfile,
|
|
1645
1792
|
onChange: (e) => {
|
|
1646
1793
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
1647
1794
|
},
|
|
1648
1795
|
children: [
|
|
1649
|
-
|
|
1650
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
1796
|
+
import_vector9.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
1797
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
1651
1798
|
]
|
|
1652
1799
|
}
|
|
1653
1800
|
),
|
|
1654
|
-
/* @__PURE__ */ (0,
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1655
1802
|
"button",
|
|
1656
1803
|
{
|
|
1657
1804
|
type: "button",
|
|
1658
|
-
className:
|
|
1805
|
+
className: buttonClass6,
|
|
1659
1806
|
title: "Reset to uniform width",
|
|
1660
1807
|
"aria-label": "Reset to uniform width",
|
|
1661
1808
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -1665,20 +1812,20 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1665
1812
|
),
|
|
1666
1813
|
mixed("widthProfile")
|
|
1667
1814
|
] }),
|
|
1668
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
1815
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1669
1816
|
arrowRow("start", "Start"),
|
|
1670
1817
|
arrowRow("end", "End"),
|
|
1671
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
1672
|
-
/* @__PURE__ */ (0,
|
|
1673
|
-
/* @__PURE__ */ (0,
|
|
1674
|
-
/* @__PURE__ */ (0,
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1818
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass6, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
1821
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
1676
1823
|
] })
|
|
1677
1824
|
] })
|
|
1678
1825
|
] }),
|
|
1679
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
1680
|
-
/* @__PURE__ */ (0,
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
1826
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
1828
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1682
1829
|
"input",
|
|
1683
1830
|
{
|
|
1684
1831
|
type: "number",
|
|
@@ -1693,12 +1840,12 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1693
1840
|
}
|
|
1694
1841
|
}
|
|
1695
1842
|
),
|
|
1696
|
-
/* @__PURE__ */ (0,
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Corner kind", className: selectClass6, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector9.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: k, children: import_vector9.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
1697
1844
|
mixed("cornerRadius")
|
|
1698
1845
|
] }),
|
|
1699
|
-
style && /* @__PURE__ */ (0,
|
|
1700
|
-
/* @__PURE__ */ (0,
|
|
1701
|
-
/* @__PURE__ */ (0,
|
|
1846
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
1848
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1702
1849
|
"input",
|
|
1703
1850
|
{
|
|
1704
1851
|
type: "range",
|
|
@@ -1712,20 +1859,21 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1712
1859
|
}
|
|
1713
1860
|
)
|
|
1714
1861
|
] }),
|
|
1715
|
-
style && /* @__PURE__ */ (0,
|
|
1716
|
-
style && /* @__PURE__ */ (0,
|
|
1717
|
-
style && /* @__PURE__ */ (0,
|
|
1862
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorAppearancePanel, { controller }),
|
|
1863
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorEffectsPanel, { controller }),
|
|
1864
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorEnvelopePanel, { controller }),
|
|
1865
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorMaskPanel, { controller })
|
|
1718
1866
|
] });
|
|
1719
1867
|
}
|
|
1720
1868
|
|
|
1721
1869
|
// src/vector/VectorEditor.tsx
|
|
1722
|
-
var
|
|
1870
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1723
1871
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
1724
|
-
return /* @__PURE__ */ (0,
|
|
1725
|
-
/* @__PURE__ */ (0,
|
|
1726
|
-
/* @__PURE__ */ (0,
|
|
1727
|
-
/* @__PURE__ */ (0,
|
|
1728
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
1872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
1873
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(VectorToolbar, { controller, tools }),
|
|
1874
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
1875
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.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_runtime9.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
1876
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
1729
1877
|
] })
|
|
1730
1878
|
] });
|
|
1731
1879
|
}
|
|
@@ -1740,6 +1888,8 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
1740
1888
|
VectorGradientAnnotator,
|
|
1741
1889
|
VectorGradientDefs,
|
|
1742
1890
|
VectorGradientEditor,
|
|
1891
|
+
VectorMaskPanel,
|
|
1892
|
+
VectorMaskedNodes,
|
|
1743
1893
|
VectorSceneNodes,
|
|
1744
1894
|
VectorStylePanel,
|
|
1745
1895
|
VectorToolbar,
|