@pixerate/editor-react 0.31.0 → 0.32.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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/vector/index.ts
@@ -22,6 +32,7 @@ var vector_exports = {};
22
32
  __export(vector_exports, {
23
33
  VectorCanvas: () => VectorCanvas,
24
34
  VectorEditor: () => VectorEditor,
35
+ VectorEffectsPanel: () => VectorEffectsPanel,
25
36
  VectorGradientDefs: () => VectorGradientDefs,
26
37
  VectorSceneNodes: () => VectorSceneNodes,
27
38
  VectorStylePanel: () => VectorStylePanel,
@@ -499,14 +510,157 @@ function VectorCanvas({
499
510
  }
500
511
 
501
512
  // src/vector/VectorToolbar.tsx
513
+ var import_react4 = __toESM(require("react"), 1);
514
+ var import_vector5 = require("@pixerate/editor/vector");
515
+
516
+ // src/vector/VectorEffectsPanel.tsx
502
517
  var import_vector4 = require("@pixerate/editor/vector");
503
518
  var import_jsx_runtime3 = require("react/jsx-runtime");
519
+ var buttonClass = "inline-flex h-7 min-w-7 items-center justify-center rounded-md border border-border bg-background px-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-40";
520
+ var numberClass = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
521
+ var selectClass = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
522
+ var labelClass = "w-full truncate text-[11px] text-muted-foreground";
523
+ function VectorEffectsPanel({ controller, className }) {
524
+ const state = useVectorEditorState(controller);
525
+ const panel = (0, import_vector4.getVectorEffectsPanel)(state);
526
+ if (!panel) return null;
527
+ const nodeId = panel.nodeId;
528
+ const end = () => controller.endMergedEdit();
529
+ const set = (e, key, value, merge) => {
530
+ if (nodeId) controller.updateEffect(nodeId, e.id, { params: { [key]: value } }, { merge });
531
+ };
532
+ const number = (e, spec) => {
533
+ const value = Number(e.params[spec.key] ?? 0);
534
+ const label = `${e.label} ${spec.label}`;
535
+ const onChange = (ev) => {
536
+ const n = parseFloat(ev.target.value);
537
+ if (Number.isFinite(n)) set(e, spec.key, n, true);
538
+ };
539
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClass, children: spec.label }),
541
+ spec.slider && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
542
+ "input",
543
+ {
544
+ type: "range",
545
+ min: spec.min,
546
+ max: spec.max,
547
+ step: spec.step,
548
+ "aria-label": `${label} slider`,
549
+ className: "h-4 min-w-0 flex-1 accent-primary",
550
+ value,
551
+ onChange,
552
+ onPointerUp: end,
553
+ onKeyUp: end,
554
+ onBlur: end
555
+ }
556
+ ),
557
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
558
+ "input",
559
+ {
560
+ type: "number",
561
+ min: spec.min,
562
+ max: spec.max,
563
+ step: spec.step,
564
+ "aria-label": label,
565
+ className: numberClass,
566
+ value: Math.round(value * 1e3) / 1e3,
567
+ onChange,
568
+ onBlur: end
569
+ }
570
+ )
571
+ ] }, spec.key);
572
+ };
573
+ const vec2 = (e, spec) => {
574
+ const v = e.params[spec.key] ?? { x: 0, y: 0 };
575
+ const field = (axis) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
576
+ "input",
577
+ {
578
+ type: "number",
579
+ step: spec.kind === "vec2" ? spec.step : 1,
580
+ "aria-label": `${e.label} ${spec.label} ${axis}`,
581
+ className: numberClass,
582
+ value: Math.round(v[axis] * 1e3) / 1e3,
583
+ onChange: (ev) => {
584
+ const n = parseFloat(ev.target.value);
585
+ if (Number.isFinite(n)) set(e, spec.key, { ...v, [axis]: n }, true);
586
+ },
587
+ onBlur: end
588
+ }
589
+ );
590
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
591
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClass, children: spec.label }),
592
+ field("x"),
593
+ field("y")
594
+ ] }, spec.key);
595
+ };
596
+ const param = (e, spec) => {
597
+ if (spec.kind === "number") return number(e, spec);
598
+ if (spec.kind === "vec2") return vec2(e, spec);
599
+ if (spec.kind === "boolean")
600
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
601
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "min-w-0 flex-1 truncate", children: spec.label }),
602
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", "aria-label": `${e.label} ${spec.label}`, checked: !!e.params[spec.key], onChange: (ev) => set(e, spec.key, ev.target.checked, false) })
603
+ ] }, spec.key);
604
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-foreground", "data-vector-effect-param": spec.key, children: [
605
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: labelClass, children: spec.label }),
606
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": `${e.label} ${spec.label}`, className: selectClass, value: String(e.params[spec.key] ?? ""), onChange: (ev) => set(e, spec.key, ev.target.value, false), children: spec.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: o.value, children: o.label }, o.value)) })
607
+ ] }, spec.key);
608
+ };
609
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "data-vector-effects": "", "aria-label": "Effects", children: [
610
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: "Effects" }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
613
+ "select",
614
+ {
615
+ "aria-label": "Add effect",
616
+ className: selectClass,
617
+ value: "",
618
+ onChange: (ev) => {
619
+ if (ev.target.value) controller.addEffect(ev.target.value);
620
+ },
621
+ children: [
622
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "Add effect\u2026" }),
623
+ import_vector4.VECTOR_EFFECT_MENU.map((m) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: m.type, children: m.label }, m.type))
624
+ ]
625
+ }
626
+ ),
627
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: buttonClass, title: "Expand Appearance", "aria-label": "Expand Appearance", disabled: !panel.expandable, onClick: () => controller.expandAppearance(), children: "Expand" })
628
+ ] }),
629
+ panel.count > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Select one object to edit its effects." }),
630
+ nodeId && panel.effects.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-1 rounded border border-border p-1.5", "data-vector-effect": e.id, "data-vector-effect-type": e.type, children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-1", children: [
632
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-xs font-medium text-foreground", children: [
633
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", "aria-label": `${e.label} on`, checked: e.enabled, onChange: (ev) => controller.updateEffect(nodeId, e.id, { enabled: ev.target.checked }) }),
634
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate", children: e.label })
635
+ ] }),
636
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: buttonClass, title: "Move up", "aria-label": `Move ${e.label} up`, disabled: i === 0, onClick: () => controller.moveEffect(nodeId, e.id, i - 1), children: "\u2191" }),
637
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
638
+ "button",
639
+ {
640
+ type: "button",
641
+ className: buttonClass,
642
+ title: "Move down",
643
+ "aria-label": `Move ${e.label} down`,
644
+ disabled: i === panel.effects.length - 1,
645
+ onClick: () => controller.moveEffect(nodeId, e.id, i + 1),
646
+ children: "\u2193"
647
+ }
648
+ ),
649
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: buttonClass, title: "Remove", "aria-label": `Remove ${e.label}`, onClick: () => controller.removeEffect(nodeId, e.id), children: "\xD7" })
650
+ ] }),
651
+ e.specs.map((spec) => param(e, spec))
652
+ ] }, e.id))
653
+ ] });
654
+ }
655
+
656
+ // src/vector/VectorToolbar.tsx
657
+ var import_jsx_runtime4 = require("react/jsx-runtime");
504
658
  var VECTOR_SNAP_TITLE = "Snap to objects";
