@pixerate/editor-react 0.70.0 → 0.72.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/index.cjs CHANGED
@@ -63,6 +63,7 @@ __export(src_exports, {
63
63
  RefineEdgePanel: () => RefineEdgePanel,
64
64
  ReviewToolbar: () => ReviewToolbar,
65
65
  SelectionOptionsBar: () => SelectionOptionsBar,
66
+ ShapeOptionsBar: () => ShapeOptionsBar,
66
67
  SheetTabs: () => SheetTabs,
67
68
  SpreadsheetConditionalFormatPanel: () => SpreadsheetConditionalFormatPanel,
68
69
  SpreadsheetContextMenu: () => SpreadsheetContextMenu,
@@ -75,6 +76,7 @@ __export(src_exports, {
75
76
  TableToolbar: () => TableToolbar,
76
77
  TemplateRenderer: () => TemplateRenderer,
77
78
  TrackedChangesList: () => TrackedChangesList,
79
+ TypeOptionsBar: () => TypeOptionsBar,
78
80
  VariableForm: () => VariableForm,
79
81
  bindDirtyToHistory: () => import_editor21.bindDirtyToHistory,
80
82
  createDirtyTracker: () => import_editor21.createDirtyTracker,
@@ -3785,8 +3787,8 @@ function useImageEditor(options = {}) {
3785
3787
  }
3786
3788
 
3787
3789
  // src/image-editor/ImageEditor.tsx
3788
- var import_react44 = __toESM(require("react"), 1);
3789
- var import_image_editor12 = require("@pixerate/editor/image-editor");
3790
+ var import_react46 = __toESM(require("react"), 1);
3791
+ var import_image_editor14 = require("@pixerate/editor/image-editor");
3790
3792
 
3791
3793
  // src/image-editor/ControlSlider.tsx
3792
3794
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -4496,7 +4498,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
4496
4498
  const placement = (0, import_image_editor7.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor7.dropZone)(fraction, row.layer.type === "group"));
4497
4499
  if (placement) attempt(() => controller.moveLayer(id, placement));
4498
4500
  };
4499
- const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
4501
+ const thumb = (layer) => (0, import_image_editor7.layerHasThumbnail)(layer) ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
4500
4502
  const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
4501
4503
  const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
4502
4504
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
@@ -4689,15 +4691,25 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
4689
4691
  }
4690
4692
  ),
4691
4693
  row.clipped && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
4692
- layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4693
- Thumbnail,
4694
- {
4695
- pixels: thumb(layer),
4696
- size: thumbnailSize,
4697
- label: `${row.label} pixels`,
4698
- selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
4699
- }
4700
- ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4694
+ (0, import_image_editor7.layerHasThumbnail)(layer) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "relative shrink-0", children: [
4695
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4696
+ Thumbnail,
4697
+ {
4698
+ pixels: thumb(layer),
4699
+ size: thumbnailSize,
4700
+ label: `${row.label} pixels`,
4701
+ selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
4702
+ }
4703
+ ),
4704
+ layer.type !== "pixel" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4705
+ "span",
4706
+ {
4707
+ "data-testid": "layer-kind-badge",
4708
+ className: "absolute -bottom-1 -right-1 rounded bg-slate-700 px-0.5 text-[8px] font-bold leading-tight text-slate-100 ring-1 ring-slate-900",
4709
+ children: (0, import_image_editor7.layerBadge)(layer)
4710
+ }
4711
+ )
4712
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4701
4713
  "span",
4702
4714
  {
4703
4715
  className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
@@ -4764,6 +4776,7 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
4764
4776
  children: row.label
4765
4777
  }
4766
4778
  ),
4779
+ (0, import_image_editor7.layerWarning)(layer) && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { role: "img", "data-testid": "layer-warning", "aria-label": (0, import_image_editor7.layerWarning)(layer), title: (0, import_image_editor7.layerWarning)(layer), className: "text-[10px] text-amber-400", children: "\u26A0" }),
4767
4780
  (0, import_image_editor7.layerEffectsBadge)(layer) && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4768
4781
  "button",
4769
4782
  {
@@ -4823,7 +4836,8 @@ var BrushOptionsBar = ({ controller, className }) => {
4823
4836
  (0, import_react40.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
4824
4837
  const [error, setError] = (0, import_react40.useState)(null);
4825
4838
  const state = controller.getState();
4826
- const { brush, foreground, background, mixer, mixerLoad } = state.paint;
4839
+ const { brush, foreground, background, mixer, mixerLoad, retouch, cloneSource } = state.paint;
4840
+ const tool = state.activeTool;
4827
4841
  const attempt = (fn) => {
4828
4842
  try {
4829
4843
  setError(null);
@@ -4833,12 +4847,12 @@ var BrushOptionsBar = ({ controller, className }) => {
4833
4847
  }
4834
4848
  };
4835
4849
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
4836
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor8.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4850
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor8.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4837
4851
  "button",
4838
4852
  {
4839
4853
  type: "button",
4840
4854
  "aria-pressed": state.activeTool === t.id,
4841
- title: `${t.label} (${t.shortcut})`,
4855
+ title: t.shortcut ? `${t.label} (${t.shortcut})` : t.label,
4842
4856
  className: chip(state.activeTool === t.id),
4843
4857
  onClick: () => controller.setTool(t.id),
4844
4858
  children: t.label
@@ -4940,6 +4954,41 @@ var BrushOptionsBar = ({ controller, className }) => {
4940
4954
  ] })
4941
4955
  ] })
4942
4956
  ] }),
4957
+ (0, import_image_editor8.isRetouchPaintTool)(tool) && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-2 border-t border-slate-800 pt-2", role: "group", "aria-label": "Retouch options", "data-testid": "retouch-options", children: [
4958
+ (tool === "clone" || tool === "heal") && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
4959
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-slate-400", "data-testid": "clone-source", children: (0, import_image_editor8.cloneSourceLabel)(controller) }),
4960
+ cloneSource && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", title: "Forget the source point", className: chip(false), onClick: () => controller.setCloneSource(null), children: "Clear source" })
4961
+ ] }),
4962
+ import_image_editor8.RETOUCH_CHOICES.filter((c) => c.tools.includes(tool)).map((choice) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": choice.label, children: [
4963
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-slate-400", children: choice.label }),
4964
+ choice.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4965
+ "button",
4966
+ {
4967
+ type: "button",
4968
+ "aria-pressed": retouch[choice.id] === o.id,
4969
+ title: o.title,
4970
+ className: chip(retouch[choice.id] === o.id),
4971
+ onClick: () => (0, import_image_editor8.setRetouchChoice)(controller, choice.id, o.id),
4972
+ children: o.label
4973
+ },
4974
+ o.id
4975
+ ))
4976
+ ] }, choice.id)),
4977
+ import_image_editor8.RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(tool)).map((spec) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ControlSlider, { spec, value: retouch[spec.id], onChange: (v) => controller.setPaintOptions({ retouch: { [spec.id]: v } }) }, spec.id)),
4978
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap gap-3 text-slate-300", children: import_image_editor8.RETOUCH_TOGGLES.filter((t) => t.tools.includes(tool)).map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4979
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4980
+ "input",
4981
+ {
4982
+ type: "checkbox",
4983
+ "aria-label": t.label,
4984
+ checked: retouch[t.id],
4985
+ onChange: (e) => controller.setPaintOptions({ retouch: { [t.id]: e.target.checked } }),
4986
+ className: "accent-indigo-500"
4987
+ }
4988
+ ),
4989
+ t.label
4990
+ ] }, t.id)) })
4991
+ ] }),
4943
4992
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
4944
4993
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4945
4994
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
@@ -5371,8 +5420,215 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
5371
5420
  ] });
5372
5421
  };
5373
5422
 
5374
- // src/image-editor/ImageEditor.tsx
5423
+ // src/image-editor/ShapeOptionsBar.tsx
5424
+ var import_react44 = require("react");
5425
+ var import_image_editor12 = require("@pixerate/editor/image-editor");
5375
5426
  var import_jsx_runtime27 = require("react/jsx-runtime");
5427
+ var chip3 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
5428
+ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
5429
+ const [, setTick] = (0, import_react44.useState)(0);
5430
+ (0, import_react44.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
5431
+ const [error, setError] = (0, import_react44.useState)(null);
5432
+ const active = controller.getActiveLayer();
5433
+ const shapeId = active?.type === "shape" ? active.id : null;
5434
+ const set = (change) => {
5435
+ onChange({ ...options, ...change });
5436
+ if (!shapeId) return;
5437
+ try {
5438
+ setError(null);
5439
+ (0, import_image_editor12.applyShapeOptions)(controller, shapeId, change);
5440
+ } catch (e) {
5441
+ setError(e instanceof Error ? e.message : String(e));
5442
+ }
5443
+ };
5444
+ const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
5445
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "shape-options", children: [
5446
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Shape kind", children: import_image_editor12.LIVE_SHAPE_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", "aria-pressed": options.kind === k, className: chip3(options.kind === k), onClick: () => onChange({ ...options, kind: k }), children: import_image_editor12.SHAPE_KIND_LABELS[k] }, k)) }),
5447
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
5448
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5449
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "checkbox", "aria-label": "Fill", checked: options.fill !== null, onChange: (e) => set({ fill: e.target.checked ? "#4f46e5" : null }) }),
5450
+ "Fill",
5451
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5452
+ "input",
5453
+ {
5454
+ type: "color",
5455
+ "aria-label": "Fill colour",
5456
+ disabled: options.fill === null,
5457
+ value: options.fill ?? "#4f46e5",
5458
+ onChange: (e) => set({ fill: e.target.value }),
5459
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
5460
+ }
5461
+ )
5462
+ ] }),
5463
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5464
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "checkbox", "aria-label": "Stroke", checked: options.stroke !== null, onChange: (e) => set({ stroke: e.target.checked ? "#000000" : null }) }),
5465
+ "Stroke",
5466
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5467
+ "input",
5468
+ {
5469
+ type: "color",
5470
+ "aria-label": "Stroke colour",
5471
+ disabled: options.stroke === null,
5472
+ value: options.stroke ?? "#000000",
5473
+ onChange: (e) => set({ stroke: e.target.value }),
5474
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
5475
+ }
5476
+ )
5477
+ ] }),
5478
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5479
+ "Width",
5480
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5481
+ "input",
5482
+ {
5483
+ type: "number",
5484
+ "aria-label": "Stroke width",
5485
+ min: 0,
5486
+ max: 200,
5487
+ value: options.strokeWidth,
5488
+ onChange: (e) => set({ strokeWidth: num(e.target.value, 0, 200) }),
5489
+ className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5490
+ }
5491
+ )
5492
+ ] })
5493
+ ] }),
5494
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
5495
+ options.kind === "rect" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5496
+ "Radius",
5497
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "number", "aria-label": "Corner radius", min: 0, max: 1e3, value: options.radius, onChange: (e) => set({ radius: num(e.target.value, 0, 1e3) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
5498
+ ] }),
5499
+ options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5500
+ "Sides",
5501
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "number", "aria-label": "Sides", min: 3, max: 100, value: options.sides, onChange: (e) => set({ sides: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
5502
+ ] }),
5503
+ options.kind === "star" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
5504
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5505
+ "Points",
5506
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "number", "aria-label": "Points", min: 3, max: 100, value: options.points, onChange: (e) => set({ points: num(e.target.value, 3, 100) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
5507
+ ] }),
5508
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5509
+ "Inner",
5510
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5511
+ "input",
5512
+ {
5513
+ type: "range",
5514
+ "aria-label": "Inner radius",
5515
+ min: 0.05,
5516
+ max: 1,
5517
+ step: 0.05,
5518
+ value: options.innerRatio,
5519
+ onChange: (e) => set({ innerRatio: Number(e.target.value) }),
5520
+ className: "accent-indigo-500"
5521
+ }
5522
+ )
5523
+ ] })
5524
+ ] }),
5525
+ options.kind === "line" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
5526
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5527
+ "Weight",
5528
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "number", "aria-label": "Line weight", min: 1, max: 200, value: options.weight, onChange: (e) => set({ weight: num(e.target.value, 1, 200) }), className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5" })
5529
+ ] }),
5530
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5531
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
5532
+ "Arrowhead"
5533
+ ] })
5534
+ ] })
5535
+ ] }),
5536
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-[10px] text-slate-500", children: "Drag on the image to draw. Shift: square, circle or 45\xB0 line. Alt: from the centre." }),
5537
+ error && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
5538
+ ] });
5539
+ };
5540
+
5541
+ // src/image-editor/TypeOptionsBar.tsx
5542
+ var import_react45 = require("react");
5543
+ var import_image_editor13 = require("@pixerate/editor/image-editor");
5544
+ var import_jsx_runtime28 = require("react/jsx-runtime");
5545
+ var chip4 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
5546
+ var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
5547
+ var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
5548
+ const [, setTick] = (0, import_react45.useState)(0);
5549
+ (0, import_react45.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
5550
+ (0, import_react45.useEffect)(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
5551
+ const [error, setError] = (0, import_react45.useState)(null);
5552
+ const active = controller.getActiveLayer();
5553
+ const typeId = !session && active?.type === "type" ? active.id : null;
5554
+ const here = session?.alive ? session.styleHere() : {};
5555
+ const shown = {
5556
+ ...options,
5557
+ ...here.fontFamily ? { fontFamily: here.fontFamily } : {},
5558
+ ...here.fontSize ? { fontSize: here.fontSize } : {},
5559
+ ...here.fontWeight ? { fontWeight: here.fontWeight } : {},
5560
+ ...session?.alive ? { italic: Boolean(here.italic), color: here.color ?? options.color } : {}
5561
+ };
5562
+ const fonts = controller.listFonts();
5563
+ const missing = active?.type === "type" ? active.missingFonts ?? [] : [];
5564
+ const style = (change) => {
5565
+ onChange({ ...options, ...change });
5566
+ const s = {};
5567
+ for (const k of ["fontFamily", "fontSize", "fontWeight", "italic", "color"]) if (k in change) s[k] = change[k];
5568
+ const p = change.align ? { align: change.align } : null;
5569
+ try {
5570
+ setError(null);
5571
+ if (session?.alive) {
5572
+ if (Object.keys(s).length) session.setStyle(s);
5573
+ if (p) session.setParagraph(p);
5574
+ if (session.error) setError(session.error);
5575
+ } else if (typeId) {
5576
+ if (Object.keys(s).length) controller.setTextStyle(typeId, s);
5577
+ if (p) controller.setParagraphStyle(typeId, p);
5578
+ }
5579
+ } catch (e) {
5580
+ setError(e instanceof Error ? e.message : String(e));
5581
+ }
5582
+ };
5583
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "type-options", children: [
5584
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
5585
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { className: "flex items-center gap-1", children: [
5586
+ "Font",
5587
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5588
+ "input",
5589
+ {
5590
+ list: "pixerate-type-fonts",
5591
+ "aria-label": "Font family",
5592
+ value: shown.fontFamily,
5593
+ onChange: (e) => e.target.value.trim() && style({ fontFamily: e.target.value }),
5594
+ className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5595
+ }
5596
+ ),
5597
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("datalist", { id: "pixerate-type-fonts", children: fonts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("option", { value: f }, f)) })
5598
+ ] }),
5599
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { className: "flex items-center gap-1", children: [
5600
+ "Size",
5601
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5602
+ "input",
5603
+ {
5604
+ type: "number",
5605
+ "aria-label": "Font size",
5606
+ min: 1,
5607
+ max: 2e3,
5608
+ value: Math.round(shown.fontSize * 10) / 10,
5609
+ onChange: (e) => Number(e.target.value) > 0 && style({ fontSize: Number(e.target.value) }),
5610
+ className: "w-16 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5611
+ }
5612
+ )
5613
+ ] }),
5614
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", "aria-pressed": shown.fontWeight >= 600, className: `${chip4(shown.fontWeight >= 600)} font-bold`, onClick: () => style({ fontWeight: shown.fontWeight >= 600 ? 400 : 700 }), children: "B" }),
5615
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", "aria-pressed": shown.italic, className: `${chip4(shown.italic)} italic`, onClick: () => style({ italic: !shown.italic }), children: "I" }),
5616
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("input", { type: "color", "aria-label": "Text colour", value: shown.color, onChange: (e) => style({ color: e.target.value }), className: "h-6 w-8 rounded border border-slate-700 bg-transparent" })
5617
+ ] }),
5618
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Alignment", children: import_image_editor13.TEXT_ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", "aria-pressed": options.align === a, className: chip4(options.align === a), onClick: () => style({ align: a }), children: ALIGN_LABELS[a] }, a)) }),
5619
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-[10px] text-slate-500", children: "Click to type point text, drag for a paragraph box, click text to edit it. Esc finishes." }),
5620
+ missing.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
5621
+ "Missing ",
5622
+ missing.length === 1 ? "font" : "fonts",
5623
+ ": ",
5624
+ missing.join(", ")
5625
+ ] }),
5626
+ error && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
5627
+ ] });
5628
+ };
5629
+
5630
+ // src/image-editor/ImageEditor.tsx
5631
+ var import_jsx_runtime29 = require("react/jsx-runtime");
5376
5632
  var ImageEditor = ({
5377
5633
  editor: externalEditor,
5378
5634
  src,
@@ -5387,47 +5643,65 @@ var ImageEditor = ({
5387
5643
  const internalEditor = useImageEditor({ image: src });
5388
5644
  const editor = externalEditor || internalEditor;
5389
5645
  const { state, controller } = editor;
5390
- const legacyProcess = (0, import_image_editor12.normalizeProcessVersion)(state.adjustments.process) < import_image_editor12.LATEST_PROCESS_VERSION;
5391
- const canvasRef = (0, import_react44.useRef)(null);
5392
- const containerRef = (0, import_react44.useRef)(null);
5393
- const [activeTab, setActiveTab] = (0, import_react44.useState)("crop");
5394
- const [activeCropRatio, setActiveCropRatio] = (0, import_react44.useState)(null);
5395
- const [selectionOptions, setSelectionOptions] = (0, import_react44.useState)(import_image_editor12.DEFAULT_SELECTION_TOOL_OPTIONS);
5396
- const selectionOptionsRef = (0, import_react44.useRef)(selectionOptions);
5646
+ const legacyProcess = (0, import_image_editor14.normalizeProcessVersion)(state.adjustments.process) < import_image_editor14.LATEST_PROCESS_VERSION;
5647
+ const canvasRef = (0, import_react46.useRef)(null);
5648
+ const containerRef = (0, import_react46.useRef)(null);
5649
+ const [activeTab, setActiveTab] = (0, import_react46.useState)("crop");
5650
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react46.useState)(null);
5651
+ const [selectionOptions, setSelectionOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_SELECTION_TOOL_OPTIONS);
5652
+ const selectionOptionsRef = (0, import_react46.useRef)(selectionOptions);
5397
5653
  selectionOptionsRef.current = selectionOptions;
5398
- const selectionGestureRef = (0, import_react44.useRef)(null);
5654
+ const selectionGestureRef = (0, import_react46.useRef)(null);
5399
5655
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
5400
- selectionGestureRef.current = new import_image_editor12.SelectionGesture(controller, () => selectionOptionsRef.current);
5656
+ selectionGestureRef.current = new import_image_editor14.SelectionGesture(controller, () => selectionOptionsRef.current);
5401
5657
  }
5402
- const selectionDraftRef = (0, import_react44.useRef)(null);
5403
- const [selectionError, setSelectionError] = (0, import_react44.useState)(null);
5404
- const paintGestureRef = (0, import_react44.useRef)(null);
5405
- const paintControllerRef = (0, import_react44.useRef)(controller);
5658
+ const selectionDraftRef = (0, import_react46.useRef)(null);
5659
+ const [selectionError, setSelectionError] = (0, import_react46.useState)(null);
5660
+ const paintGestureRef = (0, import_react46.useRef)(null);
5661
+ const paintControllerRef = (0, import_react46.useRef)(controller);
5406
5662
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
5407
- paintGestureRef.current = new import_image_editor12.PaintGesture(controller);
5663
+ paintGestureRef.current = new import_image_editor14.PaintGesture(controller);
5408
5664
  paintControllerRef.current = controller;
5409
5665
  }
5410
- const brushCursorRef = (0, import_react44.useRef)(null);
5411
- const [paintError, setPaintError] = (0, import_react44.useState)(null);
5412
- const transformToolRef = (0, import_react44.useRef)(null);
5413
- const transformControllerRef = (0, import_react44.useRef)(controller);
5666
+ const brushCursorRef = (0, import_react46.useRef)(null);
5667
+ const [paintError, setPaintError] = (0, import_react46.useState)(null);
5668
+ const transformToolRef = (0, import_react46.useRef)(null);
5669
+ const transformControllerRef = (0, import_react46.useRef)(controller);
5414
5670
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
5415
5671
  transformToolRef.current?.cancel();
5416
- transformToolRef.current = new import_image_editor12.FreeTransformTool(controller, {
5672
+ transformToolRef.current = new import_image_editor14.FreeTransformTool(controller, {
5417
5673
  schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
5418
5674
  });
5419
5675
  transformControllerRef.current = controller;
5420
5676
  }
5421
5677
  const transformTool = transformToolRef.current;
5422
- const [, setTransformTick] = (0, import_react44.useState)(0);
5423
- const [transformCursor, setTransformCursor] = (0, import_react44.useState)("default");
5424
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react44.useState)("");
5425
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react44.useState)("annotations");
5426
- const [isRemovingBg, setIsRemovingBg] = (0, import_react44.useState)(false);
5427
- const [isInpainting, setIsInpainting] = (0, import_react44.useState)(false);
5428
- const [aiError, setAiError] = (0, import_react44.useState)(null);
5429
- const [aiSuccess, setAiSuccess] = (0, import_react44.useState)(null);
5430
- const [aiTarget, setAiTarget] = (0, import_react44.useState)("auto");
5678
+ const [, setTransformTick] = (0, import_react46.useState)(0);
5679
+ const [transformCursor, setTransformCursor] = (0, import_react46.useState)("default");
5680
+ const [shapeOptions, setShapeOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_SHAPE_TOOL_OPTIONS);
5681
+ const shapeOptionsRef = (0, import_react46.useRef)(shapeOptions);
5682
+ shapeOptionsRef.current = shapeOptions;
5683
+ const [typeOptions, setTypeOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_TYPE_TOOL_OPTIONS);
5684
+ const typeOptionsRef = (0, import_react46.useRef)(typeOptions);
5685
+ typeOptionsRef.current = typeOptions;
5686
+ const shapeGestureRef = (0, import_react46.useRef)(null);
5687
+ const typeToolRef = (0, import_react46.useRef)(null);
5688
+ const shapeTypeControllerRef = (0, import_react46.useRef)(controller);
5689
+ if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
5690
+ typeToolRef.current?.finish();
5691
+ shapeGestureRef.current = new import_image_editor14.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
5692
+ typeToolRef.current = new import_image_editor14.TypeToolGesture(controller, () => typeOptionsRef.current);
5693
+ shapeTypeControllerRef.current = controller;
5694
+ }
5695
+ const typeInputRef = (0, import_react46.useRef)(null);
5696
+ const [typeSession, setTypeSession] = (0, import_react46.useState)(typeToolRef.current.session);
5697
+ const [shapeTypeError, setShapeTypeError] = (0, import_react46.useState)(null);
5698
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react46.useState)("");
5699
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react46.useState)("annotations");
5700
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react46.useState)(false);
5701
+ const [isInpainting, setIsInpainting] = (0, import_react46.useState)(false);
5702
+ const [aiError, setAiError] = (0, import_react46.useState)(null);
5703
+ const [aiSuccess, setAiSuccess] = (0, import_react46.useState)(null);
5704
+ const [aiTarget, setAiTarget] = (0, import_react46.useState)("auto");
5431
5705
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
5432
5706
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
5433
5707
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -5490,18 +5764,18 @@ var ImageEditor = ({
5490
5764
  setIsInpainting(false);
5491
5765
  }
5492
5766
  };
