@pixerate/editor-react 0.72.0 → 0.74.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/{chunk-YAFNCBDA.js → chunk-LWMUV5TC.js} +477 -377
- package/dist/chunk-LWMUV5TC.js.map +1 -0
- package/dist/image-editor/index.cjs +540 -440
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +12 -1
- package/dist/image-editor/index.d.ts +12 -1
- package/dist/image-editor/index.js +3 -1
- package/dist/index.cjs +969 -869
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/vector/index.cjs +910 -175
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +67 -3
- package/dist/vector/index.d.ts +67 -3
- package/dist/vector/index.js +915 -164
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-YAFNCBDA.js.map +0 -1
package/dist/vector/index.cjs
CHANGED
|
@@ -32,10 +32,13 @@ var vector_exports = {};
|
|
|
32
32
|
__export(vector_exports, {
|
|
33
33
|
VectorAppearancePanel: () => VectorAppearancePanel,
|
|
34
34
|
VectorCanvas: () => VectorCanvas,
|
|
35
|
+
VectorConnectorPanel: () => VectorConnectorPanel,
|
|
36
|
+
VectorConstraintsPanel: () => VectorConstraintsPanel,
|
|
35
37
|
VectorEditor: () => VectorEditor,
|
|
36
38
|
VectorEffectsPanel: () => VectorEffectsPanel,
|
|
37
39
|
VectorEnvelopePanel: () => VectorEnvelopePanel,
|
|
38
40
|
VectorFilterDefs: () => VectorFilterDefs,
|
|
41
|
+
VectorFramePanel: () => VectorFramePanel,
|
|
39
42
|
VectorGradientAnnotator: () => VectorGradientAnnotator,
|
|
40
43
|
VectorGradientDefs: () => VectorGradientDefs,
|
|
41
44
|
VectorGradientEditor: () => VectorGradientEditor,
|
|
@@ -43,6 +46,9 @@ __export(vector_exports, {
|
|
|
43
46
|
VectorMaskedNodes: () => VectorMaskedNodes,
|
|
44
47
|
VectorSceneNodes: () => VectorSceneNodes,
|
|
45
48
|
VectorStylePanel: () => VectorStylePanel,
|
|
49
|
+
VectorSymbolsPanel: () => VectorSymbolsPanel,
|
|
50
|
+
VectorTextElement: () => VectorTextElement,
|
|
51
|
+
VectorTextPanel: () => VectorTextPanel,
|
|
46
52
|
VectorToolbar: () => VectorToolbar,
|
|
47
53
|
VectorWidthPointEditor: () => VectorWidthPointEditor,
|
|
48
54
|
useVectorCommands: () => useVectorCommands,
|
|
@@ -115,11 +121,11 @@ function VectorWidthPointEditor({ controller, edit, accentColor = import_vector2
|
|
|
115
121
|
refocus();
|
|
116
122
|
controller.closeWidthPointEdit();
|
|
117
123
|
};
|
|
118
|
-
const
|
|
124
|
+
const num2 = (v) => v.trim() !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
119
125
|
const apply = () => {
|
|
120
|
-
const t =
|
|
126
|
+
const t = num2(position);
|
|
121
127
|
refocus();
|
|
122
|
-
controller.commitWidthPointEdit({ t: t === void 0 ? void 0 : Math.min(Math.max(t, 0), 100) / 100, left:
|
|
128
|
+
controller.commitWidthPointEdit({ t: t === void 0 ? void 0 : Math.min(Math.max(t, 0), 100) / 100, left: num2(left), right: num2(right) });
|
|
123
129
|
};
|
|
124
130
|
const stop = (e) => e.stopPropagation();
|
|
125
131
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -235,9 +241,42 @@ function VectorFilterDefs({ filters }) {
|
|
|
235
241
|
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)) });
|
|
236
242
|
}
|
|
237
243
|
var blendStyle = (blendMode) => blendMode ? { mixBlendMode: blendMode } : void 0;
|
|
244
|
+
function VectorTextElement({ node }) {
|
|
245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-id": node.id, "data-vector-text": "", transform: node.transform, opacity: node.opacity < 1 ? node.opacity : void 0, filter: node.filter, style: blendStyle(node.blendMode), children: node.layers.map((layer, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
246
|
+
"text",
|
|
247
|
+
{
|
|
248
|
+
"data-vector-layer": layer.kind,
|
|
249
|
+
xmlSpace: "preserve",
|
|
250
|
+
fill: layer.fill,
|
|
251
|
+
stroke: layer.stroke,
|
|
252
|
+
strokeWidth: layer.stroke === "none" ? void 0 : layer.strokeWidth,
|
|
253
|
+
strokeLinejoin: layer.strokeLinejoin,
|
|
254
|
+
strokeDasharray: layer.strokeDasharray,
|
|
255
|
+
opacity: layer.opacity < 1 ? layer.opacity : void 0,
|
|
256
|
+
style: { whiteSpace: "pre", ...blendStyle(layer.blendMode) },
|
|
257
|
+
children: node.spans.map((sp, k) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
258
|
+
"tspan",
|
|
259
|
+
{
|
|
260
|
+
x: sp.x,
|
|
261
|
+
y: sp.y,
|
|
262
|
+
rotate: sp.rotate,
|
|
263
|
+
fontFamily: sp.fontFamily,
|
|
264
|
+
fontSize: sp.fontSize,
|
|
265
|
+
fontWeight: sp.fontWeight,
|
|
266
|
+
fontStyle: sp.fontStyle,
|
|
267
|
+
textDecoration: sp.textDecoration,
|
|
268
|
+
fill: layer.runFills && sp.fill ? sp.fill : void 0,
|
|
269
|
+
children: sp.text
|
|
270
|
+
},
|
|
271
|
+
k
|
|
272
|
+
))
|
|
273
|
+
},
|
|
274
|
+
i
|
|
275
|
+
)) });
|
|
276
|
+
}
|
|
238
277
|
function VectorSceneNodes({ nodes }) {
|
|
239
278
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map(
|
|
240
|
-
(node) => node.kind === "group" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
279
|
+
(node) => node.kind === "text" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorTextElement, { node }, node.id) : node.kind === "group" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
241
280
|
"g",
|
|
242
281
|
{
|
|
243
282
|
"data-vector-id": node.id,
|
|
@@ -368,10 +407,13 @@ function VectorCanvas({
|
|
|
368
407
|
}) {
|
|
369
408
|
const state = useVectorEditorState(controller);
|
|
370
409
|
const svgRef = (0, import_react3.useRef)(null);
|
|
410
|
+
const textRef = (0, import_react3.useRef)(null);
|
|
411
|
+
const editingText = state.textEdit?.nodeId ?? null;
|
|
371
412
|
const fitted = (0, import_react3.useRef)(!fitOnMount);
|
|
372
413
|
const uid = (0, import_react3.useId)().replace(/:/g, "");
|
|
373
414
|
const scene = (0, import_vector3.getVectorSceneRenderData)(state, { idPrefix: `ve${uid}-` });
|
|
374
415
|
const overlay = (0, import_vector3.getVectorOverlayRenderData)(state);
|
|
416
|
+
const host = (0, import_vector3.getVectorSymbolEditBackground)(state, { idPrefix: `ve${uid}-host-` });
|
|
375
417
|
(0, import_react3.useEffect)(() => {
|
|
376
418
|
const el = svgRef.current;
|
|
377
419
|
if (!el || fitted.current) return;
|
|
@@ -387,6 +429,11 @@ function VectorCanvas({
|
|
|
387
429
|
observer.observe(el);
|
|
388
430
|
return () => observer.disconnect();
|
|
389
431
|
}, [controller]);
|
|
432
|
+
(0, import_react3.useEffect)(() => {
|
|
433
|
+
if (!editingText) return;
|
|
434
|
+
const t = setTimeout(() => textRef.current?.focus({ preventScroll: true }), 0);
|
|
435
|
+
return () => clearTimeout(t);
|
|
436
|
+
}, [editingText]);
|
|
390
437
|
(0, import_react3.useEffect)(() => {
|
|
391
438
|
const el = svgRef.current;
|
|
392
439
|
if (!el) return;
|
|
@@ -472,7 +519,30 @@ function VectorCanvas({
|
|
|
472
519
|
stroke: "rgba(0,0,0,0.12)"
|
|
473
520
|
}
|
|
474
521
|
),
|
|
522
|
+
host && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-symbol-host": "", opacity: 0.3, pointerEvents: "none", transform: host.transform, children: [
|
|
523
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorGradientDefs, { defs: host.defs }),
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorFilterDefs, { filters: host.filters }),
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: host.nodes })
|
|
526
|
+
] }),
|
|
475
527
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-scene": "", transform: scene.transform, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorSceneNodes, { nodes: scene.nodes }) }),
|
|
528
|
+
overlay.frames.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { "data-vector-frame-labels": "", children: overlay.frames.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
529
|
+
"text",
|
|
530
|
+
{
|
|
531
|
+
"data-vector-frame-label": f.id,
|
|
532
|
+
x: f.x,
|
|
533
|
+
y: f.y - 6,
|
|
534
|
+
fontSize: 11,
|
|
535
|
+
fontWeight: f.selected ? 600 : 400,
|
|
536
|
+
fill: f.selected ? accentColor : "#737373",
|
|
537
|
+
style: { fontFamily: "system-ui, sans-serif", cursor: "default", userSelect: "none" },
|
|
538
|
+
onPointerDown: (e) => {
|
|
539
|
+
e.stopPropagation();
|
|
540
|
+
controller.select([f.id]);
|
|
541
|
+
},
|
|
542
|
+
children: f.name
|
|
543
|
+
},
|
|
544
|
+
f.id
|
|
545
|
+
)) }),
|
|
476
546
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-overlay": "", pointerEvents: "none", fill: "none", children: [
|
|
477
547
|
overlay.outlines.map((o) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: o.d, stroke: accentColor, strokeWidth: o.selected ? 1 : 1.5, opacity: o.selected ? 1 : 0.7 }, o.id)),
|
|
478
548
|
overlay.penPreview && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: overlay.penPreview, stroke: accentColor, strokeDasharray: "4 3" }),
|
|
@@ -614,6 +684,38 @@ function VectorCanvas({
|
|
|
614
684
|
}
|
|
615
685
|
),
|
|
616
686
|
overlay.cutPoint && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { "data-vector-cut-point": "", cx: overlay.cutPoint.x, cy: overlay.cutPoint.y, r: import_vector3.VECTOR_OVERLAY_THEME.handleRadius + 1, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
687
|
+
overlay.text && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-text-edit": overlay.text.nodeId, "data-editing": overlay.text.editing || void 0, children: [
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: overlay.text.frame, stroke: accentColor, strokeDasharray: overlay.text.editing ? "3 2" : void 0, opacity: 0.8 }),
|
|
689
|
+
overlay.text.selection.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-text-selection": "", d, fill: accentColor, fillOpacity: 0.25, stroke: "none" }, i)),
|
|
690
|
+
overlay.text.caret && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { "data-vector-text-caret": "", x1: overlay.text.caret.x1, y1: overlay.text.caret.y1, x2: overlay.text.caret.x2, y2: overlay.text.caret.y2, stroke: accentColor, strokeWidth: 1.5 }),
|
|
691
|
+
overlay.text.overflow && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-text-overflow": "", transform: `translate(${overlay.text.overflow.x} ${overlay.text.overflow.y})`, children: [
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: -5, y: -5, width: 10, height: 10, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: "#dc2626" }),
|
|
693
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M-3 0H3M0 -3V3", stroke: "#dc2626" })
|
|
694
|
+
] })
|
|
695
|
+
] }),
|
|
696
|
+
overlay.trackingPoints.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { "data-vector-tracking-point": "", d: `M${t.x - 5} ${t.y}H${t.x + 5}M${t.x} ${t.y - 5}V${t.y + 5}`, stroke: guideColor, strokeWidth: 1.5 }, `track:${i}`)),
|
|
697
|
+
overlay.typedEntry && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-typed-entry": "", transform: `translate(${overlay.typedEntry.x + 14} ${overlay.typedEntry.y + 18})`, children: [
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: -3, y: -12, width: overlay.typedEntry.text.length * 7 + 8, height: 17, rx: 3, fill: import_vector3.VECTOR_OVERLAY_THEME.handleFill, stroke: accentColor }),
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: 1, y: 1, fontSize: 11, fill: accentColor, style: { fontFamily: "ui-monospace, monospace" }, children: overlay.typedEntry.text })
|
|
700
|
+
] }),
|
|
701
|
+
overlay.connectorSites.map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
702
|
+
"circle",
|
|
703
|
+
{
|
|
704
|
+
"data-vector-connection-site": s.side,
|
|
705
|
+
"data-active": s.active || void 0,
|
|
706
|
+
cx: s.x,
|
|
707
|
+
cy: s.y,
|
|
708
|
+
r: s.active ? 5 : 3.5,
|
|
709
|
+
fill: s.active ? accentColor : import_vector3.VECTOR_OVERLAY_THEME.handleFill,
|
|
710
|
+
stroke: accentColor
|
|
711
|
+
},
|
|
712
|
+
`site:${s.nodeId}:${s.side}`
|
|
713
|
+
)),
|
|
714
|
+
overlay.constraints.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { "data-vector-constraint-glyph": c.kind, "data-satisfied": c.satisfied ? "true" : "false", children: [
|
|
715
|
+
c.dimension && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: c.dimension.x1, y1: c.dimension.y1, x2: c.dimension.x2, y2: c.dimension.y2, stroke: c.satisfied ? import_vector3.VECTOR_OVERLAY_THEME.guide : "#dc2626", strokeDasharray: "2 2" }),
|
|
716
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: c.x, y: c.y, fontSize: 10, textAnchor: "middle", fill: c.satisfied ? accentColor : "#dc2626", stroke: "#ffffff", strokeWidth: 3, paintOrder: "stroke", style: { fontFamily: "system-ui, sans-serif" }, children: c.label })
|
|
717
|
+
] }, `constraint:${c.id}`)),
|
|
718
|
+
overlay.textBox && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { "data-vector-text-box": "", x: overlay.textBox.x, y: overlay.textBox.y, width: overlay.textBox.width, height: overlay.textBox.height, stroke: accentColor, strokeDasharray: "3 2" }),
|
|
617
719
|
overlay.marquee && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
618
720
|
"rect",
|
|
619
721
|
{
|
|
@@ -646,6 +748,78 @@ function VectorCanvas({
|
|
|
646
748
|
)),
|
|
647
749
|
overlay.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { "data-vector-status": "", x: 8, y: "100%", dy: -8, fontSize: 11, fill: accentColor, style: { fontFamily: "system-ui, sans-serif" }, children: overlay.status })
|
|
648
750
|
] }),
|
|
751
|
+
state.textEdit && overlay.text && // A hidden textarea at the caret takes typing and composed (IME) text.
|
|
752
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("foreignObject", { x: overlay.text.caret?.x1 ?? 0, y: overlay.text.caret?.y1 ?? 0, width: 1, height: 1, style: { overflow: "visible" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
753
|
+
"textarea",
|
|
754
|
+
{
|
|
755
|
+
ref: textRef,
|
|
756
|
+
"data-testid": "vector-type-input",
|
|
757
|
+
"aria-label": "Text",
|
|
758
|
+
autoCapitalize: "off",
|
|
759
|
+
autoCorrect: "off",
|
|
760
|
+
spellCheck: false,
|
|
761
|
+
style: { position: "absolute", width: 1, height: 1, padding: 0, border: 0, opacity: 0, resize: "none", overflow: "hidden" },
|
|
762
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
763
|
+
onInput: (e) => {
|
|
764
|
+
const el = e.currentTarget;
|
|
765
|
+
if (e.nativeEvent.isComposing) return;
|
|
766
|
+
if (el.value) controller.textInput(el.value);
|
|
767
|
+
el.value = "";
|
|
768
|
+
},
|
|
769
|
+
onCompositionEnd: (e) => {
|
|
770
|
+
const el = e.currentTarget;
|
|
771
|
+
if (el.value) controller.textInput(el.value);
|
|
772
|
+
el.value = "";
|
|
773
|
+
},
|
|
774
|
+
onKeyDown: (e) => {
|
|
775
|
+
e.stopPropagation();
|
|
776
|
+
if (e.nativeEvent.isComposing) return;
|
|
777
|
+
if (e.key.length === 1 && !e.metaKey && !e.ctrlKey) return;
|
|
778
|
+
if (controller.keyDown((0, import_vector3.toVectorKeyInput)(e))) e.preventDefault();
|
|
779
|
+
if (!controller.getState().textEdit) svgRef.current?.focus({ preventScroll: true });
|
|
780
|
+
},
|
|
781
|
+
onKeyUp: (e) => e.stopPropagation(),
|
|
782
|
+
onCopy: (e) => {
|
|
783
|
+
const text = controller.getSelectedText();
|
|
784
|
+
if (text) {
|
|
785
|
+
e.clipboardData.setData("text/plain", text);
|
|
786
|
+
e.preventDefault();
|
|
787
|
+
}
|
|
788
|
+
e.stopPropagation();
|
|
789
|
+
},
|
|
790
|
+
onCut: (e) => {
|
|
791
|
+
const text = controller.cutText();
|
|
792
|
+
if (text) {
|
|
793
|
+
e.clipboardData.setData("text/plain", text);
|
|
794
|
+
e.preventDefault();
|
|
795
|
+
}
|
|
796
|
+
e.stopPropagation();
|
|
797
|
+
},
|
|
798
|
+
onPaste: (e) => {
|
|
799
|
+
const text = e.clipboardData.getData("text/plain");
|
|
800
|
+
if (text) controller.textInput(text);
|
|
801
|
+
e.preventDefault();
|
|
802
|
+
e.stopPropagation();
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
) }),
|
|
806
|
+
state.symbolEdit && // Isolation mode: which symbol, and the way out (Escape with nothing selected works too).
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("foreignObject", { "data-vector-symbol-edit": state.symbolEdit.symbolId, x: 8, y: 8, width: 320, height: 32, style: { overflow: "visible" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
808
|
+
"div",
|
|
809
|
+
{
|
|
810
|
+
style: { display: "inline-flex", alignItems: "center", gap: 8, padding: "4px 8px", borderRadius: 6, background: "rgba(15,23,42,0.85)", color: "#fff", font: "12px system-ui, sans-serif" },
|
|
811
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
812
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
813
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
814
|
+
children: [
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
816
|
+
"Symbol: ",
|
|
817
|
+
state.symbolEdit.name
|
|
818
|
+
] }),
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", "aria-label": "Exit symbol", style: { border: "1px solid rgba(255,255,255,0.4)", borderRadius: 4, padding: "0 6px", background: "transparent", color: "#fff", cursor: "pointer" }, onClick: () => controller.exitSymbolEdit(), children: "Done" })
|
|
820
|
+
]
|
|
821
|
+
}
|
|
822
|
+
) }),
|
|
649
823
|
edit && editAt && // Width Point Edit (double-click with the width tool), beside the point.
|
|
650
824
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("foreignObject", { "data-vector-width-point-edit": "", x: editAt.x + 12, y: editAt.y + 12, width: 180, height: 140, style: { overflow: "visible" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VectorWidthPointEditor, { controller, edit, accentColor }, `${edit.nodeId}:${edit.index}:${edit.t}`) })
|
|
651
825
|
]
|
|
@@ -654,8 +828,8 @@ function VectorCanvas({
|
|
|
654
828
|
}
|
|
655
829
|
|
|
656
830
|
// src/vector/VectorToolbar.tsx
|
|
657
|
-
var
|
|
658
|
-
var
|
|
831
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
832
|
+
var import_vector14 = require("@pixerate/editor/vector");
|
|
659
833
|
|
|
660
834
|
// src/vector/VectorEffectsPanel.tsx
|
|
661
835
|
var import_vector4 = require("@pixerate/editor/vector");
|
|
@@ -1234,16 +1408,528 @@ function VectorMaskPanel({ controller, className }) {
|
|
|
1234
1408
|
] });
|
|
1235
1409
|
}
|
|
1236
1410
|
|
|
1237
|
-
// src/vector/
|
|
1411
|
+
// src/vector/VectorTextPanel.tsx
|
|
1412
|
+
var import_react5 = require("react");
|
|
1238
1413
|
var import_vector8 = require("@pixerate/editor/vector");
|
|
1239
1414
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1415
|
+
var buttonClass5 = "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";
|
|
1416
|
+
var inputClass = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1417
|
+
var labelClass4 = "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground";
|
|
1418
|
+
var num = (v) => {
|
|
1419
|
+
const n = parseFloat(v);
|
|
1420
|
+
return Number.isFinite(n) ? n : null;
|
|
1421
|
+
};
|
|
1422
|
+
function VectorTextPanel({ controller, className }) {
|
|
1423
|
+
const state = useVectorEditorState(controller);
|
|
1424
|
+
const listId = `vector-fonts-${(0, import_react5.useId)().replace(/:/g, "")}`;
|
|
1425
|
+
const panel = (0, import_vector8.getVectorTextPanel)(state);
|
|
1426
|
+
if (!panel) return null;
|
|
1427
|
+
const f = panel.font;
|
|
1428
|
+
const style = (patch, merge) => (0, import_vector8.applyVectorTextStyle)(controller, patch, merge ? { merge } : {});
|
|
1429
|
+
const where = panel.target === "range" ? "Selected characters" : panel.target === "nodes" ? "Selected text" : "New text";
|
|
1430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-text-panel": panel.target, "aria-label": "Text", children: [
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: labelClass4, children: "Text" }),
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[11px] text-muted-foreground", children: where })
|
|
1434
|
+
] }),
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1437
|
+
"input",
|
|
1438
|
+
{
|
|
1439
|
+
"aria-label": "Font family",
|
|
1440
|
+
className: inputClass,
|
|
1441
|
+
list: listId,
|
|
1442
|
+
placeholder: "Mixed",
|
|
1443
|
+
defaultValue: f.fontFamily ?? "",
|
|
1444
|
+
onKeyDown: (e) => {
|
|
1445
|
+
if (e.key === "Enter") e.target.blur();
|
|
1446
|
+
},
|
|
1447
|
+
onBlur: (e) => {
|
|
1448
|
+
const v = e.target.value.trim();
|
|
1449
|
+
if (v && v !== f.fontFamily) style({ fontFamily: v });
|
|
1450
|
+
}
|
|
1451
|
+
},
|
|
1452
|
+
`family:${f.fontFamily}`
|
|
1453
|
+
),
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("datalist", { id: listId, children: panel.families.map((fam) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: fam }, fam)) })
|
|
1455
|
+
] }),
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { "aria-label": "Font weight", className: inputClass, value: f.fontWeight ?? "", onChange: (e) => style({ fontWeight: Number(e.target.value) }), children: [
|
|
1458
|
+
f.fontWeight === null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "Mixed" }),
|
|
1459
|
+
import_vector8.VECTOR_FONT_WEIGHTS.map((w) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: w.value, children: w.label }, w.value)),
|
|
1460
|
+
f.fontWeight !== null && !import_vector8.VECTOR_FONT_WEIGHTS.some((w) => w.value === f.fontWeight) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: f.fontWeight, children: f.fontWeight })
|
|
1461
|
+
] }),
|
|
1462
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1463
|
+
"input",
|
|
1464
|
+
{
|
|
1465
|
+
type: "number",
|
|
1466
|
+
"aria-label": "Font size",
|
|
1467
|
+
title: "Font size",
|
|
1468
|
+
className: `${inputClass} w-14 flex-none`,
|
|
1469
|
+
min: 0.5,
|
|
1470
|
+
step: 1,
|
|
1471
|
+
placeholder: "\u2014",
|
|
1472
|
+
value: f.fontSize === null ? "" : Math.round(f.fontSize * 100) / 100,
|
|
1473
|
+
onChange: (e) => {
|
|
1474
|
+
const v = num(e.target.value);
|
|
1475
|
+
if (v !== null && v >= 0.5) style({ fontSize: v }, "text-size");
|
|
1476
|
+
},
|
|
1477
|
+
onBlur: () => controller.endMergedEdit()
|
|
1478
|
+
}
|
|
1479
|
+
)
|
|
1480
|
+
] }),
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Bold", "aria-pressed": (f.fontWeight ?? 0) >= 600, onClick: () => style({ fontWeight: (f.fontWeight ?? 400) >= 600 ? 400 : 700 }), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: "B" }) }),
|
|
1483
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Italic", "aria-pressed": f.italic === true, onClick: () => style({ italic: !f.italic }), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("i", { children: "I" }) }),
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Underline", "aria-pressed": f.underline === true, onClick: () => style({ underline: !f.underline }), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("u", { children: "U" }) }),
|
|
1485
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Strike through", "aria-pressed": f.strikethrough === true, onClick: () => style({ strikethrough: !f.strikethrough }), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("s", { children: "S" }) })
|
|
1486
|
+
] }),
|
|
1487
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex flex-1 items-center gap-1 text-xs text-foreground", title: "Tracking (1/1000 em)", children: [
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "VA" }),
|
|
1490
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1491
|
+
"input",
|
|
1492
|
+
{
|
|
1493
|
+
type: "number",
|
|
1494
|
+
"aria-label": "Tracking",
|
|
1495
|
+
className: inputClass,
|
|
1496
|
+
step: 10,
|
|
1497
|
+
placeholder: "\u2014",
|
|
1498
|
+
value: f.tracking ?? "",
|
|
1499
|
+
onChange: (e) => style({ tracking: num(e.target.value) ?? 0 }, "text-tracking"),
|
|
1500
|
+
onBlur: () => controller.endMergedEdit()
|
|
1501
|
+
}
|
|
1502
|
+
)
|
|
1503
|
+
] }),
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "flex flex-1 items-center gap-1 text-xs text-foreground", title: "Leading (empty: auto)", children: [
|
|
1505
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "\u2195" }),
|
|
1506
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1507
|
+
"input",
|
|
1508
|
+
{
|
|
1509
|
+
type: "number",
|
|
1510
|
+
"aria-label": "Leading",
|
|
1511
|
+
className: inputClass,
|
|
1512
|
+
min: 0,
|
|
1513
|
+
step: 1,
|
|
1514
|
+
placeholder: "Auto",
|
|
1515
|
+
value: f.leading ?? "",
|
|
1516
|
+
onChange: (e) => style({ leading: num(e.target.value) }, "text-leading"),
|
|
1517
|
+
onBlur: () => controller.endMergedEdit()
|
|
1518
|
+
}
|
|
1519
|
+
)
|
|
1520
|
+
] })
|
|
1521
|
+
] }),
|
|
1522
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Alignment", children: import_vector8.VECTOR_TEXT_ALIGN_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1523
|
+
"button",
|
|
1524
|
+
{
|
|
1525
|
+
type: "button",
|
|
1526
|
+
className: buttonClass5,
|
|
1527
|
+
"aria-label": `Align ${o.label}`,
|
|
1528
|
+
"aria-pressed": panel.align === o.value,
|
|
1529
|
+
onClick: () => (0, import_vector8.applyVectorParagraphStyle)(controller, { align: o.value }),
|
|
1530
|
+
children: o.label
|
|
1531
|
+
},
|
|
1532
|
+
o.value
|
|
1533
|
+
)) }),
|
|
1534
|
+
panel.target !== "defaults" && panel.ids.length === 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1536
|
+
"button",
|
|
1537
|
+
{
|
|
1538
|
+
type: "button",
|
|
1539
|
+
className: buttonClass5,
|
|
1540
|
+
"aria-pressed": panel.frame === "point",
|
|
1541
|
+
title: "Point text: no wrapping",
|
|
1542
|
+
onClick: () => controller.setTextFrame(panel.ids[0], { kind: "point" }),
|
|
1543
|
+
children: "Point"
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1547
|
+
"button",
|
|
1548
|
+
{
|
|
1549
|
+
type: "button",
|
|
1550
|
+
className: buttonClass5,
|
|
1551
|
+
"aria-pressed": panel.frame === "area",
|
|
1552
|
+
title: "Area text: wraps in a box",
|
|
1553
|
+
onClick: () => controller.setTextFrame(panel.ids[0], { kind: "area" }),
|
|
1554
|
+
children: "Area"
|
|
1555
|
+
}
|
|
1556
|
+
)
|
|
1557
|
+
] }),
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1560
|
+
"button",
|
|
1561
|
+
{
|
|
1562
|
+
type: "button",
|
|
1563
|
+
className: buttonClass5,
|
|
1564
|
+
"data-vector-text-action": "type-on-path",
|
|
1565
|
+
disabled: !panel.pathId,
|
|
1566
|
+
title: panel.pathId ? "Type on a Path: set text along the selected path" : "Select a path to set text along it",
|
|
1567
|
+
onClick: () => {
|
|
1568
|
+
const r = controller.typeOnPath(panel.pathId, { text: "Text on a path" });
|
|
1569
|
+
if (r.ok && r.id) controller.editText(r.id, { anchor: 0, focus: "Text on a path".length });
|
|
1570
|
+
},
|
|
1571
|
+
children: "Type on path"
|
|
1572
|
+
}
|
|
1573
|
+
),
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1575
|
+
"button",
|
|
1576
|
+
{
|
|
1577
|
+
type: "button",
|
|
1578
|
+
className: buttonClass5,
|
|
1579
|
+
"data-vector-text-action": "create-outlines",
|
|
1580
|
+
disabled: panel.target !== "nodes" || !panel.outlines,
|
|
1581
|
+
title: panel.outlines ? "Create Outlines: turn the text into paths" : "Create Outlines needs a font with outlines (load one)",
|
|
1582
|
+
onClick: () => controller.createOutlines({ ids: panel.ids }),
|
|
1583
|
+
children: "Create outlines"
|
|
1584
|
+
}
|
|
1585
|
+
)
|
|
1586
|
+
] })
|
|
1587
|
+
] });
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
// src/vector/VectorSymbolsPanel.tsx
|
|
1591
|
+
var import_react6 = require("react");
|
|
1592
|
+
var import_vector9 = require("@pixerate/editor/vector");
|
|
1593
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1594
|
+
var buttonClass6 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40 aria-pressed:bg-primary aria-pressed:text-primary-foreground";
|
|
1240
1595
|
var selectClass5 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1241
|
-
var
|
|
1242
|
-
|
|
1596
|
+
var labelClass5 = "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground";
|
|
1597
|
+
function VectorSymbolsPanel({ controller, className }) {
|
|
1598
|
+
const state = useVectorEditorState(controller);
|
|
1599
|
+
const uid = (0, import_react6.useId)().replace(/:/g, "");
|
|
1600
|
+
const panel = (0, import_vector9.getVectorSymbolsPanel)(state, { idPrefix: `vsym${uid}-` });
|
|
1601
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
1602
|
+
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1603
|
+
const inst = panel.instance;
|
|
1604
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-symbols-panel": "", "aria-label": "Symbols", children: [
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: labelClass5, children: "Symbols" }),
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "data-vector-symbol-action": "make", disabled: !panel.canMake, title: "New Symbol from the selection (F8)", onClick: () => report(controller.makeSymbol()), children: "New" }),
|
|
1608
|
+
panel.editing && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "data-vector-symbol-action": "exit", title: "Leave the symbol (Escape)", onClick: () => controller.exitSymbolEdit(), children: "Done" })
|
|
1609
|
+
] }),
|
|
1610
|
+
panel.symbols.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-1", children: panel.symbols.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { "data-vector-symbol": s.id, "data-editing": s.editing || void 0, className: "flex items-center gap-1", children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { viewBox: s.viewBox, width: 28, height: 28, className: "shrink-0 rounded border border-border bg-background", "aria-hidden": "true", children: [
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorGradientDefs, { defs: s.scene.defs }),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorFilterDefs, { filters: s.scene.filters }),
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(VectorSceneNodes, { nodes: s.scene.nodes })
|
|
1615
|
+
] }),
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "min-w-0 flex-1 truncate text-xs text-foreground", title: `${s.name} \xB7 ${s.instances} instance${s.instances === 1 ? "" : "s"}`, children: [
|
|
1617
|
+
s.name,
|
|
1618
|
+
" ",
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
1620
|
+
"\xB7 ",
|
|
1621
|
+
s.instances
|
|
1622
|
+
] })
|
|
1623
|
+
] }),
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "aria-label": `Place ${s.name}`, title: "Place an instance", onClick: () => report(controller.placeSymbol(s.id)), children: "+" }),
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "aria-label": `Edit ${s.name}`, "aria-pressed": s.editing, title: "Edit Symbol (isolation mode)", onClick: () => report(controller.editSymbol(s.id)), children: "\u270E" }),
|
|
1626
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "aria-label": `Delete ${s.name}`, title: "Delete the symbol (its instances become groups)", onClick: () => report(controller.deleteSymbol(s.id, { detach: true })), children: "\xD7" })
|
|
1627
|
+
] }, s.id)) }),
|
|
1628
|
+
inst && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-1", "data-vector-instance": inst.id, children: [
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("select", { "aria-label": "Instance symbol", className: selectClass5, value: inst.symbolId, onChange: (e) => report(controller.replaceSymbol(e.target.value, { ids: [inst.id] })), children: panel.symbols.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: s.id, children: s.name }, s.id)) }),
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, title: "Break Link to Symbol: a plain group of its art", onClick: () => report(controller.detachInstances({ ids: [inst.id] })), children: "Detach" })
|
|
1632
|
+
] }),
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1635
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", "aria-label": "Scale strokes", checked: inst.scaleStrokes, onChange: (e) => report(controller.setInstanceOptions({ scaleStrokes: e.target.checked }, { ids: [inst.id] })) }),
|
|
1636
|
+
"Scale strokes"
|
|
1637
|
+
] }),
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Paint every fill of the art in this instance", children: [
|
|
1639
|
+
"Tint",
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1641
|
+
"input",
|
|
1642
|
+
{
|
|
1643
|
+
type: "color",
|
|
1644
|
+
"aria-label": "Instance fill",
|
|
1645
|
+
className: "h-6 w-8 rounded border border-border",
|
|
1646
|
+
value: (0, import_vector9.vectorPaintToHex)(inst.fill ?? void 0) ?? "#000000",
|
|
1647
|
+
onChange: (e) => report(controller.setInstanceOptions({ fill: e.target.value }, { ids: [inst.id] }))
|
|
1648
|
+
}
|
|
1649
|
+
)
|
|
1650
|
+
] }),
|
|
1651
|
+
inst.fill !== null && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: buttonClass6, "aria-label": "Clear tint", onClick: () => report(controller.setInstanceOptions({ fill: null }, { ids: [inst.id] })), children: "\xD7" })
|
|
1652
|
+
] })
|
|
1653
|
+
] }),
|
|
1654
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-destructive", children: error })
|
|
1655
|
+
] });
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
// src/vector/VectorConstraintsPanel.tsx
|
|
1659
|
+
var import_react7 = require("react");
|
|
1660
|
+
var import_vector10 = require("@pixerate/editor/vector");
|
|
1661
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1662
|
+
var buttonClass7 = "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";
|
|
1663
|
+
var inputClass2 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1664
|
+
var labelClass6 = "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground";
|
|
1665
|
+
function VectorConstraintsPanel({ controller, className }) {
|
|
1666
|
+
const state = useVectorEditorState(controller);
|
|
1667
|
+
const panel = (0, import_vector10.getVectorConstraintPanel)(state);
|
|
1668
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
1669
|
+
const [param, setParam] = (0, import_react7.useState)({ name: "", value: "" });
|
|
1670
|
+
const report = (r) => setError(r.ok ? null : r.message ?? null);
|
|
1671
|
+
const add = (a) => report(controller.addConstraint({ kind: a.kind, refs: a.refs }));
|
|
1672
|
+
if (!panel.actions.length && !panel.constraints.length && !state.document.constraints?.length && state.tool !== "direct") return null;
|
|
1673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-constraints-panel": "", "data-dof-status": panel.dof.status, "aria-label": "Constraints", children: [
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: labelClass6, children: "Constraints" }),
|
|
1676
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "flex-1 truncate text-[11px] text-muted-foreground", "data-vector-dof": "", children: panel.dof.message }),
|
|
1677
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: buttonClass7, title: "Auto Constrain: add what the selection (or the drawing) nearly satisfies", onClick: () => report(controller.autoConstrain()), children: "Auto" })
|
|
1678
|
+
] }),
|
|
1679
|
+
panel.actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-wrap gap-1", role: "group", "aria-label": "Add constraint", children: panel.actions.map((a) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: buttonClass7, "data-vector-constraint-action": a.kind, title: `Add ${a.label}`, onClick: () => add(a), children: a.label }, a.kind)) }),
|
|
1680
|
+
panel.constraints.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: "space-y-1", children: panel.constraints.map((c) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { "data-vector-constraint": c.id, "data-satisfied": c.satisfied && !c.conflict ? "true" : "false", className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1681
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: `min-w-0 flex-1 truncate ${c.conflict || !c.satisfied ? "text-destructive" : ""}`, children: [
|
|
1682
|
+
c.label,
|
|
1683
|
+
c.name ? ` ${c.name}` : ""
|
|
1684
|
+
] }),
|
|
1685
|
+
c.value !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1686
|
+
"input",
|
|
1687
|
+
{
|
|
1688
|
+
"aria-label": `Value of ${c.name ?? c.id}`,
|
|
1689
|
+
className: `${inputClass2} w-16 flex-none`,
|
|
1690
|
+
defaultValue: c.value,
|
|
1691
|
+
onKeyDown: (e) => {
|
|
1692
|
+
if (e.key === "Enter") e.target.blur();
|
|
1693
|
+
},
|
|
1694
|
+
onBlur: (e) => {
|
|
1695
|
+
if (e.target.value.trim() !== c.value) report(controller.setConstraintValue(c.id, e.target.value));
|
|
1696
|
+
}
|
|
1697
|
+
},
|
|
1698
|
+
`${c.id}:${c.value}`
|
|
1699
|
+
),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: buttonClass7, "aria-label": `Remove ${c.label} constraint`, onClick: () => report(controller.removeConstraints([c.id])), children: "\xD7" })
|
|
1701
|
+
] }, c.id)) }),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1", "aria-label": "Parameters", children: [
|
|
1703
|
+
panel.parameters.map((p) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs", children: [
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-12 truncate font-mono", children: p.name }),
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1706
|
+
"input",
|
|
1707
|
+
{
|
|
1708
|
+
"aria-label": `Parameter ${p.name}`,
|
|
1709
|
+
className: inputClass2,
|
|
1710
|
+
defaultValue: p.value,
|
|
1711
|
+
onKeyDown: (e) => {
|
|
1712
|
+
if (e.key === "Enter") e.target.blur();
|
|
1713
|
+
},
|
|
1714
|
+
onBlur: (e) => {
|
|
1715
|
+
if (e.target.value.trim() !== p.value) report(controller.setConstraintValue(p.name, e.target.value));
|
|
1716
|
+
}
|
|
1717
|
+
},
|
|
1718
|
+
`${p.name}:${p.value}`
|
|
1719
|
+
),
|
|
1720
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-10 text-right text-muted-foreground", children: p.result === null ? "!" : Math.round(p.result * 100) / 100 })
|
|
1721
|
+
] }, p.name)),
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1723
|
+
"form",
|
|
1724
|
+
{
|
|
1725
|
+
className: "flex items-center gap-1",
|
|
1726
|
+
onSubmit: (e) => {
|
|
1727
|
+
e.preventDefault();
|
|
1728
|
+
if (!param.name.trim()) return;
|
|
1729
|
+
const r = controller.setConstraintValue(param.name.trim(), param.value);
|
|
1730
|
+
report(r);
|
|
1731
|
+
if (r.ok) setParam({ name: "", value: "" });
|
|
1732
|
+
},
|
|
1733
|
+
children: [
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { "aria-label": "New parameter name", placeholder: "name", className: `${inputClass2} w-12 flex-none`, value: param.name, onChange: (e) => setParam({ ...param, name: e.target.value }) }),
|
|
1735
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { "aria-label": "New parameter value", placeholder: "value", className: inputClass2, value: param.value, onChange: (e) => setParam({ ...param, value: e.target.value }) }),
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "submit", className: buttonClass7, "aria-label": "Add parameter", children: "+" })
|
|
1737
|
+
]
|
|
1738
|
+
}
|
|
1739
|
+
)
|
|
1740
|
+
] }),
|
|
1741
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-[11px] text-destructive", children: error })
|
|
1742
|
+
] });
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
// src/vector/VectorFramePanel.tsx
|
|
1746
|
+
var import_vector11 = require("@pixerate/editor/vector");
|
|
1747
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1748
|
+
var buttonClass8 = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
|
|
1749
|
+
var selectClass6 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1750
|
+
var numberClass4 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
1751
|
+
function VectorFramePanel({ controller, className }) {
|
|
1752
|
+
const state = useVectorEditorState(controller);
|
|
1753
|
+
const panel = (0, import_vector11.getVectorFramePanel)(state);
|
|
1754
|
+
const f = panel.frame;
|
|
1755
|
+
const ids = f ? [f.id] : void 0;
|
|
1756
|
+
const fillHex = f ? (0, import_vector11.vectorPaintToHex)(f.frame.fill ?? null) : null;
|
|
1757
|
+
const number = (key, label) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "w-4 text-muted-foreground", children: label }),
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1760
|
+
"input",
|
|
1761
|
+
{
|
|
1762
|
+
type: "number",
|
|
1763
|
+
step: "1",
|
|
1764
|
+
min: key === "width" || key === "height" ? 1 : void 0,
|
|
1765
|
+
"aria-label": `Frame ${key}`,
|
|
1766
|
+
className: numberClass4,
|
|
1767
|
+
defaultValue: Math.round(f.frame[key] * 100) / 100,
|
|
1768
|
+
onKeyDown: (e) => {
|
|
1769
|
+
if (e.key === "Enter") e.currentTarget.blur();
|
|
1770
|
+
},
|
|
1771
|
+
onBlur: (e) => {
|
|
1772
|
+
const n = parseFloat(e.target.value);
|
|
1773
|
+
if (Number.isFinite(n) && n !== Math.round(f.frame[key] * 100) / 100 && (key === "x" || key === "y" || n > 0)) controller.setFrame({ [key]: n }, { ids });
|
|
1774
|
+
}
|
|
1775
|
+
},
|
|
1776
|
+
`${f.id}:${f.frame[key]}`
|
|
1777
|
+
)
|
|
1778
|
+
] });
|
|
1779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-frame-panel": "", "aria-label": "Frame", children: [
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Frame" }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1783
|
+
"button",
|
|
1784
|
+
{
|
|
1785
|
+
type: "button",
|
|
1786
|
+
"data-vector-frame-action": "frame-selection",
|
|
1787
|
+
className: buttonClass8,
|
|
1788
|
+
title: "Frame Selection: put the selection in a frame fitted to it",
|
|
1789
|
+
"aria-label": "Frame Selection",
|
|
1790
|
+
disabled: !state.selection.length,
|
|
1791
|
+
onClick: () => controller.frameSelection(),
|
|
1792
|
+
children: "Frame selection"
|
|
1793
|
+
}
|
|
1794
|
+
)
|
|
1795
|
+
] }),
|
|
1796
|
+
f && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-2", "data-vector-frame": f.id, children: [
|
|
1797
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-2 gap-1", children: [
|
|
1798
|
+
number("x", "X"),
|
|
1799
|
+
number("y", "Y"),
|
|
1800
|
+
number("width", "W"),
|
|
1801
|
+
number("height", "H")
|
|
1802
|
+
] }),
|
|
1803
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1804
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
1805
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1806
|
+
"input",
|
|
1807
|
+
{
|
|
1808
|
+
type: "checkbox",
|
|
1809
|
+
"aria-label": "Frame fill on",
|
|
1810
|
+
checked: f.frame.fill !== void 0 && f.frame.fill !== null,
|
|
1811
|
+
onChange: (e) => controller.setFrame({ fill: e.target.checked ? fillHex ?? "#ffffff" : null }, { ids })
|
|
1812
|
+
}
|
|
1813
|
+
),
|
|
1814
|
+
"Fill"
|
|
1815
|
+
] }),
|
|
1816
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1817
|
+
"input",
|
|
1818
|
+
{
|
|
1819
|
+
type: "color",
|
|
1820
|
+
"aria-label": "Frame fill colour",
|
|
1821
|
+
className: "h-7 w-10 cursor-pointer rounded border border-border bg-background disabled:opacity-40",
|
|
1822
|
+
disabled: f.frame.fill === void 0 || f.frame.fill === null,
|
|
1823
|
+
value: fillHex ?? "#ffffff",
|
|
1824
|
+
onChange: (e) => controller.setFrame({ fill: e.target.value }, { ids, merge: "frame-fill" })
|
|
1825
|
+
}
|
|
1826
|
+
),
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", title: "Hide what lies outside the frame", children: [
|
|
1828
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", "aria-label": "Clip content", checked: f.frame.clip !== false, onChange: (e) => controller.setFrame({ clip: e.target.checked }, { ids }) }),
|
|
1829
|
+
"Clip"
|
|
1830
|
+
] })
|
|
1831
|
+
] })
|
|
1832
|
+
] }),
|
|
1833
|
+
panel.resizing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-1", "data-vector-resizing": "", children: [
|
|
1834
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1835
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "w-16", children: "Horizontal" }),
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1837
|
+
"select",
|
|
1838
|
+
{
|
|
1839
|
+
"aria-label": "Horizontal constraint",
|
|
1840
|
+
className: selectClass6,
|
|
1841
|
+
value: panel.resizing.horizontal,
|
|
1842
|
+
onChange: (e) => controller.setResizing({ horizontal: e.target.value }, { ids: panel.resizing.ids }),
|
|
1843
|
+
children: [
|
|
1844
|
+
panel.resizing.horizontal === "mixed" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "mixed", disabled: true, children: "Mixed" }),
|
|
1845
|
+
import_vector11.VECTOR_HORIZONTAL_RESIZING.map((h) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: h, children: import_vector11.VECTOR_HORIZONTAL_RESIZING_LABELS[h] }, h))
|
|
1846
|
+
]
|
|
1847
|
+
}
|
|
1848
|
+
)
|
|
1849
|
+
] }),
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "w-16", children: "Vertical" }),
|
|
1852
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1853
|
+
"select",
|
|
1854
|
+
{
|
|
1855
|
+
"aria-label": "Vertical constraint",
|
|
1856
|
+
className: selectClass6,
|
|
1857
|
+
value: panel.resizing.vertical,
|
|
1858
|
+
onChange: (e) => controller.setResizing({ vertical: e.target.value }, { ids: panel.resizing.ids }),
|
|
1859
|
+
children: [
|
|
1860
|
+
panel.resizing.vertical === "mixed" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "mixed", disabled: true, children: "Mixed" }),
|
|
1861
|
+
import_vector11.VECTOR_VERTICAL_RESIZING.map((v) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: v, children: import_vector11.VECTOR_VERTICAL_RESIZING_LABELS[v] }, v))
|
|
1862
|
+
]
|
|
1863
|
+
}
|
|
1864
|
+
)
|
|
1865
|
+
] })
|
|
1866
|
+
] })
|
|
1867
|
+
] });
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
// src/vector/VectorConnectorPanel.tsx
|
|
1871
|
+
var import_vector12 = require("@pixerate/editor/vector");
|
|
1872
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1873
|
+
var buttonClass9 = "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";
|
|
1874
|
+
var selectClass7 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1875
|
+
var numberClass5 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
1876
|
+
function VectorConnectorPanel({ controller, className }) {
|
|
1877
|
+
const state = useVectorEditorState(controller);
|
|
1878
|
+
const panel = (0, import_vector12.getVectorConnectorPanel)(state);
|
|
1879
|
+
if (!panel) return null;
|
|
1880
|
+
const ids = [panel.id];
|
|
1881
|
+
const end = (key, label, e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", "data-vector-connector-end": key, children: [
|
|
1882
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
1883
|
+
e ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1885
|
+
"select",
|
|
1886
|
+
{
|
|
1887
|
+
"aria-label": `${label} side`,
|
|
1888
|
+
className: selectClass7,
|
|
1889
|
+
value: e.side ?? "auto",
|
|
1890
|
+
onChange: (ev) => controller.setConnector({ [key]: { nodeId: e.nodeId, side: ev.target.value } }, { ids }),
|
|
1891
|
+
children: import_vector12.VECTOR_CONNECTOR_SIDES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: s, children: import_vector12.VECTOR_CONNECTOR_SIDE_LABELS[s] }, s))
|
|
1892
|
+
}
|
|
1893
|
+
),
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass9, title: "Unglue: the end stays where it is", "aria-label": `Unglue ${label.toLowerCase()}`, onClick: () => controller.setConnector({ [key]: null }, { ids }), children: "Unglue" })
|
|
1895
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Free" })
|
|
1896
|
+
] });
|
|
1897
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-connector-panel": panel.id, "aria-label": "Connector", children: [
|
|
1898
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1899
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Connector" }),
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("select", { "aria-label": "Connector route", className: selectClass7, value: panel.route, onChange: (e) => controller.setConnector({ route: e.target.value }, { ids }), children: import_vector12.VECTOR_CONNECTOR_ROUTES.map((r) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: r, children: import_vector12.VECTOR_CONNECTOR_ROUTE_LABELS[r] }, r)) }),
|
|
1901
|
+
panel.route === "elbow" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1902
|
+
"input",
|
|
1903
|
+
{
|
|
1904
|
+
type: "number",
|
|
1905
|
+
min: "0",
|
|
1906
|
+
step: "1",
|
|
1907
|
+
"aria-label": "Elbow radius",
|
|
1908
|
+
title: "Corner radius of the bends",
|
|
1909
|
+
className: numberClass5,
|
|
1910
|
+
value: panel.radius,
|
|
1911
|
+
onChange: (e) => {
|
|
1912
|
+
const n = parseFloat(e.target.value);
|
|
1913
|
+
if (Number.isFinite(n) && n >= 0) controller.setConnector({ radius: n }, { ids });
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
)
|
|
1917
|
+
] }),
|
|
1918
|
+
end("start", "Start", panel.start),
|
|
1919
|
+
end("end", "End", panel.end)
|
|
1920
|
+
] });
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// src/vector/VectorGradientEditor.tsx
|
|
1924
|
+
var import_vector13 = require("@pixerate/editor/vector");
|
|
1925
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1926
|
+
var selectClass8 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
1927
|
+
var numberClass6 = "h-7 w-14 rounded border border-border bg-background px-1.5 text-xs";
|
|
1928
|
+
var buttonClass10 = "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";
|
|
1243
1929
|
var percent = (v) => Math.round(v * 1e3) / 10;
|
|
1244
1930
|
function VectorGradientEditor({ controller, className }) {
|
|
1245
1931
|
const state = useVectorEditorState(controller);
|
|
1246
|
-
const ed = (0,
|
|
1932
|
+
const ed = (0, import_vector13.getVectorGradientEditor)(state);
|
|
1247
1933
|
if (!ed) return null;
|
|
1248
1934
|
const g = ed.gradient;
|
|
1249
1935
|
const sel = ed.selected;
|
|
@@ -1251,26 +1937,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1251
1937
|
const setType = (value) => {
|
|
1252
1938
|
if (value === "solid") {
|
|
1253
1939
|
const first = ed.stops[0];
|
|
1254
|
-
controller.setStyle({ [ed.target]: (0,
|
|
1940
|
+
controller.setStyle({ [ed.target]: (0, import_vector13.vectorPaintToHex)(first?.color) ?? first?.color ?? "#000000" }, void 0, { label: "Solid Colour" });
|
|
1255
1941
|
} else controller.setGradient({ type: value });
|
|
1256
1942
|
};
|
|
1257
|
-
return /* @__PURE__ */ (0,
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
1259
|
-
/* @__PURE__ */ (0,
|
|
1260
|
-
["fill", "stroke"].map((t) => /* @__PURE__ */ (0,
|
|
1261
|
-
ed.mixed && /* @__PURE__ */ (0,
|
|
1943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `space-y-1.5 ${className ?? ""}`, "data-vector-gradient-editor": ed.target, "aria-label": "Gradient", children: [
|
|
1944
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1945
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Gradient" }),
|
|
1946
|
+
["fill", "stroke"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "aria-pressed": ed.target === t, onClick: () => controller.setGradientTarget(t), children: t === "fill" ? "Fill" : "Stroke" }, t)),
|
|
1947
|
+
ed.mixed && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1262
1948
|
] }),
|
|
1263
|
-
/* @__PURE__ */ (0,
|
|
1264
|
-
/* @__PURE__ */ (0,
|
|
1265
|
-
/* @__PURE__ */ (0,
|
|
1266
|
-
/* @__PURE__ */ (0,
|
|
1267
|
-
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Type" }),
|
|
1951
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("select", { "aria-label": "Gradient type", className: selectClass8, value: ed.type ?? "solid", onChange: (e) => setType(e.target.value), children: [
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "solid", children: "Solid" }),
|
|
1953
|
+
import_vector13.VECTOR_GRADIENT_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: t, children: import_vector13.VECTOR_GRADIENT_TYPE_LABELS[t] }, t))
|
|
1268
1954
|
] }),
|
|
1269
|
-
/* @__PURE__ */ (0,
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "aria-label": "Reverse gradient", title: "Reverse gradient", disabled: !g, onClick: () => controller.reverseGradient(), children: "\u21C4" })
|
|
1270
1956
|
] }),
|
|
1271
|
-
g && /* @__PURE__ */ (0,
|
|
1272
|
-
/* @__PURE__ */ (0,
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1957
|
+
g && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1958
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative h-8", "data-vector-gradient-ramp": "", children: [
|
|
1959
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1274
1960
|
"div",
|
|
1275
1961
|
{
|
|
1276
1962
|
role: "button",
|
|
@@ -1284,7 +1970,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1284
1970
|
}
|
|
1285
1971
|
}
|
|
1286
1972
|
),
|
|
1287
|
-
ed.stops.map((s) => /* @__PURE__ */ (0,
|
|
1973
|
+
ed.stops.map((s) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1288
1974
|
"button",
|
|
1289
1975
|
{
|
|
1290
1976
|
type: "button",
|
|
@@ -1298,21 +1984,21 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1298
1984
|
s.index
|
|
1299
1985
|
))
|
|
1300
1986
|
] }),
|
|
1301
|
-
sel && /* @__PURE__ */ (0,
|
|
1302
|
-
/* @__PURE__ */ (0,
|
|
1987
|
+
sel && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", "data-vector-gradient-selected-stop": sel.index, children: [
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1303
1989
|
"input",
|
|
1304
1990
|
{
|
|
1305
1991
|
type: "color",
|
|
1306
1992
|
"aria-label": "Stop colour",
|
|
1307
1993
|
className: "h-7 w-9 cursor-pointer rounded border border-border bg-background",
|
|
1308
|
-
value: (0,
|
|
1994
|
+
value: (0, import_vector13.vectorPaintToHex)(sel.color) ?? "#000000",
|
|
1309
1995
|
onChange: (e) => controller.setGradientStop(sel.index, { color: e.target.value }, { merge: `gradient-stop-color-${sel.index}` }),
|
|
1310
1996
|
onBlur: end
|
|
1311
1997
|
}
|
|
1312
1998
|
),
|
|
1313
|
-
/* @__PURE__ */ (0,
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1314
2000
|
"Opacity",
|
|
1315
|
-
/* @__PURE__ */ (0,
|
|
2001
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1316
2002
|
"input",
|
|
1317
2003
|
{
|
|
1318
2004
|
type: "number",
|
|
@@ -1320,7 +2006,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1320
2006
|
max: 100,
|
|
1321
2007
|
step: 5,
|
|
1322
2008
|
"aria-label": "Stop opacity",
|
|
1323
|
-
className:
|
|
2009
|
+
className: numberClass6,
|
|
1324
2010
|
value: percent(sel.opacity ?? 1),
|
|
1325
2011
|
onChange: (e) => {
|
|
1326
2012
|
const n = parseFloat(e.target.value);
|
|
@@ -1329,9 +2015,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1329
2015
|
}
|
|
1330
2016
|
)
|
|
1331
2017
|
] }),
|
|
1332
|
-
/* @__PURE__ */ (0,
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1333
2019
|
"At",
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
2020
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1335
2021
|
"input",
|
|
1336
2022
|
{
|
|
1337
2023
|
type: "number",
|
|
@@ -1339,7 +2025,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1339
2025
|
max: 100,
|
|
1340
2026
|
step: 1,
|
|
1341
2027
|
"aria-label": "Stop position",
|
|
1342
|
-
className:
|
|
2028
|
+
className: numberClass6,
|
|
1343
2029
|
value: percent(sel.offset),
|
|
1344
2030
|
onChange: (e) => {
|
|
1345
2031
|
const n = parseFloat(e.target.value);
|
|
@@ -1348,9 +2034,9 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1348
2034
|
}
|
|
1349
2035
|
)
|
|
1350
2036
|
] }),
|
|
1351
|
-
!sel.last && /* @__PURE__ */ (0,
|
|
2037
|
+
!sel.last && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
1352
2038
|
"Midpoint",
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
2039
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1354
2040
|
"input",
|
|
1355
2041
|
{
|
|
1356
2042
|
type: "number",
|
|
@@ -1358,7 +2044,7 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1358
2044
|
max: 95,
|
|
1359
2045
|
step: 1,
|
|
1360
2046
|
"aria-label": "Stop midpoint",
|
|
1361
|
-
className:
|
|
2047
|
+
className: numberClass6,
|
|
1362
2048
|
value: percent(sel.midpoint ?? 0.5),
|
|
1363
2049
|
onChange: (e) => {
|
|
1364
2050
|
const n = parseFloat(e.target.value);
|
|
@@ -1367,15 +2053,15 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1367
2053
|
}
|
|
1368
2054
|
)
|
|
1369
2055
|
] }),
|
|
1370
|
-
/* @__PURE__ */ (0,
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass10, "aria-label": "Delete stop", title: "Delete stop", disabled: ed.stops.length <= 2, onClick: () => controller.removeGradientStop(sel.index), children: "\u2715" })
|
|
1371
2057
|
] }),
|
|
1372
|
-
/* @__PURE__ */ (0,
|
|
1373
|
-
/* @__PURE__ */ (0,
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16", children: "Colours" }),
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient interpolation", className: selectClass8, value: ed.interpolation, onChange: (e) => controller.setGradient({ interpolation: e.target.value }), children: import_vector13.VECTOR_GRADIENT_INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: i, children: import_vector13.VECTOR_GRADIENT_INTERPOLATION_LABELS[i] }, i)) })
|
|
1375
2061
|
] }),
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1377
|
-
/* @__PURE__ */ (0,
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
2062
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2063
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16", children: "Smooth" }),
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1379
2065
|
"input",
|
|
1380
2066
|
{
|
|
1381
2067
|
type: "range",
|
|
@@ -1391,26 +2077,26 @@ function VectorGradientEditor({ controller, className }) {
|
|
|
1391
2077
|
}
|
|
1392
2078
|
)
|
|
1393
2079
|
] }),
|
|
1394
|
-
/* @__PURE__ */ (0,
|
|
1395
|
-
/* @__PURE__ */ (0,
|
|
1396
|
-
/* @__PURE__ */ (0,
|
|
2080
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16", children: "Spread" }),
|
|
2082
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient spread", className: selectClass8, value: ed.spread, onChange: (e) => controller.setGradient({ spread: e.target.value }), children: import_vector13.VECTOR_GRADIENT_SPREADS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: sp, children: import_vector13.VECTOR_GRADIENT_SPREAD_LABELS[sp] }, sp)) })
|
|
1397
2083
|
] }),
|
|
1398
|
-
ed.target === "stroke" && /* @__PURE__ */ (0,
|
|
1399
|
-
/* @__PURE__ */ (0,
|
|
1400
|
-
/* @__PURE__ */ (0,
|
|
2084
|
+
ed.target === "stroke" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "flex items-center gap-1.5 text-xs text-foreground", children: [
|
|
2085
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-16", children: "On stroke" }),
|
|
2086
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("select", { "aria-label": "Gradient on stroke", className: selectClass8, value: ed.strokeMode, onChange: (e) => controller.setGradient({ strokeMode: e.target.value }), children: import_vector13.VECTOR_STROKE_GRADIENT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: m, children: import_vector13.VECTOR_STROKE_GRADIENT_MODE_LABELS[m] }, m)) })
|
|
1401
2087
|
] })
|
|
1402
2088
|
] })
|
|
1403
2089
|
] });
|
|
1404
2090
|
}
|
|
1405
2091
|
|
|
1406
2092
|
// src/vector/VectorToolbar.tsx
|
|
1407
|
-
var
|
|
2093
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1408
2094
|
var VECTOR_SNAP_TITLE = "Snap to objects";
|
|
1409
2095
|
var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
|
|
1410
|
-
var
|
|
2096
|
+
var buttonClass11 = "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";
|
|
1411
2097
|
function VectorToolbar({
|
|
1412
2098
|
controller,
|
|
1413
|
-
tools =
|
|
2099
|
+
tools = import_vector14.VECTOR_TOOLS,
|
|
1414
2100
|
showHistory = true,
|
|
1415
2101
|
showArrange = true,
|
|
1416
2102
|
showSnap = true,
|
|
@@ -1424,49 +2110,69 @@ function VectorToolbar({
|
|
|
1424
2110
|
const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
|
|
1425
2111
|
const editing = state.editing;
|
|
1426
2112
|
const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
|
|
1427
|
-
const maskSelected = state.selection.some((id) => (0,
|
|
1428
|
-
const [live, setLive] =
|
|
2113
|
+
const maskSelected = state.selection.some((id) => (0, import_vector14.isVectorMaskGroup)(controller.getNode(id)));
|
|
2114
|
+
const [live, setLive] = import_react8.default.useState(false);
|
|
1429
2115
|
const booleanDisabled = live ? count < 1 : count < 2;
|
|
1430
|
-
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0,
|
|
1431
|
-
return /* @__PURE__ */ (0,
|
|
1432
|
-
/* @__PURE__ */ (0,
|
|
2116
|
+
const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: buttonClass11, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
|
|
2117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1433
2119
|
"button",
|
|
1434
2120
|
{
|
|
1435
2121
|
type: "button",
|
|
1436
2122
|
"data-vector-tool": tool,
|
|
1437
|
-
className:
|
|
2123
|
+
className: buttonClass11,
|
|
1438
2124
|
"aria-pressed": state.tool === tool,
|
|
1439
|
-
title: `${(0,
|
|
1440
|
-
"aria-label": (0,
|
|
2125
|
+
title: `${(0, import_vector14.vectorToolLabel)(tool)} (${import_vector14.VECTOR_TOOL_SHORTCUTS[tool]})`,
|
|
2126
|
+
"aria-label": (0, import_vector14.vectorToolLabel)(tool),
|
|
1441
2127
|
onClick: () => controller.setTool(tool),
|
|
1442
|
-
children:
|
|
2128
|
+
children: import_vector14.VECTOR_TOOL_GLYPHS[tool]
|
|
1443
2129
|
},
|
|
1444
2130
|
tool
|
|
1445
2131
|
)) }),
|
|
1446
|
-
showHistory && /* @__PURE__ */ (0,
|
|
2132
|
+
showHistory && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
|
|
1447
2133
|
act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
|
|
1448
2134
|
act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
|
|
1449
2135
|
] }),
|
|
1450
|
-
showSnap && /* @__PURE__ */ (0,
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
2136
|
+
showSnap && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: [
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2138
|
+
"button",
|
|
2139
|
+
{
|
|
2140
|
+
type: "button",
|
|
2141
|
+
"data-vector-snap": "",
|
|
2142
|
+
className: buttonClass11,
|
|
2143
|
+
"aria-pressed": state.snap.objects,
|
|
2144
|
+
title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
|
|
2145
|
+
"aria-label": VECTOR_SNAP_TITLE,
|
|
2146
|
+
onClick: () => controller.toggleSnapping(),
|
|
2147
|
+
children: "Snap"
|
|
2148
|
+
}
|
|
2149
|
+
),
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2151
|
+
"select",
|
|
2152
|
+
{
|
|
2153
|
+
"data-vector-polar": "",
|
|
2154
|
+
"aria-label": "Polar tracking increment",
|
|
2155
|
+
title: "Polar tracking: the angles drawn points snap to from where they leave",
|
|
2156
|
+
className: "h-8 rounded-md border border-border bg-background px-1 text-xs",
|
|
2157
|
+
value: String((0, import_vector14.vectorPolarIncrementOf)(state.snap.angles) ?? ""),
|
|
2158
|
+
onChange: (e) => controller.setSnap({ angles: (0, import_vector14.vectorPolarAngles)(Number(e.target.value)) }),
|
|
2159
|
+
children: [
|
|
2160
|
+
(0, import_vector14.vectorPolarIncrementOf)(state.snap.angles) === null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: "Custom" }),
|
|
2161
|
+
[90, 45, 30, 15].map((n) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("option", { value: n, children: [
|
|
2162
|
+
n,
|
|
2163
|
+
"\xB0"
|
|
2164
|
+
] }, n))
|
|
2165
|
+
]
|
|
2166
|
+
}
|
|
2167
|
+
)
|
|
2168
|
+
] }),
|
|
2169
|
+
showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
|
|
2170
|
+
import_vector14.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1465
2171
|
"button",
|
|
1466
2172
|
{
|
|
1467
2173
|
type: "button",
|
|
1468
2174
|
"data-vector-path-action": a.id,
|
|
1469
|
-
className:
|
|
2175
|
+
className: buttonClass11,
|
|
1470
2176
|
title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
|
|
1471
2177
|
"aria-label": a.title,
|
|
1472
2178
|
disabled: !a.enabled(count, points),
|
|
@@ -1475,12 +2181,12 @@ function VectorToolbar({
|
|
|
1475
2181
|
},
|
|
1476
2182
|
a.id
|
|
1477
2183
|
)),
|
|
1478
|
-
|
|
2184
|
+
import_vector14.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1479
2185
|
"button",
|
|
1480
2186
|
{
|
|
1481
2187
|
type: "button",
|
|
1482
2188
|
"data-vector-edit": t.key,
|
|
1483
|
-
className:
|
|
2189
|
+
className: buttonClass11,
|
|
1484
2190
|
"aria-pressed": editing[t.key],
|
|
1485
2191
|
title: t.title,
|
|
1486
2192
|
"aria-label": t.title,
|
|
@@ -1489,9 +2195,9 @@ function VectorToolbar({
|
|
|
1489
2195
|
},
|
|
1490
2196
|
t.key
|
|
1491
2197
|
)),
|
|
1492
|
-
state.tool === "pencil" && /* @__PURE__ */ (0,
|
|
2198
|
+
state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1493
2199
|
"Smoothing",
|
|
1494
|
-
/* @__PURE__ */ (0,
|
|
2200
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1495
2201
|
"input",
|
|
1496
2202
|
{
|
|
1497
2203
|
type: "range",
|
|
@@ -1505,9 +2211,9 @@ function VectorToolbar({
|
|
|
1505
2211
|
}
|
|
1506
2212
|
)
|
|
1507
2213
|
] }),
|
|
1508
|
-
state.tool === "eraser" && /* @__PURE__ */ (0,
|
|
2214
|
+
state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
|
|
1509
2215
|
"Size",
|
|
1510
|
-
/* @__PURE__ */ (0,
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1511
2217
|
"input",
|
|
1512
2218
|
{
|
|
1513
2219
|
type: "number",
|
|
@@ -1523,26 +2229,26 @@ function VectorToolbar({
|
|
|
1523
2229
|
}
|
|
1524
2230
|
)
|
|
1525
2231
|
] }),
|
|
1526
|
-
state.tool === "paintBucket" && /* @__PURE__ */ (0,
|
|
2232
|
+
state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1527
2233
|
"button",
|
|
1528
2234
|
{
|
|
1529
2235
|
type: "button",
|
|
1530
2236
|
"data-vector-fill-gap": "",
|
|
1531
|
-
className:
|
|
2237
|
+
className: buttonClass11,
|
|
1532
2238
|
"aria-pressed": editing.fillGap > 0,
|
|
1533
2239
|
title: "Close small gaps between path ends when filling",
|
|
1534
2240
|
"aria-label": "Close gaps",
|
|
1535
|
-
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 :
|
|
2241
|
+
onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector14.VECTOR_FILL_GAP }),
|
|
1536
2242
|
children: "Gaps"
|
|
1537
2243
|
}
|
|
1538
2244
|
)
|
|
1539
2245
|
] }),
|
|
1540
|
-
showDistort && /* @__PURE__ */ (0,
|
|
2246
|
+
showDistort && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Distort", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1541
2247
|
"button",
|
|
1542
2248
|
{
|
|
1543
2249
|
type: "button",
|
|
1544
2250
|
"data-vector-free-distort": "",
|
|
1545
|
-
className:
|
|
2251
|
+
className: buttonClass11,
|
|
1546
2252
|
"aria-pressed": state.freeDistort,
|
|
1547
2253
|
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)`,
|
|
1548
2254
|
"aria-label": "Free Distort",
|
|
@@ -1550,15 +2256,15 @@ function VectorToolbar({
|
|
|
1550
2256
|
children: "Distort"
|
|
1551
2257
|
}
|
|
1552
2258
|
) }),
|
|
1553
|
-
showBlend && /* @__PURE__ */ (0,
|
|
1554
|
-
showArrange && /* @__PURE__ */ (0,
|
|
1555
|
-
/* @__PURE__ */ (0,
|
|
1556
|
-
/* @__PURE__ */ (0,
|
|
2259
|
+
showBlend && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorBlendControls, { controller }),
|
|
2260
|
+
showArrange && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1557
2263
|
"button",
|
|
1558
2264
|
{
|
|
1559
2265
|
type: "button",
|
|
1560
2266
|
"data-vector-live-boolean": "",
|
|
1561
|
-
className:
|
|
2267
|
+
className: buttonClass11,
|
|
1562
2268
|
"aria-pressed": live,
|
|
1563
2269
|
title: "Live booleans: keep the shapes editable",
|
|
1564
2270
|
"aria-label": "Live booleans",
|
|
@@ -1575,12 +2281,12 @@ function VectorToolbar({
|
|
|
1575
2281
|
act("\u25D0", `Make Clipping Mask (${modKeyLabel()}+7)`, () => controller.makeMask("clip"), count < 2),
|
|
1576
2282
|
act("\u25D1", `Release Mask (${modKeyLabel()}+Alt+7)`, () => controller.releaseMask(), !maskSelected)
|
|
1577
2283
|
] }),
|
|
1578
|
-
/* @__PURE__ */ (0,
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector14.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1579
2285
|
"button",
|
|
1580
2286
|
{
|
|
1581
2287
|
type: "button",
|
|
1582
2288
|
"data-vector-pathfinder": a.id,
|
|
1583
|
-
className:
|
|
2289
|
+
className: buttonClass11,
|
|
1584
2290
|
title: a.title,
|
|
1585
2291
|
"aria-label": a.title,
|
|
1586
2292
|
disabled: count < a.min,
|
|
@@ -1589,7 +2295,7 @@ function VectorToolbar({
|
|
|
1589
2295
|
},
|
|
1590
2296
|
a.id
|
|
1591
2297
|
)) }),
|
|
1592
|
-
/* @__PURE__ */ (0,
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
|
|
1593
2299
|
act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
|
|
1594
2300
|
act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
|
|
1595
2301
|
act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
|
|
@@ -1604,22 +2310,22 @@ function VectorToolbar({
|
|
|
1604
2310
|
}
|
|
1605
2311
|
function VectorBlendControls({ controller }) {
|
|
1606
2312
|
const state = useVectorEditorState(controller);
|
|
1607
|
-
const blend = (0,
|
|
2313
|
+
const blend = (0, import_vector14.getVectorBlendControls)(state);
|
|
1608
2314
|
const o = blend.options;
|
|
1609
2315
|
const selected = blend.ids.length > 0;
|
|
1610
|
-
return /* @__PURE__ */ (0,
|
|
1611
|
-
/* @__PURE__ */ (0,
|
|
1612
|
-
/* @__PURE__ */ (0,
|
|
2316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
|
|
2317
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass11, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
|
|
2318
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1613
2319
|
"select",
|
|
1614
2320
|
{
|
|
1615
2321
|
"aria-label": "Blend spacing",
|
|
1616
2322
|
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
1617
2323
|
value: o.spacing,
|
|
1618
|
-
onChange: (e) => (0,
|
|
1619
|
-
children:
|
|
2324
|
+
onChange: (e) => (0, import_vector14.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
|
|
2325
|
+
children: import_vector14.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: sp, children: import_vector14.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
|
|
1620
2326
|
}
|
|
1621
2327
|
),
|
|
1622
|
-
o.spacing !== "smoothColor" && /* @__PURE__ */ (0,
|
|
2328
|
+
o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1623
2329
|
"input",
|
|
1624
2330
|
{
|
|
1625
2331
|
type: "number",
|
|
@@ -1631,29 +2337,29 @@ function VectorBlendControls({ controller }) {
|
|
|
1631
2337
|
onChange: (e) => {
|
|
1632
2338
|
const n = parseFloat(e.target.value);
|
|
1633
2339
|
if (!Number.isFinite(n) || n <= 0) return;
|
|
1634
|
-
(0,
|
|
2340
|
+
(0, import_vector14.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
|
|
1635
2341
|
}
|
|
1636
2342
|
}
|
|
1637
2343
|
),
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
2344
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1639
2345
|
"button",
|
|
1640
2346
|
{
|
|
1641
2347
|
type: "button",
|
|
1642
2348
|
"data-vector-blend-action": "orient",
|
|
1643
|
-
className:
|
|
2349
|
+
className: buttonClass11,
|
|
1644
2350
|
"aria-pressed": o.orientToSpine,
|
|
1645
2351
|
title: "Orient steps to the spine",
|
|
1646
2352
|
"aria-label": "Orient to spine",
|
|
1647
|
-
onClick: () => (0,
|
|
2353
|
+
onClick: () => (0, import_vector14.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
|
|
1648
2354
|
children: "\u293F"
|
|
1649
2355
|
}
|
|
1650
2356
|
),
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
2357
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1652
2358
|
"button",
|
|
1653
2359
|
{
|
|
1654
2360
|
type: "button",
|
|
1655
2361
|
"data-vector-blend-action": "spine",
|
|
1656
|
-
className:
|
|
2362
|
+
className: buttonClass11,
|
|
1657
2363
|
title: "Replace Spine (select a blend and a path)",
|
|
1658
2364
|
"aria-label": "Replace Spine",
|
|
1659
2365
|
disabled: !blend.canReplaceSpine,
|
|
@@ -1661,15 +2367,15 @@ function VectorBlendControls({ controller }) {
|
|
|
1661
2367
|
children: "\u2307"
|
|
1662
2368
|
}
|
|
1663
2369
|
),
|
|
1664
|
-
/* @__PURE__ */ (0,
|
|
1665
|
-
/* @__PURE__ */ (0,
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass11, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass11, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
|
|
1666
2372
|
] });
|
|
1667
2373
|
}
|
|
1668
|
-
var
|
|
1669
|
-
var
|
|
2374
|
+
var selectClass9 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
|
|
2375
|
+
var numberClass7 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
|
|
1670
2376
|
function VectorStylePanel({ controller, className }) {
|
|
1671
2377
|
const state = useVectorEditorState(controller);
|
|
1672
|
-
const style = (0,
|
|
2378
|
+
const style = (0, import_vector14.getVectorSelectionStyle)(state);
|
|
1673
2379
|
const d = state.defaults;
|
|
1674
2380
|
const source = style ?? {
|
|
1675
2381
|
fill: d.fill ?? null,
|
|
@@ -1682,9 +2388,10 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1682
2388
|
arrowAlign: d.arrowAlign ?? "extend",
|
|
1683
2389
|
startArrowScale: d.startArrowScale ?? 1,
|
|
1684
2390
|
endArrowScale: d.endArrowScale ?? 1,
|
|
1685
|
-
widthProfile: (0,
|
|
2391
|
+
widthProfile: (0, import_vector14.widthProfilePresetId)(d.strokeWidthProfile),
|
|
1686
2392
|
cornerRadius: d.cornerRadius,
|
|
1687
2393
|
cornerKind: d.cornerKind ?? "round",
|
|
2394
|
+
cornerSmoothing: 0,
|
|
1688
2395
|
corners: 1,
|
|
1689
2396
|
hasOpenPath: true
|
|
1690
2397
|
};
|
|
@@ -1695,19 +2402,19 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1695
2402
|
};
|
|
1696
2403
|
const setProfile = (id) => {
|
|
1697
2404
|
if (style) controller.setWidthProfile(id);
|
|
1698
|
-
else controller.setDefaults({ strokeWidthProfile: (0,
|
|
2405
|
+
else controller.setDefaults({ strokeWidthProfile: (0, import_vector14.widthProfilePreset)(id)?.length ? (0, import_vector14.widthProfilePreset)(id) : null });
|
|
1699
2406
|
};
|
|
1700
|
-
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0,
|
|
2407
|
+
const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
|
|
1701
2408
|
const arrowRow = (end, label) => {
|
|
1702
2409
|
const key = end === "start" ? "startArrow" : "endArrow";
|
|
1703
2410
|
const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
|
|
1704
|
-
return /* @__PURE__ */ (0,
|
|
1705
|
-
/* @__PURE__ */ (0,
|
|
1706
|
-
/* @__PURE__ */ (0,
|
|
1707
|
-
/* @__PURE__ */ (0,
|
|
1708
|
-
|
|
2411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2412
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
|
|
2413
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass9, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
|
|
2414
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: "None" }),
|
|
2415
|
+
import_vector14.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: h, children: import_vector14.VECTOR_ARROWHEAD_LABELS[h] }, h))
|
|
1709
2416
|
] }),
|
|
1710
|
-
/* @__PURE__ */ (0,
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1711
2418
|
"input",
|
|
1712
2419
|
{
|
|
1713
2420
|
type: "number",
|
|
@@ -1715,7 +2422,7 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1715
2422
|
step: 0.25,
|
|
1716
2423
|
"aria-label": `${label} arrowhead scale`,
|
|
1717
2424
|
title: "Scale (\xD7 stroke width)",
|
|
1718
|
-
className:
|
|
2425
|
+
className: numberClass7,
|
|
1719
2426
|
value: source[scaleKey],
|
|
1720
2427
|
onChange: (e) => {
|
|
1721
2428
|
const n = parseFloat(e.target.value);
|
|
@@ -1731,14 +2438,14 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1731
2438
|
};
|
|
1732
2439
|
const paintRow = (key, label) => {
|
|
1733
2440
|
const paint = source[key];
|
|
1734
|
-
const hex = (0,
|
|
2441
|
+
const hex = (0, import_vector14.vectorPaintToHex)(paint);
|
|
1735
2442
|
const on = paint !== null && paint !== "none";
|
|
1736
|
-
return /* @__PURE__ */ (0,
|
|
1737
|
-
/* @__PURE__ */ (0,
|
|
1738
|
-
/* @__PURE__ */ (0,
|
|
2443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
|
|
2444
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
|
|
1739
2446
|
label
|
|
1740
2447
|
] }),
|
|
1741
|
-
/* @__PURE__ */ (0,
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1742
2449
|
"input",
|
|
1743
2450
|
{
|
|
1744
2451
|
type: "color",
|
|
@@ -1749,18 +2456,18 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1749
2456
|
onChange: (e) => apply({ [key]: e.target.value })
|
|
1750
2457
|
}
|
|
1751
2458
|
),
|
|
1752
|
-
on && !hex && /* @__PURE__ */ (0,
|
|
1753
|
-
style?.mixed[key] && /* @__PURE__ */ (0,
|
|
2459
|
+
on && !hex && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
|
|
2460
|
+
style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
|
|
1754
2461
|
] });
|
|
1755
2462
|
};
|
|
1756
|
-
return /* @__PURE__ */ (0,
|
|
1757
|
-
/* @__PURE__ */ (0,
|
|
2463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
|
|
1758
2465
|
paintRow("fill", "Fill"),
|
|
1759
2466
|
paintRow("stroke", "Stroke"),
|
|
1760
|
-
style && /* @__PURE__ */ (0,
|
|
1761
|
-
/* @__PURE__ */ (0,
|
|
1762
|
-
/* @__PURE__ */ (0,
|
|
1763
|
-
/* @__PURE__ */ (0,
|
|
2467
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorGradientEditor, { controller }),
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Width" }),
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1764
2471
|
"input",
|
|
1765
2472
|
{
|
|
1766
2473
|
type: "number",
|
|
@@ -1776,33 +2483,33 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1776
2483
|
}
|
|
1777
2484
|
)
|
|
1778
2485
|
] }),
|
|
1779
|
-
/* @__PURE__ */ (0,
|
|
1780
|
-
/* @__PURE__ */ (0,
|
|
1781
|
-
/* @__PURE__ */ (0,
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
|
|
2487
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Align" }),
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass9, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector14.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: a, children: import_vector14.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
|
|
1782
2489
|
mixed("strokeAlign")
|
|
1783
2490
|
] }),
|
|
1784
|
-
/* @__PURE__ */ (0,
|
|
1785
|
-
/* @__PURE__ */ (0,
|
|
1786
|
-
/* @__PURE__ */ (0,
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Profile" }),
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1787
2494
|
"select",
|
|
1788
2495
|
{
|
|
1789
2496
|
"aria-label": "Width profile",
|
|
1790
|
-
className:
|
|
2497
|
+
className: selectClass9,
|
|
1791
2498
|
value: source.widthProfile,
|
|
1792
2499
|
onChange: (e) => {
|
|
1793
2500
|
if (e.target.value !== "custom") setProfile(e.target.value);
|
|
1794
2501
|
},
|
|
1795
2502
|
children: [
|
|
1796
|
-
|
|
1797
|
-
source.widthProfile === "custom" && /* @__PURE__ */ (0,
|
|
2503
|
+
import_vector14.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: p.id, children: p.label }, p.id)),
|
|
2504
|
+
source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
|
|
1798
2505
|
]
|
|
1799
2506
|
}
|
|
1800
2507
|
),
|
|
1801
|
-
/* @__PURE__ */ (0,
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1802
2509
|
"button",
|
|
1803
2510
|
{
|
|
1804
2511
|
type: "button",
|
|
1805
|
-
className:
|
|
2512
|
+
className: buttonClass11,
|
|
1806
2513
|
title: "Reset to uniform width",
|
|
1807
2514
|
"aria-label": "Reset to uniform width",
|
|
1808
2515
|
disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
|
|
@@ -1812,27 +2519,27 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1812
2519
|
),
|
|
1813
2520
|
mixed("widthProfile")
|
|
1814
2521
|
] }),
|
|
1815
|
-
source.hasOpenPath && /* @__PURE__ */ (0,
|
|
2522
|
+
source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
1816
2523
|
arrowRow("start", "Start"),
|
|
1817
2524
|
arrowRow("end", "End"),
|
|
1818
|
-
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0,
|
|
1819
|
-
/* @__PURE__ */ (0,
|
|
1820
|
-
/* @__PURE__ */ (0,
|
|
1821
|
-
/* @__PURE__ */ (0,
|
|
1822
|
-
/* @__PURE__ */ (0,
|
|
2525
|
+
(source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Heads" }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass9, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "extend", children: "Tip past end" }),
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "tip", children: "Tip at end" })
|
|
1823
2530
|
] })
|
|
1824
2531
|
] })
|
|
1825
2532
|
] }),
|
|
1826
|
-
source.corners > 0 && /* @__PURE__ */ (0,
|
|
1827
|
-
/* @__PURE__ */ (0,
|
|
1828
|
-
/* @__PURE__ */ (0,
|
|
2533
|
+
source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
|
|
2534
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
|
|
2535
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1829
2536
|
"input",
|
|
1830
2537
|
{
|
|
1831
2538
|
type: "number",
|
|
1832
2539
|
min: 0,
|
|
1833
2540
|
step: 1,
|
|
1834
2541
|
"aria-label": "Corner radius",
|
|
1835
|
-
className:
|
|
2542
|
+
className: numberClass7,
|
|
1836
2543
|
value: Math.round(source.cornerRadius * 100) / 100,
|
|
1837
2544
|
onChange: (e) => {
|
|
1838
2545
|
const n = parseFloat(e.target.value);
|
|
@@ -1840,12 +2547,29 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1840
2547
|
}
|
|
1841
2548
|
}
|
|
1842
2549
|
),
|
|
1843
|
-
/* @__PURE__ */ (0,
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("select", { "aria-label": "Corner kind", className: selectClass9, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector14.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: k, children: import_vector14.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
|
|
1844
2551
|
mixed("cornerRadius")
|
|
1845
2552
|
] }),
|
|
1846
|
-
style && /* @__PURE__ */ (0,
|
|
1847
|
-
/* @__PURE__ */ (0,
|
|
1848
|
-
/* @__PURE__ */ (0,
|
|
2553
|
+
style && source.corners > 0 && source.cornerKind === "round" && source.cornerRadius > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.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: [
|
|
2554
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Smoothing" }),
|
|
2555
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2556
|
+
"input",
|
|
2557
|
+
{
|
|
2558
|
+
type: "range",
|
|
2559
|
+
min: 0,
|
|
2560
|
+
max: 1,
|
|
2561
|
+
step: 0.05,
|
|
2562
|
+
"aria-label": "Corner smoothing",
|
|
2563
|
+
className: "h-4 flex-1 accent-primary",
|
|
2564
|
+
value: source.cornerSmoothing,
|
|
2565
|
+
onChange: (e) => controller.setCornerSmoothing(parseFloat(e.target.value), { merge: "corner-smoothing" }),
|
|
2566
|
+
onPointerUp: () => controller.endMergedEdit()
|
|
2567
|
+
}
|
|
2568
|
+
)
|
|
2569
|
+
] }),
|
|
2570
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
|
|
2571
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-16", children: "Opacity" }),
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1849
2573
|
"input",
|
|
1850
2574
|
{
|
|
1851
2575
|
type: "range",
|
|
@@ -1859,21 +2583,26 @@ function VectorStylePanel({ controller, className }) {
|
|
|
1859
2583
|
}
|
|
1860
2584
|
)
|
|
1861
2585
|
] }),
|
|
1862
|
-
|
|
1863
|
-
style && /* @__PURE__ */ (0,
|
|
1864
|
-
style && /* @__PURE__ */ (0,
|
|
1865
|
-
style && /* @__PURE__ */ (0,
|
|
2586
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorTextPanel, { controller }),
|
|
2587
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorAppearancePanel, { controller }),
|
|
2588
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorEffectsPanel, { controller }),
|
|
2589
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorEnvelopePanel, { controller }),
|
|
2590
|
+
style && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorMaskPanel, { controller }),
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorFramePanel, { controller }),
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorConnectorPanel, { controller }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorConstraintsPanel, { controller }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(VectorSymbolsPanel, { controller })
|
|
1866
2595
|
] });
|
|
1867
2596
|
}
|
|
1868
2597
|
|
|
1869
2598
|
// src/vector/VectorEditor.tsx
|
|
1870
|
-
var
|
|
2599
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1871
2600
|
function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
|
|
1872
|
-
return /* @__PURE__ */ (0,
|
|
1873
|
-
/* @__PURE__ */ (0,
|
|
1874
|
-
/* @__PURE__ */ (0,
|
|
1875
|
-
/* @__PURE__ */ (0,
|
|
1876
|
-
showStylePanel && /* @__PURE__ */ (0,
|
|
2601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
|
|
2602
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VectorToolbar, { controller, tools }),
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.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_runtime14.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
|
|
2605
|
+
showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
|
|
1877
2606
|
] })
|
|
1878
2607
|
] });
|
|
1879
2608
|
}
|
|
@@ -1881,10 +2610,13 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
1881
2610
|
0 && (module.exports = {
|
|
1882
2611
|
VectorAppearancePanel,
|
|
1883
2612
|
VectorCanvas,
|
|
2613
|
+
VectorConnectorPanel,
|
|
2614
|
+
VectorConstraintsPanel,
|
|
1884
2615
|
VectorEditor,
|
|
1885
2616
|
VectorEffectsPanel,
|
|
1886
2617
|
VectorEnvelopePanel,
|
|
1887
2618
|
VectorFilterDefs,
|
|
2619
|
+
VectorFramePanel,
|
|
1888
2620
|
VectorGradientAnnotator,
|
|
1889
2621
|
VectorGradientDefs,
|
|
1890
2622
|
VectorGradientEditor,
|
|
@@ -1892,6 +2624,9 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
|
|
|
1892
2624
|
VectorMaskedNodes,
|
|
1893
2625
|
VectorSceneNodes,
|
|
1894
2626
|
VectorStylePanel,
|
|
2627
|
+
VectorSymbolsPanel,
|
|
2628
|
+
VectorTextElement,
|
|
2629
|
+
VectorTextPanel,
|
|
1895
2630
|
VectorToolbar,
|
|
1896
2631
|
VectorWidthPointEditor,
|
|
1897
2632
|
useVectorCommands,
|