505
659
  var modKeyLabel = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "") ? "\u2318" : "Ctrl";
506
- var buttonClass = "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";
660
+ var buttonClass2 = "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";
507
661
  function VectorToolbar({
508
662
  controller,
509
- tools = import_vector4.VECTOR_TOOLS,
663
+ tools = import_vector5.VECTOR_TOOLS,
510
664
  showHistory = true,
511
665
  showArrange = true,
512
666
  showSnap = true,
@@ -519,32 +673,34 @@ function VectorToolbar({
519
673
  const points = state.tool === "direct" ? state.selectedAnchors.length : 0;
520
674
  const editing = state.editing;
521
675
  const groupSelected = state.selection.some((id) => controller.getNode(id)?.type === "group");
522
- const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: buttonClass, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
523
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
676
+ const [live, setLive] = import_react4.default.useState(false);
677
+ const booleanDisabled = live ? count < 1 : count < 2;
678
+ const act = (label, title, run, disabled = false) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: buttonClass2, title, "aria-label": title, disabled, onClick: () => void run(), children: label }, label);
679
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { role: "toolbar", "aria-label": "Vector tools", className: `flex flex-wrap items-center gap-1 ${className ?? ""}`, children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Tools", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
525
681
  "button",
526
682
  {
527
683
  type: "button",
528
684
  "data-vector-tool": tool,
529
- className: buttonClass,
685
+ className: buttonClass2,
530
686
  "aria-pressed": state.tool === tool,
531
- title: `${(0, import_vector4.vectorToolLabel)(tool)} (${import_vector4.VECTOR_TOOL_SHORTCUTS[tool]})`,
532
- "aria-label": (0, import_vector4.vectorToolLabel)(tool),
687
+ title: `${(0, import_vector5.vectorToolLabel)(tool)} (${import_vector5.VECTOR_TOOL_SHORTCUTS[tool]})`,
688
+ "aria-label": (0, import_vector5.vectorToolLabel)(tool),
533
689
  onClick: () => controller.setTool(tool),
534
- children: import_vector4.VECTOR_TOOL_GLYPHS[tool]
690
+ children: import_vector5.VECTOR_TOOL_GLYPHS[tool]
535
691
  },
536
692
  tool
537
693
  )) }),