5493
- const [activeColor, setActiveColor] = (0, import_react44.useState)("#ef4444");
5494
- const [strokeWidth, setStrokeWidth] = (0, import_react44.useState)(3);
5495
- const [fontSize, setFontSize] = (0, import_react44.useState)(24);
5496
- const [textInput, setTextInput] = (0, import_react44.useState)("");
5497
- const draftAnnotationRef = (0, import_react44.useRef)(null);
5498
- const draftCropRef = (0, import_react44.useRef)(null);
5499
- const cropDragInfoRef = (0, import_react44.useRef)(null);
5500
- const annotationDragInfoRef = (0, import_react44.useRef)(null);
5501
- const isDrawingRef = (0, import_react44.useRef)(false);
5502
- const currentPathRef = (0, import_react44.useRef)([]);
5503
- const dragStartPointRef = (0, import_react44.useRef)(null);
5504
- const renderCanvas = (0, import_react44.useCallback)(
5767
+ const [activeColor, setActiveColor] = (0, import_react46.useState)("#ef4444");
5768
+ const [strokeWidth, setStrokeWidth] = (0, import_react46.useState)(3);
5769
+ const [fontSize, setFontSize] = (0, import_react46.useState)(24);
5770
+ const [textInput, setTextInput] = (0, import_react46.useState)("");
5771
+ const draftAnnotationRef = (0, import_react46.useRef)(null);
5772
+ const draftCropRef = (0, import_react46.useRef)(null);
5773
+ const cropDragInfoRef = (0, import_react46.useRef)(null);
5774
+ const annotationDragInfoRef = (0, import_react46.useRef)(null);
5775
+ const isDrawingRef = (0, import_react46.useRef)(false);
5776
+ const currentPathRef = (0, import_react46.useRef)([]);
5777
+ const dragStartPointRef = (0, import_react46.useRef)(null);
5778
+ const renderCanvas = (0, import_react46.useCallback)(
5505
5779
  async (draftAnnotation, draftCrop) => {
5506
5780
  const canvas = canvasRef.current;
5507
5781
  const container = containerRef.current;
@@ -5518,12 +5792,49 @@ var ImageEditor = ({
5518
5792
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
5519
5793
  draftSelectionPath: selectionDraftRef.current,
5520
5794
  brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
5521
- freeTransform: transformTool.overlay()
5795
+ freeTransform: transformTool.overlay(),
5796
+ textEdit: typeToolRef.current?.session?.alive ? typeToolRef.current.session.overlay() : null
5522
5797
  });
5523
5798
  },
5524
5799
  [controller, activeTab, transformTool]
5525
5800
  );
5526
- (0, import_react44.useEffect)(() => transformTool.subscribe(() => {
5801
+ (0, import_react46.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
5802
+ (0, import_react46.useEffect)(() => {
5803
+ if (activeTab === "annotate" && state.activeTool === "type") return;
5804
+ if (typeToolRef.current?.session) {
5805
+ typeToolRef.current.finish();
5806
+ setTypeSession(null);
5807
+ void renderCanvas();
5808
+ }
5809
+ }, [activeTab, state.activeTool, renderCanvas]);
5810
+ const finishTyping = () => {
5811
+ typeToolRef.current?.finish();
5812
+ setTypeSession(null);
5813
+ void renderCanvas();
5814
+ };
5815
+ const handleTypeKeyDown = (e) => {
5816
+ const session = typeToolRef.current?.session;
5817
+ if (!session || e.nativeEvent.isComposing) return;
5818
+ if (e.key === "Escape") {
5819
+ e.preventDefault();
5820
+ finishTyping();
5821
+ return;
5822
+ }
5823
+ if ((e.metaKey || e.ctrlKey) && ["z", "y", "c", "x", "v"].includes(e.key.toLowerCase())) return;
5824
+ if (session.handleKey(e)) {
5825
+ e.preventDefault();
5826
+ setShapeTypeError(session.error);
5827
+ }
5828
+ };
5829
+ const handleTypeInput = (e) => {
5830
+ const el = e.currentTarget;
5831
+ const session = typeToolRef.current?.session;
5832
+ if (session && el.value && !e.nativeEvent.isComposing) {
5833
+ session.insert(el.value);
5834
+ el.value = "";
5835
+ }
5836
+ };
5837
+ (0, import_react46.useEffect)(() => transformTool.subscribe(() => {
5527
5838
  setTransformTick((n) => n + 1);
5528
5839
  void renderCanvas();
5529
5840
  }), [transformTool, renderCanvas]);
@@ -5534,8 +5845,8 @@ var ImageEditor = ({
5534
5845
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5535
5846
  const s = controller.getState();
5536
5847
  const cropping = activeTab === "crop";
5537
- const projection = (0, import_image_editor12.getViewportProjection)(s, canvas.width, canvas.height, cropping);
5538
- const pt = (0, import_image_editor12.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
5848
+ const projection = (0, import_image_editor14.getViewportProjection)(s, canvas.width, canvas.height, cropping);
5849
+ const pt = (0, import_image_editor14.canvasToImagePoint)({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvas.width, canvas.height, cropping);
5539
5850
  transformTool.setView(projection.scale);
5540
5851
  return { pt, tolerance: 6 / (projection.scale || 1) };
5541
5852
  };
@@ -5566,7 +5877,7 @@ var ImageEditor = ({
5566
5877
  transformTool.up();
5567
5878
  return true;
5568
5879
  };
5569
- (0, import_react44.useEffect)(() => {
5880
+ (0, import_react46.useEffect)(() => {
5570
5881
  if (typeof window === "undefined") return;
5571
5882
  const onKey = (e) => {
5572
5883
  if (transformTool.key(e)) e.preventDefault();
@@ -5574,7 +5885,7 @@ var ImageEditor = ({
5574
5885
  window.addEventListener("keydown", onKey);
5575
5886
  return () => window.removeEventListener("keydown", onKey);
5576
5887
  }, [transformTool]);
5577
- (0, import_react44.useEffect)(() => {
5888
+ (0, import_react46.useEffect)(() => {
5578
5889
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
5579
5890
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
5580
5891
  const animId = raf(() => {
@@ -5582,12 +5893,12 @@ var ImageEditor = ({
5582
5893
  });
5583
5894
  return () => caf(animId);
5584
5895
  }, [renderCanvas, state]);
5585
- (0, import_react44.useEffect)(() => {
5896
+ (0, import_react46.useEffect)(() => {
5586
5897
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
5587
5898
  editor.setTool("crop");
5588
5899
  }
5589
5900
  }, [activeTab, editor]);
5590
- (0, import_react44.useEffect)(() => {
5901
+ (0, import_react46.useEffect)(() => {
5591
5902
  const container = containerRef.current;
5592
5903
  if (!container) return;
5593
5904
  if (typeof ResizeObserver !== "undefined") {
@@ -5623,8 +5934,8 @@ var ImageEditor = ({
5623
5934
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5624
5935
  const s = controller.getState();
5625
5936
  return list.map((ev) => ({
5626
- ...(0, import_image_editor12.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5627
- pressure: (0, import_image_editor12.pointerPressure)(ev)
5937
+ ...(0, import_image_editor14.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5938
+ pressure: (0, import_image_editor14.pointerPressure)(ev)
5628
5939
  }));
5629
5940
  };
5630
5941
  const handlePaintPointerDown = (e) => {
@@ -5636,7 +5947,7 @@ var ImageEditor = ({
5636
5947
  } catch {
5637
5948
  }
5638
5949
  const [first] = paintSamples(e);
5639
- setPaintError(paintGestureRef.current.down(first));
5950
+ setPaintError(paintGestureRef.current.down({ ...first, altKey: e.altKey }));
5640
5951
  };
5641
5952
  const handlePaintPointerMove = (e) => {
5642
5953
  if (handleTransformPointerMove(e)) return;
@@ -5655,10 +5966,10 @@ var ImageEditor = ({
5655
5966
  if (g.error) setPaintError(g.error);
5656
5967
  }
5657
5968
  };
5658
- (0, import_react44.useEffect)(() => {
5969
+ (0, import_react46.useEffect)(() => {
5659
5970
  if (activeTab !== "paint" || typeof window === "undefined") return;
5660
5971
  const onKey = (e) => {
5661
- if ((0, import_image_editor12.handlePaintShortcut)(controller, e)) e.preventDefault();
5972
+ if ((0, import_image_editor14.handlePaintShortcut)(controller, e)) e.preventDefault();
5662
5973
  };
5663
5974
  window.addEventListener("keydown", onKey);
5664
5975
  return () => window.removeEventListener("keydown", onKey);
@@ -5669,7 +5980,7 @@ var ImageEditor = ({
5669
5980
  const canvasPt = getCanvasEventPoint(e);
5670
5981
  if (activeTab === "select") {
5671
5982
  const gesture = selectionGestureRef.current;
5672
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5983
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5673
5984
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
5674
5985
  return;
5675
5986
  }
@@ -5680,8 +5991,8 @@ var ImageEditor = ({
5680
5991
  width: state.imageDimensions.width,
5681
5992
  height: state.imageDimensions.height
5682
5993
  };
5683
- const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5684
- const startImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5994
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5995
+ const startImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5685
5996
  if (handle) {
5686
5997
  cropDragInfoRef.current = {
5687
5998
  handle,
@@ -5699,13 +6010,24 @@ var ImageEditor = ({
5699
6010
  }
5700
6011
  return;
5701
6012
  }
6013
+ if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
6014
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6015
+ setShapeTypeError(null);
6016
+ if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
6017
+ else {
6018
+ typeToolRef.current.down(imgPt, { shift: e.shiftKey });
6019
+ setTypeSession(typeToolRef.current.session);
6020
+ void renderCanvas();
6021
+ }
6022
+ return;
6023
+ }
5702
6024
  if (activeTab === "annotate") {
5703
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6025
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5704
6026
  dragStartPointRef.current = imgPt;
5705
6027
  if (state.activeTool === "select") {
5706
6028
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5707
6029
  const ann = state.annotations[i];
5708
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, ann)) {
6030
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, ann)) {
5709
6031
  editor.selectAnnotation(ann.id);
5710
6032
  annotationDragInfoRef.current = {
5711
6033
  annId: ann.id,
@@ -5741,7 +6063,7 @@ var ImageEditor = ({
5741
6063
  const canvasPt = getCanvasEventPoint(e);
5742
6064
  if (activeTab === "select") {
5743
6065
  const gesture = selectionGestureRef.current;
5744
- if (gesture.active && gesture.move((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
6066
+ if (gesture.active && gesture.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5745
6067
  selectionDraftRef.current = gesture.draftPath;
5746
6068
  renderCanvas();
5747
6069
  }
@@ -5750,7 +6072,7 @@ var ImageEditor = ({
5750
6072
  if (activeTab === "crop") {
5751
6073
  const drag = cropDragInfoRef.current;
5752
6074
  if (drag) {
5753
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
6075
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5754
6076
  let newCrop;
5755
6077
  if (drag.handle === "new") {
5756
6078
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -5764,7 +6086,7 @@ var ImageEditor = ({
5764
6086
  height: Math.round(Math.max(20, maxY - minY))
5765
6087
  };
5766
6088
  } else {
5767
- newCrop = (0, import_image_editor12.calculateCropDrag)(
6089
+ newCrop = (0, import_image_editor14.calculateCropDrag)(
5768
6090
  drag.startCrop,
5769
6091
  drag.handle,
5770
6092
  drag.startImgPt,
@@ -5784,15 +6106,23 @@ var ImageEditor = ({
5784
6106
  width: state.imageDimensions.width,
5785
6107
  height: state.imageDimensions.height
5786
6108
  };
5787
- const handle = (0, import_image_editor12.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5788
- canvas.style.cursor = (0, import_image_editor12.getCropCursor)(handle, state.transform);
6109
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
6110
+ canvas.style.cursor = (0, import_image_editor14.getCropCursor)(handle, state.transform);
6111
+ }
6112
+ return;
6113
+ }
6114
+ if (activeTab === "annotate" && state.activeTool === "shape") {
6115
+ const g = shapeGestureRef.current;
6116
+ if (g.active) {
6117
+ g.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
6118
+ if (g.error) setShapeTypeError(g.error);
5789
6119
  }
5790
6120
  return;
5791
6121
  }
5792
6122
  if (activeTab === "annotate") {
5793
6123
  if (annotationDragInfoRef.current) {
5794
6124
  const drag = annotationDragInfoRef.current;
5795
- const currentImgPt2 = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6125
+ const currentImgPt2 = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5796
6126
  const dx = currentImgPt2.x - drag.startImgPt.x;
5797
6127
  const dy = currentImgPt2.y - drag.startImgPt.y;
5798
6128
  editor.updateAnnotation(drag.annId, {
@@ -5804,10 +6134,10 @@ var ImageEditor = ({
5804
6134
  const startPt = dragStartPointRef.current;
5805
6135
  if (!startPt) {
5806
6136
  if (state.activeTool === "select") {
5807
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6137
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5808
6138
  let hovered = false;
5809
6139
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5810
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, state.annotations[i])) {
6140
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, state.annotations[i])) {
5811
6141
  hovered = true;
5812
6142
  break;
5813
6143
  }
@@ -5818,7 +6148,7 @@ var ImageEditor = ({
5818
6148
  }
5819
6149
  return;
5820
6150
  }
5821
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6151
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5822
6152
  if (state.activeTool === "pen" && isDrawingRef.current) {
5823
6153
  currentPathRef.current.push(currentImgPt);
5824
6154
  const draft = {
@@ -5898,7 +6228,7 @@ var ImageEditor = ({
5898
6228
  if (activeTab === "select") {
5899
6229
  const gesture = selectionGestureRef.current;
5900
6230
  if (gesture.active) {
5901
- gesture.end((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
6231
+ gesture.end((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5902
6232
  selectionDraftRef.current = null;
5903
6233
  renderCanvas();
5904
6234
  }
@@ -5915,6 +6245,19 @@ var ImageEditor = ({
5915
6245
  }
5916
6246
  return;
5917
6247
  }
6248
+ if (activeTab === "annotate" && state.activeTool === "shape") {
6249
+ shapeGestureRef.current.up();
6250
+ return;
6251
+ }
6252
+ if (activeTab === "annotate" && state.activeTool === "type") {
6253
+ const tool = typeToolRef.current;
6254
+ tool.up((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
6255
+ setTypeSession(tool.session);
6256
+ if (tool.error) setShapeTypeError(tool.error);
6257
+ void renderCanvas();
6258
+ if (tool.session) setTimeout(() => typeInputRef.current?.focus(), 0);
6259
+ return;
6260
+ }
5918
6261
  if (activeTab === "annotate") {
5919
6262
  if (annotationDragInfoRef.current) {
5920
6263
  annotationDragInfoRef.current = null;
@@ -5922,7 +6265,7 @@ var ImageEditor = ({
5922
6265
  }
5923
6266
  const startPt = dragStartPointRef.current;
5924
6267
  if (startPt) {
5925
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6268
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5926
6269
  if (state.activeTool === "pen" && isDrawingRef.current) {
5927
6270
  if (currentPathRef.current.length > 1) {
5928
6271
  editor.addAnnotation({
@@ -6018,15 +6361,15 @@ var ImageEditor = ({
6018
6361
  link.click();
6019
6362
  }
6020
6363
  };
6021
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6364
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6022
6365
  "div",
6023
6366
  {
6024
6367
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
6025
6368
  style,
6026
6369
  children: [
6027
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
6028
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
6029
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6370
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
6371
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
6372
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6030
6373
  "button",
6031
6374
  {
6032
6375
  type: "button",
@@ -6038,7 +6381,7 @@ var ImageEditor = ({
6038
6381
  children: "Transform & Crop"
6039
6382
  }
6040
6383
  ),
6041
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6384
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6042
6385
  "button",
6043
6386
  {
6044
6387
  type: "button",
@@ -6050,7 +6393,7 @@ var ImageEditor = ({
6050
6393
  children: "Adjustments"
6051
6394
  }
6052
6395
  ),
6053
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6396
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6054
6397
  "button",
6055
6398
  {
6056
6399
  type: "button",
@@ -6062,7 +6405,7 @@ var ImageEditor = ({
6062
6405
  children: "Layers"
6063
6406
  }
6064
6407
  ),
6065
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6408
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6066
6409
  "button",
6067
6410
  {
6068
6411
  type: "button",
@@ -6074,7 +6417,7 @@ var ImageEditor = ({
6074
6417
  children: "Paint"
6075
6418
  }
6076
6419
  ),
6077
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6420
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6078
6421
  "button",
6079
6422
  {
6080
6423
  type: "button",
@@ -6086,7 +6429,7 @@ var ImageEditor = ({
6086
6429
  children: "Select & Mask"
6087
6430
  }
6088
6431
  ),
6089
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6432
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6090
6433
  "button",
6091
6434
  {
6092
6435
  type: "button",
@@ -6098,7 +6441,7 @@ var ImageEditor = ({
6098
6441
  children: "Annotations"
6099
6442
  }
6100
6443
  ),
6101
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6444
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6102
6445
  "button",
6103
6446
  {
6104
6447
  type: "button",
@@ -6110,7 +6453,7 @@ var ImageEditor = ({
6110
6453
  children: "Depth Mask"
6111
6454
  }
6112
6455
  ),
6113
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6456
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6114
6457
  "button",
6115
6458
  {
6116
6459
  type: "button",
@@ -6120,14 +6463,14 @@ var ImageEditor = ({
6120
6463
  },
6121
6464
  className: `px-3 py-1.5 rounded-md font-medium transition-colors flex items-center gap-1.5 ${activeTab === "ai" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
6122
6465
  children: [
6123
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
6466
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
6124
6467
  "AI Tools"
6125
6468
  ]
6126
6469
  }
6127
6470
  )
6128
6471
  ] }),
6129
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
6130
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6472
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
6473
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6131
6474
  "button",
6132
6475
  {
6133
6476
  type: "button",
@@ -6138,7 +6481,7 @@ var ImageEditor = ({
6138
6481
  children: "\u21A9"
6139
6482
  }
6140
6483
  ),
6141
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6484
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6142
6485
  "button",
6143
6486
  {
6144
6487
  type: "button",
@@ -6149,7 +6492,7 @@ var ImageEditor = ({
6149
6492
  children: "\u21AA"
6150
6493
  }
6151
6494
  ),
6152
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6495
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6153
6496
  "button",
6154
6497
  {
6155
6498
  type: "button",
@@ -6158,8 +6501,8 @@ var ImageEditor = ({
6158
6501
  children: "Reset"
6159
6502
  }
6160
6503
  ),
6161
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6162
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6504
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6505
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6163
6506
  "button",
6164
6507
  {
6165
6508
  type: "button",
@@ -6169,11 +6512,11 @@ var ImageEditor = ({
6169
6512
  children: "-"
6170
6513
  }
6171
6514
  ),
6172
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
6515
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
6173
6516
  Math.round(state.zoom * 100),
6174
6517
  "%"
6175
6518
  ] }),
6176
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6519
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6177
6520
  "button",
6178
6521
  {
6179
6522
  type: "button",
@@ -6183,8 +6526,8 @@ var ImageEditor = ({
6183
6526
  children: "+"
6184
6527
  }
6185
6528
  ),
6186
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6187
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6529
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6530
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6188
6531
  "button",
6189
6532
  {
6190
6533
  type: "button",
@@ -6195,7 +6538,7 @@ var ImageEditor = ({
6195
6538
  children: "Hold Compare"
6196
6539
  }
6197
6540
  ),
6198
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6541
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6199
6542
  "button",
6200
6543
  {
6201
6544
  type: "button",
@@ -6206,38 +6549,59 @@ var ImageEditor = ({
6206
6549
  )
6207
6550
  ] })
6208
6551
  ] }),
6209
- transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
6210
- !transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "alert", className: "border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200", children: transformTool.error }),
6211
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
6212
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6552
+ transformTool.active && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(FreeTransformOptionsBar, { tool: transformTool, className: "border-b border-slate-800 bg-slate-900/95 px-4 py-2" }),
6553
+ !transformTool.active && transformTool.error && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { role: "alert", className: "border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200", children: transformTool.error }),
6554
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
6555
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6213
6556
  "div",
6214
6557
  {
6215
6558
  ref: containerRef,
6216
6559
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
6217
- children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6218
- "canvas",
6219
- {
6220
- ref: canvasRef,
6221
- onMouseDown: handleMouseDown,
6222
- onMouseMove: handleMouseMove,
6223
- onMouseUp: handleMouseUp,
6224
- onMouseLeave: handleMouseUp,
6225
- onPointerDown: handlePaintPointerDown,
6226
- onPointerMove: handlePaintPointerMove,
6227
- onPointerUp: handlePaintPointerUp,
6228
- onPointerCancel: () => paintGestureRef.current?.cancel(),
6229
- "data-testid": "image-editor-canvas",
6230
- style: transformTool.active ? { cursor: transformCursor } : void 0,
6231
- className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
6232
- }
6233
- )
6560
+ children: [
6561
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6562
+ "canvas",
6563
+ {
6564
+ ref: canvasRef,
6565
+ onMouseDown: handleMouseDown,
6566
+ onMouseMove: handleMouseMove,
6567
+ onMouseUp: handleMouseUp,
6568
+ onMouseLeave: handleMouseUp,
6569
+ onPointerDown: handlePaintPointerDown,
6570
+ onPointerMove: handlePaintPointerMove,
6571
+ onPointerUp: handlePaintPointerUp,
6572
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
6573
+ "data-testid": "image-editor-canvas",
6574
+ style: transformTool.active ? { cursor: transformCursor } : void 0,
6575
+ className: `absolute inset-0 w-full h-full block ${transformTool.active ? "touch-none" : activeTab === "paint" ? "touch-none cursor-crosshair" : activeTab === "annotate" && state.activeTool === "type" ? "cursor-text" : activeTab === "annotate" && state.activeTool === "shape" ? "cursor-crosshair" : ""}`
6576
+ }
6577
+ ),
6578
+ typeSession && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6579
+ "textarea",
6580
+ {
6581
+ ref: typeInputRef,
6582
+ "aria-label": "Edit text",
6583
+ "data-testid": "type-input",
6584
+ autoCapitalize: "off",
6585
+ autoCorrect: "off",
6586
+ spellCheck: false,
6587
+ onKeyDown: handleTypeKeyDown,
6588
+ onInput: handleTypeInput,
6589
+ onCompositionEnd: (e) => {
6590
+ const session = typeToolRef.current?.session;
6591
+ if (session && e.data) session.insert(e.data);
6592
+ e.currentTarget.value = "";
6593
+ },
6594
+ className: "absolute left-0 top-0 h-px w-px opacity-0"
6595
+ }
6596
+ )
6597
+ ]
6234
6598
  }
6235
6599
  ),
6236
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
6237
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6238
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
6239
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
6240
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6600
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
6601
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6602
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
6603
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
6604
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6241
6605
  "button",
6242
6606
  {
6243
6607
  type: "button",
@@ -6249,7 +6613,7 @@ var ImageEditor = ({
6249
6613
  children: "Freeform"
6250
6614
  }
6251
6615
  ),
6252
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6616
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6253
6617
  "button",
6254
6618
  {
6255
6619
  type: "button",
@@ -6261,7 +6625,7 @@ var ImageEditor = ({
6261
6625
  children: "1:1 Square"
6262
6626
  }
6263
6627
  ),
6264
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6628
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6265
6629
  "button",
6266
6630
  {
6267
6631
  type: "button",
@@ -6273,7 +6637,7 @@ var ImageEditor = ({
6273
6637
  children: "4:3 Standard"
6274
6638
  }
6275
6639
  ),
6276
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6640
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6277
6641
  "button",
6278
6642
  {
6279
6643
  type: "button",
@@ -6285,7 +6649,7 @@ var ImageEditor = ({
6285
6649
  children: "16:9 Wide"
6286
6650
  }
6287
6651
  ),
6288
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6652
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6289
6653
  "button",
6290
6654
  {
6291
6655
  type: "button",
@@ -6297,7 +6661,7 @@ var ImageEditor = ({
6297
6661
  children: "3:2 Photo"
6298
6662
  }
6299
6663
  ),
6300
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6664
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6301
6665
  "button",
6302
6666
  {
6303
6667
  type: "button",
@@ -6310,10 +6674,10 @@ var ImageEditor = ({
6310
6674
  }
6311
6675
  )
6312
6676
  ] }),
6313
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6314
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
6315
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
6316
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6677
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6678
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
6679
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
6680
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6317
6681
  "button",
6318
6682
  {
6319
6683
  type: "button",
@@ -6322,7 +6686,7 @@ var ImageEditor = ({
6322
6686
  children: "Rotate -90\xB0"
6323
6687
  }
6324
6688
  ),
6325
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6689
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6326
6690
  "button",
6327
6691
  {
6328
6692
  type: "button",
@@ -6331,7 +6695,7 @@ var ImageEditor = ({
6331
6695
  children: "Rotate +90\xB0"
6332
6696
  }
6333
6697
  ),
6334
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6698
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6335
6699
  "button",
6336
6700
  {
6337
6701
  type: "button",
@@ -6340,7 +6704,7 @@ var ImageEditor = ({
6340
6704
  children: "Flip Horizontal"
6341
6705
  }
6342
6706
  ),
6343
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6707
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6344
6708
  "button",
6345
6709
  {
6346
6710
  type: "button",
@@ -6351,10 +6715,10 @@ var ImageEditor = ({
6351
6715
  )
6352
6716
  ] })
6353
6717
  ] }),
6354
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6355
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
6356
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
6357
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6718
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6719
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6720
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
6721
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6358
6722
  "button",
6359
6723
  {
6360
6724
  type: "button",
@@ -6364,25 +6728,25 @@ var ImageEditor = ({
6364
6728
  }
6365
6729
  )
6366
6730
  ] }),
6367
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Histogram, { histogram: editor.histogram }),
6368
- import_image_editor12.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react44.default.Fragment, { children: [
6369
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6731
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Histogram, { histogram: editor.histogram }),
6732
+ import_image_editor14.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react46.default.Fragment, { children: [
6733
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6370
6734
  ControlSlider,
6371
6735
  {
6372
6736
  spec,
6373
- value: (0, import_image_editor12.readAdjustmentControls)(state.adjustments)[spec.id],
6737
+ value: (0, import_image_editor14.readAdjustmentControls)(state.adjustments)[spec.id],
6374
6738
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
6375
6739
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
6376
6740
  }
6377
6741
  ),
6378
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6742
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6379
6743
  "div",
6380
6744
  {
6381
6745
  className: "flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200",
6382
6746
  "data-testid": "image-editor-process-notice",
6383
6747
  children: [
6384
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
6385
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6748
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
6749
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6386
6750
  "button",
6387
6751
  {
6388
6752
  type: "button",
@@ -6395,7 +6759,7 @@ var ImageEditor = ({
6395
6759
  }
6396
6760
  )
6397
6761
  ] }, spec.id)),
6398
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6762
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6399
6763
  AdjustmentLayersPanel,
6400
6764
  {
6401
6765
  controller,
@@ -6404,9 +6768,9 @@ var ImageEditor = ({
6404
6768
  }
6405
6769
  ) })
6406
6770
  ] }),
6407
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6408
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
6409
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6771
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6772
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
6773
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6410
6774
  "button",
6411
6775
  {
6412
6776
  type: "button",
@@ -6417,12 +6781,12 @@ var ImageEditor = ({
6417
6781
  children: "Free Transform"
6418
6782
  }
6419
6783
  ),
6420
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LayersPanel, { controller })
6784
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(LayersPanel, { controller })
6421
6785
  ] }),
6422
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6423
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
6424
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(BrushOptionsBar, { controller }),
6425
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6786
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6787
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
6788
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(BrushOptionsBar, { controller }),
6789
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6426
6790
  "button",
6427
6791
  {
6428
6792
  type: "button",
@@ -6433,12 +6797,29 @@ var ImageEditor = ({
6433
6797
  children: "Free Transform"
6434
6798
  }
6435
6799
  ),
6436
- paintError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
6437
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LayersPanel, { controller }) })
6800
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
6801
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(LayersPanel, { controller }) })
6438
6802
  ] }),
6439
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6440
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
6441
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6803
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6804
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
6805
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "grid grid-cols-2 gap-1.5", children: ["shape", "type"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6806
+ "button",
6807
+ {
6808
+ type: "button",
6809
+ "aria-pressed": state.activeTool === t,
6810
+ onClick: () => editor.setTool(t),
6811
+ className: `py-1.5 px-2 rounded-lg font-medium border transition-colors ${state.activeTool === t ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-800 border-slate-700 text-slate-300 hover:bg-slate-700"}`,
6812
+ children: t === "shape" ? "Shape" : "Type"
6813
+ },
6814
+ t
6815
+ )) }),
6816
+ state.activeTool === "shape" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
6817
+ state.activeTool === "type" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
6818
+ state.activeTool === "type" && typeSession && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", onClick: finishTyping, className: "self-start rounded bg-slate-800 px-2 py-1 text-[11px] text-slate-200 hover:bg-slate-700", children: "Done editing text" }),
6819
+ shapeTypeError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
6820
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6821
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
6822
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6442
6823
  "button",
6443
6824
  {
6444
6825
  type: "button",
@@ -6448,9 +6829,9 @@ var ImageEditor = ({
6448
6829
  },
6449
6830
  t
6450
6831
  )) }),
6451
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
6452
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("label", { className: "text-slate-400", children: "Color:" }),
6453
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6832
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
6833
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { className: "text-slate-400", children: "Color:" }),
6834
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6454
6835
  "input",
6455
6836
  {
6456
6837
  type: "color",
@@ -6459,15 +6840,15 @@ var ImageEditor = ({
6459
6840
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
6460
6841
  }
6461
6842
  ),
6462
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1 ml-2", children: [
6463
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
6464
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Width:" }),
6465
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-mono", children: [
6843
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex-1 ml-2", children: [
6844
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
6845
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Width:" }),
6846
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono", children: [
6466
6847
  strokeWidth,
6467
6848
  "px"
6468
6849
  ] })
6469
6850
  ] }),
6470
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6851
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6471
6852
  "input",
6472
6853
  {
6473
6854
  type: "range",
@@ -6480,10 +6861,10 @@ var ImageEditor = ({
6480
6861
  )
6481
6862
  ] })
6482
6863
  ] }),
6483
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6484
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
6485
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-2", children: [
6486
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6864
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6865
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
6866
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-2", children: [
6867
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6487
6868
  "input",
6488
6869
  {
6489
6870
  type: "text",
@@ -6494,7 +6875,7 @@ var ImageEditor = ({
6494
6875
  className: "flex-1 bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1.5 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-indigo-500"
6495
6876
  }
6496
6877
  ),
6497
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6878
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6498
6879
  "button",
6499
6880
  {
6500
6881
  type: "button",
@@ -6504,14 +6885,14 @@ var ImageEditor = ({
6504
6885
  }
6505
6886
  )
6506
6887
  ] }),
6507
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
6508
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Font Size:" }),
6509
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-mono", children: [
6888
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
6889
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Font Size:" }),
6890
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono", children: [
6510
6891
  fontSize,
6511
6892
  "px"
6512
6893
  ] })
6513
6894
  ] }),
6514
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6895
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6515
6896
  "input",
6516
6897
  {
6517
6898
  type: "range",
@@ -6522,14 +6903,14 @@ var ImageEditor = ({
6522
6903
  className: "w-full accent-indigo-500"
6523
6904
  }
6524
6905
  ),
6525
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6526
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
6527
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "text-slate-400", children: [
6906
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6907
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6908
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "text-slate-400", children: [
6528
6909
  "Layers (",
6529
6910
  state.annotations.length,
6530
6911
  ")"
6531
6912
  ] }),
6532
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6913
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6533
6914
  "button",
6534
6915
  {
6535
6916
  type: "button",
@@ -6538,7 +6919,7 @@ var ImageEditor = ({
6538
6919
  children: "Delete Selected"
6539
6920
  }
6540
6921
  ),
6541
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6922
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6542
6923
  "button",
6543
6924
  {
6544
6925
  type: "button",
@@ -6549,10 +6930,10 @@ var ImageEditor = ({
6549
6930
  )
6550
6931
  ] })
6551
6932
  ] }),
6552
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6553
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
6554
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
6555
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6933
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6934
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6935
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
6936
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6556
6937
  "button",
6557
6938
  {
6558
6939
  type: "button",
@@ -6562,8 +6943,8 @@ var ImageEditor = ({
6562
6943
  }
6563
6944
  )
6564
6945
  ] }),
6565
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6566
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6946
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6947
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6567
6948
  "input",
6568
6949
  {
6569
6950
  type: "checkbox",
@@ -6572,12 +6953,12 @@ var ImageEditor = ({
6572
6953
  className: "rounded accent-indigo-500"
6573
6954
  }
6574
6955
  ),
6575
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6956
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6576
6957
  ] }),
6577
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6578
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
6579
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6580
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6958
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
6959
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6960
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6961
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6581
6962
  "input",
6582
6963
  {
6583
6964
  type: "text",
@@ -6588,8 +6969,8 @@ var ImageEditor = ({
6588
6969
  }
6589
6970
  )
6590
6971
  ] }),
6591
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-2", children: [
6592
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6972
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-2", children: [
6973
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6593
6974
  "button",
6594
6975
  {
6595
6976
  type: "button",
@@ -6598,7 +6979,7 @@ var ImageEditor = ({
6598
6979
  children: "Threshold Mode"
6599
6980
  }
6600
6981
  ),
6601
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6982
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6602
6983
  "button",
6603
6984
  {
6604
6985
  type: "button",
@@ -6608,12 +6989,12 @@ var ImageEditor = ({
6608
6989
  }
6609
6990
  )
6610
6991
  ] }),
6611
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
6612
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6613
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Depth Start (Lower):" }),
6614
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
6992
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6993
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6994
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Depth Start (Lower):" }),
6995
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
6615
6996
  ] }),
6616
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6997
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6617
6998
  "input",
6618
6999
  {
6619
7000
  type: "range",
@@ -6627,12 +7008,12 @@ var ImageEditor = ({
6627
7008
  }
6628
7009
  )
6629
7010
  ] }),
6630
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
6631
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6632
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Depth Stop (Upper):" }),
6633
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
7011
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
7012
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
7013
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Depth Stop (Upper):" }),
7014
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
6634
7015
  ] }),
6635
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7016
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6636
7017
  "input",
6637
7018
  {
6638
7019
  type: "range",
@@ -6646,12 +7027,12 @@ var ImageEditor = ({
6646
7027
  }
6647
7028
  )
6648
7029
  ] }),
6649
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
6650
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6651
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Softness:" }),
6652
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
7030
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
7031
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
7032
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Softness:" }),
7033
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
6653
7034
  ] }),
6654
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7035
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6655
7036
  "input",
6656
7037
  {
6657
7038
  type: "range",
@@ -6663,8 +7044,8 @@ var ImageEditor = ({
6663
7044
  }
6664
7045
  )
6665
7046
  ] }),
6666
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
6667
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7047
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
7048
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6668
7049
  "input",
6669
7050
  {
6670
7051
  type: "checkbox",
@@ -6673,12 +7054,12 @@ var ImageEditor = ({
6673
7054
  className: "rounded accent-indigo-500"
6674
7055
  }
6675
7056
  ),
6676
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Invert Mask" })
7057
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Invert Mask" })
6677
7058
  ] })
6678
7059
  ] })
6679
7060
  ] }),
6680
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6681
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7061
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
7062
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6682
7063
  SelectionOptionsBar,
6683
7064
  {
6684
7065
  controller,
@@ -6688,9 +7069,9 @@ var ImageEditor = ({
6688
7069
  quickMask: Boolean(state.quickMask)
6689
7070
  }
6690
7071
  ),
6691
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
6692
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-1", children: [
6693
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7072
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
7073
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-1", children: [
7074
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6694
7075
  "button",
6695
7076
  {
6696
7077
  type: "button",
@@ -6701,7 +7082,7 @@ var ImageEditor = ({
6701
7082
  children: "Transform Selection"
6702
7083
  }
6703
7084
  ),
6704
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7085
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6705
7086
  "button",
6706
7087
  {
6707
7088
  type: "button",
@@ -6713,12 +7094,12 @@ var ImageEditor = ({
6713
7094
  }
6714
7095
  )
6715
7096
  ] }),
6716
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
7097
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
6717
7098
  ] }),
6718
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6719
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
6720
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Results go to" }),
6721
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
7099
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
7100
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
7101
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Results go to" }),
7102
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6722
7103
  "select",
6723
7104
  {
6724
7105
  "aria-label": "AI result target",
@@ -6726,54 +7107,54 @@ var ImageEditor = ({
6726
7107
  onChange: (e) => setAiTarget(e.target.value),
6727
7108
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
6728
7109
  children: [
6729
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
6730
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
6731
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "replace", children: "Replace image" })
7110
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
7111
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
7112
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "replace", children: "Replace image" })
6732
7113
  ]
6733
7114
  }
6734
7115
  )
6735
7116
  ] }),
6736
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6737
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
6738
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6739
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
7117
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
7118
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
7119
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
7120
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
6740
7121
  "Background Removal"
6741
7122
  ] }),
6742
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
7123
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
6743
7124
  ] }),
6744
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
6745
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7125
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
7126
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6746
7127
  "button",
6747
7128
  {
6748
7129
  type: "button",
6749
7130
  onClick: handleRemoveBackground,
6750
7131
  disabled: isRemovingBg || isInpainting,
6751
7132
  className: "mt-1 px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
6752
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6753
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
7133
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7134
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
6754
7135
  "Removing Background..."
6755
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6756
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
7136
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7137
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
6757
7138
  "Remove Background"
6758
7139
  ] })
6759
7140
  }
6760
7141
  )
6761
7142
  ] }),
6762
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6763
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
6764
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6765
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
6766
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
6767
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "m14 7 3 3" })
7143
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
7144
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
7145
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
7146
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
7147
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
7148
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "m14 7 3 3" })
6768
7149
  ] }),
6769
7150
  "Generative Inpainting"
6770
7151
  ] }),
