@pixerate/editor-react 0.69.0 → 0.71.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
  {
@@ -5371,8 +5384,215 @@ var FreeTransformOptionsBar = ({ tool, className }) => {
5371
5384
  ] });
5372
5385
  };
5373
5386
 
5374
- // src/image-editor/ImageEditor.tsx
5387
+ // src/image-editor/ShapeOptionsBar.tsx
5388
+ var import_react44 = require("react");
5389
+ var import_image_editor12 = require("@pixerate/editor/image-editor");
5375
5390
  var import_jsx_runtime27 = require("react/jsx-runtime");
5391
+ 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"}`;
5392
+ var ShapeOptionsBar = ({ controller, options, onChange, className }) => {
5393
+ const [, setTick] = (0, import_react44.useState)(0);
5394
+ (0, import_react44.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
5395
+ const [error, setError] = (0, import_react44.useState)(null);
5396
+ const active = controller.getActiveLayer();
5397
+ const shapeId = active?.type === "shape" ? active.id : null;
5398
+ const set = (change) => {
5399
+ onChange({ ...options, ...change });
5400
+ if (!shapeId) return;
5401
+ try {
5402
+ setError(null);
5403
+ (0, import_image_editor12.applyShapeOptions)(controller, shapeId, change);
5404
+ } catch (e) {
5405
+ setError(e instanceof Error ? e.message : String(e));
5406
+ }
5407
+ };
5408
+ const num = (v, min, max) => Math.max(min, Math.min(max, Number(v) || min));
5409
+ 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: [
5410
+ /* @__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)) }),
5411
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
5412
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5413
+ /* @__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 }) }),
5414
+ "Fill",
5415
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5416
+ "input",
5417
+ {
5418
+ type: "color",
5419
+ "aria-label": "Fill colour",
5420
+ disabled: options.fill === null,
5421
+ value: options.fill ?? "#4f46e5",
5422
+ onChange: (e) => set({ fill: e.target.value }),
5423
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
5424
+ }
5425
+ )
5426
+ ] }),
5427
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5428
+ /* @__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 }) }),
5429
+ "Stroke",
5430
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5431
+ "input",
5432
+ {
5433
+ type: "color",
5434
+ "aria-label": "Stroke colour",
5435
+ disabled: options.stroke === null,
5436
+ value: options.stroke ?? "#000000",
5437
+ onChange: (e) => set({ stroke: e.target.value }),
5438
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
5439
+ }
5440
+ )
5441
+ ] }),
5442
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5443
+ "Width",
5444
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5445
+ "input",
5446
+ {
5447
+ type: "number",
5448
+ "aria-label": "Stroke width",
5449
+ min: 0,
5450
+ max: 200,
5451
+ value: options.strokeWidth,
5452
+ onChange: (e) => set({ strokeWidth: num(e.target.value, 0, 200) }),
5453
+ className: "w-14 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5454
+ }
5455
+ )
5456
+ ] })
5457
+ ] }),
5458
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-wrap items-center gap-3", children: [
5459
+ options.kind === "rect" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5460
+ "Radius",
5461
+ /* @__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" })
5462
+ ] }),
5463
+ options.kind === "polygon" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5464
+ "Sides",
5465
+ /* @__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" })
5466
+ ] }),
5467
+ options.kind === "star" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
5468
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5469
+ "Points",
5470
+ /* @__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" })
5471
+ ] }),
5472
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5473
+ "Inner",
5474
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5475
+ "input",
5476
+ {
5477
+ type: "range",
5478
+ "aria-label": "Inner radius",
5479
+ min: 0.05,
5480
+ max: 1,
5481
+ step: 0.05,
5482
+ value: options.innerRatio,
5483
+ onChange: (e) => set({ innerRatio: Number(e.target.value) }),
5484
+ className: "accent-indigo-500"
5485
+ }
5486
+ )
5487
+ ] })
5488
+ ] }),
5489
+ options.kind === "line" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
5490
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5491
+ "Weight",
5492
+ /* @__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" })
5493
+ ] }),
5494
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "flex items-center gap-1", children: [
5495
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("input", { type: "checkbox", "aria-label": "Arrowhead", checked: options.arrow, onChange: (e) => set({ arrow: e.target.checked }) }),
5496
+ "Arrowhead"
5497
+ ] })
5498
+ ] })
5499
+ ] }),
5500
+ /* @__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." }),
5501
+ error && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
5502
+ ] });
5503
+ };
5504
+
5505
+ // src/image-editor/TypeOptionsBar.tsx
5506
+ var import_react45 = require("react");
5507
+ var import_image_editor13 = require("@pixerate/editor/image-editor");
5508
+ var import_jsx_runtime28 = require("react/jsx-runtime");
5509
+ 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"}`;
5510
+ var ALIGN_LABELS = { left: "Left", center: "Centre", right: "Right", justify: "Justify" };
5511
+ var TypeOptionsBar = ({ controller, options, onChange, session, className }) => {
5512
+ const [, setTick] = (0, import_react45.useState)(0);
5513
+ (0, import_react45.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
5514
+ (0, import_react45.useEffect)(() => session?.subscribe(() => setTick((n) => n + 1)), [session]);
5515
+ const [error, setError] = (0, import_react45.useState)(null);
5516
+ const active = controller.getActiveLayer();
5517
+ const typeId = !session && active?.type === "type" ? active.id : null;
5518
+ const here = session?.alive ? session.styleHere() : {};
5519
+ const shown = {
5520
+ ...options,
5521
+ ...here.fontFamily ? { fontFamily: here.fontFamily } : {},
5522
+ ...here.fontSize ? { fontSize: here.fontSize } : {},
5523
+ ...here.fontWeight ? { fontWeight: here.fontWeight } : {},
5524
+ ...session?.alive ? { italic: Boolean(here.italic), color: here.color ?? options.color } : {}
5525
+ };
5526
+ const fonts = controller.listFonts();
5527
+ const missing = active?.type === "type" ? active.missingFonts ?? [] : [];
5528
+ const style = (change) => {
5529
+ onChange({ ...options, ...change });
5530
+ const s = {};
5531
+ for (const k of ["fontFamily", "fontSize", "fontWeight", "italic", "color"]) if (k in change) s[k] = change[k];
5532
+ const p = change.align ? { align: change.align } : null;
5533
+ try {
5534
+ setError(null);
5535
+ if (session?.alive) {
5536
+ if (Object.keys(s).length) session.setStyle(s);
5537
+ if (p) session.setParagraph(p);
5538
+ if (session.error) setError(session.error);
5539
+ } else if (typeId) {
5540
+ if (Object.keys(s).length) controller.setTextStyle(typeId, s);
5541
+ if (p) controller.setParagraphStyle(typeId, p);
5542
+ }
5543
+ } catch (e) {
5544
+ setError(e instanceof Error ? e.message : String(e));
5545
+ }
5546
+ };
5547
+ 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: [
5548
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
5549
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { className: "flex items-center gap-1", children: [
5550
+ "Font",
5551
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5552
+ "input",
5553
+ {
5554
+ list: "pixerate-type-fonts",
5555
+ "aria-label": "Font family",
5556
+ value: shown.fontFamily,
5557
+ onChange: (e) => e.target.value.trim() && style({ fontFamily: e.target.value }),
5558
+ className: "w-32 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5559
+ }
5560
+ ),
5561
+ /* @__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)) })
5562
+ ] }),
5563
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { className: "flex items-center gap-1", children: [
5564
+ "Size",
5565
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5566
+ "input",
5567
+ {
5568
+ type: "number",
5569
+ "aria-label": "Font size",
5570
+ min: 1,
5571
+ max: 2e3,
5572
+ value: Math.round(shown.fontSize * 10) / 10,
5573
+ onChange: (e) => Number(e.target.value) > 0 && style({ fontSize: Number(e.target.value) }),
5574
+ className: "w-16 rounded border border-slate-700 bg-slate-950 px-1 py-0.5"
5575
+ }
5576
+ )
5577
+ ] }),
5578
+ /* @__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" }),
5579
+ /* @__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" }),
5580
+ /* @__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" })
5581
+ ] }),
5582
+ /* @__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)) }),
5583
+ /* @__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." }),
5584
+ missing.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { role: "status", className: "text-amber-400", "data-testid": "type-missing-fonts", children: [
5585
+ "Missing ",
5586
+ missing.length === 1 ? "font" : "fonts",
5587
+ ": ",
5588
+ missing.join(", ")
5589
+ ] }),
5590
+ error && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
5591
+ ] });
5592
+ };
5593
+
5594
+ // src/image-editor/ImageEditor.tsx
5595
+ var import_jsx_runtime29 = require("react/jsx-runtime");
5376
5596
  var ImageEditor = ({
5377
5597
  editor: externalEditor,
5378
5598
  src,
@@ -5387,47 +5607,65 @@ var ImageEditor = ({
5387
5607
  const internalEditor = useImageEditor({ image: src });
5388
5608
  const editor = externalEditor || internalEditor;
5389
5609
  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);
5610
+ const legacyProcess = (0, import_image_editor14.normalizeProcessVersion)(state.adjustments.process) < import_image_editor14.LATEST_PROCESS_VERSION;
5611
+ const canvasRef = (0, import_react46.useRef)(null);
5612
+ const containerRef = (0, import_react46.useRef)(null);
5613
+ const [activeTab, setActiveTab] = (0, import_react46.useState)("crop");
5614
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react46.useState)(null);
5615
+ const [selectionOptions, setSelectionOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_SELECTION_TOOL_OPTIONS);
5616
+ const selectionOptionsRef = (0, import_react46.useRef)(selectionOptions);
5397
5617
  selectionOptionsRef.current = selectionOptions;
5398
- const selectionGestureRef = (0, import_react44.useRef)(null);
5618
+ const selectionGestureRef = (0, import_react46.useRef)(null);
5399
5619
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
5400
- selectionGestureRef.current = new import_image_editor12.SelectionGesture(controller, () => selectionOptionsRef.current);
5620
+ selectionGestureRef.current = new import_image_editor14.SelectionGesture(controller, () => selectionOptionsRef.current);
5401
5621
  }
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);
5622
+ const selectionDraftRef = (0, import_react46.useRef)(null);
5623
+ const [selectionError, setSelectionError] = (0, import_react46.useState)(null);
5624
+ const paintGestureRef = (0, import_react46.useRef)(null);
5625
+ const paintControllerRef = (0, import_react46.useRef)(controller);
5406
5626
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
5407
- paintGestureRef.current = new import_image_editor12.PaintGesture(controller);
5627
+ paintGestureRef.current = new import_image_editor14.PaintGesture(controller);
5408
5628
  paintControllerRef.current = controller;
5409
5629
  }
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);
5630
+ const brushCursorRef = (0, import_react46.useRef)(null);
5631
+ const [paintError, setPaintError] = (0, import_react46.useState)(null);
5632
+ const transformToolRef = (0, import_react46.useRef)(null);
5633
+ const transformControllerRef = (0, import_react46.useRef)(controller);
5414
5634
  if (!transformToolRef.current || transformControllerRef.current !== controller) {
5415
5635
  transformToolRef.current?.cancel();
5416
- transformToolRef.current = new import_image_editor12.FreeTransformTool(controller, {
5636
+ transformToolRef.current = new import_image_editor14.FreeTransformTool(controller, {
5417
5637
  schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
5418
5638
  });
5419
5639
  transformControllerRef.current = controller;
5420
5640
  }
5421
5641
  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");
5642
+ const [, setTransformTick] = (0, import_react46.useState)(0);
5643
+ const [transformCursor, setTransformCursor] = (0, import_react46.useState)("default");
5644
+ const [shapeOptions, setShapeOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_SHAPE_TOOL_OPTIONS);
5645
+ const shapeOptionsRef = (0, import_react46.useRef)(shapeOptions);
5646
+ shapeOptionsRef.current = shapeOptions;
5647
+ const [typeOptions, setTypeOptions] = (0, import_react46.useState)(import_image_editor14.DEFAULT_TYPE_TOOL_OPTIONS);
5648
+ const typeOptionsRef = (0, import_react46.useRef)(typeOptions);
5649
+ typeOptionsRef.current = typeOptions;
5650
+ const shapeGestureRef = (0, import_react46.useRef)(null);
5651
+ const typeToolRef = (0, import_react46.useRef)(null);
5652
+ const shapeTypeControllerRef = (0, import_react46.useRef)(controller);
5653
+ if (!shapeGestureRef.current || !typeToolRef.current || shapeTypeControllerRef.current !== controller) {
5654
+ typeToolRef.current?.finish();
5655
+ shapeGestureRef.current = new import_image_editor14.ShapeDrawGesture(controller, () => shapeOptionsRef.current);
5656
+ typeToolRef.current = new import_image_editor14.TypeToolGesture(controller, () => typeOptionsRef.current);
5657
+ shapeTypeControllerRef.current = controller;
5658
+ }
5659
+ const typeInputRef = (0, import_react46.useRef)(null);
5660
+ const [typeSession, setTypeSession] = (0, import_react46.useState)(typeToolRef.current.session);
5661
+ const [shapeTypeError, setShapeTypeError] = (0, import_react46.useState)(null);
5662
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react46.useState)("");
5663
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react46.useState)("annotations");
5664
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react46.useState)(false);
5665
+ const [isInpainting, setIsInpainting] = (0, import_react46.useState)(false);
5666
+ const [aiError, setAiError] = (0, import_react46.useState)(null);
5667
+ const [aiSuccess, setAiSuccess] = (0, import_react46.useState)(null);
5668
+ const [aiTarget, setAiTarget] = (0, import_react46.useState)("auto");
5431
5669
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
5432
5670
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
5433
5671
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -5490,18 +5728,18 @@ var ImageEditor = ({
5490
5728
  setIsInpainting(false);
5491
5729
  }
5492
5730
  };
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)(
5731
+ const [activeColor, setActiveColor] = (0, import_react46.useState)("#ef4444");
5732
+ const [strokeWidth, setStrokeWidth] = (0, import_react46.useState)(3);
5733
+ const [fontSize, setFontSize] = (0, import_react46.useState)(24);
5734
+ const [textInput, setTextInput] = (0, import_react46.useState)("");
5735
+ const draftAnnotationRef = (0, import_react46.useRef)(null);
5736
+ const draftCropRef = (0, import_react46.useRef)(null);
5737
+ const cropDragInfoRef = (0, import_react46.useRef)(null);
5738
+ const annotationDragInfoRef = (0, import_react46.useRef)(null);
5739
+ const isDrawingRef = (0, import_react46.useRef)(false);
5740
+ const currentPathRef = (0, import_react46.useRef)([]);
5741
+ const dragStartPointRef = (0, import_react46.useRef)(null);
5742
+ const renderCanvas = (0, import_react46.useCallback)(
5505
5743
  async (draftAnnotation, draftCrop) => {
5506
5744
  const canvas = canvasRef.current;
5507
5745
  const container = containerRef.current;
@@ -5518,12 +5756,49 @@ var ImageEditor = ({
5518
5756
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
5519
5757
  draftSelectionPath: selectionDraftRef.current,
5520
5758
  brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
5521
- freeTransform: transformTool.overlay()
5759
+ freeTransform: transformTool.overlay(),
5760
+ textEdit: typeToolRef.current?.session?.alive ? typeToolRef.current.session.overlay() : null
5522
5761
  });
5523
5762
  },
5524
5763
  [controller, activeTab, transformTool]
5525
5764
  );
5526
- (0, import_react44.useEffect)(() => transformTool.subscribe(() => {
5765
+ (0, import_react46.useEffect)(() => typeSession?.subscribe(() => void renderCanvas()), [typeSession, renderCanvas]);
5766
+ (0, import_react46.useEffect)(() => {
5767
+ if (activeTab === "annotate" && state.activeTool === "type") return;
5768
+ if (typeToolRef.current?.session) {
5769
+ typeToolRef.current.finish();
5770
+ setTypeSession(null);
5771
+ void renderCanvas();
5772
+ }
5773
+ }, [activeTab, state.activeTool, renderCanvas]);
5774
+ const finishTyping = () => {
5775
+ typeToolRef.current?.finish();
5776
+ setTypeSession(null);
5777
+ void renderCanvas();
5778
+ };
5779
+ const handleTypeKeyDown = (e) => {
5780
+ const session = typeToolRef.current?.session;
5781
+ if (!session || e.nativeEvent.isComposing) return;
5782
+ if (e.key === "Escape") {
5783
+ e.preventDefault();
5784
+ finishTyping();
5785
+ return;
5786
+ }
5787
+ if ((e.metaKey || e.ctrlKey) && ["z", "y", "c", "x", "v"].includes(e.key.toLowerCase())) return;
5788
+ if (session.handleKey(e)) {
5789
+ e.preventDefault();
5790
+ setShapeTypeError(session.error);
5791
+ }
5792
+ };
5793
+ const handleTypeInput = (e) => {
5794
+ const el = e.currentTarget;
5795
+ const session = typeToolRef.current?.session;
5796
+ if (session && el.value && !e.nativeEvent.isComposing) {
5797
+ session.insert(el.value);
5798
+ el.value = "";
5799
+ }
5800
+ };
5801
+ (0, import_react46.useEffect)(() => transformTool.subscribe(() => {
5527
5802
  setTransformTick((n) => n + 1);
5528
5803
  void renderCanvas();
5529
5804
  }), [transformTool, renderCanvas]);
@@ -5534,8 +5809,8 @@ var ImageEditor = ({
5534
5809
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5535
5810
  const s = controller.getState();
5536
5811
  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);
5812
+ const projection = (0, import_image_editor14.getViewportProjection)(s, canvas.width, canvas.height, cropping);
5813
+ 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
5814
  transformTool.setView(projection.scale);
5540
5815
  return { pt, tolerance: 6 / (projection.scale || 1) };
5541
5816
  };
@@ -5566,7 +5841,7 @@ var ImageEditor = ({
5566
5841
  transformTool.up();
5567
5842
  return true;
5568
5843
  };
5569
- (0, import_react44.useEffect)(() => {
5844
+ (0, import_react46.useEffect)(() => {
5570
5845
  if (typeof window === "undefined") return;
5571
5846
  const onKey = (e) => {
5572
5847
  if (transformTool.key(e)) e.preventDefault();
@@ -5574,7 +5849,7 @@ var ImageEditor = ({
5574
5849
  window.addEventListener("keydown", onKey);
5575
5850
  return () => window.removeEventListener("keydown", onKey);
5576
5851
  }, [transformTool]);
5577
- (0, import_react44.useEffect)(() => {
5852
+ (0, import_react46.useEffect)(() => {
5578
5853
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
5579
5854
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
5580
5855
  const animId = raf(() => {
@@ -5582,12 +5857,12 @@ var ImageEditor = ({
5582
5857
  });
5583
5858
  return () => caf(animId);
5584
5859
  }, [renderCanvas, state]);
5585
- (0, import_react44.useEffect)(() => {
5860
+ (0, import_react46.useEffect)(() => {
5586
5861
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
5587
5862
  editor.setTool("crop");
5588
5863
  }
5589
5864
  }, [activeTab, editor]);
5590
- (0, import_react44.useEffect)(() => {
5865
+ (0, import_react46.useEffect)(() => {
5591
5866
  const container = containerRef.current;
5592
5867
  if (!container) return;
5593
5868
  if (typeof ResizeObserver !== "undefined") {
@@ -5623,8 +5898,8 @@ var ImageEditor = ({
5623
5898
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5624
5899
  const s = controller.getState();
5625
5900
  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)
5901
+ ...(0, import_image_editor14.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5902
+ pressure: (0, import_image_editor14.pointerPressure)(ev)
5628
5903
  }));
5629
5904
  };
5630
5905
  const handlePaintPointerDown = (e) => {
@@ -5655,10 +5930,10 @@ var ImageEditor = ({
5655
5930
  if (g.error) setPaintError(g.error);
5656
5931
  }
5657
5932
  };
5658
- (0, import_react44.useEffect)(() => {
5933
+ (0, import_react46.useEffect)(() => {
5659
5934
  if (activeTab !== "paint" || typeof window === "undefined") return;
5660
5935
  const onKey = (e) => {
5661
- if ((0, import_image_editor12.handlePaintShortcut)(controller, e)) e.preventDefault();
5936
+ if ((0, import_image_editor14.handlePaintShortcut)(controller, e)) e.preventDefault();
5662
5937
  };
5663
5938
  window.addEventListener("keydown", onKey);
5664
5939
  return () => window.removeEventListener("keydown", onKey);
@@ -5669,7 +5944,7 @@ var ImageEditor = ({
5669
5944
  const canvasPt = getCanvasEventPoint(e);
5670
5945
  if (activeTab === "select") {
5671
5946
  const gesture = selectionGestureRef.current;
5672
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5947
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5673
5948
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
5674
5949
  return;
5675
5950
  }
@@ -5680,8 +5955,8 @@ var ImageEditor = ({
5680
5955
  width: state.imageDimensions.width,
5681
5956
  height: state.imageDimensions.height
5682
5957
  };
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);
5958
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5959
+ const startImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5685
5960
  if (handle) {
5686
5961
  cropDragInfoRef.current = {
5687
5962
  handle,
@@ -5699,13 +5974,24 @@ var ImageEditor = ({
5699
5974
  }
5700
5975
  return;
5701
5976
  }
5977
+ if (activeTab === "annotate" && (state.activeTool === "shape" || state.activeTool === "type")) {
5978
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5979
+ setShapeTypeError(null);
5980
+ if (state.activeTool === "shape") shapeGestureRef.current.down(imgPt);
5981
+ else {
5982
+ typeToolRef.current.down(imgPt, { shift: e.shiftKey });
5983
+ setTypeSession(typeToolRef.current.session);
5984
+ void renderCanvas();
5985
+ }
5986
+ return;
5987
+ }
5702
5988
  if (activeTab === "annotate") {
5703
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5989
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5704
5990
  dragStartPointRef.current = imgPt;
5705
5991
  if (state.activeTool === "select") {
5706
5992
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5707
5993
  const ann = state.annotations[i];
5708
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, ann)) {
5994
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, ann)) {
5709
5995
  editor.selectAnnotation(ann.id);
5710
5996
  annotationDragInfoRef.current = {
5711
5997
  annId: ann.id,
@@ -5741,7 +6027,7 @@ var ImageEditor = ({
5741
6027
  const canvasPt = getCanvasEventPoint(e);
5742
6028
  if (activeTab === "select") {
5743
6029
  const gesture = selectionGestureRef.current;
5744
- if (gesture.active && gesture.move((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
6030
+ if (gesture.active && gesture.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5745
6031
  selectionDraftRef.current = gesture.draftPath;
5746
6032
  renderCanvas();
5747
6033
  }
@@ -5750,7 +6036,7 @@ var ImageEditor = ({
5750
6036
  if (activeTab === "crop") {
5751
6037
  const drag = cropDragInfoRef.current;
5752
6038
  if (drag) {
5753
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
6039
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5754
6040
  let newCrop;
5755
6041
  if (drag.handle === "new") {
5756
6042
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -5764,7 +6050,7 @@ var ImageEditor = ({
5764
6050
  height: Math.round(Math.max(20, maxY - minY))
5765
6051
  };
5766
6052
  } else {
5767
- newCrop = (0, import_image_editor12.calculateCropDrag)(
6053
+ newCrop = (0, import_image_editor14.calculateCropDrag)(
5768
6054
  drag.startCrop,
5769
6055
  drag.handle,
5770
6056
  drag.startImgPt,
@@ -5784,15 +6070,23 @@ var ImageEditor = ({
5784
6070
  width: state.imageDimensions.width,
5785
6071
  height: state.imageDimensions.height
5786
6072
  };
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);
6073
+ const handle = (0, import_image_editor14.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
6074
+ canvas.style.cursor = (0, import_image_editor14.getCropCursor)(handle, state.transform);
6075
+ }
6076
+ return;
6077
+ }
6078
+ if (activeTab === "annotate" && state.activeTool === "shape") {
6079
+ const g = shapeGestureRef.current;
6080
+ if (g.active) {
6081
+ g.move((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), { shift: e.shiftKey, alt: e.altKey });
6082
+ if (g.error) setShapeTypeError(g.error);
5789
6083
  }
5790
6084
  return;
5791
6085
  }
5792
6086
  if (activeTab === "annotate") {
5793
6087
  if (annotationDragInfoRef.current) {
5794
6088
  const drag = annotationDragInfoRef.current;
5795
- const currentImgPt2 = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6089
+ const currentImgPt2 = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5796
6090
  const dx = currentImgPt2.x - drag.startImgPt.x;
5797
6091
  const dy = currentImgPt2.y - drag.startImgPt.y;
5798
6092
  editor.updateAnnotation(drag.annId, {
@@ -5804,10 +6098,10 @@ var ImageEditor = ({
5804
6098
  const startPt = dragStartPointRef.current;
5805
6099
  if (!startPt) {
5806
6100
  if (state.activeTool === "select") {
5807
- const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6101
+ const imgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5808
6102
  let hovered = false;
5809
6103
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5810
- if ((0, import_image_editor12.hitTestAnnotation)(imgPt, state.annotations[i])) {
6104
+ if ((0, import_image_editor14.hitTestAnnotation)(imgPt, state.annotations[i])) {
5811
6105
  hovered = true;
5812
6106
  break;
5813
6107
  }
@@ -5818,7 +6112,7 @@ var ImageEditor = ({
5818
6112
  }
5819
6113
  return;
5820
6114
  }
5821
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6115
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5822
6116
  if (state.activeTool === "pen" && isDrawingRef.current) {
5823
6117
  currentPathRef.current.push(currentImgPt);
5824
6118
  const draft = {
@@ -5898,7 +6192,7 @@ var ImageEditor = ({
5898
6192
  if (activeTab === "select") {
5899
6193
  const gesture = selectionGestureRef.current;
5900
6194
  if (gesture.active) {
5901
- gesture.end((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
6195
+ gesture.end((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5902
6196
  selectionDraftRef.current = null;
5903
6197
  renderCanvas();
5904
6198
  }
@@ -5915,6 +6209,19 @@ var ImageEditor = ({
5915
6209
  }
5916
6210
  return;
5917
6211
  }
6212
+ if (activeTab === "annotate" && state.activeTool === "shape") {
6213
+ shapeGestureRef.current.up();
6214
+ return;
6215
+ }
6216
+ if (activeTab === "annotate" && state.activeTool === "type") {
6217
+ const tool = typeToolRef.current;
6218
+ tool.up((0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false));
6219
+ setTypeSession(tool.session);
6220
+ if (tool.error) setShapeTypeError(tool.error);
6221
+ void renderCanvas();
6222
+ if (tool.session) setTimeout(() => typeInputRef.current?.focus(), 0);
6223
+ return;
6224
+ }
5918
6225
  if (activeTab === "annotate") {
5919
6226
  if (annotationDragInfoRef.current) {
5920
6227
  annotationDragInfoRef.current = null;
@@ -5922,7 +6229,7 @@ var ImageEditor = ({
5922
6229
  }
5923
6230
  const startPt = dragStartPointRef.current;
5924
6231
  if (startPt) {
5925
- const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
6232
+ const currentImgPt = (0, import_image_editor14.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5926
6233
  if (state.activeTool === "pen" && isDrawingRef.current) {
5927
6234
  if (currentPathRef.current.length > 1) {
5928
6235
  editor.addAnnotation({
@@ -6018,15 +6325,15 @@ var ImageEditor = ({
6018
6325
  link.click();
6019
6326
  }
6020
6327
  };
6021
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6328
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6022
6329
  "div",
6023
6330
  {
6024
6331
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
6025
6332
  style,
6026
6333
  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)(
6334
+ /* @__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: [
6335
+ /* @__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: [
6336
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6030
6337
  "button",
6031
6338
  {
6032
6339
  type: "button",
@@ -6038,7 +6345,7 @@ var ImageEditor = ({
6038
6345
  children: "Transform & Crop"
6039
6346
  }
6040
6347
  ),
6041
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6348
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6042
6349
  "button",
6043
6350
  {
6044
6351
  type: "button",
@@ -6050,7 +6357,7 @@ var ImageEditor = ({
6050
6357
  children: "Adjustments"
6051
6358
  }
6052
6359
  ),
6053
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6360
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6054
6361
  "button",
6055
6362
  {
6056
6363
  type: "button",
@@ -6062,7 +6369,7 @@ var ImageEditor = ({
6062
6369
  children: "Layers"
6063
6370
  }
6064
6371
  ),
6065
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6372
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6066
6373
  "button",
6067
6374
  {
6068
6375
  type: "button",
@@ -6074,7 +6381,7 @@ var ImageEditor = ({
6074
6381
  children: "Paint"
6075
6382
  }
6076
6383
  ),
6077
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6384
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6078
6385
  "button",
6079
6386
  {
6080
6387
  type: "button",
@@ -6086,7 +6393,7 @@ var ImageEditor = ({
6086
6393
  children: "Select & Mask"
6087
6394
  }
6088
6395
  ),
6089
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6396
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6090
6397
  "button",
6091
6398
  {
6092
6399
  type: "button",
@@ -6098,7 +6405,7 @@ var ImageEditor = ({
6098
6405
  children: "Annotations"
6099
6406
  }
6100
6407
  ),
6101
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6408
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6102
6409
  "button",
6103
6410
  {
6104
6411
  type: "button",
@@ -6110,7 +6417,7 @@ var ImageEditor = ({
6110
6417
  children: "Depth Mask"
6111
6418
  }
6112
6419
  ),
6113
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6420
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6114
6421
  "button",
6115
6422
  {
6116
6423
  type: "button",
@@ -6120,14 +6427,14 @@ var ImageEditor = ({
6120
6427
  },
6121
6428
  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
6429
  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" }) }),
6430
+ /* @__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
6431
  "AI Tools"
6125
6432
  ]
6126
6433
  }
6127
6434
  )
6128
6435
  ] }),
6129
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
6130
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6436
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
6437
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6131
6438
  "button",
6132
6439
  {
6133
6440
  type: "button",
@@ -6138,7 +6445,7 @@ var ImageEditor = ({
6138
6445
  children: "\u21A9"
6139
6446
  }
6140
6447
  ),
6141
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6448
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6142
6449
  "button",
6143
6450
  {
6144
6451
  type: "button",
@@ -6149,7 +6456,7 @@ var ImageEditor = ({
6149
6456
  children: "\u21AA"
6150
6457
  }
6151
6458
  ),
6152
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6459
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6153
6460
  "button",
6154
6461
  {
6155
6462
  type: "button",
@@ -6158,8 +6465,8 @@ var ImageEditor = ({
6158
6465
  children: "Reset"
6159
6466
  }
6160
6467
  ),
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)(
6468
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6469
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6163
6470
  "button",
6164
6471
  {
6165
6472
  type: "button",
@@ -6169,11 +6476,11 @@ var ImageEditor = ({
6169
6476
  children: "-"
6170
6477
  }
6171
6478
  ),
6172
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
6479
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
6173
6480
  Math.round(state.zoom * 100),
6174
6481
  "%"
6175
6482
  ] }),
6176
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6483
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6177
6484
  "button",
6178
6485
  {
6179
6486
  type: "button",
@@ -6183,8 +6490,8 @@ var ImageEditor = ({
6183
6490
  children: "+"
6184
6491
  }
6185
6492
  ),
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)(
6493
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
6494
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6188
6495
  "button",
6189
6496
  {
6190
6497
  type: "button",
@@ -6195,7 +6502,7 @@ var ImageEditor = ({
6195
6502
  children: "Hold Compare"
6196
6503
  }
6197
6504
  ),
6198
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6505
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6199
6506
  "button",
6200
6507
  {
6201
6508
  type: "button",
@@ -6206,38 +6513,59 @@ var ImageEditor = ({
6206
6513
  )
6207
6514
  ] })
6208
6515
  ] }),
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)(
6516
+ 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" }),
6517
+ !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 }),
6518
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
6519
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6213
6520
  "div",
6214
6521
  {
6215
6522
  ref: containerRef,
6216
6523
  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
- )
6524
+ children: [
6525
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6526
+ "canvas",
6527
+ {
6528
+ ref: canvasRef,
6529
+ onMouseDown: handleMouseDown,
6530
+ onMouseMove: handleMouseMove,
6531
+ onMouseUp: handleMouseUp,
6532
+ onMouseLeave: handleMouseUp,
6533
+ onPointerDown: handlePaintPointerDown,
6534
+ onPointerMove: handlePaintPointerMove,
6535
+ onPointerUp: handlePaintPointerUp,
6536
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
6537
+ "data-testid": "image-editor-canvas",
6538
+ style: transformTool.active ? { cursor: transformCursor } : void 0,
6539
+ 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" : ""}`
6540
+ }
6541
+ ),
6542
+ typeSession && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6543
+ "textarea",
6544
+ {
6545
+ ref: typeInputRef,
6546
+ "aria-label": "Edit text",
6547
+ "data-testid": "type-input",
6548
+ autoCapitalize: "off",
6549
+ autoCorrect: "off",
6550
+ spellCheck: false,
6551
+ onKeyDown: handleTypeKeyDown,
6552
+ onInput: handleTypeInput,
6553
+ onCompositionEnd: (e) => {
6554
+ const session = typeToolRef.current?.session;
6555
+ if (session && e.data) session.insert(e.data);
6556
+ e.currentTarget.value = "";
6557
+ },
6558
+ className: "absolute left-0 top-0 h-px w-px opacity-0"
6559
+ }
6560
+ )
6561
+ ]
6234
6562
  }
6235
6563
  ),
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)(
6564
+ /* @__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: [
6565
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6566
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
6567
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
6568
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6241
6569
  "button",
6242
6570
  {
6243
6571
  type: "button",
@@ -6249,7 +6577,7 @@ var ImageEditor = ({
6249
6577
  children: "Freeform"
6250
6578
  }
6251
6579
  ),
6252
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6580
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6253
6581
  "button",
6254
6582
  {
6255
6583
  type: "button",
@@ -6261,7 +6589,7 @@ var ImageEditor = ({
6261
6589
  children: "1:1 Square"
6262
6590
  }
6263
6591
  ),
6264
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6592
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6265
6593
  "button",
6266
6594
  {
6267
6595
  type: "button",
@@ -6273,7 +6601,7 @@ var ImageEditor = ({
6273
6601
  children: "4:3 Standard"
6274
6602
  }
6275
6603
  ),
6276
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6604
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6277
6605
  "button",
6278
6606
  {
6279
6607
  type: "button",
@@ -6285,7 +6613,7 @@ var ImageEditor = ({
6285
6613
  children: "16:9 Wide"
6286
6614
  }
6287
6615
  ),
6288
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6616
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6289
6617
  "button",
6290
6618
  {
6291
6619
  type: "button",
@@ -6297,7 +6625,7 @@ var ImageEditor = ({
6297
6625
  children: "3:2 Photo"
6298
6626
  }
6299
6627
  ),
6300
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6628
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6301
6629
  "button",
6302
6630
  {
6303
6631
  type: "button",
@@ -6310,10 +6638,10 @@ var ImageEditor = ({
6310
6638
  }
6311
6639
  )
6312
6640
  ] }),
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)(
6641
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6642
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
6643
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
6644
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6317
6645
  "button",
6318
6646
  {
6319
6647
  type: "button",
@@ -6322,7 +6650,7 @@ var ImageEditor = ({
6322
6650
  children: "Rotate -90\xB0"
6323
6651
  }
6324
6652
  ),
6325
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6653
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6326
6654
  "button",
6327
6655
  {
6328
6656
  type: "button",
@@ -6331,7 +6659,7 @@ var ImageEditor = ({
6331
6659
  children: "Rotate +90\xB0"
6332
6660
  }
6333
6661
  ),
6334
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6662
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6335
6663
  "button",
6336
6664
  {
6337
6665
  type: "button",
@@ -6340,7 +6668,7 @@ var ImageEditor = ({
6340
6668
  children: "Flip Horizontal"
6341
6669
  }
6342
6670
  ),
6343
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6671
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6344
6672
  "button",
6345
6673
  {
6346
6674
  type: "button",
@@ -6351,10 +6679,10 @@ var ImageEditor = ({
6351
6679
  )
6352
6680
  ] })
6353
6681
  ] }),
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)(
6682
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6683
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6684
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
6685
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6358
6686
  "button",
6359
6687
  {
6360
6688
  type: "button",
@@ -6364,25 +6692,25 @@ var ImageEditor = ({
6364
6692
  }
6365
6693
  )
6366
6694
  ] }),
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)(
6695
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Histogram, { histogram: editor.histogram }),
6696
+ import_image_editor14.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react46.default.Fragment, { children: [
6697
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6370
6698
  ControlSlider,
6371
6699
  {
6372
6700
  spec,
6373
- value: (0, import_image_editor12.readAdjustmentControls)(state.adjustments)[spec.id],
6701
+ value: (0, import_image_editor14.readAdjustmentControls)(state.adjustments)[spec.id],
6374
6702
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
6375
6703
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
6376
6704
  }
6377
6705
  ),
6378
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6706
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6379
6707
  "div",
6380
6708
  {
6381
6709
  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
6710
  "data-testid": "image-editor-process-notice",
6383
6711
  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)(
6712
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
6713
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6386
6714
  "button",
6387
6715
  {
6388
6716
  type: "button",
@@ -6395,7 +6723,7 @@ var ImageEditor = ({
6395
6723
  }
6396
6724
  )
6397
6725
  ] }, 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)(
6726
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6399
6727
  AdjustmentLayersPanel,
6400
6728
  {
6401
6729
  controller,
@@ -6404,9 +6732,9 @@ var ImageEditor = ({
6404
6732
  }
6405
6733
  ) })
6406
6734
  ] }),
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)(
6735
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6736
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
6737
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6410
6738
  "button",
6411
6739
  {
6412
6740
  type: "button",
@@ -6417,12 +6745,12 @@ var ImageEditor = ({
6417
6745
  children: "Free Transform"
6418
6746
  }
6419
6747
  ),
6420
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LayersPanel, { controller })
6748
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(LayersPanel, { controller })
6421
6749
  ] }),
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)(
6750
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6751
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
6752
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(BrushOptionsBar, { controller }),
6753
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6426
6754
  "button",
6427
6755
  {
6428
6756
  type: "button",
@@ -6433,12 +6761,29 @@ var ImageEditor = ({
6433
6761
  children: "Free Transform"
6434
6762
  }
6435
6763
  ),
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 }) })
6764
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
6765
+ /* @__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
6766
  ] }),
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)(
6767
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6768
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Shape & Type Layers" }),
6769
+ /* @__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)(
6770
+ "button",
6771
+ {
6772
+ type: "button",
6773
+ "aria-pressed": state.activeTool === t,
6774
+ onClick: () => editor.setTool(t),
6775
+ 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"}`,
6776
+ children: t === "shape" ? "Shape" : "Type"
6777
+ },
6778
+ t
6779
+ )) }),
6780
+ state.activeTool === "shape" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ShapeOptionsBar, { controller, options: shapeOptions, onChange: setShapeOptions }),
6781
+ state.activeTool === "type" && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TypeOptionsBar, { controller, options: typeOptions, onChange: setTypeOptions, session: typeSession }),
6782
+ 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" }),
6783
+ shapeTypeError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "shape-type-error", children: shapeTypeError }),
6784
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6785
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
6786
+ /* @__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
6787
  "button",
6443
6788
  {
6444
6789
  type: "button",
@@ -6448,9 +6793,9 @@ var ImageEditor = ({
6448
6793
  },
6449
6794
  t
6450
6795
  )) }),
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)(
6796
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
6797
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { className: "text-slate-400", children: "Color:" }),
6798
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6454
6799
  "input",
6455
6800
  {
6456
6801
  type: "color",
@@ -6459,15 +6804,15 @@ var ImageEditor = ({
6459
6804
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
6460
6805
  }
6461
6806
  ),
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: [
6807
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex-1 ml-2", children: [
6808
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
6809
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Width:" }),
6810
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono", children: [
6466
6811
  strokeWidth,
6467
6812
  "px"
6468
6813
  ] })
6469
6814
  ] }),
6470
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6815
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6471
6816
  "input",
6472
6817
  {
6473
6818
  type: "range",
@@ -6480,10 +6825,10 @@ var ImageEditor = ({
6480
6825
  )
6481
6826
  ] })
6482
6827
  ] }),
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)(
6828
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6829
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
6830
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-2", children: [
6831
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6487
6832
  "input",
6488
6833
  {
6489
6834
  type: "text",
@@ -6494,7 +6839,7 @@ var ImageEditor = ({
6494
6839
  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
6840
  }
6496
6841
  ),
6497
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6842
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6498
6843
  "button",
6499
6844
  {
6500
6845
  type: "button",
@@ -6504,14 +6849,14 @@ var ImageEditor = ({
6504
6849
  }
6505
6850
  )
6506
6851
  ] }),
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: [
6852
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
6853
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Font Size:" }),
6854
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "font-mono", children: [
6510
6855
  fontSize,
6511
6856
  "px"
6512
6857
  ] })
6513
6858
  ] }),
6514
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6859
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6515
6860
  "input",
6516
6861
  {
6517
6862
  type: "range",
@@ -6522,14 +6867,14 @@ var ImageEditor = ({
6522
6867
  className: "w-full accent-indigo-500"
6523
6868
  }
6524
6869
  ),
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: [
6870
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6871
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6872
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "text-slate-400", children: [
6528
6873
  "Layers (",
6529
6874
  state.annotations.length,
6530
6875
  ")"
6531
6876
  ] }),
6532
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6877
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6533
6878
  "button",
6534
6879
  {
6535
6880
  type: "button",
@@ -6538,7 +6883,7 @@ var ImageEditor = ({
6538
6883
  children: "Delete Selected"
6539
6884
  }
6540
6885
  ),
6541
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6886
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6542
6887
  "button",
6543
6888
  {
6544
6889
  type: "button",
@@ -6549,10 +6894,10 @@ var ImageEditor = ({
6549
6894
  )
6550
6895
  ] })
6551
6896
  ] }),
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)(
6897
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6898
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
6899
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
6900
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6556
6901
  "button",
6557
6902
  {
6558
6903
  type: "button",
@@ -6562,8 +6907,8 @@ var ImageEditor = ({
6562
6907
  }
6563
6908
  )
6564
6909
  ] }),
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)(
6910
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6911
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6567
6912
  "input",
6568
6913
  {
6569
6914
  type: "checkbox",
@@ -6572,12 +6917,12 @@ var ImageEditor = ({
6572
6917
  className: "rounded accent-indigo-500"
6573
6918
  }
6574
6919
  ),
6575
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6920
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6576
6921
  ] }),
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)(
6922
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
6923
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6924
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6925
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6581
6926
  "input",
6582
6927
  {
6583
6928
  type: "text",
@@ -6588,8 +6933,8 @@ var ImageEditor = ({
6588
6933
  }
6589
6934
  )
6590
6935
  ] }),
6591
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-2", children: [
6592
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6936
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-2", children: [
6937
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6593
6938
  "button",
6594
6939
  {
6595
6940
  type: "button",
@@ -6598,7 +6943,7 @@ var ImageEditor = ({
6598
6943
  children: "Threshold Mode"
6599
6944
  }
6600
6945
  ),
6601
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6946
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6602
6947
  "button",
6603
6948
  {
6604
6949
  type: "button",
@@ -6608,12 +6953,12 @@ var ImageEditor = ({
6608
6953
  }
6609
6954
  )
6610
6955
  ] }),
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] })
6956
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6957
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6958
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Depth Start (Lower):" }),
6959
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
6615
6960
  ] }),
6616
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6961
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6617
6962
  "input",
6618
6963
  {
6619
6964
  type: "range",
@@ -6627,12 +6972,12 @@ var ImageEditor = ({
6627
6972
  }
6628
6973
  )
6629
6974
  ] }),
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] })
6975
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6976
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6977
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Depth Stop (Upper):" }),
6978
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
6634
6979
  ] }),
6635
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6980
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6636
6981
  "input",
6637
6982
  {
6638
6983
  type: "range",
@@ -6646,12 +6991,12 @@ var ImageEditor = ({
6646
6991
  }
6647
6992
  )
6648
6993
  ] }),
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 })
6994
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
6995
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6996
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Softness:" }),
6997
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
6653
6998
  ] }),
6654
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6999
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6655
7000
  "input",
6656
7001
  {
6657
7002
  type: "range",
@@ -6663,8 +7008,8 @@ var ImageEditor = ({
6663
7008
  }
6664
7009
  )
6665
7010
  ] }),
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)(
7011
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
7012
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6668
7013
  "input",
6669
7014
  {
6670
7015
  type: "checkbox",
@@ -6673,12 +7018,12 @@ var ImageEditor = ({
6673
7018
  className: "rounded accent-indigo-500"
6674
7019
  }
6675
7020
  ),
6676
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Invert Mask" })
7021
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Invert Mask" })
6677
7022
  ] })
6678
7023
  ] })
6679
7024
  ] }),
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)(
7025
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
7026
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6682
7027
  SelectionOptionsBar,
6683
7028
  {
6684
7029
  controller,
@@ -6688,9 +7033,9 @@ var ImageEditor = ({
6688
7033
  quickMask: Boolean(state.quickMask)
6689
7034
  }
6690
7035
  ),
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)(
7036
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
7037
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-1", children: [
7038
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6694
7039
  "button",
6695
7040
  {
6696
7041
  type: "button",
@@ -6701,7 +7046,7 @@ var ImageEditor = ({
6701
7046
  children: "Transform Selection"
6702
7047
  }
6703
7048
  ),
6704
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7049
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6705
7050
  "button",
6706
7051
  {
6707
7052
  type: "button",
@@ -6713,12 +7058,12 @@ var ImageEditor = ({
6713
7058
  }
6714
7059
  )
6715
7060
  ] }),
6716
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
7061
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
6717
7062
  ] }),
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)(
7063
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
7064
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
7065
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { children: "Results go to" }),
7066
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6722
7067
  "select",
6723
7068
  {
6724
7069
  "aria-label": "AI result target",
@@ -6726,54 +7071,54 @@ var ImageEditor = ({
6726
7071
  onChange: (e) => setAiTarget(e.target.value),
6727
7072
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
6728
7073
  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" })
7074
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
7075
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
7076
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "replace", children: "Replace image" })
6732
7077
  ]
6733
7078
  }
6734
7079
  )
6735
7080
  ] }),
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" }) }),
7081
+ /* @__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: [
7082
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
7083
+ /* @__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: [
7084
+ /* @__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
7085
  "Background Removal"
6741
7086
  ] }),
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..." })
7087
+ 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
7088
  ] }),
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)(
7089
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
7090
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6746
7091
  "button",
6747
7092
  {
6748
7093
  type: "button",
6749
7094
  onClick: handleRemoveBackground,
6750
7095
  disabled: isRemovingBg || isInpainting,
6751
7096
  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" }),
7097
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7098
+ /* @__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
7099
  "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" }) }),
7100
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7101
+ /* @__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
7102
  "Remove Background"
6758
7103
  ] })
6759
7104
  }
6760
7105
  )
6761
7106
  ] }),
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" })
7107
+ /* @__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: [
7108
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center justify-between", children: [
7109
+ /* @__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: [
7110
+ /* @__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: [
7111
+ /* @__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" }),
7112
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "m14 7 3 3" })
6768
7113
  ] }),
6769
7114
  "Generative Inpainting"
6770
7115
  ] }),
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..." })
7116
+ 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
7117
  ] }),
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)(
7118
+ /* @__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." }),
7119
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
7120
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
7121
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6777
7122
  "textarea",
6778
7123
  {
6779
7124
  id: "ai-inpaint-prompt-react",
@@ -6785,10 +7130,10 @@ var ImageEditor = ({
6785
7130
  }
6786
7131
  )
6787
7132
  ] }),
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)(
7133
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1", children: [
7134
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
7135
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
7136
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6792
7137
  "button",
6793
7138
  {
6794
7139
  type: "button",
@@ -6801,7 +7146,7 @@ var ImageEditor = ({
6801
7146
  ]
6802
7147
  }
6803
7148
  ),
6804
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
7149
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6805
7150
  "button",
6806
7151
  {
6807
7152
  type: "button",
@@ -6816,25 +7161,25 @@ var ImageEditor = ({
6816
7161
  )
6817
7162
  ] })
6818
7163
  ] }),
6819
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7164
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6820
7165
  "button",
6821
7166
  {
6822
7167
  type: "button",
6823
7168
  onClick: handleInpaint,
6824
7169
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
6825
7170
  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" }),
7171
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7172
+ /* @__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
7173
  "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" }) }),
7174
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
7175
+ /* @__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
7176
  "Apply Inpainting"
6832
7177
  ] })
6833
7178
  }
6834
7179
  )
6835
7180
  ] }),
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 })
7181
+ 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 }),
7182
+ 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
7183
  ] })
6839
7184
  ] })
6840
7185
  ] })
@@ -6844,7 +7189,7 @@ var ImageEditor = ({
6844
7189
  };
6845
7190
 
6846
7191
  // src/review/useReview.ts
6847
- var import_react45 = require("react");
7192
+ var import_react47 = require("react");
6848
7193
  var import_editor12 = require("@pixerate/editor");
6849
7194
  var EMPTY_COMMENTS = Object.freeze({
6850
7195
  threads: [],
@@ -6863,23 +7208,23 @@ function isCommentStore(value) {
6863
7208
  }
6864
7209
  function useComments(source) {
6865
7210
  const store = isCommentStore(source) ? source : (0, import_editor12.getCommentStore)(source);
6866
- const subscribe = (0, import_react45.useCallback)(
7211
+ const subscribe = (0, import_react47.useCallback)(
6867
7212
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6868
7213
  [store]
6869
7214
  );
6870
7215
  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]);
7216
+ const snapshot = (0, import_react47.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7217
+ return (0, import_react47.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
6873
7218
  }
6874
7219
  function useTrackChanges(editor) {
6875
7220
  const store = (0, import_editor12.getTrackChangesStore)(editor ?? null);
6876
- const subscribe = (0, import_react45.useCallback)(
7221
+ const subscribe = (0, import_react47.useCallback)(
6877
7222
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6878
7223
  [store]
6879
7224
  );
6880
7225
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
6881
- const snapshot = (0, import_react45.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6882
- return (0, import_react45.useMemo)(() => {
7226
+ const snapshot = (0, import_react47.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7227
+ return (0, import_react47.useMemo)(() => {
6883
7228
  const run = (fn) => () => {
6884
7229
  if (editor && !editor.isDestroyed) fn(editor);
6885
7230
  };
@@ -6902,9 +7247,9 @@ function useTrackChanges(editor) {
6902
7247
  }
6903
7248
 
6904
7249
  // src/review/CommentsPanel.tsx
6905
- var import_react46 = require("react");
7250
+ var import_react48 = require("react");
6906
7251
  var import_editor13 = require("@pixerate/editor");
6907
- var import_jsx_runtime28 = require("react/jsx-runtime");
7252
+ var import_jsx_runtime30 = require("react/jsx-runtime");
6908
7253
  var buttonClass2 = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
6909
7254
  var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
6910
7255
  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 +7263,18 @@ var CommentsPanel = ({
6918
7263
  emptyMessage = "No comments yet. Select text and add a comment."
6919
7264
  }) => {
6920
7265
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
6921
- const [showResolved, setShowResolved] = (0, import_react46.useState)(showResolvedInitial);
7266
+ const [showResolved, setShowResolved] = (0, import_react48.useState)(showResolvedInitial);
6922
7267
  const author = authorProp ?? (0, import_editor13.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
6923
7268
  const visible = threads.filter((t) => showResolved || !t.resolved);
6924
7269
  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: [
7270
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("aside", { className, "aria-label": "Comments", children: [
7271
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
7272
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
6928
7273
  threads.length - resolvedCount,
6929
7274
  " open",
6930
7275
  resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
6931
7276
  ] }),
6932
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7277
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6933
7278
  "button",
6934
7279
  {
6935
7280
  type: "button",
@@ -6940,7 +7285,7 @@ var CommentsPanel = ({
6940
7285
  }
6941
7286
  )
6942
7287
  ] }),
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)(
7288
+ 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
7289
  CommentThreadCard,
6945
7290
  {
6946
7291
  thread,
@@ -6962,7 +7307,7 @@ var CommentThreadCard = ({
6962
7307
  author,
6963
7308
  formatTime
6964
7309
  }) => {
6965
- const [draft, setDraft] = (0, import_react46.useState)("");
7310
+ const [draft, setDraft] = (0, import_react48.useState)("");
6966
7311
  const isDraft = thread.body === "";
6967
7312
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
6968
7313
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -6988,7 +7333,7 @@ var CommentThreadCard = ({
6988
7333
  setDraft("");
6989
7334
  };
6990
7335
  const stop = (e) => e.stopPropagation();
6991
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
7336
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
6992
7337
  "li",
6993
7338
  {
6994
7339
  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 +7349,24 @@ var CommentThreadCard = ({
7004
7349
  }
7005
7350
  },
7006
7351
  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) })
7352
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
7353
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: thread.author.name }),
7354
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
7010
7355
  ] }),
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 }),
7356
+ 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 }),
7357
+ thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
7358
+ thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
7359
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
7360
+ 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: [
7361
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "text-xs", children: [
7362
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: reply.author.name }),
7018
7363
  " ",
7019
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
7364
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
7020
7365
  ] }),
7021
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
7366
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
7022
7367
  ] }, 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)(
7368
+ (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
7369
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7025
7370
  "textarea",
7026
7371
  {
7027
7372
  className: textareaClass,
@@ -7039,9 +7384,9 @@ var CommentThreadCard = ({
7039
7384
  }
7040
7385
  }
7041
7386
  ),
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)(
7387
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex justify-end gap-1", children: [
7388
+ isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
7389
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7045
7390
  "button",
7046
7391
  {
7047
7392
  type: "button",
@@ -7053,9 +7398,9 @@ var CommentThreadCard = ({
7053
7398
  )
7054
7399
  ] })
7055
7400
  ] }),
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)(
7401
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
7402
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
7403
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7059
7404
  "button",
7060
7405
  {
7061
7406
  type: "button",
@@ -7071,7 +7416,7 @@ var CommentThreadCard = ({
7071
7416
  };
7072
7417
 
7073
7418
  // src/review/ReviewToolbar.tsx
7074
- var import_jsx_runtime29 = require("react/jsx-runtime");
7419
+ var import_jsx_runtime31 = require("react/jsx-runtime");
7075
7420
  var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
7076
7421
  var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
7077
7422
  var ReviewToolbar = ({
@@ -7084,8 +7429,8 @@ var ReviewToolbar = ({
7084
7429
  const count = review.changes.length;
7085
7430
  const current = review.currentChange;
7086
7431
  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)(
7432
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
7433
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7089
7434
  "button",
7090
7435
  {
7091
7436
  type: "button",
@@ -7096,8 +7441,8 @@ var ReviewToolbar = ({
7096
7441
  children: review.enabled ? "Tracking on" : "Track changes"
7097
7442
  }
7098
7443
  ),
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)(
7444
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
7445
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7101
7446
  "button",
7102
7447
  {
7103
7448
  type: "button",
@@ -7108,8 +7453,8 @@ var ReviewToolbar = ({
7108
7453
  children: "\u2039"
7109
7454
  }
7110
7455
  ),
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)(
7456
+ /* @__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` }),
7457
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7113
7458
  "button",
7114
7459
  {
7115
7460
  type: "button",
@@ -7120,7 +7465,7 @@ var ReviewToolbar = ({
7120
7465
  children: "\u203A"
7121
7466
  }
7122
7467
  ),
7123
- showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7468
+ showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7124
7469
  "span",
7125
7470
  {
7126
7471
  className: descriptionClassName,
@@ -7132,8 +7477,8 @@ var ReviewToolbar = ({
7132
7477
  ]
7133
7478
  }
7134
7479
  ),
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)(
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)(
7137
7482
  "button",
7138
7483
  {
7139
7484
  type: "button",
@@ -7143,7 +7488,7 @@ var ReviewToolbar = ({
7143
7488
  children: "Accept"
7144
7489
  }
7145
7490
  ),
7146
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7491
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7147
7492
  "button",
7148
7493
  {
7149
7494
  type: "button",
@@ -7153,18 +7498,18 @@ var ReviewToolbar = ({
7153
7498
  children: "Reject"
7154
7499
  }
7155
7500
  ),
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" })
7501
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
7502
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
7158
7503
  ] });
7159
7504
  };
7160
7505
 
7161
7506
  // src/review/CommentButton.tsx
7162
- var import_jsx_runtime30 = require("react/jsx-runtime");
7507
+ var import_jsx_runtime32 = require("react/jsx-runtime");
7163
7508
  var CommentButton = ({
7164
7509
  editor,
7165
7510
  className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
7166
7511
  children = "Comment"
7167
- }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7512
+ }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7168
7513
  "button",
7169
7514
  {
7170
7515
  type: "button",
@@ -7176,13 +7521,13 @@ var CommentButton = ({
7176
7521
  );
7177
7522
 
7178
7523
  // src/review/useDocumentCompare.ts
7179
- var import_react47 = require("react");
7524
+ var import_react49 = require("react");
7180
7525
  var import_editor14 = require("@pixerate/editor");
7181
7526
  function useDocumentCompare(editor, options) {
7182
- const [summary, setSummary] = (0, import_react47.useState)(null);
7183
- const defaults = (0, import_react47.useRef)(options);
7527
+ const [summary, setSummary] = (0, import_react49.useState)(null);
7528
+ const defaults = (0, import_react49.useRef)(options);
7184
7529
  defaults.current = options;
7185
- const compare = (0, import_react47.useCallback)(
7530
+ const compare = (0, import_react49.useCallback)(
7186
7531
  (original, revised, overrides) => {
7187
7532
  if (!editor || editor.isDestroyed) return null;
7188
7533
  const result = (0, import_editor14.applyDocumentComparison)(editor, original, revised, {
@@ -7194,13 +7539,13 @@ function useDocumentCompare(editor, options) {
7194
7539
  },
7195
7540
  [editor]
7196
7541
  );
7197
- const clear = (0, import_react47.useCallback)(() => setSummary(null), []);
7198
- return (0, import_react47.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
7542
+ const clear = (0, import_react49.useCallback)(() => setSummary(null), []);
7543
+ return (0, import_react49.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
7199
7544
  }
7200
7545
 
7201
7546
  // src/review/TrackedChangesList.tsx
7202
7547
  var import_editor15 = require("@pixerate/editor");
7203
- var import_jsx_runtime31 = require("react/jsx-runtime");
7548
+ var import_jsx_runtime33 = require("react/jsx-runtime");
7204
7549
  var buttonClass4 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
7205
7550
  var TrackedChangesList = ({
7206
7551
  editor,
@@ -7211,18 +7556,18 @@ var TrackedChangesList = ({
7211
7556
  }) => {
7212
7557
  const review = useTrackChanges(editor);
7213
7558
  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 }) });
7559
+ 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
7560
  }
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) => {
7561
+ 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
7562
  const active = change.id === review.currentChangeId;
7218
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7563
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7219
7564
  "li",
7220
7565
  {
7221
7566
  className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
7222
7567
  "data-change-type": change.type,
7223
7568
  "data-change-id": change.id,
7224
7569
  children: [
7225
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7570
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7226
7571
  "button",
7227
7572
  {
7228
7573
  type: "button",
@@ -7230,14 +7575,14 @@ var TrackedChangesList = ({
7230
7575
  title: `${change.author.name}: ${change.description}`,
7231
7576
  onClick: () => review.select(change.id),
7232
7577
  children: [
7233
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
7578
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
7234
7579
  change.author.name ? ` \xB7 ${change.author.name}` : "",
7235
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
7580
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
7236
7581
  ]
7237
7582
  }
7238
7583
  ),
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" })
7584
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
7585
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
7241
7586
  ]
7242
7587
  },
7243
7588
  `${change.type}:${change.id}`
@@ -7246,12 +7591,12 @@ var TrackedChangesList = ({
7246
7591
  };
7247
7592
 
7248
7593
  // src/commands/useCommandPalette.ts
7249
- var import_react48 = require("react");
7594
+ var import_react50 = require("react");
7250
7595
  var import_commands2 = require("@pixerate/editor/commands");
7251
7596
  function useCommandPalette(registry, options = {}) {
7252
- const optionsRef = (0, import_react48.useRef)(options);
7597
+ const optionsRef = (0, import_react50.useRef)(options);
7253
7598
  optionsRef.current = options;
7254
- const controller = (0, import_react48.useMemo)(
7599
+ const controller = (0, import_react50.useMemo)(
7255
7600
  () => (0, import_commands2.createCommandPaletteController)(registry, {
7256
7601
  context: () => {
7257
7602
  const c = optionsRef.current.context;
@@ -7272,9 +7617,9 @@ function useCommandPalette(registry, options = {}) {
7272
7617
  // eslint-disable-next-line react-hooks/exhaustive-deps
7273
7618
  [registry]
7274
7619
  );
7275
- const state = (0, import_react48.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7620
+ const state = (0, import_react50.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7276
7621
  const { hotkey, hotkeyTarget } = options;
7277
- (0, import_react48.useEffect)(() => {
7622
+ (0, import_react50.useEffect)(() => {
7278
7623
  if (!hotkey) return;
7279
7624
  const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
7280
7625
  if (!target) return;
@@ -7302,13 +7647,13 @@ function useCommandPalette(registry, options = {}) {
7302
7647
  }
7303
7648
 
7304
7649
  // src/commands/CommandPalette.tsx
7305
- var import_react49 = __toESM(require("react"), 1);
7306
- var import_jsx_runtime32 = require("react/jsx-runtime");
7650
+ var import_react51 = __toESM(require("react"), 1);
7651
+ var import_jsx_runtime34 = require("react/jsx-runtime");
7307
7652
  function HighlightedLabel({ item }) {
7308
- if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: item.label });
7653
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children: item.label });
7309
7654
  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)
7655
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children: Array.from(item.label).map(
7656
+ (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
7657
  ) });
7313
7658
  }
7314
7659
  var CommandPalette = ({
@@ -7317,22 +7662,22 @@ var CommandPalette = ({
7317
7662
  emptyMessage = "No matching commands",
7318
7663
  className = ""
7319
7664
  }) => {
7320
- const inputRef = (0, import_react49.useRef)(null);
7321
- const listRef = (0, import_react49.useRef)(null);
7322
- const baseId = (0, import_react49.useId)();
7665
+ const inputRef = (0, import_react51.useRef)(null);
7666
+ const listRef = (0, import_react51.useRef)(null);
7667
+ const baseId = (0, import_react51.useId)();
7323
7668
  const listId = `${baseId}-list`;
7324
7669
  const optionId = (index) => `${baseId}-option-${index}`;
7325
7670
  const { open, query, items, activeIndex } = palette;
7326
- (0, import_react49.useEffect)(() => {
7671
+ (0, import_react51.useEffect)(() => {
7327
7672
  if (open) inputRef.current?.focus();
7328
7673
  }, [open]);
7329
- (0, import_react49.useEffect)(() => {
7674
+ (0, import_react51.useEffect)(() => {
7330
7675
  if (!open) return;
7331
7676
  const active = listRef.current?.querySelector('[aria-selected="true"]');
7332
7677
  active?.scrollIntoView?.({ block: "nearest" });
7333
7678
  }, [open, activeIndex]);
7334
7679
  if (!open) return null;
7335
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7680
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7336
7681
  "div",
7337
7682
  {
7338
7683
  className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
@@ -7340,7 +7685,7 @@ var CommandPalette = ({
7340
7685
  onMouseDown: (e) => {
7341
7686
  if (e.target === e.currentTarget) palette.setOpen(false);
7342
7687
  },
7343
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7688
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
7344
7689
  "div",
7345
7690
  {
7346
7691
  role: "dialog",
@@ -7349,7 +7694,7 @@ var CommandPalette = ({
7349
7694
  className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
7350
7695
  style: { background: "var(--popover, var(--background, #fff))" },
7351
7696
  children: [
7352
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7697
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7353
7698
  "input",
7354
7699
  {
7355
7700
  ref: inputRef,
@@ -7369,7 +7714,7 @@ var CommandPalette = ({
7369
7714
  className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
7370
7715
  }
7371
7716
  ),
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)(
7717
+ 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
7718
  "li",
7374
7719
  {
7375
7720
  id: optionId(index),
@@ -7384,12 +7729,12 @@ var CommandPalette = ({
7384
7729
  onClick: () => palette.run(item.id),
7385
7730
  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
7731
  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 })
7732
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
7733
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(HighlightedLabel, { item }),
7734
+ item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
7390
7735
  ] }),
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 })
7736
+ item.group && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
7737
+ 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
7738
  ]
7394
7739
  },
7395
7740
  item.id
@@ -7402,12 +7747,12 @@ var CommandPalette = ({
7402
7747
  };
7403
7748
 
7404
7749
  // src/commands/useCommandShortcuts.ts
7405
- var import_react50 = require("react");
7750
+ var import_react52 = require("react");
7406
7751
  function useCommandShortcuts(registry, options = {}) {
7407
- const optionsRef = (0, import_react50.useRef)(options);
7752
+ const optionsRef = (0, import_react52.useRef)(options);
7408
7753
  optionsRef.current = options;
7409
7754
  const { enabled = true, target } = options;
7410
- (0, import_react50.useEffect)(() => {
7755
+ (0, import_react52.useEffect)(() => {
7411
7756
  if (!registry || !enabled) return;
7412
7757
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
7413
7758
  if (!eventTarget) return;
@@ -7425,14 +7770,14 @@ function useCommandShortcuts(registry, options = {}) {
7425
7770
  }, [registry, enabled, target]);
7426
7771
  }
7427
7772
  function useRegisterCommands(registry, specs) {
7428
- (0, import_react50.useEffect)(() => {
7773
+ (0, import_react52.useEffect)(() => {
7429
7774
  if (!registry || !specs || specs.length === 0) return;
7430
7775
  return registry.register(specs);
7431
7776
  }, [registry, specs]);
7432
7777
  }
7433
7778
 
7434
7779
  // src/persistence/useAutosave.ts
7435
- var import_react51 = require("react");
7780
+ var import_react53 = require("react");
7436
7781
  var import_persistence = require("@pixerate/editor/persistence");
7437
7782
  var IDLE = {
7438
7783
  status: "idle",
@@ -7443,18 +7788,18 @@ var IDLE = {
7443
7788
  ready: false
7444
7789
  };
7445
7790
  function useAutosave(options) {
7446
- const optionsRef = (0, import_react51.useRef)(options);
7791
+ const optionsRef = (0, import_react53.useRef)(options);
7447
7792
  optionsRef.current = options;
7448
7793
  const { storage, key, history, dirty } = options;
7449
7794
  const recover = options.recover !== false;
7450
7795
  const flushOnHide = options.flushOnHide !== false;
7451
7796
  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)(() => {
7797
+ const [controller, setController] = (0, import_react53.useState)(null);
7798
+ const [status, setStatus] = (0, import_react53.useState)(IDLE);
7799
+ const [recovery, setRecovery] = (0, import_react53.useState)(null);
7800
+ const [pendingRecovery, setPendingRecovery] = (0, import_react53.useState)(recover);
7801
+ const revisionsRef = (0, import_react53.useRef)(null);
7802
+ (0, import_react53.useEffect)(() => {
7458
7803
  const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
7459
7804
  const o = optionsRef.current;
7460
7805
  const instance = (0, import_persistence.createAutosaveController)({
@@ -7497,10 +7842,10 @@ function useAutosave(options) {
7497
7842
  if (revisionsRef.current === revisions) revisionsRef.current = null;
7498
7843
  };
7499
7844
  }, [storage, key, history, dirty, recover]);
7500
- (0, import_react51.useEffect)(() => {
7845
+ (0, import_react53.useEffect)(() => {
7501
7846
  if (controller && ready && !pendingRecovery) controller.ready();
7502
7847
  }, [controller, ready, pendingRecovery]);
7503
- (0, import_react51.useEffect)(() => {
7848
+ (0, import_react53.useEffect)(() => {
7504
7849
  if (!controller || !flushOnHide || typeof window === "undefined") return;
7505
7850
  const flush = () => void controller.flushNow();
7506
7851
  const onVisibility = () => {
@@ -7513,31 +7858,31 @@ function useAutosave(options) {
7513
7858
  document.removeEventListener("visibilitychange", onVisibility);
7514
7859
  };
7515
7860
  }, [controller, flushOnHide]);
7516
- const restore = (0, import_react51.useCallback)(() => {
7861
+ const restore = (0, import_react53.useCallback)(() => {
7517
7862
  const snapshot = recovery?.snapshot;
7518
7863
  setRecovery(null);
7519
7864
  setPendingRecovery(false);
7520
7865
  return snapshot;
7521
7866
  }, [recovery]);
7522
- const discard = (0, import_react51.useCallback)(async () => {
7867
+ const discard = (0, import_react53.useCallback)(async () => {
7523
7868
  if (controller) await controller.discardRecovery();
7524
7869
  setRecovery(null);
7525
7870
  setPendingRecovery(false);
7526
7871
  }, [controller]);
7527
- const flushNow = (0, import_react51.useCallback)(async () => {
7872
+ const flushNow = (0, import_react53.useCallback)(async () => {
7528
7873
  await controller?.flushNow();
7529
7874
  }, [controller]);
7530
- const markClean = (0, import_react51.useCallback)(async () => {
7875
+ const markClean = (0, import_react53.useCallback)(async () => {
7531
7876
  revisionsRef.current?.markSaved();
7532
7877
  await controller?.markClean();
7533
7878
  }, [controller]);
7534
- const notifyChange = (0, import_react51.useCallback)(() => revisionsRef.current?.bump(), []);
7879
+ const notifyChange = (0, import_react53.useCallback)(() => revisionsRef.current?.bump(), []);
7535
7880
  return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
7536
7881
  }
7537
7882
 
7538
7883
  // src/persistence/RecoveryPrompt.tsx
7539
7884
  var import_persistence2 = require("@pixerate/editor/persistence");
7540
- var import_jsx_runtime33 = require("react/jsx-runtime");
7885
+ var import_jsx_runtime35 = require("react/jsx-runtime");
7541
7886
  var RecoveryPrompt = ({
7542
7887
  recovery,
7543
7888
  onRestore,
@@ -7549,7 +7894,7 @@ var RecoveryPrompt = ({
7549
7894
  }) => {
7550
7895
  if (!recovery) return null;
7551
7896
  const { name } = recovery.meta;
7552
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7897
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
7553
7898
  "div",
7554
7899
  {
7555
7900
  role: "alertdialog",
@@ -7557,15 +7902,15 @@ var RecoveryPrompt = ({
7557
7902
  "data-recovery-prompt": "",
7558
7903
  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
7904
  children: [
7560
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "min-w-0 flex-1", children: [
7905
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "min-w-0 flex-1", children: [
7561
7906
  (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: [
7907
+ name ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7563
7908
  "(",
7564
7909
  name,
7565
7910
  ")"
7566
7911
  ] }) : null
7567
7912
  ] }),
7568
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7913
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7569
7914
  "button",
7570
7915
  {
7571
7916
  type: "button",
@@ -7575,7 +7920,7 @@ var RecoveryPrompt = ({
7575
7920
  children: restoreLabel
7576
7921
  }
7577
7922
  ),
7578
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7923
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7579
7924
  "button",
7580
7925
  {
7581
7926
  type: "button",
@@ -7591,17 +7936,17 @@ var RecoveryPrompt = ({
7591
7936
  };
7592
7937
 
7593
7938
  // src/generation/useGenerationPlan.ts
7594
- var import_react52 = require("react");
7939
+ var import_react54 = require("react");
7595
7940
  var import_generation = require("@pixerate/editor/generation");
7596
7941
  function useGenerationPlan(request, capabilities, options = {}) {
7597
7942
  const key = JSON.stringify([request, capabilities, options]);
7598
- return (0, import_react52.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7943
+ return (0, import_react54.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7599
7944
  }
7600
7945
  function useJobProgress(options) {
7601
7946
  const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
7602
- const [tick, setTick] = (0, import_react52.useState)(() => Date.now());
7947
+ const [tick, setTick] = (0, import_react54.useState)(() => Date.now());
7603
7948
  const ticking = !done && now === void 0;
7604
- (0, import_react52.useEffect)(() => {
7949
+ (0, import_react54.useEffect)(() => {
7605
7950
  if (!ticking) return;
7606
7951
  setTick(Date.now());
7607
7952
  const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
@@ -7611,9 +7956,9 @@ function useJobProgress(options) {
7611
7956
  }
7612
7957
 
7613
7958
  // src/generation/GenerationSettings.tsx
7614
- var import_react53 = require("react");
7959
+ var import_react55 = require("react");
7615
7960
  var import_generation2 = require("@pixerate/editor/generation");
7616
- var import_jsx_runtime34 = require("react/jsx-runtime");
7961
+ var import_jsx_runtime36 = require("react/jsx-runtime");
7617
7962
  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
7963
  function Control({
7619
7964
  control,
@@ -7623,7 +7968,7 @@ function Control({
7623
7968
  }) {
7624
7969
  const shown = value ?? control.defaultValue;
7625
7970
  if (control.kind === "checkbox") {
7626
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7971
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7627
7972
  "input",
7628
7973
  {
7629
7974
  id,
@@ -7635,7 +7980,7 @@ function Control({
7635
7980
  );
7636
7981
  }
7637
7982
  if (control.kind === "select") {
7638
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
7983
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7639
7984
  "select",
7640
7985
  {
7641
7986
  id,
@@ -7644,14 +7989,14 @@ function Control({
7644
7989
  value: shown === void 0 ? "" : String(shown),
7645
7990
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
7646
7991
  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)))
7992
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: "", children: "Default" }),
7993
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
7649
7994
  ]
7650
7995
  }
7651
7996
  );
7652
7997
  }
7653
7998
  if (control.kind === "textarea") {
7654
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7999
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7655
8000
  "textarea",
7656
8001
  {
7657
8002
  id,
@@ -7665,8 +8010,8 @@ function Control({
7665
8010
  );
7666
8011
  }
7667
8012
  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)(
8013
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
8014
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7670
8015
  "input",
7671
8016
  {
7672
8017
  id,
@@ -7680,7 +8025,7 @@ function Control({
7680
8025
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
7681
8026
  }
7682
8027
  ),
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" })
8028
+ 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
8029
  ] });
7685
8030
  }
7686
8031
  var GenerationSettings = ({
@@ -7694,17 +8039,17 @@ var GenerationSettings = ({
7694
8039
  renderReference,
7695
8040
  className = ""
7696
8041
  }) => {
7697
- const baseId = (0, import_react53.useId)();
7698
- const controls = (0, import_react53.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
8042
+ const baseId = (0, import_react55.useId)();
8043
+ const controls = (0, import_react55.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7699
8044
  const computed = useGenerationPlan(value, capabilities, { strategy });
7700
8045
  const plan = planProp ?? computed;
7701
8046
  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: [
8047
+ 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
8048
  controls.map((control) => {
7704
8049
  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)(
8050
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
8051
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
8052
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7708
8053
  Control,
7709
8054
  {
7710
8055
  control,
@@ -7715,23 +8060,23 @@ var GenerationSettings = ({
7715
8060
  )
7716
8061
  ] }, control.key);
7717
8062
  }),
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: [
8063
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
8064
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
7720
8065
  slot.label,
7721
8066
  " ",
7722
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
8067
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7723
8068
  "(",
7724
8069
  slot.references.length,
7725
8070
  "/",
7726
8071
  slot.max,
7727
8072
  ")"
7728
8073
  ] }),
7729
- slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-destructive", children: " *" })
8074
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-destructive", children: " *" })
7730
8075
  ] }),
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)(
8076
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
8077
+ 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: [
8078
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
8079
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7735
8080
  "button",
7736
8081
  {
7737
8082
  type: "button",
@@ -7742,7 +8087,7 @@ var GenerationSettings = ({
7742
8087
  }
7743
8088
  )
7744
8089
  ] }, ref.id)),
7745
- onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8090
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7746
8091
  "button",
7747
8092
  {
7748
8093
  type: "button",
@@ -7753,21 +8098,21 @@ var GenerationSettings = ({
7753
8098
  ) })
7754
8099
  ] })
7755
8100
  ] }, 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)) })
8101
+ 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)) }),
8102
+ 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
8103
  ] });
7759
8104
  };
7760
8105
 
7761
8106
  // src/generation/JobProgress.tsx
7762
- var import_jsx_runtime35 = require("react/jsx-runtime");
8107
+ var import_jsx_runtime37 = require("react/jsx-runtime");
7763
8108
  var JobProgress = ({ title, className = "", ...options }) => {
7764
8109
  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 })
8110
+ 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: [
8111
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
8112
+ title && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "truncate text-foreground", children: title }),
8113
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
7769
8114
  ] }),
7770
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8115
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7771
8116
  "div",
7772
8117
  {
7773
8118
  role: "progressbar",
@@ -7777,7 +8122,7 @@ var JobProgress = ({ title, className = "", ...options }) => {
7777
8122
  "aria-valuenow": progress.percent,
7778
8123
  "aria-valuetext": `${progress.percent}%, ${progress.label}`,
7779
8124
  className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
7780
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8125
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7781
8126
  "div",
7782
8127
  {
7783
8128
  className: "h-full rounded-full bg-primary transition-[width] duration-500",
@@ -7790,9 +8135,9 @@ var JobProgress = ({ title, className = "", ...options }) => {
7790
8135
  };
7791
8136
 
7792
8137
  // src/generation/AssetMentionChips.tsx
7793
- var import_react54 = require("react");
8138
+ var import_react56 = require("react");
7794
8139
  var import_generation3 = require("@pixerate/editor/generation");
7795
- var import_jsx_runtime36 = require("react/jsx-runtime");
8140
+ var import_jsx_runtime38 = require("react/jsx-runtime");
7796
8141
  var AssetMentionChips = ({
7797
8142
  content,
7798
8143
  onChange,
@@ -7802,14 +8147,14 @@ var AssetMentionChips = ({
7802
8147
  renderAsset,
7803
8148
  className = ""
7804
8149
  }) => {
7805
- const [open, setOpen] = (0, import_react54.useState)(null);
7806
- const rootRef = (0, import_react54.useRef)(null);
7807
- const chips = (0, import_react54.useMemo)(
8150
+ const [open, setOpen] = (0, import_react56.useState)(null);
8151
+ const rootRef = (0, import_react56.useRef)(null);
8152
+ const chips = (0, import_react56.useMemo)(
7808
8153
  () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
7809
8154
  [content, assets, capabilities]
7810
8155
  );
7811
8156
  const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
7812
- (0, import_react54.useEffect)(() => {
8157
+ (0, import_react56.useEffect)(() => {
7813
8158
  if (open === null) return;
7814
8159
  const onPointer = (event) => {
7815
8160
  if (!rootRef.current?.contains(event.target)) setOpen(null);
@@ -7817,19 +8162,19 @@ var AssetMentionChips = ({
7817
8162
  document.addEventListener("mousedown", onPointer);
7818
8163
  return () => document.removeEventListener("mousedown", onPointer);
7819
8164
  }, [open]);
7820
- const pick = (chip3, role) => {
8165
+ const pick = (chip5, role) => {
7821
8166
  setOpen(null);
7822
- if (chip3.start === void 0) return;
7823
- onChange((0, import_generation3.setMentionRoleInText)(content, chip3.start, role));
8167
+ if (chip5.start === void 0) return;
8168
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip5.start, role));
7824
8169
  };
7825
8170
  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");
8171
+ 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) => {
8172
+ const error = chip5.issues.find((issue) => issue.severity === "error");
8173
+ const warning = chip5.issues.find((issue) => issue.severity === "warning");
7829
8174
  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)(
8175
+ const isOpen = open === chip5.index;
8176
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip5.asset.id, children: [
8177
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7833
8178
  "button",
7834
8179
  {
7835
8180
  type: "button",
@@ -7837,82 +8182,82 @@ var AssetMentionChips = ({
7837
8182
  "aria-expanded": isOpen,
7838
8183
  title: problem?.message,
7839
8184
  "data-issue": problem?.code,
7840
- onClick: () => setOpen(isOpen ? null : chip3.index),
8185
+ onClick: () => setOpen(isOpen ? null : chip5.index),
7841
8186
  onKeyDown: (e) => {
7842
8187
  if (e.key === "Escape") setOpen(null);
7843
8188
  },
7844
8189
  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
8190
  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)(
8191
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: renderAsset ? renderAsset(chip5) : `@${chip5.asset.label ?? chip5.handle}` }),
8192
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7848
8193
  "span",
7849
8194
  {
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"
8195
+ className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip5.role ? "bg-primary/15" : "opacity-60"}`,
8196
+ "data-role-badge": chip5.role ?? "",
8197
+ children: chip5.roleLabel ?? "No role"
7853
8198
  }
7854
8199
  )
7855
8200
  ]
7856
8201
  }
7857
8202
  ),
7858
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8203
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7859
8204
  "div",
7860
8205
  {
7861
8206
  role: "listbox",
7862
- "aria-label": `Role for ${chip3.asset.label ?? chip3.handle}`,
8207
+ "aria-label": `Role for ${chip5.asset.label ?? chip5.handle}`,
7863
8208
  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
8209
  "data-role-picker": "",
7865
8210
  onKeyDown: (e) => {
7866
8211
  if (e.key === "Escape") setOpen(null);
7867
8212
  },
7868
8213
  children: [
7869
- options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8214
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7870
8215
  "button",
7871
8216
  {
7872
8217
  type: "button",
7873
8218
  role: "option",
7874
- "aria-selected": chip3.role === option.role,
8219
+ "aria-selected": chip5.role === option.role,
7875
8220
  "data-role-option": option.role,
7876
8221
  title: option.description,
7877
- onClick: () => pick(chip3, option.role),
8222
+ onClick: () => pick(chip5, option.role),
7878
8223
  className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
7879
8224
  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
8225
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: option.label }),
8226
+ option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
7882
8227
  ]
7883
8228
  },
7884
8229
  option.role
7885
8230
  )),
7886
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8231
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7887
8232
  "button",
7888
8233
  {
7889
8234
  type: "button",
7890
8235
  role: "option",
7891
- "aria-selected": !chip3.role,
8236
+ "aria-selected": !chip5.role,
7892
8237
  "data-role-option": "",
7893
- onClick: () => pick(chip3, null),
8238
+ onClick: () => pick(chip5, null),
7894
8239
  className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
7895
8240
  children: "No role"
7896
8241
  }
7897
8242
  ),
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)) })
8243
+ 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
8244
  ]
7900
8245
  }
7901
8246
  )
7902
- ] }, `${chip3.start}-${chip3.index}`);
8247
+ ] }, `${chip5.start}-${chip5.index}`);
7903
8248
  }) });
7904
8249
  };
7905
8250
 
7906
8251
  // src/generation/GenerationHistory.tsx
7907
- var import_react55 = require("react");
8252
+ var import_react57 = require("react");
7908
8253
  var import_generation4 = require("@pixerate/editor/generation");
7909
- var import_jsx_runtime37 = require("react/jsx-runtime");
8254
+ var import_jsx_runtime39 = require("react/jsx-runtime");
7910
8255
  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);
8256
+ const [records, setRecords] = (0, import_react57.useState)([]);
8257
+ const [loading, setLoading] = (0, import_react57.useState)(!!store);
8258
+ const [error, setError] = (0, import_react57.useState)(null);
7914
8259
  const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
7915
- const refresh = (0, import_react55.useCallback)(async () => {
8260
+ const refresh = (0, import_react57.useCallback)(async () => {
7916
8261
  if (!store) {
7917
8262
  setRecords([]);
7918
8263
  setLoading(false);
@@ -7929,7 +8274,7 @@ function useGenerationRecords(store, filter) {
7929
8274
  setLoading(false);
7930
8275
  }
7931
8276
  }, [store, filterKey]);
7932
- (0, import_react55.useEffect)(() => {
8277
+ (0, import_react57.useEffect)(() => {
7933
8278
  void refresh();
7934
8279
  if (!store) return;
7935
8280
  return store.subscribe(() => void refresh());
@@ -7955,21 +8300,21 @@ var GenerationHistory = ({
7955
8300
  emptyText = "No generations yet.",
7956
8301
  className = ""
7957
8302
  }) => {
7958
- const [innerMode, setInnerMode] = (0, import_react55.useState)("exact");
8303
+ const [innerMode, setInnerMode] = (0, import_react57.useState)("exact");
7959
8304
  const mode = modeProp ?? innerMode;
7960
8305
  const setMode = (next) => {
7961
8306
  if (modeProp === void 0) setInnerMode(next);
7962
8307
  onModeChange?.(next);
7963
8308
  };
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)(
8309
+ const options = (0, import_react57.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
8310
+ const results = (0, import_react57.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
8311
+ const models = (0, import_react57.useMemo)(
7967
8312
  () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
7968
8313
  [capabilities]
7969
8314
  );
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)(
8315
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
8316
+ /* @__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: [
8317
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7973
8318
  "input",
7974
8319
  {
7975
8320
  type: "radio",
@@ -7982,34 +8327,34 @@ var GenerationHistory = ({
7982
8327
  ),
7983
8328
  value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
7984
8329
  ] }, 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) => {
8330
+ records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
8331
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
7987
8332
  const result = results[i];
7988
8333
  const model = models.find((m) => m.id === record.provenance.modelId);
7989
8334
  const blocked = !result.ok;
7990
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
8335
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
7991
8336
  "li",
7992
8337
  {
7993
8338
  className: "rounded-md border border-border p-2",
7994
8339
  "data-record": record.id,
7995
8340
  "data-drift": result.drift.length,
7996
8341
  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: [
8342
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
8343
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
8344
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-muted-foreground", children: [
8345
+ record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { "data-kind": "", children: [
8001
8346
  record.kind,
8002
8347
  " \xB7 "
8003
8348
  ] }),
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: [
8349
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
8350
+ record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
8006
8351
  " \xB7 seed ",
8007
8352
  record.seed
8008
8353
  ] })
8009
8354
  ] })
8010
8355
  ] }),
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)(
8356
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
8357
+ 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
8358
  "span",
8014
8359
  {
8015
8360
  className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
@@ -8023,16 +8368,16 @@ var GenerationHistory = ({
8023
8368
  `${asset.role}:${asset.id}`
8024
8369
  )) }),
8025
8370
  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: [
8371
+ 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: [
8372
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("strong", { children: [
8028
8373
  import_generation4.DRIFT_TYPE_LABELS[item.type],
8029
8374
  ":"
8030
8375
  ] }),
8031
8376
  " ",
8032
8377
  item.message
8033
8378
  ] }, j)) }),
8034
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-2 flex gap-2", children: [
8035
- onRecreate && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8379
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "mt-2 flex gap-2", children: [
8380
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8036
8381
  "button",
8037
8382
  {
8038
8383
  type: "button",
@@ -8044,7 +8389,7 @@ var GenerationHistory = ({
8044
8389
  children: "Recreate"
8045
8390
  }
8046
8391
  ),
8047
- onVariation && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8392
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8048
8393
  "button",
8049
8394
  {
8050
8395
  type: "button",
@@ -8054,7 +8399,7 @@ var GenerationHistory = ({
8054
8399
  children: "Variation"
8055
8400
  }
8056
8401
  ),
8057
- onRemove && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8402
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8058
8403
  "button",
8059
8404
  {
8060
8405
  type: "button",
@@ -8074,19 +8419,19 @@ var GenerationHistory = ({
8074
8419
  };
8075
8420
 
8076
8421
  // src/find-replace/useFindReplace.ts
8077
- var import_react56 = require("react");
8422
+ var import_react58 = require("react");
8078
8423
  var import_editor16 = require("@pixerate/editor");
8079
8424
  var noopUnsubscribe2 = () => {
8080
8425
  };
8081
8426
  function useFindReplace(editor) {
8082
8427
  const store = (0, import_editor16.getFindReplaceStore)(editor ?? null);
8083
- const subscribe = (0, import_react56.useCallback)(
8428
+ const subscribe = (0, import_react58.useCallback)(
8084
8429
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
8085
8430
  [store]
8086
8431
  );
8087
8432
  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)(() => {
8433
+ const snapshot = (0, import_react58.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8434
+ return (0, import_react58.useMemo)(() => {
8090
8435
  const run = (fn) => {
8091
8436
  if (editor && !editor.isDestroyed && store) fn(editor);
8092
8437
  };
@@ -8110,9 +8455,9 @@ function useFindReplace(editor) {
8110
8455
  }
8111
8456
 
8112
8457
  // src/find-replace/FindReplaceBar.tsx
8113
- var import_react57 = require("react");
8458
+ var import_react59 = require("react");
8114
8459
  var import_editor17 = require("@pixerate/editor");
8115
- var import_jsx_runtime38 = require("react/jsx-runtime");
8460
+ var import_jsx_runtime40 = require("react/jsx-runtime");
8116
8461
  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
8462
  var buttonClass5 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
8118
8463
  var toggleClass = (on) => `${buttonClass5} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
@@ -8125,10 +8470,10 @@ var FindReplaceBar = ({
8125
8470
  onClose
8126
8471
  }) => {
8127
8472
  const find = useFindReplace(editor);
8128
- const findInput = (0, import_react57.useRef)(null);
8129
- const [moreOpen, setMoreOpen] = (0, import_react57.useState)(false);
8473
+ const findInput = (0, import_react59.useRef)(null);
8474
+ const [moreOpen, setMoreOpen] = (0, import_react59.useState)(false);
8130
8475
  const visible = find.available && (alwaysOpen || find.open);
8131
- (0, import_react57.useEffect)(() => {
8476
+ (0, import_react59.useEffect)(() => {
8132
8477
  if (!visible || find.focusRequest === 0) return;
8133
8478
  findInput.current?.focus();
8134
8479
  findInput.current?.select();
@@ -8166,9 +8511,9 @@ var FindReplaceBar = ({
8166
8511
  if (isMod(e)) find.replaceAll();
8167
8512
  else find.replace();
8168
8513
  };
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)(
8514
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
8515
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1", children: [
8516
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8172
8517
  "button",
8173
8518
  {
8174
8519
  type: "button",
@@ -8179,7 +8524,7 @@ var FindReplaceBar = ({
8179
8524
  children: showReplace ? "\u25BE" : "\u25B8"
8180
8525
  }
8181
8526
  ),
8182
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8527
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8183
8528
  "input",
8184
8529
  {
8185
8530
  ref: findInput,
@@ -8193,7 +8538,7 @@ var FindReplaceBar = ({
8193
8538
  onKeyDown: onFindKeyDown
8194
8539
  }
8195
8540
  ),
8196
- import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8541
+ import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8197
8542
  "button",
8198
8543
  {
8199
8544
  type: "button",
@@ -8206,7 +8551,7 @@ var FindReplaceBar = ({
8206
8551
  },
8207
8552
  t.key
8208
8553
  )),
8209
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8554
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8210
8555
  "span",
8211
8556
  {
8212
8557
  className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
@@ -8216,9 +8561,9 @@ var FindReplaceBar = ({
8216
8561
  children: status
8217
8562
  }
8218
8563
  ),
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)(
8564
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
8565
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
8566
+ showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8222
8567
  "button",
8223
8568
  {
8224
8569
  type: "button",
@@ -8229,10 +8574,10 @@ var FindReplaceBar = ({
8229
8574
  children: "\u2026"
8230
8575
  }
8231
8576
  ),
8232
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
8577
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
8233
8578
  ] }),
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)(
8579
+ showReplace && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
8580
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8236
8581
  "input",
8237
8582
  {
8238
8583
  type: "text",
@@ -8244,7 +8589,7 @@ var FindReplaceBar = ({
8244
8589
  onKeyDown: onReplaceKeyDown
8245
8590
  }
8246
8591
  ),
8247
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
8592
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8248
8593
  "button",
8249
8594
  {
8250
8595
  type: "button",
@@ -8254,11 +8599,11 @@ var FindReplaceBar = ({
8254
8599
  children: "Replace"
8255
8600
  }
8256
8601
  ),
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` })
8602
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
8603
+ 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
8604
  ] }),
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)(
8605
+ 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: [
8606
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8262
8607
  "input",
8263
8608
  {
8264
8609
  type: "checkbox",
@@ -8272,12 +8617,12 @@ var FindReplaceBar = ({
8272
8617
  };
8273
8618
 
8274
8619
  // src/tables/useTableMenu.ts
8275
- var import_react58 = require("react");
8620
+ var import_react60 = require("react");
8276
8621
  var import_editor18 = require("@pixerate/editor");
8277
8622
  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)(
8623
+ const store = (0, import_react60.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
8624
+ const snapshot = (0, import_react60.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
8625
+ return (0, import_react60.useMemo)(
8281
8626
  () => ({
8282
8627
  ...snapshot,
8283
8628
  run: (action, params) => (0, import_editor18.runTableAction)(editor, action, params, { focus: true }),
@@ -8288,9 +8633,9 @@ function useTableMenu(editor) {
8288
8633
  }
8289
8634
 
8290
8635
  // src/tables/TableToolbar.tsx
8291
- var import_react59 = __toESM(require("react"), 1);
8636
+ var import_react61 = __toESM(require("react"), 1);
8292
8637
  var import_editor19 = require("@pixerate/editor");
8293
- var import_jsx_runtime39 = require("react/jsx-runtime");
8638
+ var import_jsx_runtime41 = require("react/jsx-runtime");
8294
8639
  var keepSelection2 = (event) => event.preventDefault();
8295
8640
  var TableToolbar = ({
8296
8641
  editor,
@@ -8304,14 +8649,14 @@ var TableToolbar = ({
8304
8649
  }) => {
8305
8650
  const table = useTableMenu(editor);
8306
8651
  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) => {
8652
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
8308
8653
  const status = table.check(item.action, item.params);
8309
8654
  const enabled = status === true;
8310
8655
  const active = item.active?.(table);
8311
8656
  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)(
8657
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react61.default.Fragment, { children: [
8658
+ separator && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
8659
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8315
8660
  "button",
8316
8661
  {
8317
8662
  type: "button",
@@ -8333,8 +8678,8 @@ var TableToolbar = ({
8333
8678
  };
8334
8679
 
8335
8680
  // src/tables/InsertTableGrid.tsx
8336
- var import_react60 = require("react");
8337
- var import_jsx_runtime40 = require("react/jsx-runtime");
8681
+ var import_react62 = require("react");
8682
+ var import_jsx_runtime42 = require("react/jsx-runtime");
8338
8683
  var keepSelection3 = (event) => event.preventDefault();
8339
8684
  var InsertTableGrid = ({
8340
8685
  editor,
@@ -8347,14 +8692,14 @@ var InsertTableGrid = ({
8347
8692
  onInsert
8348
8693
  }) => {
8349
8694
  const table = useTableMenu(editor);
8350
- const [hover, setHover] = (0, import_react60.useState)(null);
8695
+ const [hover, setHover] = (0, import_react62.useState)(null);
8351
8696
  const status = table.actions.insertTable;
8352
8697
  const disabled = !editor || !status.enabled;
8353
8698
  const insert = (size) => {
8354
8699
  if (table.run("insertTable", { ...size, withHeaderRow })) onInsert?.(size);
8355
8700
  setHover(null);
8356
8701
  };
8357
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8702
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
8358
8703
  "div",
8359
8704
  {
8360
8705
  className,
@@ -8364,7 +8709,7 @@ var InsertTableGrid = ({
8364
8709
  "data-insert-table-grid": "",
8365
8710
  onMouseLeave: () => setHover(null),
8366
8711
  children: [
8367
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8712
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8368
8713
  "div",
8369
8714
  {
8370
8715
  role: "grid",
@@ -8373,7 +8718,7 @@ var InsertTableGrid = ({
8373
8718
  children: Array.from({ length: rows * cols }, (_, i) => {
8374
8719
  const size = { rows: Math.floor(i / cols) + 1, cols: i % cols + 1 };
8375
8720
  const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols;
8376
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8721
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8377
8722
  "button",
8378
8723
  {
8379
8724
  type: "button",
@@ -8393,7 +8738,7 @@ var InsertTableGrid = ({
8393
8738
  })
8394
8739
  }
8395
8740
  ),
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" })
8741
+ /* @__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
8742
  ]
8398
8743
  }
8399
8744
  );
@@ -8401,31 +8746,31 @@ var InsertTableGrid = ({
8401
8746
 
8402
8747
  // src/tables/TableBubbleMenu.tsx
8403
8748
  var import_editor20 = require("@pixerate/editor");
8404
- var import_jsx_runtime41 = require("react/jsx-runtime");
8749
+ var import_jsx_runtime43 = require("react/jsx-runtime");
8405
8750
  var TableBubbleMenu = ({
8406
8751
  editor,
8407
8752
  children,
8408
8753
  toolbarProps,
8409
8754
  pluginKey = "tableBubbleMenu",
8410
8755
  ...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 }) });
8756
+ }) => /* @__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
8757
 
8413
8758
  // src/chart-node/ChartNodeView.tsx
8414
8759
  var import_client = require("react-dom/client");
8415
8760
 
8416
8761
  // src/chart/ChartCanvas.tsx
8417
- var import_react62 = require("react");
8762
+ var import_react64 = require("react");
8418
8763
  var import_chart2 = require("@pixerate/editor/chart");
8419
8764
 
8420
8765
  // src/chart/useChartEditor.ts
8421
- var import_react61 = require("react");
8766
+ var import_react63 = require("react");
8422
8767
  var import_chart = require("@pixerate/editor/chart");
8423
8768
  function useChartState(controller) {
8424
- return (0, import_react61.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8769
+ return (0, import_react63.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8425
8770
  }
8426
8771
 
8427
8772
  // src/chart/ChartCanvas.tsx
8428
- var import_jsx_runtime42 = require("react/jsx-runtime");
8773
+ var import_jsx_runtime44 = require("react/jsx-runtime");
8429
8774
  function renderChartMark(mark, fontFamily, interactive) {
8430
8775
  const common = {
8431
8776
  "data-role": mark.role,
@@ -8437,9 +8782,9 @@ function renderChartMark(mark, fontFamily, interactive) {
8437
8782
  };
8438
8783
  switch (mark.kind) {
8439
8784
  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);
8785
+ 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
8786
  case "path":
8442
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8787
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8443
8788
  "path",
8444
8789
  {
8445
8790
  ...common,
@@ -8452,11 +8797,11 @@ function renderChartMark(mark, fontFamily, interactive) {
8452
8797
  mark.key
8453
8798
  );
8454
8799
  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);
8800
+ 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
8801
  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);
8802
+ 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
8803
  case "text":
8459
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8804
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8460
8805
  "text",
8461
8806
  {
8462
8807
  ...common,
@@ -8473,23 +8818,23 @@ function renderChartMark(mark, fontFamily, interactive) {
8473
8818
  }
8474
8819
  }
8475
8820
  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 })
8821
+ const { actors } = (0, import_react64.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
8822
+ 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: [
8823
+ /* @__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 }),
8824
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("g", { transform: "translate(13 16)", children: [
8825
+ /* @__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 } }),
8826
+ /* @__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
8827
  ] })
8483
8828
  ] }, a.id)) });
8484
8829
  }
8485
8830
  function ChartCanvas({ controller, width = 640, height = 400, responsive = true, theme, editable = true, measureText, emptyMessage, className, presence, sceneRef }) {
8486
8831
  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)(() => {
8832
+ const wrapper = (0, import_react64.useRef)(null);
8833
+ const svg = (0, import_react64.useRef)(null);
8834
+ const drag = (0, import_react64.useRef)(null);
8835
+ const [measured, setMeasured] = (0, import_react64.useState)(null);
8836
+ const [frozen, setFrozen] = (0, import_react64.useState)(null);
8837
+ (0, import_react64.useEffect)(() => {
8493
8838
  const el = wrapper.current;
8494
8839
  if (!responsive || !el || typeof ResizeObserver === "undefined") return;
8495
8840
  const observer = new ResizeObserver(([entry]) => {
@@ -8500,8 +8845,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8500
8845
  return () => observer.disconnect();
8501
8846
  }, [responsive]);
8502
8847
  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)(
8848
+ const fullTheme = (0, import_react64.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
8849
+ const scene = (0, import_react64.useMemo)(
8505
8850
  () => (0, import_chart2.layoutChart)(state.spec, {
8506
8851
  width: sceneWidth,
8507
8852
  height,
@@ -8517,8 +8862,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8517
8862
  [state.spec, state.selection, sceneWidth, height, fullTheme, editable, measureText, emptyMessage, frozen]
8518
8863
  );
8519
8864
  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(), []);
8865
+ const byKey = (0, import_react64.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
8866
+ (0, import_react64.useEffect)(() => () => drag.current?.end(), []);
8522
8867
  const scenePoint = (e) => (0, import_chart2.chartClientToScene)(scene, svg.current.getBoundingClientRect(), e.clientX, e.clientY);
8523
8868
  const onPointerDown = (e) => {
8524
8869
  if (!editable || e.button !== 0) return;
@@ -8551,7 +8896,7 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8551
8896
  if (editable && (0, import_chart2.handleChartKey)(controller, scene, e)) e.preventDefault();
8552
8897
  };
8553
8898
  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)(
8899
+ 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
8900
  "svg",
8556
8901
  {
8557
8902
  ref: svg,
@@ -8569,14 +8914,14 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8569
8914
  onKeyDown,
8570
8915
  children: [
8571
8916
  scene.marks.map((m) => renderChartMark(m, scene.theme.fontFamily, editable)),
8572
- presence && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartPresenceLayer, { presence })
8917
+ presence && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartPresenceLayer, { presence })
8573
8918
  ]
8574
8919
  }
8575
8920
  ) });
8576
8921
  }
8577
8922
 
8578
8923
  // src/chart/ChartDataGrid.tsx
8579
- var import_react63 = require("react");
8924
+ var import_react65 = require("react");
8580
8925
  var import_chart3 = require("@pixerate/editor/chart");
8581
8926
 
8582
8927
  // src/chart/styles.ts
@@ -8589,11 +8934,11 @@ var chartSectionClass = "space-y-2 border-b border-border pb-3 last:border-b-0";
8589
8934
  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
8935
 
8591
8936
  // src/chart/ChartDataGrid.tsx
8592
- var import_jsx_runtime43 = require("react/jsx-runtime");
8937
+ var import_jsx_runtime45 = require("react/jsx-runtime");
8593
8938
  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)(() => {
8939
+ const [draft, setDraft] = (0, import_react65.useState)(value);
8940
+ const typing = (0, import_react65.useRef)(false);
8941
+ (0, import_react65.useEffect)(() => {
8597
8942
  if (!typing.current) setDraft(value);
8598
8943
  }, [value]);
8599
8944
  const commit = () => {
@@ -8602,7 +8947,7 @@ function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
8602
8947
  if (draft === value) return;
8603
8948
  if (onCommit(draft) === false) setDraft(value);
8604
8949
  };
8605
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8950
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8606
8951
  "input",
8607
8952
  {
8608
8953
  ...rest,
@@ -8637,15 +8982,15 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8637
8982
  e.preventDefault();
8638
8983
  controller.pasteCells(row, column, text);
8639
8984
  };
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 }),
8985
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
8986
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
8987
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { children: [
8988
+ /* @__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
8989
  spec.series.map((s, si) => {
8645
8990
  const color = (0, import_chart3.chartSeriesColor)(spec, si);
8646
8991
  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)(
8992
+ 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: [
8993
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8649
8994
  "input",
8650
8995
  {
8651
8996
  type: "color",
@@ -8658,7 +9003,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8658
9003
  className: "h-5 w-5 shrink-0 cursor-pointer rounded border-0 bg-transparent p-0"
8659
9004
  }
8660
9005
  ),
8661
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9006
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8662
9007
  ChartCommitInput,
8663
9008
  {
8664
9009
  value: s.name,
@@ -8668,8 +9013,8 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8668
9013
  className: `${chartInputClass} h-6 min-w-[5rem] border-transparent bg-transparent font-medium ${s.hidden ? "text-muted-foreground line-through" : ""}`
8669
9014
  }
8670
9015
  ),
8671
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8672
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9016
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
9017
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8673
9018
  "button",
8674
9019
  {
8675
9020
  type: "button",
@@ -8682,16 +9027,16 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8682
9027
  children: s.hidden ? "\u25CB" : "\u25CF"
8683
9028
  }
8684
9029
  ),
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" })
9030
+ /* @__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
9031
  ] })
8687
9032
  ] }) }, s.id);
8688
9033
  }),
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: "+" }) })
9034
+ !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
9035
  ] }) }),
8691
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("tbody", { children: spec.categories.map((category, i) => {
9036
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("tbody", { children: spec.categories.map((category, i) => {
8692
9037
  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)(
9038
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
9039
+ /* @__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
9040
  ChartCommitInput,
8696
9041
  {
8697
9042
  value: category,
@@ -8705,7 +9050,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8705
9050
  spec.series.map((s) => {
8706
9051
  const value = s.values[i];
8707
9052
  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)(
9053
+ 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
9054
  ChartCommitInput,
8710
9055
  {
8711
9056
  value: value === null || value === void 0 ? "" : String(value),
@@ -8720,38 +9065,38 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8720
9065
  }
8721
9066
  ) }, s.id);
8722
9067
  }),
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" }) })
9068
+ !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
9069
  ] }, i);
8725
9070
  }) })
8726
9071
  ] }),
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" }) })
9072
+ !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
9073
  ] });
8729
9074
  }
8730
9075
 
8731
9076
  // src/chart/ChartInspector.tsx
8732
- var import_react64 = require("react");
9077
+ var import_react66 = require("react");
8733
9078
  var import_chart4 = require("@pixerate/editor/chart");
8734
- var import_jsx_runtime44 = require("react/jsx-runtime");
9079
+ var import_jsx_runtime46 = require("react/jsx-runtime");
8735
9080
  var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
8736
9081
  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 })
9082
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
9083
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
9084
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "min-w-0 flex-1", children })
8740
9085
  ] });
8741
9086
  }
8742
9087
  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) }),
9088
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
9089
+ /* @__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
9090
  label
8746
9091
  ] });
8747
9092
  }
8748
9093
  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)) });
9094
+ 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
9095
  }
8751
9096
  function AxisSection({ controller, axis, value, idBase, horizontal, numeric = false, scales = false }) {
8752
9097
  const set = (patch) => controller.setAxis(axis, patch);
8753
9098
  const setFormat = (patch) => set({ format: { ...value.format, ...patch } });
8754
- const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9099
+ const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8755
9100
  ChartCommitInput,
8756
9101
  {
8757
9102
  id: `${idBase}-${axis}-${key2}`,
@@ -8766,26 +9111,26 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8766
9111
  const name = axis === "x" ? numeric ? "X axis" : "Category axis" : axis === "y" ? "Value axis" : "Secondary axis";
8767
9112
  const valueAxis = axis !== "x" || numeric;
8768
9113
  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: [
9114
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
9115
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center justify-between", children: [
9116
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
8772
9117
  name,
8773
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
9118
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8774
9119
  "(",
8775
9120
  axis === "x" ? horizontal ? "left" : "bottom" : axis === "y2" ? horizontal ? "top" : "right" : horizontal ? "bottom" : "left",
8776
9121
  ")"
8777
9122
  ] })
8778
9123
  ] }),
8779
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
9124
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8780
9125
  ] }),
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" }) })
9126
+ /* @__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 }) }) }),
9127
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
9128
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
9129
+ 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 }) }),
9130
+ scales && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
9131
+ 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
9132
  ] }),
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)(
9133
+ 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
9134
  ChartCommitInput,
8790
9135
  {
8791
9136
  id: `${idBase}-${axis}-log-base`,
@@ -8796,7 +9141,7 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8796
9141
  onCommit: (text) => set({ logBase: text.trim() === "" ? void 0 : Number(text) }).ok
8797
9142
  }
8798
9143
  ) }),
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)(
9144
+ 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
9145
  ChartCommitInput,
8801
9146
  {
8802
9147
  id: `${idBase}-${axis}-step`,
@@ -8808,14 +9153,14 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8808
9153
  onCommit: (text) => set({ step: text.trim() === "" ? null : Number(text) }).ok
8809
9154
  }
8810
9155
  ) }),
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: [
9156
+ valueAxis && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9157
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex gap-1", children: [
8813
9158
  bound("min"),
8814
9159
  bound("max")
8815
9160
  ] }) }),
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)(
9161
+ /* @__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: [
9162
+ /* @__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 }) }),
9163
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8819
9164
  ChartCommitInput,
8820
9165
  {
8821
9166
  value: value.format.decimals === void 0 ? "" : String(value.format.decimals),
@@ -8834,8 +9179,8 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8834
9179
  }
8835
9180
  )
8836
9181
  ] }) }),
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)(
9182
+ 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() }) }) }),
9183
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8839
9184
  ChartCommitInput,
8840
9185
  {
8841
9186
  id: `${idBase}-${axis}-code`,
@@ -8861,15 +9206,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8861
9206
  const values = which === "xErrorBars" ? series.x ?? [] : series.values;
8862
9207
  const set = (next) => controller.updateSeries(series.id, { [which]: next });
8863
9208
  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))
9209
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
9210
+ /* @__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: [
9211
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "None" }),
9212
+ 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
9213
  ] }) }),
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)(
9214
+ 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 }) }),
9215
+ bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9216
+ /* @__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 }) }),
9217
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8873
9218
  ChartCommitInput,
8874
9219
  {
8875
9220
  id: `${id}-minus`,
@@ -8886,15 +9231,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8886
9231
  }
8887
9232
  ) })
8888
9233
  ] }),
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 }) })
9234
+ bars && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
9235
+ /* @__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)) }),
9236
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
8892
9237
  ] })
8893
9238
  ] });
8894
9239
  }
8895
9240
  function ChartInspector({ controller, sections, className }) {
8896
9241
  const { spec, selectedSeries } = useChartState(controller);
8897
- const idBase = (0, import_react64.useId)();
9242
+ const idBase = (0, import_react66.useId)();
8898
9243
  const show = (section) => !sections || sections.includes(section);
8899
9244
  const cartesian = (0, import_chart4.isCartesianChart)(spec.type);
8900
9245
  const family = (0, import_chart4.chartFamily)(spec);
@@ -8906,29 +9251,29 @@ function ChartInspector({ controller, sections, className }) {
8906
9251
  const hasLines = cartesian && types.some((t) => t === "line" || t === "area");
8907
9252
  const seriesIndex = selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1;
8908
9253
  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))
9254
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
9255
+ 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)) }) }),
9256
+ show("style") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
9257
+ /* @__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: [
9258
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Quick layout\u2026" }),
9259
+ 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
9260
  ] }) }),
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))
9261
+ /* @__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: [
9262
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Custom" }),
9263
+ 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
9264
  ] }) }),
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" })
9265
+ !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] }),
9266
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
8922
9267
  ] }),
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) }) })
9268
+ show("titles") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
9269
+ /* @__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) }) }),
9270
+ /* @__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
9271
  ] }),
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)(
9272
+ show("options") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
9273
+ 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 }) }) }),
9274
+ 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)) }) }),
9275
+ 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 }) }) }),
9276
+ spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8932
9277
  "input",
8933
9278
  {
8934
9279
  id: `${idBase}-hole`,
@@ -8944,7 +9289,7 @@ function ChartInspector({ controller, sections, className }) {
8944
9289
  onChange: (e) => controller.update({ innerRadius: Number(e.currentTarget.value) })
8945
9290
  }
8946
9291
  ) }),
8947
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9292
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8948
9293
  "input",
8949
9294
  {
8950
9295
  id: `${idBase}-gap`,
@@ -8960,31 +9305,31 @@ function ChartInspector({ controller, sections, className }) {
8960
9305
  onChange: (e) => controller.update({ gapWidth: Number(e.currentTarget.value) })
8961
9306
  }
8962
9307
  ) }),
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 }) })
9308
+ 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 }) }) }),
9309
+ 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 }) }),
9310
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
9311
+ spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
9312
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
9313
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
8969
9314
  ] })
8970
9315
  ] }),
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 }) })
9316
+ show("legend") && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
9317
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center justify-between", children: [
9318
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
9319
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
8975
9320
  ] }),
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)) })
9321
+ 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
9322
  ] }),
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 })
9323
+ show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9324
+ 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 }),
9325
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
9326
+ usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
8982
9327
  ] }),
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)(
9328
+ show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
9329
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
9330
+ /* @__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 }) }) }),
9331
+ /* @__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: [
9332
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
8988
9333
  "input",
8989
9334
  {
8990
9335
  id: `${idBase}-series-color`,
@@ -8997,9 +9342,9 @@ function ChartInspector({ controller, sections, className }) {
8997
9342
  onChange: (e) => controller.updateSeries(selectedSeries.id, { color: e.currentTarget.value })
8998
9343
  }
8999
9344
  ),
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" })
9345
+ 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
9346
  ] }) }),
9002
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9347
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9003
9348
  "select",
9004
9349
  {
9005
9350
  id: `${idBase}-series-type`,
@@ -9008,12 +9353,12 @@ function ChartInspector({ controller, sections, className }) {
9008
9353
  "data-option": "series.type",
9009
9354
  onChange: (e) => controller.updateSeries(selectedSeries.id, { type: e.currentTarget.value || null }),
9010
9355
  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))
9356
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Chart type" }),
9357
+ 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
9358
  ]
9014
9359
  }
9015
9360
  ) }),
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)(
9361
+ (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
9362
  "select",
9018
9363
  {
9019
9364
  id: `${idBase}-series-marker`,
@@ -9022,20 +9367,20 @@ function ChartInspector({ controller, sections, className }) {
9022
9367
  "data-option": "series.marker",
9023
9368
  onChange: (e) => controller.updateSeries(selectedSeries.id, { marker: e.currentTarget.value || null }),
9024
9369
  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))
9370
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Default" }),
9371
+ import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: m, children: cap(m) }, m))
9027
9372
  ]
9028
9373
  }
9029
9374
  ) }),
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" })
9375
+ scales && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
9376
+ family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
9377
+ (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
9378
+ (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
9379
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
9380
+ /* @__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 }) }),
9381
+ /* @__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
9382
  ] }, i)),
9038
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9383
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9039
9384
  "select",
9040
9385
  {
9041
9386
  className: chartInputClass,
@@ -9044,32 +9389,32 @@ function ChartInspector({ controller, sections, className }) {
9044
9389
  "data-option": "trendline.add",
9045
9390
  onChange: (e) => e.currentTarget.value && controller.addTrendline(selectedSeries.id, { type: e.currentTarget.value }),
9046
9391
  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))
9392
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: "", children: "Add trendline\u2026" }),
9393
+ import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
9049
9394
  ]
9050
9395
  }
9051
9396
  )
9052
9397
  ] }),
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" })
9398
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
9399
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
9400
+ 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 }) }),
9401
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1" }),
9402
+ /* @__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" }),
9403
+ /* @__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" }),
9404
+ /* @__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
9405
  ] })
9061
9406
  ] })
9062
9407
  ] });
9063
9408
  }
9064
9409
 
9065
9410
  // src/chart-node/ChartNodeView.tsx
9066
- var import_jsx_runtime45 = require("react/jsx-runtime");
9411
+ var import_jsx_runtime47 = require("react/jsx-runtime");
9067
9412
  function ChartNodeView({ state, theme, showDataGrid = true }) {
9068
9413
  const { controller, editing, editable, selected, width, height, setEditing } = state;
9069
9414
  const open = () => {
9070
9415
  if (editable && !editing) setEditing(true);
9071
9416
  };
9072
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
9417
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9073
9418
  "div",
9074
9419
  {
9075
9420
  className: `not-prose my-2 rounded-md border bg-background p-1 ${selected ? "border-primary ring-1 ring-primary" : "border-border"}`,
@@ -9082,24 +9427,24 @@ function ChartNodeView({ state, theme, showDataGrid = true }) {
9082
9427
  }
9083
9428
  },
9084
9429
  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" })
9430
+ 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: [
9431
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
9432
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
9088
9433
  ] }),
9089
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
9434
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
9090
9435
  "div",
9091
9436
  {
9092
9437
  className: editable && !editing ? "cursor-pointer" : void 0,
9093
9438
  onClick: open,
9094
9439
  title: editable && !editing ? "Click to edit the chart" : void 0,
9095
9440
  "data-chart-node-canvas": "",
9096
- children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
9441
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
9097
9442
  }
9098
9443
  ),
9099
9444
  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" })
9445
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
9446
+ 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 }) }),
9447
+ /* @__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
9448
  ] })
9104
9449
  ]
9105
9450
  }
@@ -9117,7 +9462,7 @@ function createReactChartNodeView(options = {}) {
9117
9462
  scheduled = true;
9118
9463
  queueMicrotask(() => {
9119
9464
  scheduled = false;
9120
- if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Component, { ...props, state: latest }));
9465
+ if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Component, { ...props, state: latest }));
9121
9466
  });
9122
9467
  };
9123
9468
  schedule();
@@ -9168,6 +9513,7 @@ function createReactChartNodeView(options = {}) {
9168
9513
  RefineEdgePanel,
9169
9514
  ReviewToolbar,
9170
9515
  SelectionOptionsBar,
9516
+ ShapeOptionsBar,
9171
9517
  SheetTabs,
9172
9518
  SpreadsheetConditionalFormatPanel,
9173
9519
  SpreadsheetContextMenu,
@@ -9180,6 +9526,7 @@ function createReactChartNodeView(options = {}) {
9180
9526
  TableToolbar,
9181
9527
  TemplateRenderer,
9182
9528
  TrackedChangesList,
9529
+ TypeOptionsBar,
9183
9530
  VariableForm,
9184
9531
  bindDirtyToHistory,
9185
9532
  createDirtyTracker,