538
- showHistory && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
694
+ showHistory && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "History", children: [
539
695
  act("\u21B6", state.canUndo ? `Undo ${state.undoLabel}` : "Undo", () => controller.undo(), !state.canUndo),
540
696
  act("\u21B7", state.canRedo ? `Redo ${state.redoLabel}` : "Redo", () => controller.redo(), !state.canRedo)
541
697
  ] }),
542
- showSnap && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
698
+ showSnap && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Snapping", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
543
699
  "button",
544
700
  {
545
701
  type: "button",
546
702
  "data-vector-snap": "",
547
- className: buttonClass,
703
+ className: buttonClass2,
548
704
  "aria-pressed": state.snap.objects,
549
705
  title: `${VECTOR_SNAP_TITLE} (hold ${modKeyLabel()} to bypass)`,
550
706
  "aria-label": VECTOR_SNAP_TITLE,
@@ -552,13 +708,13 @@ function VectorToolbar({
552
708
  children: "Snap"
553
709
  }
554
710
  ) }),
555
- showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
556
- import_vector4.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
711
+ showPathEdit && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Path editing", children: [
712
+ import_vector5.VECTOR_PATH_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
557
713
  "button",
558
714
  {
559
715
  type: "button",
560
716
  "data-vector-path-action": a.id,
561
- className: buttonClass,
717
+ className: buttonClass2,
562
718
  title: a.shortcut ? `${a.title} (${modKeyLabel()}+${a.shortcut})` : a.title,
563
719
  "aria-label": a.title,
564
720
  disabled: !a.enabled(count, points),
@@ -567,12 +723,12 @@ function VectorToolbar({
567
723
  },
568
724
  a.id
569
725
  )),
570
- import_vector4.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
726
+ import_vector5.VECTOR_EDIT_TOGGLES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
571
727
  "button",
572
728
  {
573
729
  type: "button",
574
730
  "data-vector-edit": t.key,
575
- className: buttonClass,
731
+ className: buttonClass2,
576
732
  "aria-pressed": editing[t.key],
577
733
  title: t.title,
578
734
  "aria-label": t.title,
@@ -581,9 +737,9 @@ function VectorToolbar({
581
737
  },
582
738
  t.key
583
739
  )),
584
- state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
740
+ state.tool === "pencil" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
585
741
  "Smoothing",
586
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
742
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
587
743
  "input",
588
744
  {
589
745
  type: "range",
@@ -597,9 +753,9 @@ function VectorToolbar({
597
753
  }
598
754
  )
599
755
  ] }),
600
- state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
756
+ state.tool === "eraser" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-1 text-xs text-foreground", children: [
601
757
  "Size",
602
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
758
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
603
759
  "input",
604
760
  {
605
761
  type: "number",
@@ -615,36 +771,49 @@ function VectorToolbar({
615
771
  }
616
772
  )
617
773
  ] }),
618
- state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
774
+ state.tool === "paintBucket" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
619
775
  "button",
620
776
  {
621
777
  type: "button",
622
778
  "data-vector-fill-gap": "",
623
- className: buttonClass,
779
+ className: buttonClass2,
624
780
  "aria-pressed": editing.fillGap > 0,
625
781
  title: "Close small gaps between path ends when filling",
626
782
  "aria-label": "Close gaps",
627
- onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector4.VECTOR_FILL_GAP }),
783
+ onClick: () => controller.setEditing({ fillGap: editing.fillGap > 0 ? 0 : import_vector5.VECTOR_FILL_GAP }),
628
784
  children: "Gaps"