6771
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
7152
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
6772
7153
  ] }),
6773
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
6774
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-1", children: [
6775
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
6776
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7154
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
7155
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
7156
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
7157
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6777
7158
  "textarea",
6778
7159
  {
6779
7160
  id: "ai-inpaint-prompt-react",
@@ -6785,10 +7166,10 @@ var ImageEditor = ({
6785
7166
  }
6786
7167
  )
6787
7168
  ] }),
6788
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-1", children: [
6789
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
6790
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
6791
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
7169
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
7170
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
7171
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
7172
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6792
7173
  "button",
6793
7174
  {
6794
7175
  type: "button",
@@ -6801,7 +7182,7 @@ var ImageEditor = ({
6801
7182
  ]
6802
7183
  }
6803
7184
  ),
6804
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
7185
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6805
7186
  "button",
6806
7187
  {
6807
7188
  type: "button",
@@ -6816,25 +7197,25 @@ var ImageEditor = ({
6816
7197
  )
6817
7198
  ] })
6818
7199
  ] }),
6819
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7200
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6820
7201
  "button",
6821
7202
  {
6822
7203
  type: "button",
6823
7204
  onClick: handleInpaint,
6824
7205
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
6825
7206
  className: "mt-1 px-3 py-2 rounded-lg bg-purple-600 hover:bg-purple-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
6826
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6827
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
7207
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7208
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
6828
7209
  "Generating Inpaint..."
6829
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6830
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
7210
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7211
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
6831
7212
  "Apply Inpainting"
6832
7213
  ] })