629
785
  }
630
786
  )
631
787
  ] }),
632
- showBlend && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VectorBlendControls, { controller }),
633
- showArrange && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
634
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
635
- act("\u222A", "Union", () => controller.booleanOp("union"), count < 2),
636
- act("\u2212", "Subtract", () => controller.booleanOp("subtract"), count < 2),
637
- act("\u2229", "Intersect", () => controller.booleanOp("intersect"), count < 2),
638
- act("\u22BB", "Exclude", () => controller.booleanOp("exclude"), count < 2),
788
+ showBlend && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorBlendControls, { controller }),
789
+ showArrange && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
790
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Combine", children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
792
+ "button",
793
+ {
794
+ type: "button",
795
+ "data-vector-live-boolean": "",
796
+ className: buttonClass2,
797
+ "aria-pressed": live,
798
+ title: "Live booleans: keep the shapes editable",
799
+ "aria-label": "Live booleans",
800
+ onClick: () => setLive(!live),
801
+ children: "Live"
802
+ }
803
+ ),
804
+ act("\u222A", "Union", () => controller.booleanOp("union", { live }), booleanDisabled),
805
+ act("\u2212", "Subtract", () => controller.booleanOp("subtract", { live }), booleanDisabled),
806
+ act("\u2229", "Intersect", () => controller.booleanOp("intersect", { live }), booleanDisabled),
807
+ act("\u22BB", "Exclude", () => controller.booleanOp("exclude", { live }), booleanDisabled),
639
808
  act("G", "Group", () => controller.group(), count < 1),
640
809
  act("U", "Ungroup", () => controller.ungroup(), !groupSelected)
641
810
  ] }),
642
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector4.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
811
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Pathfinder", children: import_vector5.VECTOR_PATHFINDER_ACTIONS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
643
812
  "button",
644
813
  {
645
814
  type: "button",
646
815
  "data-vector-pathfinder": a.id,
647
- className: buttonClass,
816
+ className: buttonClass2,
648
817
  title: a.title,
649
818
  "aria-label": a.title,
650
819
  disabled: count < a.min,
@@ -653,7 +822,7 @@ function VectorToolbar({
653
822
  },
654
823
  a.id
655
824
  )) }),
656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
825
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Arrange", children: [
657
826
  act("\u21C8", "Bring to Front", () => controller.arrange("front"), count < 1),
658
827
  act("\u21CA", "Send to Back", () => controller.arrange("back"), count < 1),
659
828
  act("\u21E4", "Align Left", () => controller.align("left"), count < 1),
@@ -668,22 +837,22 @@ function VectorToolbar({
668
837
  }
669
838
  function VectorBlendControls({ controller }) {
670
839
  const state = useVectorEditorState(controller);
671
- const blend = (0, import_vector4.getVectorBlendControls)(state);
840
+ const blend = (0, import_vector5.getVectorBlendControls)(state);
672
841
  const o = blend.options;
673
842
  const selected = blend.ids.length > 0;
674
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
675
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
676
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
843
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ml-1 flex items-center gap-1", role: "group", "aria-label": "Blend", "data-vector-blend-controls": "", children: [
844
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "data-vector-blend-action": "make", className: buttonClass2, title: "Make Blend", "aria-label": "Make Blend", disabled: !blend.canBlend, onClick: () => controller.blend(), children: "\u29D3" }),
845
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
677
846
  "select",
678
847
  {
679
848
  "aria-label": "Blend spacing",
680
849
  className: "h-7 rounded border border-border bg-background px-1 text-xs",
681
850
  value: o.spacing,
682
- onChange: (e) => (0, import_vector4.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
683
- children: import_vector4.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: sp, children: import_vector4.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
851
+ onChange: (e) => (0, import_vector5.applyVectorBlendOptions)(controller, { spacing: e.target.value }),
852
+ children: import_vector5.VECTOR_BLEND_SPACINGS.map((sp) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: sp, children: import_vector5.VECTOR_BLEND_SPACING_LABELS[sp] }, sp))
684
853
  }
685
854
  ),
686
- o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
855
+ o.spacing !== "smoothColor" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
687
856
  "input",