6833
7214
  }
6834
7215
  )
6835
7216
  ] }),
6836
- aiError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
6837
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
7217
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
7218
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
6838
7219
  ] })
6839
7220
  ] })
6840
7221
  ] })
@@ -6844,7 +7225,7 @@ var ImageEditor = ({
6844
7225
  };
6845
7226
 
6846
7227
  // src/review/useReview.ts
6847
- var import_react45 = require("react");
7228
+ var import_react47 = require("react");
6848
7229
  var import_editor12 = require("@pixerate/editor");
6849
7230
  var EMPTY_COMMENTS = Object.freeze({
6850
7231
  threads: [],
@@ -6863,23 +7244,23 @@ function isCommentStore(value) {
6863
7244
  }
6864
7245
  function useComments(source) {
6865
7246
  const store = isCommentStore(source) ? source : (0, import_editor12.getCommentStore)(source);
6866
- const subscribe = (0, import_react45.useCallback)(
7247
+ const subscribe = (0, import_react47.useCallback)(
6867
7248
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6868
7249
  [store]
6869
7250
  );
6870
7251
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
6871
- const snapshot = (0, import_react45.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6872
- return (0, import_react45.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
7252
+ const snapshot = (0, import_react47.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7253
+ return (0, import_react47.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
6873
7254
  }
6874
7255
  function useTrackChanges(editor) {
6875
7256
  const store = (0, import_editor12.getTrackChangesStore)(editor ?? null);
6876
- const subscribe = (0, import_react45.useCallback)(
7257
+ const subscribe = (0, import_react47.useCallback)(
6877
7258
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6878
7259
  [store]
6879
7260
  );
6880
7261
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
6881
- const snapshot = (0, import_react45.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6882
- return (0, import_react45.useMemo)(() => {
7262
+ const snapshot = (0, import_react47.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7263
+ return (0, import_react47.useMemo)(() => {
6883
7264
  const run = (fn) => () => {
6884
7265
  if (editor && !editor.isDestroyed) fn(editor);
6885
7266
  };
@@ -6902,9 +7283,9 @@ function useTrackChanges(editor) {
6902
7283
  }
6903
7284
 
6904
7285
  // src/review/CommentsPanel.tsx
6905
- var import_react46 = require("react");
7286
+ var import_react48 = require("react");
6906
7287
  var import_editor13 = require("@pixerate/editor");
6907
- var import_jsx_runtime28 = require("react/jsx-runtime");
7288
+ var import_jsx_runtime30 = require("react/jsx-runtime");
6908
7289
  var buttonClass2 = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
6909
7290
  var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
6910
7291
  var textareaClass = "w-full resize-y rounded-md border border-input bg-background p-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary";
@@ -6918,18 +7299,18 @@ var CommentsPanel = ({
6918
7299
  emptyMessage = "No comments yet. Select text and add a comment."
6919
7300
  }) => {
6920
7301
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
6921
- const [showResolved, setShowResolved] = (0, import_react46.useState)(showResolvedInitial);
7302
+ const [showResolved, setShowResolved] = (0, import_react48.useState)(showResolvedInitial);
6922
7303
  const author = authorProp ?? (0, import_editor13.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
6923
7304
  const visible = threads.filter((t) => showResolved || !t.resolved);
6924
7305
  const resolvedCount = threads.filter((t) => t.resolved).length;
6925
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("aside", { className, "aria-label": "Comments", children: [
6926
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
6927
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
7306
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("aside", { className, "aria-label": "Comments", children: [
7307
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
7308
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
6928
7309
  threads.length - resolvedCount,
6929
7310
  " open",
6930
7311
  resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
6931
7312
  ] }),
6932
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7313
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6933
7314
  "button",
6934
7315
  {
6935
7316
  type: "button",
@@ -6940,7 +7321,7 @@ var CommentsPanel = ({
6940
7321
  }
6941
7322
  )
6942
7323
  ] }),
6943
- visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7324
+ visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6944
7325
  CommentThreadCard,
6945
7326
  {
6946
7327
  thread,
@@ -6962,7 +7343,7 @@ var CommentThreadCard = ({
6962
7343
  author,
6963
7344
  formatTime
6964
7345
  }) => {
6965
- const [draft, setDraft] = (0, import_react46.useState)("");
7346
+ const [draft, setDraft] = (0, import_react48.useState)("");
6966
7347
  const isDraft = thread.body === "";
6967
7348
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
6968
7349
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -6988,7 +7369,7 @@ var CommentThreadCard = ({
6988
7369
  setDraft("");
6989
7370
  };
6990
7371
  const stop = (e) => e.stopPropagation();
6991
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
7372
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
6992
7373
  "li",
6993
7374
  {
6994
7375
  className: `flex flex-col gap-2 rounded-md border bg-background p-3 cursor-pointer ${active ? "border-primary ring-1 ring-primary" : "border-border"} ${thread.resolved ? "opacity-70" : ""}`,
@@ -7004,24 +7385,24 @@ var CommentThreadCard = ({
7004
7385
  }
7005
7386
  },
7006
7387
  children: [
7007
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
7008
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "font-medium", children: thread.author.name }),
7009
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
7388
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
7389
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: thread.author.name }),
7390
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
7010
7391
  ] }),
7011
- quote && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
7012
- thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
7013
- thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
7014
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
7015
- thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
7016
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "text-xs", children: [
7017
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "font-medium", children: reply.author.name }),
7392
+ quote && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
7393
+ thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
7394
+ thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
7395
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
7396
+ thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
7397
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "text-xs", children: [
7398
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: reply.author.name }),
7018
7399
  " ",
7019
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
7400
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
7020
7401
  ] }),
7021
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
7402
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
7022
7403
  ] }, reply.id)) }),
7023
- (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
7024
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7404
+ (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
7405
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7025
7406
  "textarea",
7026
7407
  {
7027
7408
  className: textareaClass,
@@ -7039,9 +7420,9 @@ var CommentThreadCard = ({
7039
7420
  }
7040
7421
  }
7041
7422
  ),
7042
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex justify-end gap-1", children: [
7043
- isDraft && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
7044
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7423
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex justify-end gap-1", children: [
7424
+ isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
7425
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7045
7426
  "button",
7046
7427
  {
7047
7428
  type: "button",
@@ -7053,9 +7434,9 @@ var CommentThreadCard = ({
7053
7434
  )
7054
7435
  ] })
7055
7436
  ] }),
7056
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
7057
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
7058
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7437
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
7438
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
7439
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7059
7440
  "button",
7060
7441
  {
7061
7442
  type: "button",
@@ -7071,7 +7452,7 @@ var CommentThreadCard = ({
7071
7452
  };
7072
7453
 
7073
7454
  // src/review/ReviewToolbar.tsx
7074
- var import_jsx_runtime29 = require("react/jsx-runtime");
7455
+ var import_jsx_runtime31 = require("react/jsx-runtime");
7075
7456
  var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
7076
7457
  var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
7077
7458
  var ReviewToolbar = ({
@@ -7084,8 +7465,8 @@ var ReviewToolbar = ({
7084
7465
  const count = review.changes.length;
7085
7466
  const current = review.currentChange;
7086
7467
  const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
7087
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
7088
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7468
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
7469
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7089
7470
  "button",
7090
7471
  {
7091
7472
  type: "button",
@@ -7096,8 +7477,8 @@ var ReviewToolbar = ({
7096
7477
  children: review.enabled ? "Tracking on" : "Track changes"
7097
7478
  }
7098
7479
  ),
7099
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
7100
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7480
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
7481
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7101
7482
  "button",
7102
7483
  {
7103
7484
  type: "button",
@@ -7108,8 +7489,8 @@ var ReviewToolbar = ({
7108
7489
  children: "\u2039"
7109
7490
  }
7110
7491
  ),
7111
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "min-w-[4rem] text-center text-xs text-muted-foreground", "aria-live": "polite", children: count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes` }),
7112
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7492
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "min-w-[4rem] text-center text-xs text-muted-foreground", "aria-live": "polite", children: count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes` }),
7493
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7113
7494
  "button",
7114
7495
  {
7115
7496
  type: "button",
@@ -7120,7 +7501,7 @@ var ReviewToolbar = ({
7120
7501
  children: "\u203A"
7121
7502
  }
7122
7503
  ),
7123
- showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7504
+ showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7124
7505
  "span",
7125
7506
  {
7126
7507
  className: descriptionClassName,
@@ -7132,8 +7513,8 @@ var ReviewToolbar = ({
7132
7513
  ]
7133
7514
  }
7134
7515
  ),
7135
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
7136
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7516
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
7517
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7137
7518
  "button",
7138
7519
  {
7139
7520
  type: "button",
@@ -7143,7 +7524,7 @@ var ReviewToolbar = ({
7143
7524
  children: "Accept"
7144
7525
  }
7145
7526
  ),
7146
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7527
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7147
7528
  "button",
7148
7529
  {
7149
7530
  type: "button",
@@ -7153,18 +7534,18 @@ var ReviewToolbar = ({
7153
7534
  children: "Reject"
7154
7535
  }
7155
7536
  ),
7156
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
7157
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
7537
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
7538
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
7158
7539
  ] });
7159
7540
  };
7160
7541
 
7161
7542
  // src/review/CommentButton.tsx
7162
- var import_jsx_runtime30 = require("react/jsx-runtime");
7543
+ var import_jsx_runtime32 = require("react/jsx-runtime");
7163
7544
  var CommentButton = ({
7164
7545
  editor,
7165
7546
  className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
7166
7547
  children = "Comment"
7167
- }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7548
+ }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7168
7549
  "button",
7169
7550
  {
7170
7551
  type: "button",
@@ -7176,13 +7557,13 @@ var CommentButton = ({
7176
7557
  );
7177
7558
 
7178
7559
  // src/review/useDocumentCompare.ts
7179
- var import_react47 = require("react");
7560
+ var import_react49 = require("react");
7180
7561
  var import_editor14 = require("@pixerate/editor");
7181
7562
  function useDocumentCompare(editor, options) {
7182
- const [summary, setSummary] = (0, import_react47.useState)(null);
7183
- const defaults = (0, import_react47.useRef)(options);
7563
+ const [summary, setSummary] = (0, import_react49.useState)(null);
7564
+ const defaults = (0, import_react49.useRef)(options);
7184
7565
  defaults.current = options;
7185
- const compare = (0, import_react47.useCallback)(
7566
+ const compare = (0, import_react49.useCallback)(
7186
7567
  (original, revised, overrides) => {
7187
7568
  if (!editor || editor.isDestroyed) return null;
7188
7569
  const result = (0, import_editor14.applyDocumentComparison)(editor, original, revised, {
@@ -7194,13 +7575,13 @@ function useDocumentCompare(editor, options) {
7194
7575
  },
7195
7576
  [editor]
7196
7577
  );
7197
- const clear = (0, import_react47.useCallback)(() => setSummary(null), []);
7198
- return (0, import_react47.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
7578
+ const clear = (0, import_react49.useCallback)(() => setSummary(null), []);
7579
+ return (0, import_react49.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
7199
7580
  }
7200
7581
 
7201
7582
  // src/review/TrackedChangesList.tsx
7202
7583
  var import_editor15 = require("@pixerate/editor");
7203
- var import_jsx_runtime31 = require("react/jsx-runtime");
7584
+ var import_jsx_runtime33 = require("react/jsx-runtime");
7204
7585
  var buttonClass4 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
7205
7586
  var TrackedChangesList = ({
7206
7587
  editor,
@@ -7211,18 +7592,18 @@ var TrackedChangesList = ({
7211
7592
  }) => {
7212
7593
  const review = useTrackChanges(editor);
7213
7594
  if (review.changes.length === 0) {
7214
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
7595
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
7215
7596
  }
7216
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
7597
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
7217
7598
  const active = change.id === review.currentChangeId;
7218
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7599
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7219
7600
  "li",
7220
7601
  {
7221
7602
  className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
7222
7603
  "data-change-type": change.type,
7223
7604
  "data-change-id": change.id,
7224
7605
  children: [
7225
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7606
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7226
7607
  "button",
7227
7608
  {
7228
7609
  type: "button",
@@ -7230,14 +7611,14 @@ var TrackedChangesList = ({
7230
7611
  title: `${change.author.name}: ${change.description}`,
7231
7612
  onClick: () => review.select(change.id),
7232
7613
  children: [
7233
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
7614
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
7234
7615
  change.author.name ? ` \xB7 ${change.author.name}` : "",
7235
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
7616
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
7236
7617
  ]
7237
7618
  }
7238
7619
  ),
7239
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
7240
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
7620
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
7621
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
7241
7622
  ]
7242
7623
  },
7243
7624
  `${change.type}:${change.id}`
@@ -7246,12 +7627,12 @@ var TrackedChangesList = ({
7246
7627
  };
7247
7628
 
7248
7629
  // src/commands/useCommandPalette.ts
7249
- var import_react48 = require("react");
7630
+ var import_react50 = require("react");
7250
7631
  var import_commands2 = require("@pixerate/editor/commands");
7251
7632
  function useCommandPalette(registry, options = {}) {
7252
- const optionsRef = (0, import_react48.useRef)(options);
7633
+ const optionsRef = (0, import_react50.useRef)(options);
7253
7634
  optionsRef.current = options;
7254
- const controller = (0, import_react48.useMemo)(
7635
+ const controller = (0, import_react50.useMemo)(
7255
7636
  () => (0, import_commands2.createCommandPaletteController)(registry, {
7256
7637
  context: () => {
7257
7638
  const c = optionsRef.current.context;
@@ -7272,9 +7653,9 @@ function useCommandPalette(registry, options = {}) {
7272
7653
  // eslint-disable-next-line react-hooks/exhaustive-deps
7273
7654
  [registry]
7274
7655
  );
7275
- const state = (0, import_react48.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7656
+ const state = (0, import_react50.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7276
7657
  const { hotkey, hotkeyTarget } = options;
7277
- (0, import_react48.useEffect)(() => {
7658
+ (0, import_react50.useEffect)(() => {
7278
7659
  if (!hotkey) return;
7279
7660
  const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
7280
7661
  if (!target) return;
@@ -7302,13 +7683,13 @@ function useCommandPalette(registry, options = {}) {
7302
7683
  }
7303
7684
 
7304
7685
  // src/commands/CommandPalette.tsx
7305
- var import_react49 = __toESM(require("react"), 1);
7306
- var import_jsx_runtime32 = require("react/jsx-runtime");
7686
+ var import_react51 = __toESM(require("react"), 1);
7687
+ var import_jsx_runtime34 = require("react/jsx-runtime");
7307
7688
  function HighlightedLabel({ item }) {
7308
- if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: item.label });
7689
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children: item.label });
7309
7690
  const marked = new Set(item.labelIndices);
7310
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: Array.from(item.label).map(
7311
- (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react49.default.Fragment, { children: ch }, i)
7691
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children: Array.from(item.label).map(
7692
+ (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react51.default.Fragment, { children: ch }, i)
7312
7693
  ) });
7313
7694
  }
7314
7695
  var CommandPalette = ({
@@ -7317,22 +7698,22 @@ var CommandPalette = ({
7317
7698
  emptyMessage = "No matching commands",
7318
7699
  className = ""
7319
7700
  }) => {
7320
- const inputRef = (0, import_react49.useRef)(null);
7321
- const listRef = (0, import_react49.useRef)(null);
7322
- const baseId = (0, import_react49.useId)();
7701
+ const inputRef = (0, import_react51.useRef)(null);
7702
+ const listRef = (0, import_react51.useRef)(null);
7703
+ const baseId = (0, import_react51.useId)();
7323
7704
  const listId = `${baseId}-list`;
7324
7705
  const optionId = (index) => `${baseId}-option-${index}`;
7325
7706
  const { open, query, items, activeIndex } = palette;
7326
- (0, import_react49.useEffect)(() => {
7707
+ (0, import_react51.useEffect)(() => {
7327
7708
  if (open) inputRef.current?.focus();
7328
7709
  }, [open]);
7329
- (0, import_react49.useEffect)(() => {
7710
+ (0, import_react51.useEffect)(() => {
7330
7711
  if (!open) return;
7331
7712
  const active = listRef.current?.querySelector('[aria-selected="true"]');
7332
7713
  active?.scrollIntoView?.({ block: "nearest" });
7333
7714
  }, [open, activeIndex]);
7334
7715
  if (!open) return null;
7335
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7716
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7336
7717
  "div",
7337
7718
  {
7338
7719
  className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
@@ -7340,7 +7721,7 @@ var CommandPalette = ({
7340
7721
  onMouseDown: (e) => {
7341
7722
  if (e.target === e.currentTarget) palette.setOpen(false);
7342
7723
  },
7343
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7724
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
7344
7725
  "div",
7345
7726
  {
7346
7727
  role: "dialog",
@@ -7349,7 +7730,7 @@ var CommandPalette = ({
7349
7730
  className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
7350
7731
  style: { background: "var(--popover, var(--background, #fff))" },
7351
7732
  children: [
7352
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7733
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7353
7734
  "input",
7354
7735
  {
7355
7736
  ref: inputRef,
@@ -7369,7 +7750,7 @@ var CommandPalette = ({
7369
7750
  className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
7370
7751
  }
7371
7752
  ),
7372
- items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "max-h-80 overflow-y-auto py-1", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7753
+ items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "max-h-80 overflow-y-auto py-1", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
7373
7754
  "li",
7374
7755
  {
7375
7756
  id: optionId(index),
@@ -7384,12 +7765,12 @@ var CommandPalette = ({
7384
7765
  onClick: () => palette.run(item.id),
7385
7766
  className: `flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm ${index === activeIndex ? "bg-muted" : ""} ${item.enabled ? "" : "cursor-default opacity-50"}`,
7386
7767
  children: [
7387
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
7388
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(HighlightedLabel, { item }),
7389
- item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
7768
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
7769
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HighlightedLabel, { item }),
7770
+ item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
7390
7771
  ] }),
7391
- item.group && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
7392
- item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
7772
+ item.group && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
7773
+ item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
7393
7774
  ]
7394
7775
  },
7395
7776
  item.id
@@ -7402,12 +7783,12 @@ var CommandPalette = ({
7402
7783
  };
7403
7784
 
7404
7785
  // src/commands/useCommandShortcuts.ts
7405
- var import_react50 = require("react");
7786
+ var import_react52 = require("react");
7406
7787
  function useCommandShortcuts(registry, options = {}) {
7407
- const optionsRef = (0, import_react50.useRef)(options);
7788
+ const optionsRef = (0, import_react52.useRef)(options);
7408
7789
  optionsRef.current = options;
7409
7790
  const { enabled = true, target } = options;
7410
- (0, import_react50.useEffect)(() => {
7791
+ (0, import_react52.useEffect)(() => {
7411
7792
  if (!registry || !enabled) return;
7412
7793
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
7413
7794
  if (!eventTarget) return;
@@ -7425,14 +7806,14 @@ function useCommandShortcuts(registry, options = {}) {
7425
7806
  }, [registry, enabled, target]);
7426
7807
  }
7427
7808
  function useRegisterCommands(registry, specs) {
7428
- (0, import_react50.useEffect)(() => {
7809
+ (0, import_react52.useEffect)(() => {
7429
7810
  if (!registry || !specs || specs.length === 0) return;
7430
7811
  return registry.register(specs);
7431
7812
  }, [registry, specs]);
7432
7813
  }
7433
7814
 
7434
7815
  // src/persistence/useAutosave.ts
7435
- var import_react51 = require("react");
7816
+ var import_react53 = require("react");
7436
7817
  var import_persistence = require("@pixerate/editor/persistence");
7437
7818
  var IDLE = {
7438
7819
  status: "idle",
@@ -7443,18 +7824,18 @@ var IDLE = {
7443
7824
  ready: false
7444
7825
  };
7445
7826
  function useAutosave(options) {
7446
- const optionsRef = (0, import_react51.useRef)(options);
7827
+ const optionsRef = (0, import_react53.useRef)(options);
7447
7828
  optionsRef.current = options;
7448
7829
  const { storage, key, history, dirty } = options;
7449
7830
  const recover = options.recover !== false;
7450
7831
  const flushOnHide = options.flushOnHide !== false;
7451
7832
  const ready = options.ready !== false;
7452
- const [controller, setController] = (0, import_react51.useState)(null);
7453
- const [status, setStatus] = (0, import_react51.useState)(IDLE);
7454
- const [recovery, setRecovery] = (0, import_react51.useState)(null);
7455
- const [pendingRecovery, setPendingRecovery] = (0, import_react51.useState)(recover);
7456
- const revisionsRef = (0, import_react51.useRef)(null);
7457
- (0, import_react51.useEffect)(() => {
7833
+ const [controller, setController] = (0, import_react53.useState)(null);
7834
+ const [status, setStatus] = (0, import_react53.useState)(IDLE);
7835
+ const [recovery, setRecovery] = (0, import_react53.useState)(null);
7836
+ const [pendingRecovery, setPendingRecovery] = (0, import_react53.useState)(recover);
7837
+ const revisionsRef = (0, import_react53.useRef)(null);
7838
+ (0, import_react53.useEffect)(() => {
7458
7839
  const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
7459
7840
  const o = optionsRef.current;
7460
7841
  const instance = (0, import_persistence.createAutosaveController)({
@@ -7497,10 +7878,10 @@ function useAutosave(options) {
7497
7878
  if (revisionsRef.current === revisions) revisionsRef.current = null;
7498
7879
  };
7499
7880
  }, [storage, key, history, dirty, recover]);
7500
- (0, import_react51.useEffect)(() => {
7881
+ (0, import_react53.useEffect)(() => {
7501
7882
  if (controller && ready && !pendingRecovery) controller.ready();
7502
7883
  }, [controller, ready, pendingRecovery]);
7503
- (0, import_react51.useEffect)(() => {
7884
+ (0, import_react53.useEffect)(() => {
7504
7885
  if (!controller || !flushOnHide || typeof window === "undefined") return;
7505
7886
  const flush = () => void controller.flushNow();
7506
7887
  const onVisibility = () => {
@@ -7513,31 +7894,31 @@ function useAutosave(options) {
7513
7894
  document.removeEventListener("visibilitychange", onVisibility);
7514
7895
  };
7515
7896
  }, [controller, flushOnHide]);
7516
- const restore = (0, import_react51.useCallback)(() => {
7897
+ const restore = (0, import_react53.useCallback)(() => {
7517
7898
  const snapshot = recovery?.snapshot;
7518
7899
  setRecovery(null);
7519
7900
  setPendingRecovery(false);
7520
7901
  return snapshot;
7521
7902
  }, [recovery]);
7522
- const discard = (0, import_react51.useCallback)(async () => {
7903
+ const discard = (0, import_react53.useCallback)(async () => {
7523
7904
  if (controller) await controller.discardRecovery();
7524
7905
  setRecovery(null);
7525
7906
  setPendingRecovery(false);
7526
7907
  }, [controller]);
7527
- const flushNow = (0, import_react51.useCallback)(async () => {
7908
+ const flushNow = (0, import_react53.useCallback)(async () => {
7528
7909
  await controller?.flushNow();
7529
7910
  }, [controller]);
7530
- const markClean = (0, import_react51.useCallback)(async () => {
7911
+ const markClean = (0, import_react53.useCallback)(async () => {
7531
7912
  revisionsRef.current?.markSaved();
7532
7913
  await controller?.markClean();
7533
7914
  }, [controller]);
7534
- const notifyChange = (0, import_react51.useCallback)(() => revisionsRef.current?.bump(), []);
7915
+ const notifyChange = (0, import_react53.useCallback)(() => revisionsRef.current?.bump(), []);
7535
7916
  return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
7536
7917
  }
7537
7918
 
7538
7919
  // src/persistence/RecoveryPrompt.tsx
7539
7920
  var import_persistence2 = require("@pixerate/editor/persistence");
7540
- var import_jsx_runtime33 = require("react/jsx-runtime");
7921
+ var import_jsx_runtime35 = require("react/jsx-runtime");
7541
7922
  var RecoveryPrompt = ({
7542
7923
  recovery,
7543
7924
  onRestore,
@@ -7549,7 +7930,7 @@ var RecoveryPrompt = ({
7549
7930
  }) => {
7550
7931
  if (!recovery) return null;
7551
7932
  const { name } = recovery.meta;
7552
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7933
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
7553
7934
  "div",
7554
7935
  {
7555
7936
  role: "alertdialog",
@@ -7557,15 +7938,15 @@ var RecoveryPrompt = ({
7557
7938
  "data-recovery-prompt": "",
7558
7939
  className: `flex flex-wrap items-center gap-3 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm ${className}`,
7559
7940
  children: [
7560
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "min-w-0 flex-1", children: [
7941
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "min-w-0 flex-1", children: [
7561
7942
  (0, import_persistence2.formatRecoveryMessage)(recovery.meta, formatTime),
7562
- name ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7943
+ name ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7563
7944
  "(",
7564
7945
  name,
7565
7946
  ")"
7566
7947
  ] }) : null
7567
7948
  ] }),
7568
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7949
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7569
7950
  "button",
7570
7951
  {
7571
7952
  type: "button",
@@ -7575,7 +7956,7 @@ var RecoveryPrompt = ({
7575
7956
  children: restoreLabel
7576
7957
  }
7577
7958
  ),
7578
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7959
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7579
7960
  "button",
7580
7961
  {
7581
7962
  type: "button",
@@ -7591,17 +7972,17 @@ var RecoveryPrompt = ({
7591
7972
  };
7592
7973
 
7593
7974
  // src/generation/useGenerationPlan.ts
7594
- var import_react52 = require("react");
7975
+ var import_react54 = require("react");
7595
7976
  var import_generation = require("@pixerate/editor/generation");
7596
7977
  function useGenerationPlan(request, capabilities, options = {}) {
7597
7978
  const key = JSON.stringify([request, capabilities, options]);
7598
- return (0, import_react52.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7979
+ return (0, import_react54.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7599
7980
  }
7600
7981
  function useJobProgress(options) {
7601
7982
  const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
7602
- const [tick, setTick] = (0, import_react52.useState)(() => Date.now());
7983
+ const [tick, setTick] = (0, import_react54.useState)(() => Date.now());
7603
7984
  const ticking = !done && now === void 0;
7604
- (0, import_react52.useEffect)(() => {
7985
+ (0, import_react54.useEffect)(() => {
7605
7986
  if (!ticking) return;
7606
7987
  setTick(Date.now());
7607
7988
  const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
@@ -7611,9 +7992,9 @@ function useJobProgress(options) {
7611
7992
  }
7612
7993
 
7613
7994
  // src/generation/GenerationSettings.tsx
7614
- var import_react53 = require("react");
7995
+ var import_react55 = require("react");
7615
7996
  var import_generation2 = require("@pixerate/editor/generation");
7616
- var import_jsx_runtime34 = require("react/jsx-runtime");
7997
+ var import_jsx_runtime36 = require("react/jsx-runtime");
7617
7998
  var inputClass2 = "w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring";
7618
7999
  function Control({
7619
8000
  control,
@@ -7623,7 +8004,7 @@ function Control({
7623
8004
  }) {
7624
8005
  const shown = value ?? control.defaultValue;
7625
8006
  if (control.kind === "checkbox") {
7626
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8007
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7627
8008
  "input",
7628
8009
  {
7629
8010
  id,
@@ -7635,7 +8016,7 @@ function Control({
7635
8016
  );
7636
8017
  }
7637
8018
  if (control.kind === "select") {
7638
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
8019
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7639
8020
  "select",
7640
8021
  {
7641
8022
  id,
@@ -7644,14 +8025,14 @@ function Control({
7644
8025
  value: shown === void 0 ? "" : String(shown),
7645
8026
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
7646
8027
  children: [
7647
- shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("option", { value: "", children: "Default" }),
7648
- control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
8028
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: "", children: "Default" }),
8029
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
7649
8030
  ]
7650
8031
  }
7651
8032
  );
7652
8033
  }
7653
8034
  if (control.kind === "textarea") {
7654
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8035
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7655
8036
  "textarea",
7656
8037
  {
7657
8038
  id,
@@ -7665,8 +8046,8 @@ function Control({
7665
8046
  );
7666
8047
  }
7667
8048
  const numeric = typeof shown === "number" ? shown : void 0;
7668
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2", children: [
7669
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8049
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
8050
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7670
8051
  "input",
7671
8052
  {
7672
8053
  id,
@@ -7680,7 +8061,7 @@ function Control({
7680
8061
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
7681
8062
  }
7682
8063
  ),
7683
- control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
8064
+ control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
7684
8065
  ] });
7685
8066
  }
7686
8067
  var GenerationSettings = ({
@@ -7694,17 +8075,17 @@ var GenerationSettings = ({
7694
8075
  renderReference,
7695
8076
  className = ""
7696
8077
  }) => {
7697
- const baseId = (0, import_react53.useId)();
7698
- const controls = (0, import_react53.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
8078
+ const baseId = (0, import_react55.useId)();
8079
+ const controls = (0, import_react55.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7699
8080
  const computed = useGenerationPlan(value, capabilities, { strategy });
7700
8081
  const plan = planProp ?? computed;
7701
8082
  const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
7702
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
8083
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
7703
8084
  controls.map((control) => {
7704
8085
  const id = `${baseId}-${control.key}`;
7705
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
7706
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
7707
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8086
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
8087
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
8088
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7708
8089
  Control,
7709
8090
  {
7710
8091
  control,
@@ -7715,23 +8096,23 @@ var GenerationSettings = ({
7715
8096
  )
7716
8097
  ] }, control.key);
7717
8098
  }),
7718
- slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
7719
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
8099
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
8100
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
7720
8101
  slot.label,
7721
8102
  " ",
7722
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
8103
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7723
8104
  "(",
7724
8105
  slot.references.length,
7725
8106
  "/",
7726
8107
  slot.max,
7727
8108
  ")"
7728
8109
  ] }),
7729
- slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-destructive", children: " *" })
8110
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-destructive", children: " *" })
7730
8111
  ] }),
7731
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
7732
- slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
7733
- renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
7734
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8112
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
8113
+ slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
8114
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
8115
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7735
8116
  "button",
7736
8117
  {
7737
8118
  type: "button",
@@ -7742,7 +8123,7 @@ var GenerationSettings = ({
7742
8123
  }
7743
8124
  )
7744
8125
  ] }, ref.id)),
7745
- onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8126
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7746
8127
  "button",
7747
8128
  {
7748
8129
  type: "button",
@@ -7753,21 +8134,21 @@ var GenerationSettings = ({
7753
8134
  ) })
7754
8135
  ] })
7755
8136
  ] }, slot.role)),
7756
- showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { role: "status", className: "flex flex-col gap-0.5 text-xs text-muted-foreground", "data-generation-adjustments": "", children: plan.adjustments.map((adjustment, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
7757
- showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { role: "alert", className: "flex flex-col gap-0.5 text-xs text-destructive", "data-generation-errors": "", children: plan.errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
8137
+ showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { role: "status", className: "flex flex-col gap-0.5 text-xs text-muted-foreground", "data-generation-adjustments": "", children: plan.adjustments.map((adjustment, index) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
8138
+ showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { role: "alert", className: "flex flex-col gap-0.5 text-xs text-destructive", "data-generation-errors": "", children: plan.errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
7758
8139
  ] });
7759
8140
  };
7760
8141
 
7761
8142
  // src/generation/JobProgress.tsx
7762
- var import_jsx_runtime35 = require("react/jsx-runtime");
8143
+ var import_jsx_runtime37 = require("react/jsx-runtime");
7763
8144
  var JobProgress = ({ title, className = "", ...options }) => {
7764
8145
  const progress = useJobProgress(options);
7765
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
7766
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
7767
- title && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "truncate text-foreground", children: title }),
7768
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
8146
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
8147
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
8148
+ title && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "truncate text-foreground", children: title }),
8149
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
7769
8150
  ] }),
7770
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8151
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7771
8152
  "div",
7772
8153
  {
7773
8154
  role: "progressbar",
@@ -7777,7 +8158,7 @@ var JobProgress = ({ title, className = "", ...options }) => {
7777
8158
  "aria-valuenow": progress.percent,
7778
8159
  "aria-valuetext": `${progress.percent}%, ${progress.label}`,
7779
8160
  className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
7780
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8161
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7781
8162
  "div",
7782
8163
  {
7783
8164
  className: "h-full rounded-full bg-primary transition-[width] duration-500",
@@ -7790,9 +8171,9 @@ var JobProgress = ({ title, className = "", ...options }) => {
7790
8171
  };
7791
8172
 
7792
8173
  // src/generation/AssetMentionChips.tsx
7793
- var import_react54 = require("react");
8174
+ var import_react56 = require("react");
7794
8175
  var import_generation3 = require("@pixerate/editor/generation");
7795
- var import_jsx_runtime36 = require("react/jsx-runtime");
8176
+ var import_jsx_runtime38 = require("react/jsx-runtime");
7796
8177
  var AssetMentionChips = ({
7797
8178
  content,
7798
8179
  onChange,
@@ -7802,14 +8183,14 @@ var AssetMentionChips = ({
7802
8183
  renderAsset,
7803
8184
  className = ""
7804
8185
  }) => {
7805
- const [open, setOpen] = (0, import_react54.useState)(null);
7806
- const rootRef = (0, import_react54.useRef)(null);
7807
- const chips = (0, import_react54.useMemo)(
8186
+ const [open, setOpen] = (0, import_react56.useState)(null);
8187
+ const rootRef = (0, import_react56.useRef)(null);
8188
+ const chips = (0, import_react56.useMemo)(
7808
8189
  () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
7809
8190
  [content, assets, capabilities]
7810
8191
  );
7811
8192
  const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
7812
- (0, import_react54.useEffect)(() => {
8193
+ (0, import_react56.useEffect)(() => {
7813
8194
  if (open === null) return;
7814
8195
  const onPointer = (event) => {
7815
8196
  if (!rootRef.current?.contains(event.target)) setOpen(null);
@@ -7817,19 +8198,19 @@ var AssetMentionChips = ({
7817
8198
  document.addEventListener("mousedown", onPointer);
7818
8199
  return () => document.removeEventListener("mousedown", onPointer);
7819
8200
  }, [open]);
7820
- const pick = (chip3, role) => {
8201
+ const pick = (chip5, role) => {
7821
8202
  setOpen(null);
7822
- if (chip3.start === void 0) return;
7823
- onChange((0, import_generation3.setMentionRoleInText)(content, chip3.start, role));
8203
+ if (chip5.start === void 0) return;
8204
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip5.start, role));
7824
8205
  };
7825
8206
  if (chips.length === 0) return null;
7826
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip3) => {
7827
- const error = chip3.issues.find((issue) => issue.severity === "error");
7828
- const warning = chip3.issues.find((issue) => issue.severity === "warning");
8207
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip5) => {
8208
+ const error = chip5.issues.find((issue) => issue.severity === "error");
8209
+ const warning = chip5.issues.find((issue) => issue.severity === "warning");
7829
8210
  const problem = error ?? warning;
7830
- const isOpen = open === chip3.index;
7831
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip3.asset.id, children: [
7832
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8211
+ const isOpen = open === chip5.index;
8212
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip5.asset.id, children: [
8213
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7833
8214
  "button",
7834
8215
  {
7835
8216
  type: "button",
@@ -7837,82 +8218,82 @@ var AssetMentionChips = ({
7837
8218
  "aria-expanded": isOpen,
7838
8219
  title: problem?.message,
7839
8220
  "data-issue": problem?.code,
7840
- onClick: () => setOpen(isOpen ? null : chip3.index),
8221
+ onClick: () => setOpen(isOpen ? null : chip5.index),
7841
8222
  onKeyDown: (e) => {
7842
8223
  if (e.key === "Escape") setOpen(null);
7843
8224
  },
7844
8225
  className: `inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs ${error ? "border-red-500/60" : warning ? "border-amber-500/60" : "border-border"} bg-muted/40 hover:bg-muted`,
7845
8226
  children: [
7846
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: renderAsset ? renderAsset(chip3) : `@${chip3.asset.label ?? chip3.handle}` }),
7847
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8227
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: renderAsset ? renderAsset(chip5) : `@${chip5.asset.label ?? chip5.handle}` }),
8228
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7848
8229
  "span",
7849
8230
  {
7850
- className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip3.role ? "bg-primary/15" : "opacity-60"}`,
7851
- "data-role-badge": chip3.role ?? "",
7852
- children: chip3.roleLabel ?? "No role"
8231
+ className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip5.role ? "bg-primary/15" : "opacity-60"}`,
8232
+ "data-role-badge": chip5.role ?? "",
8233
+ children: chip5.roleLabel ?? "No role"
7853
8234
  }
7854
8235
  )
7855
8236
  ]
7856
8237
  }
7857
8238
  ),
7858
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8239
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7859
8240
  "div",
7860
8241
  {
7861
8242
  role: "listbox",
7862
- "aria-label": `Role for ${chip3.asset.label ?? chip3.handle}`,
8243
+ "aria-label": `Role for ${chip5.asset.label ?? chip5.handle}`,
7863
8244
  className: "absolute left-0 top-full z-50 mt-1 flex min-w-[12rem] flex-col rounded-md border border-border bg-background p-1 text-xs shadow-lg",
7864
8245
  "data-role-picker": "",
7865
8246
  onKeyDown: (e) => {
7866
8247
  if (e.key === "Escape") setOpen(null);
7867
8248
  },
7868
8249
  children: [
7869
- options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8250
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7870
8251
  "button",
7871
8252
  {
7872
8253
  type: "button",
7873
8254
  role: "option",
7874
- "aria-selected": chip3.role === option.role,
8255
+ "aria-selected": chip5.role === option.role,
7875
8256
  "data-role-option": option.role,
7876
8257
  title: option.description,
7877
- onClick: () => pick(chip3, option.role),
8258
+ onClick: () => pick(chip5, option.role),
7878
8259
  className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
7879
8260
  children: [
7880
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: option.label }),
7881
- option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
8261
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: option.label }),
8262
+ option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
7882
8263
  ]
7883
8264
  },
7884
8265
  option.role
7885
8266
  )),
7886
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8267
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7887
8268
  "button",
7888
8269
  {
7889
8270
  type: "button",
7890
8271
  role: "option",
7891
- "aria-selected": !chip3.role,
8272
+ "aria-selected": !chip5.role,
7892
8273
  "data-role-option": "",
7893
- onClick: () => pick(chip3, null),
8274
+ onClick: () => pick(chip5, null),
7894
8275
  className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
7895
8276
  children: "No role"
7896
8277
  }
7897
8278
  ),
7898
- chip3.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "mt-1 border-t border-border px-2 pt-1 text-[10px]", "data-chip-issues": "", children: chip3.issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
8279
+ chip5.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "mt-1 border-t border-border px-2 pt-1 text-[10px]", "data-chip-issues": "", children: chip5.issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
7899
8280
  ]
7900
8281
  }
7901
8282
  )
7902
- ] }, `${chip3.start}-${chip3.index}`);
8283
+ ] }, `${chip5.start}-${chip5.index}`);
7903
8284
  }) });
7904
8285
  };
7905
8286
 
7906
8287
  // src/generation/GenerationHistory.tsx
7907
- var import_react55 = require("react");
8288
+ var import_react57 = require("react");
7908
8289
  var import_generation4 = require("@pixerate/editor/generation");
7909
- var import_jsx_runtime37 = require("react/jsx-runtime");
8290
+ var import_jsx_runtime39 = require("react/jsx-runtime");
7910
8291
  function useGenerationRecords(store, filter) {
7911
- const [records, setRecords] = (0, import_react55.useState)([]);
7912
- const [loading, setLoading] = (0, import_react55.useState)(!!store);
7913
- const [error, setError] = (0, import_react55.useState)(null);
8292
+ const [records, setRecords] = (0, import_react57.useState)([]);
8293
+ const [loading, setLoading] = (0, import_react57.useState)(!!store);
8294
+ const [error, setError] = (0, import_react57.useState)(null);
7914
8295
  const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
7915
- const refresh = (0, import_react55.useCallback)(async () => {
8296
+ const refresh = (0, import_react57.useCallback)(async () => {
7916
8297
  if (!store) {
7917
8298
  setRecords([]);
7918
8299
  setLoading(false);
@@ -7929,7 +8310,7 @@ function useGenerationRecords(store, filter) {
7929
8310
  setLoading(false);
7930
8311
  }
7931
8312
  }, [store, filterKey]);
7932
- (0, import_react55.useEffect)(() => {
8313
+ (0, import_react57.useEffect)(() => {
7933
8314
  void refresh();
7934
8315
  if (!store) return;
7935
8316
  return store.subscribe(() => void refresh());
@@ -7955,21 +8336,21 @@ var GenerationHistory = ({
7955
8336
  emptyText = "No generations yet.",
7956
8337
  className = ""
7957
8338
  }) => {
7958
- const [innerMode, setInnerMode] = (0, import_react55.useState)("exact");
8339
+ const [innerMode, setInnerMode] = (0, import_react57.useState)("exact");
7959
8340
  const mode = modeProp ?? innerMode;
7960
8341
  const setMode = (next) => {
7961
8342
  if (modeProp === void 0) setInnerMode(next);
7962
8343
  onModeChange?.(next);
7963
8344
  };
7964
- const options = (0, import_react55.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
7965
- const results = (0, import_react55.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
7966
- const models = (0, import_react55.useMemo)(
8345
+ const options = (0, import_react57.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
8346
+ const results = (0, import_react57.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
8347
+ const models = (0, import_react57.useMemo)(
7967
8348
  () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
7968
8349
  [capabilities]
7969
8350
  );
7970
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
7971
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center gap-2 text-xs", role: "radiogroup", "aria-label": "Recreate mode", children: ["exact", "latest"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
7972
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8351
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
8352
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex items-center gap-2 text-xs", role: "radiogroup", "aria-label": "Recreate mode", children: ["exact", "latest"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
8353
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7973
8354
  "input",
7974
8355
  {
7975
8356
  type: "radio",
@@ -7982,34 +8363,34 @@ var GenerationHistory = ({
7982
8363
  ),
7983
8364
  value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
7984
8365
  ] }, value)) }),
7985
- records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
7986
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
8366
+ records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
8367
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
7987
8368
  const result = results[i];
7988
8369
  const model = models.find((m) => m.id === record.provenance.modelId);
7989
8370
  const blocked = !result.ok;
7990
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
8371
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
7991
8372
  "li",
7992
8373
  {
7993
8374
  className: "rounded-md border border-border p-2",
7994
8375
  "data-record": record.id,
7995
8376
  "data-drift": result.drift.length,
7996
8377
  children: [
7997
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
7998
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
7999
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-muted-foreground", children: [
8000
- record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { "data-kind": "", children: [
8378
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
8379
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
8380
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-muted-foreground", children: [
8381
+ record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { "data-kind": "", children: [
8001
8382
  record.kind,
8002
8383
  " \xB7 "
8003
8384
  ] }),
8004
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
8005
- record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
8385
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
8386
+ record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
8006
8387
  " \xB7 seed ",
8007
8388
  record.seed
8008
8389
  ] })
8009
8390
  ] })
8010
8391
  ] }),
8011
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
8012
- record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
8392
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
8393
+ record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
8013
8394
  "span",
8014
8395
  {
8015
8396
  className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
@@ -8023,16 +8404,16 @@ var GenerationHistory = ({
8023
8404
  `${asset.role}:${asset.id}`
8024
8405
  )) }),
8025
8406
  renderPreview?.(record),
8026
- result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "mt-1 flex flex-col gap-0.5 text-[11px]", "data-drift-report": "", children: result.drift.map((item, j) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
8027
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("strong", { children: [
8407
+ result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className: "mt-1 flex flex-col gap-0.5 text-[11px]", "data-drift-report": "", children: result.drift.map((item, j) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
8408
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("strong", { children: [
8028
8409
  import_generation4.DRIFT_TYPE_LABELS[item.type],
8029
8410
  ":"
8030
8411
  ] }),
8031
8412
  " ",
8032
8413
  item.message
8033
8414
  ] }, j)) }),
8034
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-2 flex gap-2", children: [
8035
- onRecreate && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8415
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "mt-2 flex gap-2", children: [
8416
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8036
8417
  "button",
8037
8418
  {
8038
8419
  type: "button",
@@ -8044,7 +8425,7 @@ var GenerationHistory = ({
8044
8425
  children: "Recreate"
8045
8426
  }
8046
8427
  ),
8047
- onVariation && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8428
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8048
8429
  "button",
8049
8430
  {
8050
8431
  type: "button",
@@ -8054,7 +8435,7 @@ var GenerationHistory = ({
8054
8435
  children: "Variation"
8055
8436
  }
8056
8437
  ),
8057
- onRemove && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8438
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8058
8439
  "button",
8059
8440
  {
8060
8441
  type: "button",
@@ -8074,19 +8455,19 @@ var GenerationHistory = ({
8074
8455
  };
8075
8456
 
8076
8457
  // src/find-replace/useFindReplace.ts
8077
- var import_react56 = require("react");
8458
+ var import_react58 = require("react");
8078
8459
  var import_editor16 = require("@pixerate/editor");
8079
8460
  var noopUnsubscribe2 = () => {
8080
8461
  };
8081
8462
  function useFindReplace(editor) {
8082
8463
  const store = (0, import_editor16.getFindReplaceStore)(editor ?? null);
8083
- const subscribe = (0, import_react56.useCallback)(
8464
+ const subscribe = (0, import_react58.useCallback)(
8084
8465
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
8085
8466
  [store]
8086
8467
  );
8087
8468
  const getSnapshot = () => store?.getSnapshot() ?? import_editor16.EMPTY_FIND_REPLACE_SNAPSHOT;
8088
- const snapshot = (0, import_react56.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8089
- return (0, import_react56.useMemo)(() => {
8469
+ const snapshot = (0, import_react58.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8470
+ return (0, import_react58.useMemo)(() => {
8090
8471
  const run = (fn) => {
8091
8472
  if (editor && !editor.isDestroyed && store) fn(editor);
8092
8473
  };
@@ -8110,9 +8491,9 @@ function useFindReplace(editor) {
8110
8491
  }
8111
8492
 
8112
8493
  // src/find-replace/FindReplaceBar.tsx
8113
- var import_react57 = require("react");
8494
+ var import_react59 = require("react");
8114
8495
  var import_editor17 = require("@pixerate/editor");
8115
- var import_jsx_runtime38 = require("react/jsx-runtime");
8496
+ var import_jsx_runtime40 = require("react/jsx-runtime");
8116
8497
  var inputClass3 = "min-w-0 flex-1 rounded border border-input bg-background px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring";
8117
8498
  var buttonClass5 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
8118
8499
  var toggleClass = (on) => `${buttonClass5} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
@@ -8125,10 +8506,10 @@ var FindReplaceBar = ({
8125
8506
  onClose
8126
8507
  }) => {
8127
8508
  const find = useFindReplace(editor);
8128
- const findInput = (0, import_react57.useRef)(null);
8129
- const [moreOpen, setMoreOpen] = (0, import_react57.useState)(false);
8509
+ const findInput = (0, import_react59.useRef)(null);
8510
+ const [moreOpen, setMoreOpen] = (0, import_react59.useState)(false);
8130
8511
  const visible = find.available && (alwaysOpen || find.open);
8131
- (0, import_react57.useEffect)(() => {
8512
+ (0, import_react59.useEffect)(() => {
8132
8513
  if (!visible || find.focusRequest === 0) return;
8133
8514
  findInput.current?.focus();
8134
8515
  findInput.current?.select();
@@ -8166,9 +8547,9 @@ var FindReplaceBar = ({
8166
8547
  if (isMod(e)) find.replaceAll();
8167
8548
  else find.replace();
8168
8549
  };
8169
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
8170
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-1", children: [
8171
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8550
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
8551
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1", children: [
8552
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8172
8553
  "button",
8173
8554
  {
8174
8555
  type: "button",
@@ -8179,7 +8560,7 @@ var FindReplaceBar = ({
8179
8560
  children: showReplace ? "\u25BE" : "\u25B8"
8180
8561
  }
8181
8562
  ),
8182
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8563
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8183
8564
  "input",
8184
8565
  {
8185
8566
  ref: findInput,
@@ -8193,7 +8574,7 @@ var FindReplaceBar = ({
8193
8574
  onKeyDown: onFindKeyDown
8194
8575
  }
8195
8576
  ),
8196
- import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8577
+ import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8197
8578
  "button",
8198
8579
  {
8199
8580
  type: "button",
@@ -8206,7 +8587,7 @@ var FindReplaceBar = ({
8206
8587
  },
8207
8588
  t.key
8208
8589
  )),
8209
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8590
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8210
8591
  "span",
8211
8592
  {
8212
8593
  className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
@@ -8216,9 +8597,9 @@ var FindReplaceBar = ({
8216
8597
  children: status
8217
8598
  }
8218
8599
  ),
8219
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
8220
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
8221
- showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8600
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
8601
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
8602
+ showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8222
8603
  "button",
8223
8604
  {
8224
8605
  type: "button",
@@ -8229,10 +8610,10 @@ var FindReplaceBar = ({
8229
8610
  children: "\u2026"
8230
8611
  }
8231
8612
  ),
8232
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
8613
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
8233
8614
  ] }),
8234
- showReplace && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
8235
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8615
+ showReplace && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
8616
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8236
8617
  "input",
8237
8618
  {
8238
8619
  type: "text",
@@ -8244,7 +8625,7 @@ var FindReplaceBar = ({
8244
8625
  onKeyDown: onReplaceKeyDown
8245
8626
  }
8246
8627
  ),
8247
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8628
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8248
8629
  "button",
8249
8630
  {
8250
8631
  type: "button",
@@ -8254,11 +8635,11 @@ var FindReplaceBar = ({
8254
8635
  children: "Replace"
8255
8636
  }
8256
8637
  ),
8257
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
8258
- find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
8638
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
8639
+ find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
8259
8640
  ] }),
8260
- showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pl-7 text-xs text-muted-foreground", children: import_editor17.FIND_OPTION_TOGGLES.filter((t) => t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "flex items-center gap-1", children: [
8261
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8641
+ showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pl-7 text-xs text-muted-foreground", children: import_editor17.FIND_OPTION_TOGGLES.filter((t) => t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("label", { className: "flex items-center gap-1", children: [
8642
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8262
8643
  "input",
8263
8644
  {
8264
8645
  type: "checkbox",
@@ -8272,12 +8653,12 @@ var FindReplaceBar = ({
8272
8653
  };
8273
8654
 
8274
8655
  // src/tables/useTableMenu.ts
8275
- var import_react58 = require("react");
8656
+ var import_react60 = require("react");
8276
8657
  var import_editor18 = require("@pixerate/editor");
8277
8658
  function useTableMenu(editor) {
8278
- const store = (0, import_react58.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
8279
- const snapshot = (0, import_react58.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
8280
- return (0, import_react58.useMemo)(
8659
+ const store = (0, import_react60.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
8660
+ const snapshot = (0, import_react60.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
8661
+ return (0, import_react60.useMemo)(
8281
8662
  () => ({
8282
8663
  ...snapshot,
8283
8664
  run: (action, params) => (0, import_editor18.runTableAction)(editor, action, params, { focus: true }),
@@ -8288,9 +8669,9 @@ function useTableMenu(editor) {
8288
8669
  }
8289
8670
 
8290
8671
  // src/tables/TableToolbar.tsx
8291
- var import_react59 = __toESM(require("react"), 1);
8672
+ var import_react61 = __toESM(require("react"), 1);
8292
8673
  var import_editor19 = require("@pixerate/editor");
8293
- var import_jsx_runtime39 = require("react/jsx-runtime");
8674
+ var import_jsx_runtime41 = require("react/jsx-runtime");
8294
8675
  var keepSelection2 = (event) => event.preventDefault();
8295
8676
  var TableToolbar = ({
8296
8677
  editor,
@@ -8304,14 +8685,14 @@ var TableToolbar = ({
8304
8685
  }) => {
8305
8686
  const table = useTableMenu(editor);
8306
8687
  if (!editor || !table.inTable && !showWhenOutside) return null;
8307
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
8688
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
8308
8689
  const status = table.check(item.action, item.params);
8309
8690
  const enabled = status === true;
8310
8691
  const active = item.active?.(table);
8311
8692
  const separator = index > 0 && items[index - 1].group !== item.group;
8312
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react59.default.Fragment, { children: [
8313
- separator && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
8314
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8693
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react61.default.Fragment, { children: [
8694
+ separator && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
8695
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8315
8696
  "button",
8316
8697
  {
8317
8698
  type: "button",
@@ -8333,8 +8714,8 @@ var TableToolbar = ({
8333
8714
  };
8334
8715
 
8335
8716
  // src/tables/InsertTableGrid.tsx
8336
- var import_react60 = require("react");
8337
- var import_jsx_runtime40 = require("react/jsx-runtime");
8717
+ var import_react62 = require("react");
8718
+ var import_jsx_runtime42 = require("react/jsx-runtime");
8338
8719
  var keepSelection3 = (event) => event.preventDefault();
8339
8720
  var InsertTableGrid = ({
8340
8721
  editor,
@@ -8347,14 +8728,14 @@ var InsertTableGrid = ({
8347
8728
  onInsert
8348
8729
  }) => {
8349
8730
  const table = useTableMenu(editor);
8350
- const [hover, setHover] = (0, import_react60.useState)(null);
8731
+ const [hover, setHover] = (0, import_react62.useState)(null);
8351
8732
  const status = table.actions.insertTable;
8352
8733
  const disabled = !editor || !status.enabled;
8353
8734
  const insert = (size) => {
8354
8735
  if (table.run("insertTable", { ...size, withHeaderRow })) onInsert?.(size);
8355
8736
  setHover(null);
8356
8737
  };
8357
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8738
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
8358
8739
  "div",
8359
8740
  {
8360
8741
  className,
@@ -8364,7 +8745,7 @@ var InsertTableGrid = ({
8364
8745
  "data-insert-table-grid": "",
8365
8746
  onMouseLeave: () => setHover(null),
8366
8747
  children: [
8367
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8748
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8368
8749
  "div",
8369
8750
  {
8370
8751
  role: "grid",
@@ -8373,7 +8754,7 @@ var InsertTableGrid = ({
8373
8754
  children: Array.from({ length: rows * cols }, (_, i) => {
8374
8755
  const size = { rows: Math.floor(i / cols) + 1, cols: i % cols + 1 };
8375
8756
  const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols;
8376
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8757
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8377
8758
  "button",
8378
8759
  {
8379
8760
  type: "button",
@@ -8393,7 +8774,7 @@ var InsertTableGrid = ({
8393
8774
  })
8394
8775
  }
8395
8776
  ),
8396
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { "aria-live": "polite", "data-testid": "insert-table-size", children: disabled ? status.reason : hover ? `${hover.rows} \xD7 ${hover.cols}` : "Insert table" })
8777
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { "aria-live": "polite", "data-testid": "insert-table-size", children: disabled ? status.reason : hover ? `${hover.rows} \xD7 ${hover.cols}` : "Insert table" })
8397
8778
  ]
8398
8779
  }
8399
8780
  );
@@ -8401,31 +8782,31 @@ var InsertTableGrid = ({
8401
8782
 
8402
8783
  // src/tables/TableBubbleMenu.tsx
8403
8784
  var import_editor20 = require("@pixerate/editor");
8404
- var import_jsx_runtime41 = require("react/jsx-runtime");
8785
+ var import_jsx_runtime43 = require("react/jsx-runtime");
8405
8786
  var TableBubbleMenu = ({
8406
8787
  editor,
8407
8788
  children,
8408
8789
  toolbarProps,
8409
8790
  pluginKey = "tableBubbleMenu",
8410
8791
  ...rest
8411
- }) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(BubbleMenu, { editor, pluginKey, shouldShow: import_editor20.shouldShowTableBubbleMenu, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TableToolbar, { editor, ...toolbarProps }) });
8792
+ }) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(BubbleMenu, { editor, pluginKey, shouldShow: import_editor20.shouldShowTableBubbleMenu, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TableToolbar, { editor, ...toolbarProps }) });
8412
8793
 
8413
8794
  // src/chart-node/ChartNodeView.tsx
8414
8795
  var import_client = require("react-dom/client");
8415
8796
 
8416
8797
  // src/chart/ChartCanvas.tsx
8417
- var import_react62 = require("react");
8798
+ var import_react64 = require("react");
8418
8799
  var import_chart2 = require("@pixerate/editor/chart");
8419
8800
 
8420
8801
  // src/chart/useChartEditor.ts
8421
- var import_react61 = require("react");
8802
+ var import_react63 = require("react");
8422
8803
  var import_chart = require("@pixerate/editor/chart");
8423
8804
  function useChartState(controller) {
8424
- return (0, import_react61.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8805
+ return (0, import_react63.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8425
8806
  }
8426
8807
 
8427
8808
  // src/chart/ChartCanvas.tsx
8428
- var import_jsx_runtime42 = require("react/jsx-runtime");
8809
+ var import_jsx_runtime44 = require("react/jsx-runtime");
8429
8810
  function renderChartMark(mark, fontFamily, interactive) {
8430
8811
  const common = {
8431
8812
  "data-role": mark.role,
@@ -8437,9 +8818,9 @@ function renderChartMark(mark, fontFamily, interactive) {
8437
8818
  };
8438
8819
  switch (mark.kind) {
8439
8820
  case "rect":
8440
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("rect", { ...common, x: mark.x, y: mark.y, width: mark.width, height: mark.height, rx: mark.radius, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8821
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("rect", { ...common, x: mark.x, y: mark.y, width: mark.width, height: mark.height, rx: mark.radius, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8441
8822
  case "path":
8442
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8823
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8443
8824
  "path",
8444
8825
  {
8445
8826
  ...common,
@@ -8452,11 +8833,11 @@ function renderChartMark(mark, fontFamily, interactive) {
8452
8833
  mark.key
8453
8834
  );
8454
8835
  case "circle":
8455
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8836
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8456
8837
  case "line":
8457
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("line", { ...common, x1: mark.x1, y1: mark.y1, x2: mark.x2, y2: mark.y2, strokeDasharray: mark.dash, style: { stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8838
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("line", { ...common, x1: mark.x1, y1: mark.y1, x2: mark.x2, y2: mark.y2, strokeDasharray: mark.dash, style: { stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
8458
8839
  case "text":
8459
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8840
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8460
8841
  "text",
8461
8842
  {
8462
8843
  ...common,
@@ -8473,23 +8854,23 @@ function renderChartMark(mark, fontFamily, interactive) {
8473
8854
  }
8474
8855
  }
8475
8856
  function ChartPresenceLayer({ presence }) {
8476
- const { actors } = (0, import_react62.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
8477
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("g", { "data-chart-presence": "", pointerEvents: "none", children: actors.map((a) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("g", { transform: `translate(${a.x} ${a.y})`, "data-actor": a.id, children: [
8478
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("path", { d: "M0,0 L0,14 L4,10.5 L7,17 L9.5,16 L6.5,9.5 L11.5,9.5 Z", style: { fill: a.color, stroke: "#ffffff", strokeWidth: 1 }, transform: a.pressed ? "scale(0.9)" : void 0 }),
8479
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("g", { transform: "translate(13 16)", children: [
8480
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("rect", { x: 0, y: 0, rx: 4, height: 18, width: Math.max(28, (a.message ?? a.name).length * 6.4 + 12), style: { fill: a.color } }),
8481
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("text", { x: 6, y: 9, dominantBaseline: "central", style: { fill: "#ffffff", fontSize: 11, fontWeight: 600, fontFamily: "inherit" }, children: a.message ?? a.name })
8857
+ const { actors } = (0, import_react64.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
8858
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("g", { "data-chart-presence": "", pointerEvents: "none", children: actors.map((a) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("g", { transform: `translate(${a.x} ${a.y})`, "data-actor": a.id, children: [
8859
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("path", { d: "M0,0 L0,14 L4,10.5 L7,17 L9.5,16 L6.5,9.5 L11.5,9.5 Z", style: { fill: a.color, stroke: "#ffffff", strokeWidth: 1 }, transform: a.pressed ? "scale(0.9)" : void 0 }),
8860
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("g", { transform: "translate(13 16)", children: [
8861
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("rect", { x: 0, y: 0, rx: 4, height: 18, width: Math.max(28, (a.message ?? a.name).length * 6.4 + 12), style: { fill: a.color } }),
8862
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("text", { x: 6, y: 9, dominantBaseline: "central", style: { fill: "#ffffff", fontSize: 11, fontWeight: 600, fontFamily: "inherit" }, children: a.message ?? a.name })
8482
8863
  ] })
8483
8864
  ] }, a.id)) });
8484
8865
  }
8485
8866
  function ChartCanvas({ controller, width = 640, height = 400, responsive = true, theme, editable = true, measureText, emptyMessage, className, presence, sceneRef }) {
8486
8867
  const state = useChartState(controller);
8487
- const wrapper = (0, import_react62.useRef)(null);
8488
- const svg = (0, import_react62.useRef)(null);
8489
- const drag = (0, import_react62.useRef)(null);
8490
- const [measured, setMeasured] = (0, import_react62.useState)(null);
8491
- const [frozen, setFrozen] = (0, import_react62.useState)(null);
8492
- (0, import_react62.useEffect)(() => {
8868
+ const wrapper = (0, import_react64.useRef)(null);
8869
+ const svg = (0, import_react64.useRef)(null);
8870
+ const drag = (0, import_react64.useRef)(null);
8871
+ const [measured, setMeasured] = (0, import_react64.useState)(null);
8872
+ const [frozen, setFrozen] = (0, import_react64.useState)(null);
8873
+ (0, import_react64.useEffect)(() => {
8493
8874
  const el = wrapper.current;
8494
8875
  if (!responsive || !el || typeof ResizeObserver === "undefined") return;
8495
8876
  const observer = new ResizeObserver(([entry]) => {
@@ -8500,8 +8881,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8500
8881
  return () => observer.disconnect();
8501
8882
  }, [responsive]);
8502
8883
  const sceneWidth = responsive && measured || width;
8503
- const fullTheme = (0, import_react62.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
8504
- const scene = (0, import_react62.useMemo)(
8884
+ const fullTheme = (0, import_react64.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
8885
+ const scene = (0, import_react64.useMemo)(
8505
8886
  () => (0, import_chart2.layoutChart)(state.spec, {
8506
8887
  width: sceneWidth,
8507
8888
  height,
@@ -8517,8 +8898,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8517
8898
  [state.spec, state.selection, sceneWidth, height, fullTheme, editable, measureText, emptyMessage, frozen]
8518
8899
  );
8519
8900
  if (sceneRef) sceneRef.current = scene;
8520
- const byKey = (0, import_react62.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
8521
- (0, import_react62.useEffect)(() => () => drag.current?.end(), []);
8901
+ const byKey = (0, import_react64.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
8902
+ (0, import_react64.useEffect)(() => () => drag.current?.end(), []);
8522
8903
  const scenePoint = (e) => (0, import_chart2.chartClientToScene)(scene, svg.current.getBoundingClientRect(), e.clientX, e.clientY);
8523
8904
  const onPointerDown = (e) => {
8524
8905
  if (!editable || e.button !== 0) return;
@@ -8551,7 +8932,7 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8551
8932
  if (editable && (0, import_chart2.handleChartKey)(controller, scene, e)) e.preventDefault();
8552
8933
  };
8553
8934
  const label = state.spec.title || "Chart";
8554
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ref: wrapper, className: `w-full ${className ?? ""}`, "data-chart-canvas": "", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
8935
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { ref: wrapper, className: `w-full ${className ?? ""}`, "data-chart-canvas": "", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
8555
8936
  "svg",
8556
8937
  {
8557
8938
  ref: svg,
@@ -8569,14 +8950,14 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8569
8950
  onKeyDown,
8570
8951
  children: [
8571
8952
  scene.marks.map((m) => renderChartMark(m, scene.theme.fontFamily, editable)),
8572
- presence && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartPresenceLayer, { presence })
8953
+ presence && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartPresenceLayer, { presence })
8573
8954
  ]
8574
8955
  }
8575
8956
  ) });
8576
8957
  }
8577
8958
 
8578
8959
  // src/chart/ChartDataGrid.tsx
8579
- var import_react63 = require("react");
8960
+ var import_react65 = require("react");
8580
8961
  var import_chart3 = require("@pixerate/editor/chart");
8581
8962
 
8582
8963
  // src/chart/styles.ts
@@ -8589,11 +8970,11 @@ var chartSectionClass = "space-y-2 border-b border-border pb-3 last:border-b-0";
8589
8970
  var chartCellClass = "h-7 w-full min-w-[4.5rem] bg-transparent px-2 text-right text-xs tabular-nums text-foreground focus-visible:bg-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-primary";
8590
8971
 
8591
8972
  // src/chart/ChartDataGrid.tsx
8592
- var import_jsx_runtime43 = require("react/jsx-runtime");
8973
+ var import_jsx_runtime45 = require("react/jsx-runtime");
8593
8974
  function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
8594
- const [draft, setDraft] = (0, import_react63.useState)(value);
8595
- const typing = (0, import_react63.useRef)(false);
8596
- (0, import_react63.useEffect)(() => {
8975
+ const [draft, setDraft] = (0, import_react65.useState)(value);
8976
+ const typing = (0, import_react65.useRef)(false);
8977
+ (0, import_react65.useEffect)(() => {
8597
8978
  if (!typing.current) setDraft(value);
8598
8979
  }, [value]);
8599
8980
  const commit = () => {
@@ -8602,7 +8983,7 @@ function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
8602
8983
  if (draft === value) return;
8603
8984
  if (onCommit(draft) === false) setDraft(value);
8604
8985
  };
8605
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8986
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8606
8987
  "input",
8607
8988
  {
8608
8989
  ...rest,
@@ -8637,15 +9018,15 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8637
9018
  e.preventDefault();
8638
9019
  controller.pasteCells(row, column, text);
8639
9020
  };
8640
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
8641
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
8642
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("tr", { children: [
8643
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("th", { className: "border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground", children: categoryHeader }),
9021
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
9022
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
9023
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { children: [
9024
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { className: "border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground", children: categoryHeader }),
8644
9025
  spec.series.map((s, si) => {
8645
9026
  const color = (0, import_chart3.chartSeriesColor)(spec, si);
8646
9027
  const selected = selection?.kind === "series" && selection.seriesId === s.id;
8647
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("th", { "data-series-id": s.id, className: `border-b border-r border-border px-1 py-1 font-medium ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-1", children: [
8648
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9028
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { "data-series-id": s.id, className: `border-b border-r border-border px-1 py-1 font-medium ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-1", children: [
9029
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8649
9030
  "input",
8650
9031
  {
8651
9032
  type: "color",
@@ -8658,7 +9039,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8658
9039
  className: "h-5 w-5 shrink-0 cursor-pointer rounded border-0 bg-transparent p-0"
8659
9040
  }
8660
9041
  ),
8661
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9042
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8662
9043
  ChartCommitInput,
8663
9044
  {
8664
9045
  value: s.name,
@@ -8668,8 +9049,8 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8668
9049
  className: `${chartInputClass} h-6 min-w-[5rem] border-transparent bg-transparent font-medium ${s.hidden ? "text-muted-foreground line-through" : ""}`
8669
9050
  }
8670
9051
  ),
8671
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8672
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9052
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
9053
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8673
9054
  "button",
8674
9055
  {
8675
9056
  type: "button",
@@ -8682,16 +9063,16 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8682
9063
  children: s.hidden ? "\u25CB" : "\u25CF"
8683
9064
  }
8684
9065
  ),
8685
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete series", "aria-label": `Delete ${s.name}`, "data-action": "remove-series", onClick: () => controller.removeSeries(s.id), children: "\xD7" })
9066
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete series", "aria-label": `Delete ${s.name}`, "data-action": "remove-series", onClick: () => controller.removeSeries(s.id), children: "\xD7" })
8686
9067
  ] })
8687
9068
  ] }) }, s.id);
8688
9069
  }),
8689
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("th", { className: "w-8 border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Add series", "aria-label": "Add series", "data-action": "add-series", onClick: () => controller.addSeries(), children: "+" }) })
9070
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { className: "w-8 border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Add series", "aria-label": "Add series", "data-action": "add-series", onClick: () => controller.addSeries(), children: "+" }) })
8690
9071
  ] }) }),
8691
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("tbody", { children: spec.categories.map((category, i) => {
9072
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("tbody", { children: spec.categories.map((category, i) => {
8692
9073
  const rowSelected = selection?.kind === "category" && selection.index === i;
8693
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
8694
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("th", { className: "border-b border-r border-border p-0 text-left font-normal", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9074
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
9075
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { className: "border-b border-r border-border p-0 text-left font-normal", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8695
9076
  ChartCommitInput,
8696
9077
  {
8697
9078
  value: category,
@@ -8705,7 +9086,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8705
9086
  spec.series.map((s) => {
8706
9087
  const value = s.values[i];
8707
9088
  const selected = selection?.kind === "point" && selection.seriesId === s.id && selection.index === i;
8708
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("td", { className: `border-b border-r border-border p-0 ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9089
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: `border-b border-r border-border p-0 ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8709
9090
  ChartCommitInput,
8710
9091
  {
8711
9092
  value: value === null || value === void 0 ? "" : String(value),
@@ -8720,38 +9101,38 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8720
9101
  }
8721
9102
  ) }, s.id);
8722
9103
  }),
8723
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("td", { className: "border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete category", "aria-label": `Delete ${category}`, "data-action": "remove-category", onClick: () => controller.removeCategory(i), children: "\xD7" }) })
9104
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete category", "aria-label": `Delete ${category}`, "data-action": "remove-category", onClick: () => controller.removeCategory(i), children: "\xD7" }) })
8724
9105
  ] }, i);
8725
9106
  }) })
8726
9107
  ] }),
8727
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "p-1", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: `${chartButtonClass} h-6 border-dashed`, "data-action": "add-category", onClick: () => controller.addCategory(), children: "+ Add category" }) })
9108
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "p-1", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: `${chartButtonClass} h-6 border-dashed`, "data-action": "add-category", onClick: () => controller.addCategory(), children: "+ Add category" }) })
8728
9109
  ] });
8729
9110
  }
8730
9111
 
8731
9112
  // src/chart/ChartInspector.tsx
8732
- var import_react64 = require("react");
9113
+ var import_react66 = require("react");
8733
9114
  var import_chart4 = require("@pixerate/editor/chart");
8734
- var import_jsx_runtime44 = require("react/jsx-runtime");
9115
+ var import_jsx_runtime46 = require("react/jsx-runtime");
8735
9116
  var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
8736
9117
  function Field({ label, htmlFor, children }) {
8737
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
8738
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
8739
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "min-w-0 flex-1", children })
9118
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
9119
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
9120
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "min-w-0 flex-1", children })
8740
9121
  ] });
8741
9122
  }
8742
9123
  function Toggle({ label, checked, onChange, name }) {
8743
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
8744
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { type: "checkbox", className: "h-3.5 w-3.5 accent-primary", checked, "data-option": name, onChange: (e) => onChange(e.currentTarget.checked) }),
9124
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
9125
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("input", { type: "checkbox", className: "h-3.5 w-3.5 accent-primary", checked, "data-option": name, onChange: (e) => onChange(e.currentTarget.checked) }),
8745
9126
  label
8746
9127
  ] });
8747
9128
  }
8748
9129
  function Select({ id, value, options, onChange, name, labels }) {
8749
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { id, className: chartInputClass, value, "data-option": name, onChange: (e) => onChange(e.currentTarget.value), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: o, children: labels?.[o] ?? cap(o) }, o)) });
9130
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("select", { id, className: chartInputClass, value, "data-option": name, onChange: (e) => onChange(e.currentTarget.value), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: o, children: labels?.[o] ?? cap(o) }, o)) });
8750
9131
  }
8751
9132
  function AxisSection({ controller, axis, value, idBase, horizontal, numeric = false, scales = false }) {
8752
9133
  const set = (patch) => controller.setAxis(axis, patch);
8753
9134
  const setFormat = (patch) => set({ format: { ...value.format, ...patch } });
8754
- const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9135
+ const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8755
9136
  ChartCommitInput,
8756
9137
  {
8757
9138
  id: `${idBase}-${axis}-${key2}`,
@@ -8766,26 +9147,26 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8766
9147
  const name = axis === "x" ? numeric ? "X axis" : "Category axis" : axis === "y" ? "Value axis" : "Secondary axis";
8767
9148
  const valueAxis = axis !== "x" || numeric;
8768
9149
  const key = axis === "y2" ? "yAxis2" : `${axis}Axis`;
8769
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
8770
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center justify-between", children: [
8771
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
9150
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
9151
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center justify-between", children: [
9152
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
8772
9153
  name,
8773
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
9154
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8774
9155
  "(",
8775
9156
  axis === "x" ? horizontal ? "left" : "bottom" : axis === "y2" ? horizontal ? "top" : "right" : horizontal ? "bottom" : "left",
8776
9157
  ")"
8777
9158
  ] })
8778
9159
  ] }),
8779
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
9160
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8780
9161
  ] }),
8781
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Title", htmlFor: `${idBase}-${axis}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-title`, value: value.title, "data-option": `${axis}Axis.title`, className: chartInputClass, onCommit: (title) => void set({ title }) }) }),
8782
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8783
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
8784
- axis === "x" && !numeric && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Dates", name: "xAxis.kind", checked: value.kind === "date", onChange: (dates) => set({ kind: dates ? "date" : void 0 }) }),
8785
- scales && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
8786
- scales && valueAxis && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Log scale", name: `${key}.scale`, checked: value.scale === "log", onChange: (log) => set({ scale: log ? "log" : "linear" }) })
9162
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Title", htmlFor: `${idBase}-${axis}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-title`, value: value.title, "data-option": `${axis}Axis.title`, className: chartInputClass, onCommit: (title) => void set({ title }) }) }),
9163
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
9164
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
9165
+ axis === "x" && !numeric && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Dates", name: "xAxis.kind", checked: value.kind === "date", onChange: (dates) => set({ kind: dates ? "date" : void 0 }) }),
9166
+ scales && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
9167
+ scales && valueAxis && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Log scale", name: `${key}.scale`, checked: value.scale === "log", onChange: (log) => set({ scale: log ? "log" : "linear" }) })
8787
9168
  ] }),
8788
- scales && valueAxis && value.scale === "log" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Log base", htmlFor: `${idBase}-${axis}-log-base`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9169
+ scales && valueAxis && value.scale === "log" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Log base", htmlFor: `${idBase}-${axis}-log-base`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8789
9170
  ChartCommitInput,
8790
9171
  {
8791
9172
  id: `${idBase}-${axis}-log-base`,
@@ -8796,7 +9177,7 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8796
9177
  onCommit: (text) => set({ logBase: text.trim() === "" ? void 0 : Number(text) }).ok
8797
9178
  }
8798
9179
  ) }),
8799
- valueAxis && value.scale !== "log" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Step", htmlFor: `${idBase}-${axis}-step`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9180
+ valueAxis && value.scale !== "log" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Step", htmlFor: `${idBase}-${axis}-step`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8800
9181
  ChartCommitInput,
8801
9182
  {
8802
9183
  id: `${idBase}-${axis}-step`,
@@ -8808,14 +9189,14 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8808
9189
  onCommit: (text) => set({ step: text.trim() === "" ? null : Number(text) }).ok
8809
9190
  }
8810
9191
  ) }),
8811
- valueAxis && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
8812
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex gap-1", children: [
9192
+ valueAxis && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9193
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex gap-1", children: [
8813
9194
  bound("min"),
8814
9195
  bound("max")
8815
9196
  ] }) }),
8816
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Format", htmlFor: `${idBase}-${axis}-format`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex gap-1", children: [
8817
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Select, { id: `${idBase}-${axis}-format`, name: `${key}.format.style`, value: value.format.style ?? "number", options: import_chart4.CHART_NUMBER_STYLES, onChange: (style) => setFormat({ style }) }),
8818
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9197
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Format", htmlFor: `${idBase}-${axis}-format`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex gap-1", children: [
9198
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Select, { id: `${idBase}-${axis}-format`, name: `${key}.format.style`, value: value.format.style ?? "number", options: import_chart4.CHART_NUMBER_STYLES, onChange: (style) => setFormat({ style }) }),
9199
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8819
9200
  ChartCommitInput,
8820
9201
  {
8821
9202
  value: value.format.decimals === void 0 ? "" : String(value.format.decimals),
@@ -8834,8 +9215,8 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8834
9215
  }
8835
9216
  )
8836
9217
  ] }) }),
8837
- value.format.style === "currency" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Currency", htmlFor: `${idBase}-${axis}-currency`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-currency`, value: value.format.currency ?? "USD", "data-option": `${key}.format.currency`, className: chartInputClass, onCommit: (currency) => void setFormat({ currency: currency.toUpperCase() }) }) }),
8838
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9218
+ value.format.style === "currency" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Currency", htmlFor: `${idBase}-${axis}-currency`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-currency`, value: value.format.currency ?? "USD", "data-option": `${key}.format.currency`, className: chartInputClass, onCommit: (currency) => void setFormat({ currency: currency.toUpperCase() }) }) }),
9219
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8839
9220
  ChartCommitInput,
8840
9221
  {
8841
9222
  id: `${idBase}-${axis}-code`,
@@ -8861,15 +9242,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8861
9242
  const values = which === "xErrorBars" ? series.x ?? [] : series.values;
8862
9243
  const set = (next) => controller.updateSeries(series.id, { [which]: next });
8863
9244
  const patch = (p) => bars && set({ ...bars, ...p });
8864
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
8865
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: which === "errorBars" ? "Error bars" : "X error bars", htmlFor: `${id}-type`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("select", { id: `${id}-type`, className: chartInputClass, value: bars?.type ?? "", "data-option": `${key}.type`, onChange: (e) => set((0, import_chart4.chartErrorBarsOfType)(e.currentTarget.value, bars, values)), children: [
8866
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "None" }),
8867
- import_chart4.CHART_ERROR_BAR_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: t, children: import_chart4.CHART_ERROR_BAR_LABELS[t] }, t))
9245
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
9246
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: which === "errorBars" ? "Error bars" : "X error bars", htmlFor: `${id}-type`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("select", { id: `${id}-type`, className: chartInputClass, value: bars?.type ?? "", "data-option": `${key}.type`, onChange: (e) => set((0, import_chart4.chartErrorBarsOfType)(e.currentTarget.value, bars, values)), children: [
9247
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "None" }),
9248
+ import_chart4.CHART_ERROR_BAR_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: t, children: import_chart4.CHART_ERROR_BAR_LABELS[t] }, t))
8868
9249
  ] }) }),
8869
- bars && (bars.type === "fixed" || bars.type === "percent" || bars.type === "stddev") && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: bars.type === "percent" ? "Percent" : bars.type === "stddev" ? "Deviations" : "Amount", htmlFor: `${id}-value`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${id}-value`, value: String(bars.value ?? (0, import_chart4.defaultChartErrorBarValue)(bars.type)), inputMode: "decimal", "data-option": `${key}.value`, className: chartInputClass, onCommit: (text) => !!patch({ value: text.trim() === "" ? void 0 : Number(text) })?.ok }) }),
8870
- bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
8871
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Plus", htmlFor: `${id}-plus`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${id}-plus`, value: (0, import_chart4.formatChartAmountList)(bars.plus), placeholder: "1, 2, -, 0.5", "data-option": `${key}.plus`, className: chartInputClass, onCommit: (text) => !!patch({ plus: (0, import_chart4.parseChartAmountList)(text) })?.ok }) }),
8872
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9250
+ bars && (bars.type === "fixed" || bars.type === "percent" || bars.type === "stddev") && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: bars.type === "percent" ? "Percent" : bars.type === "stddev" ? "Deviations" : "Amount", htmlFor: `${id}-value`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${id}-value`, value: String(bars.value ?? (0, import_chart4.defaultChartErrorBarValue)(bars.type)), inputMode: "decimal", "data-option": `${key}.value`, className: chartInputClass, onCommit: (text) => !!patch({ value: text.trim() === "" ? void 0 : Number(text) })?.ok }) }),
9251
+ bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9252
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Plus", htmlFor: `${id}-plus`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${id}-plus`, value: (0, import_chart4.formatChartAmountList)(bars.plus), placeholder: "1, 2, -, 0.5", "data-option": `${key}.plus`, className: chartInputClass, onCommit: (text) => !!patch({ plus: (0, import_chart4.parseChartAmountList)(text) })?.ok }) }),
9253
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8873
9254
  ChartCommitInput,
8874
9255
  {
8875
9256
  id: `${id}-minus`,
@@ -8886,15 +9267,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8886
9267
  }
8887
9268
  ) })
8888
9269
  ] }),
8889
- bars && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
8890
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { className: `${chartInputClass} flex-1`, "aria-label": "Error bar direction", value: bars.direction ?? "both", "data-option": `${key}.direction`, onChange: (e) => patch({ direction: e.currentTarget.value }), children: import_chart4.CHART_ERROR_BAR_DIRECTIONS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: d, children: d === "both" ? "Both ways" : d === "plus" ? "Plus only" : "Minus only" }, d)) }),
8891
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
9270
+ bars && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
9271
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("select", { className: `${chartInputClass} flex-1`, "aria-label": "Error bar direction", value: bars.direction ?? "both", "data-option": `${key}.direction`, onChange: (e) => patch({ direction: e.currentTarget.value }), children: import_chart4.CHART_ERROR_BAR_DIRECTIONS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: d, children: d === "both" ? "Both ways" : d === "plus" ? "Plus only" : "Minus only" }, d)) }),
9272
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
8892
9273
  ] })
8893
9274
  ] });
8894
9275
  }
8895
9276
  function ChartInspector({ controller, sections, className }) {
8896
9277
  const { spec, selectedSeries } = useChartState(controller);
8897
- const idBase = (0, import_react64.useId)();
9278
+ const idBase = (0, import_react66.useId)();
8898
9279
  const show = (section) => !sections || sections.includes(section);
8899
9280
  const cartesian = (0, import_chart4.isCartesianChart)(spec.type);
8900
9281
  const family = (0, import_chart4.chartFamily)(spec);
@@ -8906,29 +9287,29 @@ function ChartInspector({ controller, sections, className }) {
8906
9287
  const hasLines = cartesian && types.some((t) => t === "line" || t === "area");
8907
9288
  const seriesIndex = selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1;
8908
9289
  const scales = family === "cartesian" || family === "xy";
8909
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
8910
- show("type") && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: chartSectionClass, "data-section": "type", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "grid grid-cols-3 gap-0.5 rounded-md bg-muted p-0.5", role: "radiogroup", "aria-label": "Chart type", children: import_chart4.CHART_TYPES.map((type) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", role: "radio", "aria-checked": spec.type === type, "data-chart-type": type, className: chartSegmentClass(spec.type === type), onClick: () => controller.setType(type), children: import_chart4.CHART_TYPE_LABELS[type] }, type)) }) }),
8911
- show("style") && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
8912
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Layout", htmlFor: `${idBase}-layout`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("select", { id: `${idBase}-layout`, className: chartInputClass, value: "", "data-option": "preset.layout", onChange: (e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value }), children: [
8913
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "Quick layout\u2026" }),
8914
- import_chart4.CHART_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: p.id, title: p.description, children: p.label }, p.id))
9290
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
9291
+ show("type") && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: chartSectionClass, "data-section": "type", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "grid grid-cols-3 gap-0.5 rounded-md bg-muted p-0.5", role: "radiogroup", "aria-label": "Chart type", children: import_chart4.CHART_TYPES.map((type) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", role: "radio", "aria-checked": spec.type === type, "data-chart-type": type, className: chartSegmentClass(spec.type === type), onClick: () => controller.setType(type), children: import_chart4.CHART_TYPE_LABELS[type] }, type)) }) }),
9292
+ show("style") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
9293
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Layout", htmlFor: `${idBase}-layout`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("select", { id: `${idBase}-layout`, className: chartInputClass, value: "", "data-option": "preset.layout", onChange: (e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value }), children: [
9294
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Quick layout\u2026" }),
9295
+ import_chart4.CHART_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: p.id, title: p.description, children: p.label }, p.id))
8915
9296
  ] }) }),
8916
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Colours", htmlFor: `${idBase}-colors`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("select", { id: `${idBase}-colors`, className: chartInputClass, value: import_chart4.CHART_COLOR_SCHEMES.find((c) => c.palette.join() === spec.palette.join())?.id ?? "", "data-option": "preset.colors", onChange: (e) => e.currentTarget.value && controller.applyPreset({ colors: e.currentTarget.value }), children: [
8917
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "Custom" }),
8918
- import_chart4.CHART_COLOR_SCHEMES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: c.id, title: c.description, children: c.label }, c.id))
9297
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Colours", htmlFor: `${idBase}-colors`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("select", { id: `${idBase}-colors`, className: chartInputClass, value: import_chart4.CHART_COLOR_SCHEMES.find((c) => c.palette.join() === spec.palette.join())?.id ?? "", "data-option": "preset.colors", onChange: (e) => e.currentTarget.value && controller.applyPreset({ colors: e.currentTarget.value }), children: [
9298
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Custom" }),
9299
+ import_chart4.CHART_COLOR_SCHEMES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: c.id, title: c.description, children: c.label }, c.id))
8919
9300
  ] }) }),
8920
- !colorCheck.ok && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", "data-chart-color-warning": "", children: colorCheck.issues[0] }),
8921
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
9301
+ !colorCheck.ok && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", "data-chart-color-warning": "", children: colorCheck.issues[0] }),
9302
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
8922
9303
  ] }),
8923
- show("titles") && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
8924
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Title", htmlFor: `${idBase}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-title`, value: spec.title, "data-option": "title", className: chartInputClass, onCommit: (title) => void controller.setTitle(title) }) }),
8925
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Subtitle", htmlFor: `${idBase}-subtitle`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-subtitle`, value: spec.subtitle, "data-option": "subtitle", className: chartInputClass, onCommit: (subtitle) => void controller.setSubtitle(subtitle) }) })
9304
+ show("titles") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
9305
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Title", htmlFor: `${idBase}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-title`, value: spec.title, "data-option": "title", className: chartInputClass, onCommit: (title) => void controller.setTitle(title) }) }),
9306
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Subtitle", htmlFor: `${idBase}-subtitle`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-subtitle`, value: spec.subtitle, "data-option": "subtitle", className: chartInputClass, onCommit: (subtitle) => void controller.setSubtitle(subtitle) }) })
8926
9307
  ] }),
8927
- show("options") && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
8928
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Stacking", htmlFor: `${idBase}-stacking`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Select, { id: `${idBase}-stacking`, name: "stacking", value: spec.stacking, options: import_chart4.CHART_STACKINGS, labels: { none: "None", stacked: "Stacked", percent: "100%" }, onChange: (stacking) => controller.update({ stacking }) }) }),
8929
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Bars", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: ["vertical", "horizontal"].map((o) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", "aria-pressed": spec.orientation === o, "data-option": `orientation.${o}`, className: chartSegmentClass(spec.orientation === o), onClick: () => controller.update({ orientation: o }), children: cap(o) }, o)) }) }),
8930
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Lines", htmlFor: `${idBase}-curve`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Select, { id: `${idBase}-curve`, name: "curve", value: spec.curve, options: import_chart4.CHART_CURVES, onChange: (curve) => controller.update({ curve }) }) }),
8931
- spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9308
+ show("options") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
9309
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Stacking", htmlFor: `${idBase}-stacking`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Select, { id: `${idBase}-stacking`, name: "stacking", value: spec.stacking, options: import_chart4.CHART_STACKINGS, labels: { none: "None", stacked: "Stacked", percent: "100%" }, onChange: (stacking) => controller.update({ stacking }) }) }),
9310
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Bars", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: ["vertical", "horizontal"].map((o) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", "aria-pressed": spec.orientation === o, "data-option": `orientation.${o}`, className: chartSegmentClass(spec.orientation === o), onClick: () => controller.update({ orientation: o }), children: cap(o) }, o)) }) }),
9311
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Lines", htmlFor: `${idBase}-curve`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Select, { id: `${idBase}-curve`, name: "curve", value: spec.curve, options: import_chart4.CHART_CURVES, onChange: (curve) => controller.update({ curve }) }) }),
9312
+ spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8932
9313
  "input",
8933
9314
  {
8934
9315
  id: `${idBase}-hole`,
@@ -8944,7 +9325,7 @@ function ChartInspector({ controller, sections, className }) {
8944
9325
  onChange: (e) => controller.update({ innerRadius: Number(e.currentTarget.value) })
8945
9326
  }
8946
9327
  ) }),
8947
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9328
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8948
9329
  "input",
8949
9330
  {
8950
9331
  id: `${idBase}-gap`,
@@ -8960,31 +9341,31 @@ function ChartInspector({ controller, sections, className }) {
8960
9341
  onChange: (e) => controller.update({ gapWidth: Number(e.currentTarget.value) })
8961
9342
  }
8962
9343
  ) }),
8963
- spec.dataLabels && hasBars && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Labels", htmlFor: `${idBase}-label-position`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Select, { id: `${idBase}-label-position`, name: "labelPosition", value: spec.labelPosition, options: import_chart4.CHART_LABEL_POSITIONS, onChange: (labelPosition) => controller.update({ labelPosition }) }) }),
8964
- spec.type === "histogram" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Bins", htmlFor: `${idBase}-bins`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-bins`, value: spec.bins === null ? "" : String(spec.bins), placeholder: "Auto", inputMode: "numeric", "data-option": "bins", className: chartInputClass, onCommit: (text) => controller.update({ bins: text.trim() === "" ? null : Number(text) }).ok }) }),
8965
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8966
- spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
8967
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
8968
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
9344
+ spec.dataLabels && hasBars && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Labels", htmlFor: `${idBase}-label-position`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Select, { id: `${idBase}-label-position`, name: "labelPosition", value: spec.labelPosition, options: import_chart4.CHART_LABEL_POSITIONS, onChange: (labelPosition) => controller.update({ labelPosition }) }) }),
9345
+ spec.type === "histogram" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Bins", htmlFor: `${idBase}-bins`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-bins`, value: spec.bins === null ? "" : String(spec.bins), placeholder: "Auto", inputMode: "numeric", "data-option": "bins", className: chartInputClass, onCommit: (text) => controller.update({ bins: text.trim() === "" ? null : Number(text) }).ok }) }),
9346
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
9347
+ spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
9348
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
9349
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
8969
9350
  ] })