688
857
  {
689
858
  type: "number",
@@ -695,29 +864,29 @@ function VectorBlendControls({ controller }) {
695
864
  onChange: (e) => {
696
865
  const n = parseFloat(e.target.value);
697
866
  if (!Number.isFinite(n) || n <= 0) return;
698
- (0, import_vector4.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
867
+ (0, import_vector5.applyVectorBlendOptions)(controller, o.spacing === "steps" ? { steps: n } : { distance: n });
699
868
  }
700
869
  }
701
870
  ),
702
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
871
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
703
872
  "button",
704
873
  {
705
874
  type: "button",
706
875
  "data-vector-blend-action": "orient",
707
- className: buttonClass,
876
+ className: buttonClass2,
708
877
  "aria-pressed": o.orientToSpine,
709
878
  title: "Orient steps to the spine",
710
879
  "aria-label": "Orient to spine",
711
- onClick: () => (0, import_vector4.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
880
+ onClick: () => (0, import_vector5.applyVectorBlendOptions)(controller, { orientToSpine: !o.orientToSpine }),
712
881
  children: "\u293F"
713
882
  }
714
883
  ),
715
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
884
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
716
885
  "button",
717
886
  {
718
887
  type: "button",
719
888
  "data-vector-blend-action": "spine",
720
- className: buttonClass,
889
+ className: buttonClass2,
721
890
  title: "Replace Spine (select a blend and a path)",
722
891
  "aria-label": "Replace Spine",
723
892
  disabled: !blend.canReplaceSpine,
@@ -725,15 +894,15 @@ function VectorBlendControls({ controller }) {
725
894
  children: "\u2307"
726
895
  }
727
896
  ),
728
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
729
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
897
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "data-vector-blend-action": "expand", className: buttonClass2, title: "Expand Blend", "aria-label": "Expand Blend", disabled: !selected, onClick: () => controller.expandBlend(), children: "\u29C9" }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "data-vector-blend-action": "release", className: buttonClass2, title: "Release Blend", "aria-label": "Release Blend", disabled: !selected, onClick: () => controller.releaseBlend(), children: "\u29C4" })
730
899
  ] });
731
900
  }
732
- var selectClass = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
733
- var numberClass = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
901
+ var selectClass2 = "h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs";
902
+ var numberClass2 = "h-7 w-16 rounded border border-border bg-background px-1.5 text-xs";
734
903
  function VectorStylePanel({ controller, className }) {
735
904
  const state = useVectorEditorState(controller);
736
- const style = (0, import_vector4.getVectorSelectionStyle)(state);
905
+ const style = (0, import_vector5.getVectorSelectionStyle)(state);
737
906
  const d = state.defaults;
738
907
  const source = style ?? {
739
908
  fill: d.fill ?? null,
@@ -746,7 +915,7 @@ function VectorStylePanel({ controller, className }) {
746
915
  arrowAlign: d.arrowAlign ?? "extend",
747
916
  startArrowScale: d.startArrowScale ?? 1,
748
917
  endArrowScale: d.endArrowScale ?? 1,
749
- widthProfile: (0, import_vector4.widthProfilePresetId)(d.strokeWidthProfile),
918
+ widthProfile: (0, import_vector5.widthProfilePresetId)(d.strokeWidthProfile),
750
919
  cornerRadius: d.cornerRadius,
751
920
  cornerKind: d.cornerKind ?? "round",
752
921
  corners: 1,
@@ -759,19 +928,19 @@ function VectorStylePanel({ controller, className }) {
759
928
  };
760
929
  const setProfile = (id) => {
761
930
  if (style) controller.setWidthProfile(id);
762
- else controller.setDefaults({ strokeWidthProfile: (0, import_vector4.widthProfilePreset)(id)?.length ? (0, import_vector4.widthProfilePreset)(id) : null });
931
+ else controller.setDefaults({ strokeWidthProfile: (0, import_vector5.widthProfilePreset)(id)?.length ? (0, import_vector5.widthProfilePreset)(id) : null });
763
932
  };
764
- const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
933
+ const mixed = (key) => style?.mixed[key] ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" }) : null;
765
934
  const arrowRow = (end, label) => {
766
935
  const key = end === "start" ? "startArrow" : "endArrow";
767
936
  const scaleKey = end === "start" ? "startArrowScale" : "endArrowScale";
768
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
769
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
770
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
771
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "None" }),
772
- import_vector4.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: h, children: import_vector4.VECTOR_ARROWHEAD_LABELS[h] }, h))
937
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
938
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16 text-xs text-foreground", children: label }),
939
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { "aria-label": `${label} arrowhead`, className: selectClass2, value: source[key] ?? "", onChange: (e) => apply({ [key]: e.target.value || null }), children: [
940
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "None" }),
941
+ import_vector5.VECTOR_ARROWHEADS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: h, children: import_vector5.VECTOR_ARROWHEAD_LABELS[h] }, h))
773
942
  ] }),