8970
9351
  ] }),
8971
- show("legend") && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
8972
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center justify-between", children: [
8973
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
8974
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
9352
+ show("legend") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
9353
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center justify-between", children: [
9354
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
9355
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
8975
9356
  ] }),
8976
- spec.legend.show && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: import_chart4.CHART_LEGEND_POSITIONS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", "aria-pressed": spec.legend.position === p, "data-option": `legend.${p}`, className: chartSegmentClass(spec.legend.position === p), onClick: () => controller.setLegend({ position: p }), children: cap(p) }, p)) })
9357
+ spec.legend.show && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: import_chart4.CHART_LEGEND_POSITIONS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", "aria-pressed": spec.legend.position === p, "data-option": `legend.${p}`, className: chartSegmentClass(spec.legend.position === p), onClick: () => controller.setLegend({ position: p }), children: cap(p) }, p)) })
8977
9358
  ] }),
8978
- show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
8979
- family !== "box" && family !== "histogram" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AxisSection, { controller, axis: "x", value: spec.xAxis, idBase, horizontal: spec.orientation === "horizontal", numeric: family === "xy", scales }),
8980
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
8981
- usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
9359
+ show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9360
+ family !== "box" && family !== "histogram" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AxisSection, { controller, axis: "x", value: spec.xAxis, idBase, horizontal: spec.orientation === "horizontal", numeric: family === "xy", scales }),
9361
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
9362
+ usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
8982
9363
  ] }),