774
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
943
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
775
944
  "input",
776
945
  {
777
946
  type: "number",
@@ -779,7 +948,7 @@ function VectorStylePanel({ controller, className }) {
779
948
  step: 0.25,
780
949
  "aria-label": `${label} arrowhead scale`,
781
950
  title: "Scale (\xD7 stroke width)",
782
- className: numberClass,
951
+ className: numberClass2,
783
952
  value: source[scaleKey],
784
953
  onChange: (e) => {
785
954
  const n = parseFloat(e.target.value);
@@ -795,14 +964,14 @@ function VectorStylePanel({ controller, className }) {
795
964
  };
796
965
  const paintRow = (key, label) => {
797
966
  const paint = source[key];
798
- const hex = (0, import_vector4.vectorPaintToHex)(paint);
967
+ const hex = (0, import_vector5.vectorPaintToHex)(paint);
799
968
  const on = paint !== null && paint !== "none";
800
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
802
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
969
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": key, children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex w-16 items-center gap-1.5 text-xs text-foreground", children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", checked: on, "aria-label": `${label} on`, onChange: (e) => apply({ [key]: e.target.checked ? hex ?? "#000000" : null }) }),
803
972
  label
804
973
  ] }),
805
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
974
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
806
975
  "input",
807
976
  {
808
977
  type: "color",
@@ -813,17 +982,17 @@ function VectorStylePanel({ controller, className }) {
813
982
  onChange: (e) => apply({ [key]: e.target.value })
814
983
  }
815
984
  ),
816
- on && !hex && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
817
- style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
985
+ on && !hex && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: typeof paint === "string" ? paint : "Gradient" }),
986
+ style?.mixed[key] && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[11px] text-muted-foreground", children: "Mixed" })
818
987
  ] });
819
988
  };
820
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
821
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
989
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `space-y-2 ${className ?? ""}`, "aria-label": style ? "Selection style" : "New shape style", children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: style ? "Selection" : "New shapes" }),
822
991
  paintRow("fill", "Fill"),
823
992
  paintRow("stroke", "Stroke"),
824
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
825
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Width" }),
826
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
993
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
994
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Width" }),
995
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
827
996
  "input",
828
997
  {
829
998
  type: "number",
@@ -839,33 +1008,33 @@ function VectorStylePanel({ controller, className }) {
839
1008
  }
840
1009
  )
841
1010
  ] }),
842
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
843
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Align" }),
844
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector4.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: a, children: import_vector4.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
1011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "strokeAlign", children: [
1012
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Align" }),
1013
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Stroke alignment", className: selectClass2, value: source.strokeAlign, onChange: (e) => apply({ strokeAlign: e.target.value }), children: Object.keys(import_vector5.VECTOR_STROKE_ALIGN_LABELS).map((a) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: a, children: import_vector5.VECTOR_STROKE_ALIGN_LABELS[a] }, a)) }),
845
1014
  mixed("strokeAlign")
846
1015
  ] }),
847
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
848
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Profile" }),
849
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1016
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "widthProfile", children: [
1017
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Profile" }),
1018
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
850
1019
  "select",
851
1020
  {
852
1021
  "aria-label": "Width profile",
853
- className: selectClass,
1022
+ className: selectClass2,
854
1023
  value: source.widthProfile,
855
1024
  onChange: (e) => {
856
1025
  if (e.target.value !== "custom") setProfile(e.target.value);
857
1026
  },
858
1027
  children: [
859
- import_vector4.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: p.id, children: p.label }, p.id)),
860
- source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
1028
+ import_vector5.VECTOR_WIDTH_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: p.id, children: p.label }, p.id)),
1029
+ source.widthProfile === "custom" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "custom", disabled: true, children: "Custom" })
861
1030
  ]
862
1031
  }
863
1032
  ),
864
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1033
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
865
1034
  "button",