8983
- show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
8984
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
8985
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Name", htmlFor: `${idBase}-series-name`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCommitInput, { id: `${idBase}-series-name`, value: selectedSeries.name, "data-option": "series.name", className: chartInputClass, onCommit: (name) => void controller.updateSeries(selectedSeries.id, { name }) }) }),
8986
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Colour", htmlFor: `${idBase}-series-color`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1", children: [
8987
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9364
+ show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
9365
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
9366
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Name", htmlFor: `${idBase}-series-name`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartCommitInput, { id: `${idBase}-series-name`, value: selectedSeries.name, "data-option": "series.name", className: chartInputClass, onCommit: (name) => void controller.updateSeries(selectedSeries.id, { name }) }) }),
9367
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Colour", htmlFor: `${idBase}-series-color`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1", children: [
9368
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8988
9369
  "input",
8989
9370
  {
8990
9371
  id: `${idBase}-series-color`,
@@ -8997,9 +9378,9 @@ function ChartInspector({ controller, sections, className }) {
8997
9378
  onChange: (e) => controller.updateSeries(selectedSeries.id, { color: e.currentTarget.value })
8998
9379
  }
8999
9380
  ),
9000
- selectedSeries.color && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "reset-color", onClick: () => controller.updateSeries(selectedSeries.id, { color: null }), children: "Palette" })
9381
+ selectedSeries.color && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "reset-color", onClick: () => controller.updateSeries(selectedSeries.id, { color: null }), children: "Palette" })
9001
9382
  ] }) }),