866
1035
  {
867
1036
  type: "button",
868
- className: buttonClass,
1037
+ className: buttonClass2,
869
1038
  title: "Reset to uniform width",
870
1039
  "aria-label": "Reset to uniform width",
871
1040
  disabled: source.widthProfile === "uniform" && !style?.mixed.widthProfile,
@@ -875,27 +1044,27 @@ function VectorStylePanel({ controller, className }) {
875
1044
  ),
876
1045
  mixed("widthProfile")
877
1046
  ] }),
878
- source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1047
+ source.hasOpenPath && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
879
1048
  arrowRow("start", "Start"),
880
1049
  arrowRow("end", "End"),
881
- (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
882
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Heads" }),
883
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
884
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "extend", children: "Tip past end" }),
885
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "tip", children: "Tip at end" })
1050
+ (source.startArrow || source.endArrow) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", "data-vector-style": "arrowAlign", children: [
1051
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Heads" }),
1052
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { "aria-label": "Arrowhead alignment", className: selectClass2, value: source.arrowAlign, onChange: (e) => apply({ arrowAlign: e.target.value }), children: [
1053
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "extend", children: "Tip past end" }),
1054
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "tip", children: "Tip at end" })
886
1055
  ] })
887
1056
  ] })
888
1057
  ] }),
889
- source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
890
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
891
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1058
+ source.corners > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", "data-vector-style": "corners", children: [
1059
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16 text-xs text-foreground", children: "Corners" }),
1060
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
892
1061
  "input",
893
1062
  {
894
1063
  type: "number",
895
1064
  min: 0,
896
1065
  step: 1,
897
1066
  "aria-label": "Corner radius",
898
- className: numberClass,
1067
+ className: numberClass2,
899
1068
  value: Math.round(source.cornerRadius * 100) / 100,
900
1069
  onChange: (e) => {
901
1070
  const n = parseFloat(e.target.value);
@@ -903,12 +1072,12 @@ function VectorStylePanel({ controller, className }) {
903
1072
  }
904
1073
  }
905
1074
  ),
906
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { "aria-label": "Corner kind", className: selectClass, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector4.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: k, children: import_vector4.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Corner kind", className: selectClass2, value: source.cornerKind, onChange: (e) => setCorners({ kind: e.target.value }), children: import_vector5.VECTOR_CORNER_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: k, children: import_vector5.VECTOR_CORNER_KIND_LABELS[k] }, k)) }),
907
1076
  mixed("cornerRadius")
908
1077
  ] }),
909
- style && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
910
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "w-16", children: "Opacity" }),
911
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1078
+ style && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2 text-xs text-foreground", children: [
1079
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-16", children: "Opacity" }),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
912
1081
  "input",
913
1082
  {
914
1083
  type: "range",
@@ -921,18 +1090,19 @@ function VectorStylePanel({ controller, className }) {
921
1090
  onChange: (e) => apply({ opacity: parseFloat(e.target.value) })
922
1091
  }
923
1092
  )
924
- ] })
1093
+ ] }),
1094
+ style && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorEffectsPanel, { controller })
925
1095
  ] });
926
1096
  }
927
1097
 
928
1098
  // src/vector/VectorEditor.tsx
929
- var import_jsx_runtime4 = require("react/jsx-runtime");
1099
+ var import_jsx_runtime5 = require("react/jsx-runtime");
930
1100
  function VectorEditor({ controller, tools, showStylePanel = true, height = 520, canvasProps, className }) {
931
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
932
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorToolbar, { controller, tools }),
933
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
934
- /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
935
- showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
1101
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `flex flex-col gap-2 ${className ?? ""}`, "data-vector-editor": "", children: [
1102
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VectorToolbar, { controller, tools }),
1103
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-h-0 flex-col gap-2 md:flex-row", children: [
1104
+ /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.jsx)(VectorCanvas, { controller, ...canvasProps }) }),
1105
+ showStylePanel && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VectorStylePanel, { controller, className: "w-full shrink-0 rounded-md border border-border p-3 md:w-56" })
936
1106
  ] })
937
1107
  ] });
938
1108
  }
@@ -940,6 +1110,7 @@ function VectorEditor({ controller, tools, showStylePanel = true, height = 520,
940
1110
  0 && (module.exports = {
941
1111
  VectorCanvas,
942
1112
  VectorEditor,
1113
+ VectorEffectsPanel,
943
1114
  VectorGradientDefs,
944
1115
  VectorSceneNodes,
945
1116
  VectorStylePanel,