9002
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9383
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9003
9384
  "select",
9004
9385
  {
9005
9386
  id: `${idBase}-series-type`,
@@ -9008,12 +9389,12 @@ function ChartInspector({ controller, sections, className }) {
9008
9389
  "data-option": "series.type",
9009
9390
  onChange: (e) => controller.updateSeries(selectedSeries.id, { type: e.currentTarget.value || null }),
9010
9391
  children: [
9011
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "Chart type" }),
9012
- import_chart4.CHART_SERIES_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: t, children: import_chart4.CHART_TYPE_LABELS[t] }, t))
9392
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Chart type" }),
9393
+ import_chart4.CHART_SERIES_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: t, children: import_chart4.CHART_TYPE_LABELS[t] }, t))
9013
9394
  ]
9014
9395
  }
9015
9396
  ) }),
9016
- (cartesian || family === "xy") && ["line", "area", "scatter"].includes((0, import_chart4.chartSeriesType)(spec, selectedSeries)) && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Marker", htmlFor: `${idBase}-series-marker`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9397
+ (cartesian || family === "xy") && ["line", "area", "scatter"].includes((0, import_chart4.chartSeriesType)(spec, selectedSeries)) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Marker", htmlFor: `${idBase}-series-marker`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9017
9398
  "select",
9018
9399
  {
9019
9400
  id: `${idBase}-series-marker`,
@@ -9022,20 +9403,20 @@ function ChartInspector({ controller, sections, className }) {
9022
9403
  "data-option": "series.marker",
9023
9404
  onChange: (e) => controller.updateSeries(selectedSeries.id, { marker: e.currentTarget.value || null }),
9024
9405
  children: [
9025
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "Default" }),
9026
- import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: m, children: cap(m) }, m))
9406
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Default" }),
9407
+ import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: m, children: cap(m) }, m))
9027
9408
  ]
9028
9409
  }
9029
9410
  ) }),
9030
- scales && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
9031
- family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
9032
- (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
9033
- (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
9034
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
9035
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "R\xB2", name: `trendline.${i}.showR2`, checked: !!t.showR2, onChange: (showR2) => controller.updateTrendline(selectedSeries.id, i, { showR2 }) }),
9036
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, "aria-label": "Delete trendline", "data-action": "trendline-delete", onClick: () => controller.removeTrendline(selectedSeries.id, i), children: "\xD7" })
9411
+ scales && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
9412
+ family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
9413
+ (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
9414
+ (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
9415
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
9416
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "R\xB2", name: `trendline.${i}.showR2`, checked: !!t.showR2, onChange: (showR2) => controller.updateTrendline(selectedSeries.id, i, { showR2 }) }),
9417
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, "aria-label": "Delete trendline", "data-action": "trendline-delete", onClick: () => controller.removeTrendline(selectedSeries.id, i), children: "\xD7" })
9037
9418
  ] }, i)),
9038
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9419
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9039
9420
  "select",
9040
9421
  {
9041
9422
  className: chartInputClass,
@@ -9044,32 +9425,32 @@ function ChartInspector({ controller, sections, className }) {
9044
9425
  "data-option": "trendline.add",
9045
9426
  onChange: (e) => e.currentTarget.value && controller.addTrendline(selectedSeries.id, { type: e.currentTarget.value }),
9046
9427
  children: [
9047
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "Add trendline\u2026" }),
9048
- import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
9428
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Add trendline\u2026" }),
9429
+ import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
9049
9430
  ]
9050
9431
  }
9051
9432
  )
9052
9433
  ] }),
9053
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
9054
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
9055
- family === "cartesian" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Secondary axis", name: "series.axis", checked: selectedSeries.axis === "secondary", onChange: (secondary) => controller.updateSeries(selectedSeries.id, { axis: secondary ? "secondary" : null }) }),
9056
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "flex-1" }),
9057
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, disabled: seriesIndex <= 0, "aria-label": "Move series earlier", "data-action": "series-up", onClick: () => controller.moveSeries(selectedSeries.id, seriesIndex - 1), children: "\u2191" }),
9058
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, disabled: seriesIndex >= spec.series.length - 1, "aria-label": "Move series later", "data-action": "series-down", onClick: () => controller.moveSeries(selectedSeries.id, seriesIndex + 1), children: "\u2193" }),
9059
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: `${chartButtonClass} text-destructive`, "data-action": "series-delete", onClick: () => controller.removeSeries(selectedSeries.id), children: "Delete" })
9434
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
9435
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
9436
+ family === "cartesian" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Secondary axis", name: "series.axis", checked: selectedSeries.axis === "secondary", onChange: (secondary) => controller.updateSeries(selectedSeries.id, { axis: secondary ? "secondary" : null }) }),
9437
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1" }),
9438
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, disabled: seriesIndex <= 0, "aria-label": "Move series earlier", "data-action": "series-up", onClick: () => controller.moveSeries(selectedSeries.id, seriesIndex - 1), children: "\u2191" }),
9439
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, disabled: seriesIndex >= spec.series.length - 1, "aria-label": "Move series later", "data-action": "series-down", onClick: () => controller.moveSeries(selectedSeries.id, seriesIndex + 1), children: "\u2193" }),
9440
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: `${chartButtonClass} text-destructive`, "data-action": "series-delete", onClick: () => controller.removeSeries(selectedSeries.id), children: "Delete" })
9060
9441
  ] })
9061
9442
  ] })
9062
9443
  ] });
9063
9444
  }
9064
9445
 
9065
9446
  // src/chart-node/ChartNodeView.tsx
9066
- var import_jsx_runtime45 = require("react/jsx-runtime");
9447
+ var import_jsx_runtime47 = require("react/jsx-runtime");
9067
9448
  function ChartNodeView({ state, theme, showDataGrid = true }) {
9068
9449
  const { controller, editing, editable, selected, width, height, setEditing } = state;
9069
9450
  const open = () => {
9070
9451
  if (editable && !editing) setEditing(true);
9071
9452
  };
9072
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
9453
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9073
9454
  "div",
9074
9455
  {
9075
9456
  className: `not-prose my-2 rounded-md border bg-background p-1 ${selected ? "border-primary ring-1 ring-primary" : "border-border"}`,
@@ -9082,24 +9463,24 @@ function ChartNodeView({ state, theme, showDataGrid = true }) {
9082
9463
  }
9083
9464
  },
9084
9465
  children: [
9085
- editing && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mb-1 flex items-center justify-between gap-2 px-1", "data-chart-node-toolbar": "", children: [
9086
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
9087
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
9466
+ editing && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mb-1 flex items-center justify-between gap-2 px-1", "data-chart-node-toolbar": "", children: [
9467
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
9468
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
9088
9469
  ] }),
9089
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
9470
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
9090
9471
  "div",
9091
9472
  {
9092
9473
  className: editable && !editing ? "cursor-pointer" : void 0,
9093
9474
  onClick: open,
9094
9475
  title: editable && !editing ? "Click to edit the chart" : void 0,
9095
9476
  "data-chart-node-canvas": "",
9096
- children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
9477
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
9097
9478
  }
9098
9479
  ),
9099
9480
  editing && // Wraps by the document's width, not the viewport's: side by side when there is room.
9100
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
9101
- showDataGrid && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "min-w-0 flex-[1_1_20rem] overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartDataGrid, { controller }) }),
9102
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartInspector, { controller, className: "max-h-96 min-w-0 flex-[1_1_16rem] overflow-y-auto rounded-md border border-border p-3" })
9481
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
9482
+ showDataGrid && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "min-w-0 flex-[1_1_20rem] overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ChartDataGrid, { controller }) }),
9483
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ChartInspector, { controller, className: "max-h-96 min-w-0 flex-[1_1_16rem] overflow-y-auto rounded-md border border-border p-3" })
9103
9484
  ] })
9104
9485
  ]
9105
9486
  }
@@ -9117,7 +9498,7 @@ function createReactChartNodeView(options = {}) {
9117
9498
  scheduled = true;
9118
9499
  queueMicrotask(() => {
9119
9500
  scheduled = false;
9120
- if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Component, { ...props, state: latest }));
9501
+ if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Component, { ...props, state: latest }));
9121
9502
  });
9122
9503
  };
9123
9504
  schedule();
@@ -9168,6 +9549,7 @@ function createReactChartNodeView(options = {}) {
9168
9549
  RefineEdgePanel,
9169
9550
  ReviewToolbar,
9170
9551
  SelectionOptionsBar,
9552
+ ShapeOptionsBar,
9171
9553
  SheetTabs,
9172
9554
  SpreadsheetConditionalFormatPanel,
9173
9555
  SpreadsheetContextMenu,
@@ -9180,6 +9562,7 @@ function createReactChartNodeView(options = {}) {
9180
9562
  TableToolbar,
9181
9563
  TemplateRenderer,
9182
9564
  TrackedChangesList,
9565
+ TypeOptionsBar,
9183
9566
  VariableForm,
9184
9567
  bindDirtyToHistory,
9185
9568
  createDirtyTracker,