@pixerate/editor-react 0.64.0 → 0.66.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
@@ -46,6 +46,7 @@ __export(src_exports, {
46
46
  ExportDocxButton: () => ExportDocxButton,
47
47
  FindReplaceBar: () => FindReplaceBar,
48
48
  FormulaHints: () => FormulaHints,
49
+ FreeTransformOptionsBar: () => FreeTransformOptionsBar,
49
50
  GenerationHistory: () => GenerationHistory,
50
51
  GenerationSettings: () => GenerationSettings,
51
52
  Histogram: () => Histogram,
@@ -3784,8 +3785,8 @@ function useImageEditor(options = {}) {
3784
3785
  }
3785
3786
 
3786
3787
  // src/image-editor/ImageEditor.tsx
3787
- var import_react43 = __toESM(require("react"), 1);
3788
- var import_image_editor11 = require("@pixerate/editor/image-editor");
3788
+ var import_react44 = __toESM(require("react"), 1);
3789
+ var import_image_editor12 = require("@pixerate/editor/image-editor");
3789
3790
 
3790
3791
  // src/image-editor/ControlSlider.tsx
3791
3792
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -4704,6 +4705,22 @@ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "
4704
4705
  children: (0, import_image_editor7.layerBadge)(layer)
4705
4706
  }
4706
4707
  ),
4708
+ layer.mask && !layer.mask.source && layer.type === "pixel" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4709
+ "button",
4710
+ {
4711
+ type: "button",
4712
+ "aria-label": `${layer.mask.linked === false ? "Link" : "Unlink"} ${row.label} mask`,
4713
+ "aria-pressed": layer.mask.linked !== false,
4714
+ title: layer.mask.linked === false ? "Mask unlinked: it stays put when the layer moves or transforms. Click to link." : "Mask linked: it moves with the layer. Click to unlink.",
4715
+ "data-testid": "layer-mask-link",
4716
+ className: `shrink-0 text-[10px] leading-none ${layer.mask.linked === false ? "text-slate-600" : "text-slate-300"}`,
4717
+ onClick: (e) => {
4718
+ e.stopPropagation();
4719
+ attempt(() => controller.setLayerMaskProps(layer.id, { linked: layer.mask.linked === false }));
4720
+ },
4721
+ children: layer.mask.linked === false ? "\u26D3\uFE0E\u0338" : "\u26D3\uFE0E"
4722
+ }
4723
+ ),
4707
4724
  layer.mask && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4708
4725
  Thumbnail,
4709
4726
  {
@@ -5215,8 +5232,147 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
5215
5232
  ] });
5216
5233
  };
5217
5234
 
5218
- // src/image-editor/ImageEditor.tsx
5235
+ // src/image-editor/FreeTransformOptionsBar.tsx
5236
+ var import_react43 = require("react");
5237
+ var import_image_editor11 = require("@pixerate/editor/image-editor");
5219
5238
  var import_jsx_runtime26 = require("react/jsx-runtime");
5239
+ var chip2 = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
5240
+ var round = (v, unit) => unit === "px" ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100;
5241
+ var FreeTransformOptionsBar = ({ tool, className }) => {
5242
+ const [, setTick] = (0, import_react43.useState)(0);
5243
+ (0, import_react43.useEffect)(() => tool.subscribe(() => setTick((n) => n + 1)), [tool]);
5244
+ const bar = tool.bar();
5245
+ if (!tool.active || !bar) return null;
5246
+ const warp = tool.warpBar();
5247
+ const warpNumber = (key, raw) => {
5248
+ const v = Number(raw);
5249
+ if (raw.trim() !== "" && Number.isFinite(v) && v !== warp[key]) tool.setWarp({ [key]: Math.max(-100, Math.min(100, v)) });
5250
+ };
5251
+ const apply = (field, raw) => {
5252
+ const v = Number(raw);
5253
+ if (raw.trim() !== "" && Number.isFinite(v) && Math.abs(v - bar[field]) > 1e-9) tool.setField(field, v);
5254
+ };
5255
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: `flex flex-wrap items-center gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "free-transform-options", role: "toolbar", "aria-label": "Free Transform options", children: [
5256
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Transform mode", children: import_image_editor11.FREE_TRANSFORM_MODE_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", title: m.title, "aria-pressed": tool.mode === m.id, className: chip2(tool.mode === m.id), onClick: () => tool.setMode(m.id), children: m.label }, m.id)) }),
5257
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "grid grid-cols-3 gap-px", role: "group", "aria-label": "Reference point", children: import_image_editor11.TRANSFORM_ANCHORS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", "aria-label": `Reference point ${a}`, title: `Reference point: ${a}`, className: "h-2.5 w-2.5 rounded-sm bg-slate-700 hover:bg-indigo-500", onClick: () => tool.setReference(a) }, a)) }),
5258
+ tool.mode === "warp" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": "Warp options", children: [
5259
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-1", children: [
5260
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-400", children: "Warp" }),
5261
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("select", { "aria-label": "Warp style", value: warp.style, onChange: (e) => tool.setWarp({ style: e.target.value }), className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5", children: import_image_editor11.WARP_STYLE_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: o.id, children: o.label }, o.id)) })
5262
+ ] }),
5263
+ ["bend", "horizontal", "vertical"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-1", children: [
5264
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-400", children: k === "bend" ? "Bend" : k === "horizontal" ? "H" : "V" }),
5265
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5266
+ "input",
5267
+ {
5268
+ type: "number",
5269
+ "aria-label": k === "bend" ? "Warp bend in percent" : `Warp ${k} distortion in percent`,
5270
+ defaultValue: warp[k],
5271
+ min: -100,
5272
+ max: 100,
5273
+ disabled: warp.style === "custom",
5274
+ className: "w-14 rounded border border-slate-700 bg-slate-900 px-1 py-0.5 text-right disabled:opacity-40",
5275
+ onBlur: (e) => warpNumber(k, e.currentTarget.value),
5276
+ onKeyDown: (e) => {
5277
+ if (e.key === "Enter") {
5278
+ e.preventDefault();
5279
+ e.stopPropagation();
5280
+ warpNumber(k, e.currentTarget.value);
5281
+ }
5282
+ }
5283
+ },
5284
+ `${k}:${warp[k]}`
5285
+ ),
5286
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-500", children: "%" })
5287
+ ] }, k)),
5288
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5289
+ "button",
5290
+ {
5291
+ type: "button",
5292
+ title: "Bend along the vertical axis",
5293
+ "aria-pressed": warp.orientation === "vertical",
5294
+ disabled: warp.style === "custom",
5295
+ className: chip2(warp.orientation === "vertical"),
5296
+ onClick: () => tool.setWarp({ orientation: warp.orientation === "vertical" ? "horizontal" : "vertical" }),
5297
+ children: "Vertical"
5298
+ }
5299
+ ),
5300
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-1", children: [
5301
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-400", children: "Grid" }),
5302
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5303
+ "select",
5304
+ {
5305
+ "aria-label": "Warp grid",
5306
+ value: import_image_editor11.WARP_GRID_OPTIONS.find((g) => g.columns === warp.columns && g.rows === warp.rows)?.id ?? "1x1",
5307
+ onChange: (e) => {
5308
+ const g = import_image_editor11.WARP_GRID_OPTIONS.find((o) => o.id === e.target.value);
5309
+ tool.setWarp({ columns: g.columns, rows: g.rows });
5310
+ },
5311
+ className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
5312
+ children: import_image_editor11.WARP_GRID_OPTIONS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: g.id, children: g.label }, g.id))
5313
+ }
5314
+ )
5315
+ ] })
5316
+ ] }),
5317
+ tool.mode !== "warp" && import_image_editor11.FREE_TRANSFORM_FIELDS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-1", title: f.title, children: [
5318
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-400", children: f.label }),
5319
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5320
+ "input",
5321
+ {
5322
+ type: "number",
5323
+ "aria-label": f.title,
5324
+ defaultValue: round(bar[f.id], f.unit),
5325
+ disabled: !bar.affine,
5326
+ step: f.unit === "px" ? 1 : 0.1,
5327
+ className: "w-16 rounded border border-slate-700 bg-slate-900 px-1 py-0.5 text-right disabled:opacity-40",
5328
+ onBlur: (e) => apply(f.id, e.currentTarget.value),
5329
+ onKeyDown: (e) => {
5330
+ if (e.key === "Enter") {
5331
+ e.preventDefault();
5332
+ e.stopPropagation();
5333
+ apply(f.id, e.currentTarget.value);
5334
+ }
5335
+ }
5336
+ },
5337
+ `${f.id}:${round(bar[f.id], f.unit)}`
5338
+ ),
5339
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-500", children: f.unit }),
5340
+ f.id === "scaleX" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5341
+ "button",
5342
+ {
5343
+ type: "button",
5344
+ "aria-label": "Keep width and height proportional",
5345
+ "aria-pressed": tool.proportional,
5346
+ className: chip2(tool.proportional),
5347
+ onClick: () => {
5348
+ tool.proportional = !tool.proportional;
5349
+ setTick((n) => n + 1);
5350
+ },
5351
+ children: "\u26D3\uFE0E"
5352
+ }
5353
+ )
5354
+ ] }, f.id)),
5355
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-1", children: [
5356
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-400", children: "Interpolation" }),
5357
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5358
+ "select",
5359
+ {
5360
+ "aria-label": "Interpolation",
5361
+ value: tool.interpolation,
5362
+ onChange: (e) => tool.setInterpolation(e.target.value),
5363
+ className: "rounded border border-slate-700 bg-slate-900 px-1 py-0.5",
5364
+ children: import_image_editor11.INTERPOLATIONS.map((i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: i, children: i[0].toUpperCase() + i.slice(1) }, i))
5365
+ }
5366
+ )
5367
+ ] }),
5368
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", title: "Commit (Enter)", className: "px-2 py-1 rounded bg-emerald-600 text-white hover:bg-emerald-500", onClick: () => tool.commit(), children: "Commit" }),
5369
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", title: "Cancel (Esc)", className: chip2(false), onClick: () => tool.cancel(), children: "Cancel" }),
5370
+ tool.error && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { role: "alert", className: "text-rose-400", children: tool.error })
5371
+ ] });
5372
+ };
5373
+
5374
+ // src/image-editor/ImageEditor.tsx
5375
+ var import_jsx_runtime27 = require("react/jsx-runtime");
5220
5376
  var ImageEditor = ({
5221
5377
  editor: externalEditor,
5222
5378
  src,
@@ -5231,35 +5387,47 @@ var ImageEditor = ({
5231
5387
  const internalEditor = useImageEditor({ image: src });
5232
5388
  const editor = externalEditor || internalEditor;
5233
5389
  const { state, controller } = editor;
5234
- const legacyProcess = (0, import_image_editor11.normalizeProcessVersion)(state.adjustments.process) < import_image_editor11.LATEST_PROCESS_VERSION;
5235
- const canvasRef = (0, import_react43.useRef)(null);
5236
- const containerRef = (0, import_react43.useRef)(null);
5237
- const [activeTab, setActiveTab] = (0, import_react43.useState)("crop");
5238
- const [activeCropRatio, setActiveCropRatio] = (0, import_react43.useState)(null);
5239
- const [selectionOptions, setSelectionOptions] = (0, import_react43.useState)(import_image_editor11.DEFAULT_SELECTION_TOOL_OPTIONS);
5240
- const selectionOptionsRef = (0, import_react43.useRef)(selectionOptions);
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);
5241
5397
  selectionOptionsRef.current = selectionOptions;
5242
- const selectionGestureRef = (0, import_react43.useRef)(null);
5398
+ const selectionGestureRef = (0, import_react44.useRef)(null);
5243
5399
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
5244
- selectionGestureRef.current = new import_image_editor11.SelectionGesture(controller, () => selectionOptionsRef.current);
5400
+ selectionGestureRef.current = new import_image_editor12.SelectionGesture(controller, () => selectionOptionsRef.current);
5245
5401
  }
5246
- const selectionDraftRef = (0, import_react43.useRef)(null);
5247
- const [selectionError, setSelectionError] = (0, import_react43.useState)(null);
5248
- const paintGestureRef = (0, import_react43.useRef)(null);
5249
- const paintControllerRef = (0, import_react43.useRef)(controller);
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);
5250
5406
  if (!paintGestureRef.current || paintControllerRef.current !== controller) {
5251
- paintGestureRef.current = new import_image_editor11.PaintGesture(controller);
5407
+ paintGestureRef.current = new import_image_editor12.PaintGesture(controller);
5252
5408
  paintControllerRef.current = controller;
5253
5409
  }
5254
- const brushCursorRef = (0, import_react43.useRef)(null);
5255
- const [paintError, setPaintError] = (0, import_react43.useState)(null);
5256
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react43.useState)("");
5257
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react43.useState)("annotations");
5258
- const [isRemovingBg, setIsRemovingBg] = (0, import_react43.useState)(false);
5259
- const [isInpainting, setIsInpainting] = (0, import_react43.useState)(false);
5260
- const [aiError, setAiError] = (0, import_react43.useState)(null);
5261
- const [aiSuccess, setAiSuccess] = (0, import_react43.useState)(null);
5262
- const [aiTarget, setAiTarget] = (0, import_react43.useState)("auto");
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);
5414
+ if (!transformToolRef.current || transformControllerRef.current !== controller) {
5415
+ transformToolRef.current?.cancel();
5416
+ transformToolRef.current = new import_image_editor12.FreeTransformTool(controller, {
5417
+ schedule: (run) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(run) : run()
5418
+ });
5419
+ transformControllerRef.current = controller;
5420
+ }
5421
+ 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");
5263
5431
  const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
5264
5432
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
5265
5433
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
@@ -5322,18 +5490,18 @@ var ImageEditor = ({
5322
5490
  setIsInpainting(false);
5323
5491
  }
5324
5492
  };
5325
- const [activeColor, setActiveColor] = (0, import_react43.useState)("#ef4444");
5326
- const [strokeWidth, setStrokeWidth] = (0, import_react43.useState)(3);
5327
- const [fontSize, setFontSize] = (0, import_react43.useState)(24);
5328
- const [textInput, setTextInput] = (0, import_react43.useState)("");
5329
- const draftAnnotationRef = (0, import_react43.useRef)(null);
5330
- const draftCropRef = (0, import_react43.useRef)(null);
5331
- const cropDragInfoRef = (0, import_react43.useRef)(null);
5332
- const annotationDragInfoRef = (0, import_react43.useRef)(null);
5333
- const isDrawingRef = (0, import_react43.useRef)(false);
5334
- const currentPathRef = (0, import_react43.useRef)([]);
5335
- const dragStartPointRef = (0, import_react43.useRef)(null);
5336
- const renderCanvas = (0, import_react43.useCallback)(
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)(
5337
5505
  async (draftAnnotation, draftCrop) => {
5338
5506
  const canvas = canvasRef.current;
5339
5507
  const container = containerRef.current;
@@ -5349,12 +5517,64 @@ var ImageEditor = ({
5349
5517
  draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
5350
5518
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
5351
5519
  draftSelectionPath: selectionDraftRef.current,
5352
- brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null
5520
+ brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" && !transformTool.active ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null,
5521
+ freeTransform: transformTool.overlay()
5353
5522
  });
5354
5523
  },
5355
- [controller, activeTab]
5524
+ [controller, activeTab, transformTool]
5356
5525
  );
5357
- (0, import_react43.useEffect)(() => {
5526
+ (0, import_react44.useEffect)(() => transformTool.subscribe(() => {
5527
+ setTransformTick((n) => n + 1);
5528
+ void renderCanvas();
5529
+ }), [transformTool, renderCanvas]);
5530
+ const transformPoint = (e) => {
5531
+ const canvas = canvasRef.current;
5532
+ const rect = canvas.getBoundingClientRect();
5533
+ const sx = rect.width > 0 ? canvas.width / rect.width : 1;
5534
+ const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5535
+ const s = controller.getState();
5536
+ 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);
5539
+ transformTool.setView(projection.scale);
5540
+ return { pt, tolerance: 6 / (projection.scale || 1) };
5541
+ };
5542
+ const handleTransformPointerDown = (e) => {
5543
+ if (!transformTool.active) return false;
5544
+ if (e.button !== 0) return true;
5545
+ e.preventDefault();
5546
+ try {
5547
+ e.currentTarget.setPointerCapture?.(e.pointerId);
5548
+ } catch {
5549
+ }
5550
+ const { pt, tolerance } = transformPoint(e);
5551
+ transformTool.down(pt, tolerance);
5552
+ return true;
5553
+ };
5554
+ const handleTransformPointerMove = (e) => {
5555
+ if (!transformTool.active) return false;
5556
+ const { pt, tolerance } = transformPoint(e);
5557
+ if (e.buttons & 1) transformTool.move(pt, e);
5558
+ else {
5559
+ const over = transformTool.hit(pt, tolerance);
5560
+ setTransformCursor(transformTool.cursor(over));
5561
+ }
5562
+ return true;
5563
+ };
5564
+ const handleTransformPointerUp = () => {
5565
+ if (!transformTool.active) return false;
5566
+ transformTool.up();
5567
+ return true;
5568
+ };
5569
+ (0, import_react44.useEffect)(() => {
5570
+ if (typeof window === "undefined") return;
5571
+ const onKey = (e) => {
5572
+ if (transformTool.key(e)) e.preventDefault();
5573
+ };
5574
+ window.addEventListener("keydown", onKey);
5575
+ return () => window.removeEventListener("keydown", onKey);
5576
+ }, [transformTool]);
5577
+ (0, import_react44.useEffect)(() => {
5358
5578
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
5359
5579
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
5360
5580
  const animId = raf(() => {
@@ -5362,12 +5582,12 @@ var ImageEditor = ({
5362
5582
  });
5363
5583
  return () => caf(animId);
5364
5584
  }, [renderCanvas, state]);
5365
- (0, import_react43.useEffect)(() => {
5585
+ (0, import_react44.useEffect)(() => {
5366
5586
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
5367
5587
  editor.setTool("crop");
5368
5588
  }
5369
5589
  }, [activeTab, editor]);
5370
- (0, import_react43.useEffect)(() => {
5590
+ (0, import_react44.useEffect)(() => {
5371
5591
  const container = containerRef.current;
5372
5592
  if (!container) return;
5373
5593
  if (typeof ResizeObserver !== "undefined") {
@@ -5403,11 +5623,12 @@ var ImageEditor = ({
5403
5623
  const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5404
5624
  const s = controller.getState();
5405
5625
  return list.map((ev) => ({
5406
- ...(0, import_image_editor11.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5407
- pressure: (0, import_image_editor11.pointerPressure)(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)
5408
5628
  }));
5409
5629
  };
5410
5630
  const handlePaintPointerDown = (e) => {
5631
+ if (handleTransformPointerDown(e)) return;
5411
5632
  if (activeTab !== "paint" || e.button !== 0) return;
5412
5633
  e.preventDefault();
5413
5634
  try {
@@ -5418,6 +5639,7 @@ var ImageEditor = ({
5418
5639
  setPaintError(paintGestureRef.current.down(first));
5419
5640
  };
5420
5641
  const handlePaintPointerMove = (e) => {
5642
+ if (handleTransformPointerMove(e)) return;
5421
5643
  if (activeTab !== "paint") return;
5422
5644
  const samples = paintSamples(e);
5423
5645
  brushCursorRef.current = samples[samples.length - 1] ?? null;
@@ -5425,6 +5647,7 @@ var ImageEditor = ({
5425
5647
  else void renderCanvas();
5426
5648
  };
5427
5649
  const handlePaintPointerUp = () => {
5650
+ if (handleTransformPointerUp()) return;
5428
5651
  if (activeTab !== "paint") return;
5429
5652
  const g = paintGestureRef.current;
5430
5653
  if (g.active) {
@@ -5432,21 +5655,21 @@ var ImageEditor = ({
5432
5655
  if (g.error) setPaintError(g.error);
5433
5656
  }
5434
5657
  };
5435
- (0, import_react43.useEffect)(() => {
5658
+ (0, import_react44.useEffect)(() => {
5436
5659
  if (activeTab !== "paint" || typeof window === "undefined") return;
5437
5660
  const onKey = (e) => {
5438
- if ((0, import_image_editor11.handlePaintShortcut)(controller, e)) e.preventDefault();
5661
+ if ((0, import_image_editor12.handlePaintShortcut)(controller, e)) e.preventDefault();
5439
5662
  };
5440
5663
  window.addEventListener("keydown", onKey);
5441
5664
  return () => window.removeEventListener("keydown", onKey);
5442
5665
  }, [activeTab, controller]);
5443
5666
  const handleMouseDown = (e) => {
5444
5667
  const canvas = canvasRef.current;
5445
- if (!canvas) return;
5668
+ if (!canvas || transformTool.active) return;
5446
5669
  const canvasPt = getCanvasEventPoint(e);
5447
5670
  if (activeTab === "select") {
5448
5671
  const gesture = selectionGestureRef.current;
5449
- const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5672
+ const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5450
5673
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
5451
5674
  return;
5452
5675
  }
@@ -5457,8 +5680,8 @@ var ImageEditor = ({
5457
5680
  width: state.imageDimensions.width,
5458
5681
  height: state.imageDimensions.height
5459
5682
  };
5460
- const handle = (0, import_image_editor11.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5461
- const startImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
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);
5462
5685
  if (handle) {
5463
5686
  cropDragInfoRef.current = {
5464
5687
  handle,
@@ -5477,12 +5700,12 @@ var ImageEditor = ({
5477
5700
  return;
5478
5701
  }
5479
5702
  if (activeTab === "annotate") {
5480
- const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5703
+ const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5481
5704
  dragStartPointRef.current = imgPt;
5482
5705
  if (state.activeTool === "select") {
5483
5706
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5484
5707
  const ann = state.annotations[i];
5485
- if ((0, import_image_editor11.hitTestAnnotation)(imgPt, ann)) {
5708
+ if ((0, import_image_editor12.hitTestAnnotation)(imgPt, ann)) {
5486
5709
  editor.selectAnnotation(ann.id);
5487
5710
  annotationDragInfoRef.current = {
5488
5711
  annId: ann.id,
@@ -5514,11 +5737,11 @@ var ImageEditor = ({
5514
5737
  };
5515
5738
  const handleMouseMove = (e) => {
5516
5739
  const canvas = canvasRef.current;
5517
- if (!canvas) return;
5740
+ if (!canvas || transformTool.active) return;
5518
5741
  const canvasPt = getCanvasEventPoint(e);
5519
5742
  if (activeTab === "select") {
5520
5743
  const gesture = selectionGestureRef.current;
5521
- if (gesture.active && gesture.move((0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5744
+ if (gesture.active && gesture.move((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5522
5745
  selectionDraftRef.current = gesture.draftPath;
5523
5746
  renderCanvas();
5524
5747
  }
@@ -5527,7 +5750,7 @@ var ImageEditor = ({
5527
5750
  if (activeTab === "crop") {
5528
5751
  const drag = cropDragInfoRef.current;
5529
5752
  if (drag) {
5530
- const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5753
+ const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5531
5754
  let newCrop;
5532
5755
  if (drag.handle === "new") {
5533
5756
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -5541,7 +5764,7 @@ var ImageEditor = ({
5541
5764
  height: Math.round(Math.max(20, maxY - minY))
5542
5765
  };
5543
5766
  } else {
5544
- newCrop = (0, import_image_editor11.calculateCropDrag)(
5767
+ newCrop = (0, import_image_editor12.calculateCropDrag)(
5545
5768
  drag.startCrop,
5546
5769
  drag.handle,
5547
5770
  drag.startImgPt,
@@ -5561,15 +5784,15 @@ var ImageEditor = ({
5561
5784
  width: state.imageDimensions.width,
5562
5785
  height: state.imageDimensions.height
5563
5786
  };
5564
- const handle = (0, import_image_editor11.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5565
- canvas.style.cursor = (0, import_image_editor11.getCropCursor)(handle, state.transform);
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);
5566
5789
  }
5567
5790
  return;
5568
5791
  }
5569
5792
  if (activeTab === "annotate") {
5570
5793
  if (annotationDragInfoRef.current) {
5571
5794
  const drag = annotationDragInfoRef.current;
5572
- const currentImgPt2 = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5795
+ const currentImgPt2 = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5573
5796
  const dx = currentImgPt2.x - drag.startImgPt.x;
5574
5797
  const dy = currentImgPt2.y - drag.startImgPt.y;
5575
5798
  editor.updateAnnotation(drag.annId, {
@@ -5581,10 +5804,10 @@ var ImageEditor = ({
5581
5804
  const startPt = dragStartPointRef.current;
5582
5805
  if (!startPt) {
5583
5806
  if (state.activeTool === "select") {
5584
- const imgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5807
+ const imgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5585
5808
  let hovered = false;
5586
5809
  for (let i = state.annotations.length - 1; i >= 0; i--) {
5587
- if ((0, import_image_editor11.hitTestAnnotation)(imgPt, state.annotations[i])) {
5810
+ if ((0, import_image_editor12.hitTestAnnotation)(imgPt, state.annotations[i])) {
5588
5811
  hovered = true;
5589
5812
  break;
5590
5813
  }
@@ -5595,7 +5818,7 @@ var ImageEditor = ({
5595
5818
  }
5596
5819
  return;
5597
5820
  }
5598
- const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5821
+ const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5599
5822
  if (state.activeTool === "pen" && isDrawingRef.current) {
5600
5823
  currentPathRef.current.push(currentImgPt);
5601
5824
  const draft = {
@@ -5670,12 +5893,12 @@ var ImageEditor = ({
5670
5893
  };
5671
5894
  const handleMouseUp = (e) => {
5672
5895
  const canvas = canvasRef.current;
5673
- if (!canvas) return;
5896
+ if (!canvas || transformTool.active) return;
5674
5897
  const canvasPt = getCanvasEventPoint(e);
5675
5898
  if (activeTab === "select") {
5676
5899
  const gesture = selectionGestureRef.current;
5677
5900
  if (gesture.active) {
5678
- gesture.end((0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5901
+ gesture.end((0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5679
5902
  selectionDraftRef.current = null;
5680
5903
  renderCanvas();
5681
5904
  }
@@ -5699,7 +5922,7 @@ var ImageEditor = ({
5699
5922
  }
5700
5923
  const startPt = dragStartPointRef.current;
5701
5924
  if (startPt) {
5702
- const currentImgPt = (0, import_image_editor11.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5925
+ const currentImgPt = (0, import_image_editor12.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5703
5926
  if (state.activeTool === "pen" && isDrawingRef.current) {
5704
5927
  if (currentPathRef.current.length > 1) {
5705
5928
  editor.addAnnotation({
@@ -5795,15 +6018,15 @@ var ImageEditor = ({
5795
6018
  link.click();
5796
6019
  }
5797
6020
  };
5798
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6021
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5799
6022
  "div",
5800
6023
  {
5801
6024
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
5802
6025
  style,
5803
6026
  children: [
5804
- /* @__PURE__ */ (0, import_jsx_runtime26.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: [
5805
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
5806
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
5807
6030
  "button",
5808
6031
  {
5809
6032
  type: "button",
@@ -5815,7 +6038,7 @@ var ImageEditor = ({
5815
6038
  children: "Transform & Crop"
5816
6039
  }
5817
6040
  ),
5818
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6041
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5819
6042
  "button",
5820
6043
  {
5821
6044
  type: "button",
@@ -5827,7 +6050,7 @@ var ImageEditor = ({
5827
6050
  children: "Adjustments"
5828
6051
  }
5829
6052
  ),
5830
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6053
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5831
6054
  "button",
5832
6055
  {
5833
6056
  type: "button",
@@ -5839,7 +6062,7 @@ var ImageEditor = ({
5839
6062
  children: "Layers"
5840
6063
  }
5841
6064
  ),
5842
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6065
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5843
6066
  "button",
5844
6067
  {
5845
6068
  type: "button",
@@ -5851,7 +6074,7 @@ var ImageEditor = ({
5851
6074
  children: "Paint"
5852
6075
  }
5853
6076
  ),
5854
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6077
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5855
6078
  "button",
5856
6079
  {
5857
6080
  type: "button",
@@ -5863,7 +6086,7 @@ var ImageEditor = ({
5863
6086
  children: "Select & Mask"
5864
6087
  }
5865
6088
  ),
5866
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6089
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5867
6090
  "button",
5868
6091
  {
5869
6092
  type: "button",
@@ -5875,7 +6098,7 @@ var ImageEditor = ({
5875
6098
  children: "Annotations"
5876
6099
  }
5877
6100
  ),
5878
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6101
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5879
6102
  "button",
5880
6103
  {
5881
6104
  type: "button",
@@ -5887,7 +6110,7 @@ var ImageEditor = ({
5887
6110
  children: "Depth Mask"
5888
6111
  }
5889
6112
  ),
5890
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6113
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5891
6114
  "button",
5892
6115
  {
5893
6116
  type: "button",
@@ -5897,14 +6120,14 @@ var ImageEditor = ({
5897
6120
  },
5898
6121
  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"}`,
5899
6122
  children: [
5900
- /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.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" }) }),
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" }) }),
5901
6124
  "AI Tools"
5902
6125
  ]
5903
6126
  }
5904
6127
  )
5905
6128
  ] }),
5906
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
5907
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6129
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
6130
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5908
6131
  "button",
5909
6132
  {
5910
6133
  type: "button",
@@ -5915,7 +6138,7 @@ var ImageEditor = ({
5915
6138
  children: "\u21A9"
5916
6139
  }
5917
6140
  ),
5918
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6141
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5919
6142
  "button",
5920
6143
  {
5921
6144
  type: "button",
@@ -5926,7 +6149,7 @@ var ImageEditor = ({
5926
6149
  children: "\u21AA"
5927
6150
  }
5928
6151
  ),
5929
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6152
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5930
6153
  "button",
5931
6154
  {
5932
6155
  type: "button",
@@ -5935,8 +6158,8 @@ var ImageEditor = ({
5935
6158
  children: "Reset"
5936
6159
  }
5937
6160
  ),
5938
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5939
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
5940
6163
  "button",
5941
6164
  {
5942
6165
  type: "button",
@@ -5946,11 +6169,11 @@ var ImageEditor = ({
5946
6169
  children: "-"
5947
6170
  }
5948
6171
  ),
5949
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
6172
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
5950
6173
  Math.round(state.zoom * 100),
5951
6174
  "%"
5952
6175
  ] }),
5953
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6176
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5954
6177
  "button",
5955
6178
  {
5956
6179
  type: "button",
@@ -5960,8 +6183,8 @@ var ImageEditor = ({
5960
6183
  children: "+"
5961
6184
  }
5962
6185
  ),
5963
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5964
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
5965
6188
  "button",
5966
6189
  {
5967
6190
  type: "button",
@@ -5972,7 +6195,7 @@ var ImageEditor = ({
5972
6195
  children: "Hold Compare"
5973
6196
  }
5974
6197
  ),
5975
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6198
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5976
6199
  "button",
5977
6200
  {
5978
6201
  type: "button",
@@ -5983,13 +6206,15 @@ var ImageEditor = ({
5983
6206
  )
5984
6207
  ] })
5985
6208
  ] }),
5986
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
5987
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
5988
6213
  "div",
5989
6214
  {
5990
6215
  ref: containerRef,
5991
6216
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
5992
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6217
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5993
6218
  "canvas",
5994
6219
  {
5995
6220
  ref: canvasRef,
@@ -6002,16 +6227,17 @@ var ImageEditor = ({
6002
6227
  onPointerUp: handlePaintPointerUp,
6003
6228
  onPointerCancel: () => paintGestureRef.current?.cancel(),
6004
6229
  "data-testid": "image-editor-canvas",
6005
- className: `absolute inset-0 w-full h-full block ${activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
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" : ""}`
6006
6232
  }
6007
6233
  )
6008
6234
  }
6009
6235
  ),
6010
- /* @__PURE__ */ (0, import_jsx_runtime26.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: [
6011
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6012
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
6013
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
6014
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6015
6241
  "button",
6016
6242
  {
6017
6243
  type: "button",
@@ -6023,7 +6249,7 @@ var ImageEditor = ({
6023
6249
  children: "Freeform"
6024
6250
  }
6025
6251
  ),
6026
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6252
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6027
6253
  "button",
6028
6254
  {
6029
6255
  type: "button",
@@ -6035,7 +6261,7 @@ var ImageEditor = ({
6035
6261
  children: "1:1 Square"
6036
6262
  }
6037
6263
  ),
6038
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6264
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6039
6265
  "button",
6040
6266
  {
6041
6267
  type: "button",
@@ -6047,7 +6273,7 @@ var ImageEditor = ({
6047
6273
  children: "4:3 Standard"
6048
6274
  }
6049
6275
  ),
6050
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6276
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6051
6277
  "button",
6052
6278
  {
6053
6279
  type: "button",
@@ -6059,7 +6285,7 @@ var ImageEditor = ({
6059
6285
  children: "16:9 Wide"
6060
6286
  }
6061
6287
  ),
6062
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6288
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6063
6289
  "button",
6064
6290
  {
6065
6291
  type: "button",
@@ -6071,7 +6297,7 @@ var ImageEditor = ({
6071
6297
  children: "3:2 Photo"
6072
6298
  }
6073
6299
  ),
6074
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6300
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6075
6301
  "button",
6076
6302
  {
6077
6303
  type: "button",
@@ -6084,10 +6310,10 @@ var ImageEditor = ({
6084
6310
  }
6085
6311
  )
6086
6312
  ] }),
6087
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6088
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
6089
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
6090
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6091
6317
  "button",
6092
6318
  {
6093
6319
  type: "button",
@@ -6096,7 +6322,7 @@ var ImageEditor = ({
6096
6322
  children: "Rotate -90\xB0"
6097
6323
  }
6098
6324
  ),
6099
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6325
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6100
6326
  "button",
6101
6327
  {
6102
6328
  type: "button",
@@ -6105,7 +6331,7 @@ var ImageEditor = ({
6105
6331
  children: "Rotate +90\xB0"
6106
6332
  }
6107
6333
  ),
6108
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6334
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6109
6335
  "button",
6110
6336
  {
6111
6337
  type: "button",
@@ -6114,7 +6340,7 @@ var ImageEditor = ({
6114
6340
  children: "Flip Horizontal"
6115
6341
  }
6116
6342
  ),
6117
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6343
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6118
6344
  "button",
6119
6345
  {
6120
6346
  type: "button",
@@ -6125,10 +6351,10 @@ var ImageEditor = ({
6125
6351
  )
6126
6352
  ] })
6127
6353
  ] }),
6128
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6129
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
6130
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
6131
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6132
6358
  "button",
6133
6359
  {
6134
6360
  type: "button",
@@ -6138,25 +6364,25 @@ var ImageEditor = ({
6138
6364
  }
6139
6365
  )
6140
6366
  ] }),
6141
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Histogram, { histogram: editor.histogram }),
6142
- import_image_editor11.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react43.default.Fragment, { children: [
6143
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6144
6370
  ControlSlider,
6145
6371
  {
6146
6372
  spec,
6147
- value: (0, import_image_editor11.readAdjustmentControls)(state.adjustments)[spec.id],
6373
+ value: (0, import_image_editor12.readAdjustmentControls)(state.adjustments)[spec.id],
6148
6374
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
6149
6375
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
6150
6376
  }
6151
6377
  ),
6152
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6378
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6153
6379
  "div",
6154
6380
  {
6155
6381
  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",
6156
6382
  "data-testid": "image-editor-process-notice",
6157
6383
  children: [
6158
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
6159
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6160
6386
  "button",
6161
6387
  {
6162
6388
  type: "button",
@@ -6169,7 +6395,7 @@ var ImageEditor = ({
6169
6395
  }
6170
6396
  )
6171
6397
  ] }, spec.id)),
6172
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6398
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6173
6399
  AdjustmentLayersPanel,
6174
6400
  {
6175
6401
  controller,
@@ -6178,19 +6404,41 @@ var ImageEditor = ({
6178
6404
  }
6179
6405
  ) })
6180
6406
  ] }),
6181
- activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6182
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
6183
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LayersPanel, { controller })
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)(
6410
+ "button",
6411
+ {
6412
+ type: "button",
6413
+ title: "Edit \u203A Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer",
6414
+ className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
6415
+ disabled: transformTool.active,
6416
+ onClick: () => transformTool.begin(),
6417
+ children: "Free Transform"
6418
+ }
6419
+ ),
6420
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LayersPanel, { controller })
6184
6421
  ] }),
6185
- activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6186
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
6187
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BrushOptionsBar, { controller }),
6188
- paintError && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
6189
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LayersPanel, { controller }) })
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)(
6426
+ "button",
6427
+ {
6428
+ type: "button",
6429
+ title: "Edit \u203A Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer",
6430
+ className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start",
6431
+ disabled: transformTool.active,
6432
+ onClick: () => transformTool.begin(),
6433
+ children: "Free Transform"
6434
+ }
6435
+ ),
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 }) })
6190
6438
  ] }),
6191
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6192
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
6193
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6194
6442
  "button",
6195
6443
  {
6196
6444
  type: "button",
@@ -6200,9 +6448,9 @@ var ImageEditor = ({
6200
6448
  },
6201
6449
  t
6202
6450
  )) }),
6203
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
6204
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { className: "text-slate-400", children: "Color:" }),
6205
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6206
6454
  "input",
6207
6455
  {
6208
6456
  type: "color",
@@ -6211,15 +6459,15 @@ var ImageEditor = ({
6211
6459
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
6212
6460
  }
6213
6461
  ),
6214
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex-1 ml-2", children: [
6215
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
6216
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Width:" }),
6217
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "font-mono", children: [
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: [
6218
6466
  strokeWidth,
6219
6467
  "px"
6220
6468
  ] })
6221
6469
  ] }),
6222
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6470
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6223
6471
  "input",
6224
6472
  {
6225
6473
  type: "range",
@@ -6232,10 +6480,10 @@ var ImageEditor = ({
6232
6480
  )
6233
6481
  ] })
6234
6482
  ] }),
6235
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6236
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
6237
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex gap-2", children: [
6238
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6239
6487
  "input",
6240
6488
  {
6241
6489
  type: "text",
@@ -6246,7 +6494,7 @@ var ImageEditor = ({
6246
6494
  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"
6247
6495
  }
6248
6496
  ),
6249
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6497
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6250
6498
  "button",
6251
6499
  {
6252
6500
  type: "button",
@@ -6256,14 +6504,14 @@ var ImageEditor = ({
6256
6504
  }
6257
6505
  )
6258
6506
  ] }),
6259
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
6260
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Font Size:" }),
6261
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "font-mono", children: [
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: [
6262
6510
  fontSize,
6263
6511
  "px"
6264
6512
  ] })
6265
6513
  ] }),
6266
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6514
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6267
6515
  "input",
6268
6516
  {
6269
6517
  type: "range",
@@ -6274,14 +6522,14 @@ var ImageEditor = ({
6274
6522
  className: "w-full accent-indigo-500"
6275
6523
  }
6276
6524
  ),
6277
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6278
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
6279
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-slate-400", children: [
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: [
6280
6528
  "Layers (",
6281
6529
  state.annotations.length,
6282
6530
  ")"
6283
6531
  ] }),
6284
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6532
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6285
6533
  "button",
6286
6534
  {
6287
6535
  type: "button",
@@ -6290,7 +6538,7 @@ var ImageEditor = ({
6290
6538
  children: "Delete Selected"
6291
6539
  }
6292
6540
  ),
6293
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6541
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6294
6542
  "button",
6295
6543
  {
6296
6544
  type: "button",
@@ -6301,10 +6549,10 @@ var ImageEditor = ({
6301
6549
  )
6302
6550
  ] })
6303
6551
  ] }),
6304
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6305
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
6306
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
6307
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6308
6556
  "button",
6309
6557
  {
6310
6558
  type: "button",
@@ -6314,8 +6562,8 @@ var ImageEditor = ({
6314
6562
  }
6315
6563
  )
6316
6564
  ] }),
6317
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6318
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6319
6567
  "input",
6320
6568
  {
6321
6569
  type: "checkbox",
@@ -6324,12 +6572,12 @@ var ImageEditor = ({
6324
6572
  className: "rounded accent-indigo-500"
6325
6573
  }
6326
6574
  ),
6327
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6575
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6328
6576
  ] }),
6329
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6330
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
6331
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6332
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6333
6581
  "input",
6334
6582
  {
6335
6583
  type: "text",
@@ -6340,8 +6588,8 @@ var ImageEditor = ({
6340
6588
  }
6341
6589
  )
6342
6590
  ] }),
6343
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex gap-2", children: [
6344
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6591
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-2", children: [
6592
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6345
6593
  "button",
6346
6594
  {
6347
6595
  type: "button",
@@ -6350,7 +6598,7 @@ var ImageEditor = ({
6350
6598
  children: "Threshold Mode"
6351
6599
  }
6352
6600
  ),
6353
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6601
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6354
6602
  "button",
6355
6603
  {
6356
6604
  type: "button",
@@ -6360,12 +6608,12 @@ var ImageEditor = ({
6360
6608
  }
6361
6609
  )
6362
6610
  ] }),
6363
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
6364
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6365
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Depth Start (Lower):" }),
6366
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
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] })
6367
6615
  ] }),
6368
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6616
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6369
6617
  "input",
6370
6618
  {
6371
6619
  type: "range",
@@ -6379,12 +6627,12 @@ var ImageEditor = ({
6379
6627
  }
6380
6628
  )
6381
6629
  ] }),
6382
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
6383
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6384
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Depth Stop (Upper):" }),
6385
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
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] })
6386
6634
  ] }),
6387
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6635
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6388
6636
  "input",
6389
6637
  {
6390
6638
  type: "range",
@@ -6398,12 +6646,12 @@ var ImageEditor = ({
6398
6646
  }
6399
6647
  )
6400
6648
  ] }),
6401
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
6402
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6403
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Softness:" }),
6404
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
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 })
6405
6653
  ] }),
6406
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6654
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6407
6655
  "input",
6408
6656
  {
6409
6657
  type: "range",
@@ -6415,8 +6663,8 @@ var ImageEditor = ({
6415
6663
  }
6416
6664
  )
6417
6665
  ] }),
6418
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
6419
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6420
6668
  "input",
6421
6669
  {
6422
6670
  type: "checkbox",
@@ -6425,12 +6673,12 @@ var ImageEditor = ({
6425
6673
  className: "rounded accent-indigo-500"
6426
6674
  }
6427
6675
  ),
6428
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Invert Mask" })
6676
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Invert Mask" })
6429
6677
  ] })
6430
6678
  ] })
6431
6679
  ] }),
6432
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6433
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6434
6682
  SelectionOptionsBar,
6435
6683
  {
6436
6684
  controller,
@@ -6440,13 +6688,37 @@ var ImageEditor = ({
6440
6688
  quickMask: Boolean(state.quickMask)
6441
6689
  }
6442
6690
  ),
6443
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
6444
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
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)(
6694
+ "button",
6695
+ {
6696
+ type: "button",
6697
+ title: "Select \u203A Transform Selection: the outline only",
6698
+ className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
6699
+ disabled: transformTool.active,
6700
+ onClick: () => transformTool.begin({ content: "selection-outline" }),
6701
+ children: "Transform Selection"
6702
+ }
6703
+ ),
6704
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6705
+ "button",
6706
+ {
6707
+ type: "button",
6708
+ title: "Edit \u203A Free Transform: the selected pixels of the active layer",
6709
+ className: "px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40",
6710
+ disabled: transformTool.active,
6711
+ onClick: () => transformTool.begin({ content: "selection" }),
6712
+ children: "Free Transform Pixels"
6713
+ }
6714
+ )
6715
+ ] }),
6716
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
6445
6717
  ] }),
6446
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6447
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
6448
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "Results go to" }),
6449
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
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)(
6450
6722
  "select",
6451
6723
  {
6452
6724
  "aria-label": "AI result target",
@@ -6454,54 +6726,54 @@ var ImageEditor = ({
6454
6726
  onChange: (e) => setAiTarget(e.target.value),
6455
6727
  className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
6456
6728
  children: [
6457
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
6458
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
6459
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("option", { value: "replace", children: "Replace image" })
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" })
6460
6732
  ]
6461
6733
  }
6462
6734
  )
6463
6735
  ] }),
6464
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6465
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
6466
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6467
- /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.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" }) }),
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" }) }),
6468
6740
  "Background Removal"
6469
6741
  ] }),
6470
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime26.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..." })
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..." })
6471
6743
  ] }),
6472
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
6473
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6474
6746
  "button",
6475
6747
  {
6476
6748
  type: "button",
6477
6749
  onClick: handleRemoveBackground,
6478
6750
  disabled: isRemovingBg || isInpainting,
6479
6751
  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",
6480
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6481
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
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" }),
6482
6754
  "Removing Background..."
6483
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6484
- /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.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" }) }),
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" }) }),
6485
6757
  "Remove Background"
6486
6758
  ] })
6487
6759
  }
6488
6760
  )
6489
6761
  ] }),
6490
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6491
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between", children: [
6492
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6493
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
6494
- /* @__PURE__ */ (0, import_jsx_runtime26.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" }),
6495
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("path", { d: "m14 7 3 3" })
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" })
6496
6768
  ] }),
6497
6769
  "Generative Inpainting"
6498
6770
  ] }),
6499
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime26.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..." })
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..." })
6500
6772
  ] }),
6501
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
6502
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", children: [
6503
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
6504
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
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)(
6505
6777
  "textarea",
6506
6778
  {
6507
6779
  id: "ai-inpaint-prompt-react",
@@ -6513,10 +6785,10 @@ var ImageEditor = ({
6513
6785
  }
6514
6786
  )
6515
6787
  ] }),
6516
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", children: [
6517
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
6518
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
6519
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
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)(
6520
6792
  "button",
6521
6793
  {
6522
6794
  type: "button",
@@ -6529,7 +6801,7 @@ var ImageEditor = ({
6529
6801
  ]
6530
6802
  }
6531
6803
  ),
6532
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6804
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6533
6805
  "button",
6534
6806
  {
6535
6807
  type: "button",
@@ -6544,25 +6816,25 @@ var ImageEditor = ({
6544
6816
  )
6545
6817
  ] })
6546
6818
  ] }),
6547
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6819
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6548
6820
  "button",
6549
6821
  {
6550
6822
  type: "button",
6551
6823
  onClick: handleInpaint,
6552
6824
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
6553
6825
  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",
6554
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6555
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
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" }),
6556
6828
  "Generating Inpaint..."
6557
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6558
- /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.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" }) }),
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" }) }),
6559
6831
  "Apply Inpainting"
6560
6832
  ] })
6561
6833
  }
6562
6834
  )
6563
6835
  ] }),
6564
- aiError && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
6565
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
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 })
6566
6838
  ] })
6567
6839
  ] })
6568
6840
  ] })
@@ -6572,7 +6844,7 @@ var ImageEditor = ({
6572
6844
  };
6573
6845
 
6574
6846
  // src/review/useReview.ts
6575
- var import_react44 = require("react");
6847
+ var import_react45 = require("react");
6576
6848
  var import_editor12 = require("@pixerate/editor");
6577
6849
  var EMPTY_COMMENTS = Object.freeze({
6578
6850
  threads: [],
@@ -6591,23 +6863,23 @@ function isCommentStore(value) {
6591
6863
  }
6592
6864
  function useComments(source) {
6593
6865
  const store = isCommentStore(source) ? source : (0, import_editor12.getCommentStore)(source);
6594
- const subscribe = (0, import_react44.useCallback)(
6866
+ const subscribe = (0, import_react45.useCallback)(
6595
6867
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6596
6868
  [store]
6597
6869
  );
6598
6870
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
6599
- const snapshot = (0, import_react44.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6600
- return (0, import_react44.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
6871
+ const snapshot = (0, import_react45.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6872
+ return (0, import_react45.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
6601
6873
  }
6602
6874
  function useTrackChanges(editor) {
6603
6875
  const store = (0, import_editor12.getTrackChangesStore)(editor ?? null);
6604
- const subscribe = (0, import_react44.useCallback)(
6876
+ const subscribe = (0, import_react45.useCallback)(
6605
6877
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
6606
6878
  [store]
6607
6879
  );
6608
6880
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
6609
- const snapshot = (0, import_react44.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6610
- return (0, import_react44.useMemo)(() => {
6881
+ const snapshot = (0, import_react45.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6882
+ return (0, import_react45.useMemo)(() => {
6611
6883
  const run = (fn) => () => {
6612
6884
  if (editor && !editor.isDestroyed) fn(editor);
6613
6885
  };
@@ -6630,9 +6902,9 @@ function useTrackChanges(editor) {
6630
6902
  }
6631
6903
 
6632
6904
  // src/review/CommentsPanel.tsx
6633
- var import_react45 = require("react");
6905
+ var import_react46 = require("react");
6634
6906
  var import_editor13 = require("@pixerate/editor");
6635
- var import_jsx_runtime27 = require("react/jsx-runtime");
6907
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6636
6908
  var buttonClass2 = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
6637
6909
  var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
6638
6910
  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";
@@ -6646,18 +6918,18 @@ var CommentsPanel = ({
6646
6918
  emptyMessage = "No comments yet. Select text and add a comment."
6647
6919
  }) => {
6648
6920
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
6649
- const [showResolved, setShowResolved] = (0, import_react45.useState)(showResolvedInitial);
6921
+ const [showResolved, setShowResolved] = (0, import_react46.useState)(showResolvedInitial);
6650
6922
  const author = authorProp ?? (0, import_editor13.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
6651
6923
  const visible = threads.filter((t) => showResolved || !t.resolved);
6652
6924
  const resolvedCount = threads.filter((t) => t.resolved).length;
6653
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("aside", { className, "aria-label": "Comments", children: [
6654
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
6655
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
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: [
6656
6928
  threads.length - resolvedCount,
6657
6929
  " open",
6658
6930
  resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
6659
6931
  ] }),
6660
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6932
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6661
6933
  "button",
6662
6934
  {
6663
6935
  type: "button",
@@ -6668,7 +6940,7 @@ var CommentsPanel = ({
6668
6940
  }
6669
6941
  )
6670
6942
  ] }),
6671
- visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
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)(
6672
6944
  CommentThreadCard,
6673
6945
  {
6674
6946
  thread,
@@ -6690,7 +6962,7 @@ var CommentThreadCard = ({
6690
6962
  author,
6691
6963
  formatTime
6692
6964
  }) => {
6693
- const [draft, setDraft] = (0, import_react45.useState)("");
6965
+ const [draft, setDraft] = (0, import_react46.useState)("");
6694
6966
  const isDraft = thread.body === "";
6695
6967
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
6696
6968
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -6716,7 +6988,7 @@ var CommentThreadCard = ({
6716
6988
  setDraft("");
6717
6989
  };
6718
6990
  const stop = (e) => e.stopPropagation();
6719
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6991
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
6720
6992
  "li",
6721
6993
  {
6722
6994
  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" : ""}`,
@@ -6732,24 +7004,24 @@ var CommentThreadCard = ({
6732
7004
  }
6733
7005
  },
6734
7006
  children: [
6735
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
6736
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-medium", children: thread.author.name }),
6737
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
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) })
6738
7010
  ] }),
6739
- quote && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
6740
- thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
6741
- thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
6742
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
6743
- thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.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_runtime27.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
6744
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "text-xs", children: [
6745
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-medium", children: reply.author.name }),
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 }),
6746
7018
  " ",
6747
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
7019
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
6748
7020
  ] }),
6749
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
7021
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
6750
7022
  ] }, reply.id)) }),
6751
- (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
6752
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
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)(
6753
7025
  "textarea",
6754
7026
  {
6755
7027
  className: textareaClass,
@@ -6767,9 +7039,9 @@ var CommentThreadCard = ({
6767
7039
  }
6768
7040
  }
6769
7041
  ),
6770
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-end gap-1", children: [
6771
- isDraft && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
6772
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
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)(
6773
7045
  "button",
6774
7046
  {
6775
7047
  type: "button",
@@ -6781,9 +7053,9 @@ var CommentThreadCard = ({
6781
7053
  )
6782
7054
  ] })
6783
7055
  ] }),
6784
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
6785
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
6786
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
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)(
6787
7059
  "button",
6788
7060
  {
6789
7061
  type: "button",
@@ -6799,7 +7071,7 @@ var CommentThreadCard = ({
6799
7071
  };
6800
7072
 
6801
7073
  // src/review/ReviewToolbar.tsx
6802
- var import_jsx_runtime28 = require("react/jsx-runtime");
7074
+ var import_jsx_runtime29 = require("react/jsx-runtime");
6803
7075
  var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
6804
7076
  var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
6805
7077
  var ReviewToolbar = ({
@@ -6812,8 +7084,8 @@ var ReviewToolbar = ({
6812
7084
  const count = review.changes.length;
6813
7085
  const current = review.currentChange;
6814
7086
  const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
6815
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
6816
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7087
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
7088
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6817
7089
  "button",
6818
7090
  {
6819
7091
  type: "button",
@@ -6824,8 +7096,8 @@ var ReviewToolbar = ({
6824
7096
  children: review.enabled ? "Tracking on" : "Track changes"
6825
7097
  }
6826
7098
  ),
6827
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6828
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
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)(
6829
7101
  "button",
6830
7102
  {
6831
7103
  type: "button",
@@ -6836,8 +7108,8 @@ var ReviewToolbar = ({
6836
7108
  children: "\u2039"
6837
7109
  }
6838
7110
  ),
6839
- /* @__PURE__ */ (0, import_jsx_runtime28.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` }),
6840
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
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)(
6841
7113
  "button",
6842
7114
  {
6843
7115
  type: "button",
@@ -6848,7 +7120,7 @@ var ReviewToolbar = ({
6848
7120
  children: "\u203A"
6849
7121
  }
6850
7122
  ),
6851
- showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
7123
+ showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6852
7124
  "span",
6853
7125
  {
6854
7126
  className: descriptionClassName,
@@ -6860,8 +7132,8 @@ var ReviewToolbar = ({
6860
7132
  ]
6861
7133
  }
6862
7134
  ),
6863
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6864
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
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)(
6865
7137
  "button",
6866
7138
  {
6867
7139
  type: "button",
@@ -6871,7 +7143,7 @@ var ReviewToolbar = ({
6871
7143
  children: "Accept"
6872
7144
  }
6873
7145
  ),
6874
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
7146
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6875
7147
  "button",
6876
7148
  {
6877
7149
  type: "button",
@@ -6881,18 +7153,18 @@ var ReviewToolbar = ({
6881
7153
  children: "Reject"
6882
7154
  }
6883
7155
  ),
6884
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
6885
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
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" })
6886
7158
  ] });
6887
7159
  };
6888
7160
 
6889
7161
  // src/review/CommentButton.tsx
6890
- var import_jsx_runtime29 = require("react/jsx-runtime");
7162
+ var import_jsx_runtime30 = require("react/jsx-runtime");
6891
7163
  var CommentButton = ({
6892
7164
  editor,
6893
7165
  className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
6894
7166
  children = "Comment"
6895
- }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7167
+ }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6896
7168
  "button",
6897
7169
  {
6898
7170
  type: "button",
@@ -6904,13 +7176,13 @@ var CommentButton = ({
6904
7176
  );
6905
7177
 
6906
7178
  // src/review/useDocumentCompare.ts
6907
- var import_react46 = require("react");
7179
+ var import_react47 = require("react");
6908
7180
  var import_editor14 = require("@pixerate/editor");
6909
7181
  function useDocumentCompare(editor, options) {
6910
- const [summary, setSummary] = (0, import_react46.useState)(null);
6911
- const defaults = (0, import_react46.useRef)(options);
7182
+ const [summary, setSummary] = (0, import_react47.useState)(null);
7183
+ const defaults = (0, import_react47.useRef)(options);
6912
7184
  defaults.current = options;
6913
- const compare = (0, import_react46.useCallback)(
7185
+ const compare = (0, import_react47.useCallback)(
6914
7186
  (original, revised, overrides) => {
6915
7187
  if (!editor || editor.isDestroyed) return null;
6916
7188
  const result = (0, import_editor14.applyDocumentComparison)(editor, original, revised, {
@@ -6922,13 +7194,13 @@ function useDocumentCompare(editor, options) {
6922
7194
  },
6923
7195
  [editor]
6924
7196
  );
6925
- const clear = (0, import_react46.useCallback)(() => setSummary(null), []);
6926
- return (0, import_react46.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
7197
+ const clear = (0, import_react47.useCallback)(() => setSummary(null), []);
7198
+ return (0, import_react47.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
6927
7199
  }
6928
7200
 
6929
7201
  // src/review/TrackedChangesList.tsx
6930
7202
  var import_editor15 = require("@pixerate/editor");
6931
- var import_jsx_runtime30 = require("react/jsx-runtime");
7203
+ var import_jsx_runtime31 = require("react/jsx-runtime");
6932
7204
  var buttonClass4 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
6933
7205
  var TrackedChangesList = ({
6934
7206
  editor,
@@ -6939,18 +7211,18 @@ var TrackedChangesList = ({
6939
7211
  }) => {
6940
7212
  const review = useTrackChanges(editor);
6941
7213
  if (review.changes.length === 0) {
6942
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
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 }) });
6943
7215
  }
6944
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
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) => {
6945
7217
  const active = change.id === review.currentChangeId;
6946
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
7218
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
6947
7219
  "li",
6948
7220
  {
6949
7221
  className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
6950
7222
  "data-change-type": change.type,
6951
7223
  "data-change-id": change.id,
6952
7224
  children: [
6953
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
7225
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
6954
7226
  "button",
6955
7227
  {
6956
7228
  type: "button",
@@ -6958,14 +7230,14 @@ var TrackedChangesList = ({
6958
7230
  title: `${change.author.name}: ${change.description}`,
6959
7231
  onClick: () => review.select(change.id),
6960
7232
  children: [
6961
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
7233
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
6962
7234
  change.author.name ? ` \xB7 ${change.author.name}` : "",
6963
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
7235
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
6964
7236
  ]
6965
7237
  }
6966
7238
  ),
6967
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
6968
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
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" })
6969
7241
  ]
6970
7242
  },
6971
7243
  `${change.type}:${change.id}`
@@ -6974,12 +7246,12 @@ var TrackedChangesList = ({
6974
7246
  };
6975
7247
 
6976
7248
  // src/commands/useCommandPalette.ts
6977
- var import_react47 = require("react");
7249
+ var import_react48 = require("react");
6978
7250
  var import_commands2 = require("@pixerate/editor/commands");
6979
7251
  function useCommandPalette(registry, options = {}) {
6980
- const optionsRef = (0, import_react47.useRef)(options);
7252
+ const optionsRef = (0, import_react48.useRef)(options);
6981
7253
  optionsRef.current = options;
6982
- const controller = (0, import_react47.useMemo)(
7254
+ const controller = (0, import_react48.useMemo)(
6983
7255
  () => (0, import_commands2.createCommandPaletteController)(registry, {
6984
7256
  context: () => {
6985
7257
  const c = optionsRef.current.context;
@@ -7000,9 +7272,9 @@ function useCommandPalette(registry, options = {}) {
7000
7272
  // eslint-disable-next-line react-hooks/exhaustive-deps
7001
7273
  [registry]
7002
7274
  );
7003
- const state = (0, import_react47.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7275
+ const state = (0, import_react48.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7004
7276
  const { hotkey, hotkeyTarget } = options;
7005
- (0, import_react47.useEffect)(() => {
7277
+ (0, import_react48.useEffect)(() => {
7006
7278
  if (!hotkey) return;
7007
7279
  const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
7008
7280
  if (!target) return;
@@ -7030,13 +7302,13 @@ function useCommandPalette(registry, options = {}) {
7030
7302
  }
7031
7303
 
7032
7304
  // src/commands/CommandPalette.tsx
7033
- var import_react48 = __toESM(require("react"), 1);
7034
- var import_jsx_runtime31 = require("react/jsx-runtime");
7305
+ var import_react49 = __toESM(require("react"), 1);
7306
+ var import_jsx_runtime32 = require("react/jsx-runtime");
7035
7307
  function HighlightedLabel({ item }) {
7036
- if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_jsx_runtime31.Fragment, { children: item.label });
7308
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: item.label });
7037
7309
  const marked = new Set(item.labelIndices);
7038
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_jsx_runtime31.Fragment, { children: Array.from(item.label).map(
7039
- (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react48.default.Fragment, { children: ch }, i)
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)
7040
7312
  ) });
7041
7313
  }
7042
7314
  var CommandPalette = ({
@@ -7045,22 +7317,22 @@ var CommandPalette = ({
7045
7317
  emptyMessage = "No matching commands",
7046
7318
  className = ""
7047
7319
  }) => {
7048
- const inputRef = (0, import_react48.useRef)(null);
7049
- const listRef = (0, import_react48.useRef)(null);
7050
- const baseId = (0, import_react48.useId)();
7320
+ const inputRef = (0, import_react49.useRef)(null);
7321
+ const listRef = (0, import_react49.useRef)(null);
7322
+ const baseId = (0, import_react49.useId)();
7051
7323
  const listId = `${baseId}-list`;
7052
7324
  const optionId = (index) => `${baseId}-option-${index}`;
7053
7325
  const { open, query, items, activeIndex } = palette;
7054
- (0, import_react48.useEffect)(() => {
7326
+ (0, import_react49.useEffect)(() => {
7055
7327
  if (open) inputRef.current?.focus();
7056
7328
  }, [open]);
7057
- (0, import_react48.useEffect)(() => {
7329
+ (0, import_react49.useEffect)(() => {
7058
7330
  if (!open) return;
7059
7331
  const active = listRef.current?.querySelector('[aria-selected="true"]');
7060
7332
  active?.scrollIntoView?.({ block: "nearest" });
7061
7333
  }, [open, activeIndex]);
7062
7334
  if (!open) return null;
7063
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7335
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7064
7336
  "div",
7065
7337
  {
7066
7338
  className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
@@ -7068,7 +7340,7 @@ var CommandPalette = ({
7068
7340
  onMouseDown: (e) => {
7069
7341
  if (e.target === e.currentTarget) palette.setOpen(false);
7070
7342
  },
7071
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
7343
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7072
7344
  "div",
7073
7345
  {
7074
7346
  role: "dialog",
@@ -7077,7 +7349,7 @@ var CommandPalette = ({
7077
7349
  className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
7078
7350
  style: { background: "var(--popover, var(--background, #fff))" },
7079
7351
  children: [
7080
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7352
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7081
7353
  "input",
7082
7354
  {
7083
7355
  ref: inputRef,
@@ -7097,7 +7369,7 @@ var CommandPalette = ({
7097
7369
  className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
7098
7370
  }
7099
7371
  ),
7100
- items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime31.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_runtime31.jsxs)(
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)(
7101
7373
  "li",
7102
7374
  {
7103
7375
  id: optionId(index),
@@ -7112,12 +7384,12 @@ var CommandPalette = ({
7112
7384
  onClick: () => palette.run(item.id),
7113
7385
  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"}`,
7114
7386
  children: [
7115
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
7116
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(HighlightedLabel, { item }),
7117
- item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
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 })
7118
7390
  ] }),
7119
- item.group && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
7120
- item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
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 })
7121
7393
  ]
7122
7394
  },
7123
7395
  item.id
@@ -7130,12 +7402,12 @@ var CommandPalette = ({
7130
7402
  };
7131
7403
 
7132
7404
  // src/commands/useCommandShortcuts.ts
7133
- var import_react49 = require("react");
7405
+ var import_react50 = require("react");
7134
7406
  function useCommandShortcuts(registry, options = {}) {
7135
- const optionsRef = (0, import_react49.useRef)(options);
7407
+ const optionsRef = (0, import_react50.useRef)(options);
7136
7408
  optionsRef.current = options;
7137
7409
  const { enabled = true, target } = options;
7138
- (0, import_react49.useEffect)(() => {
7410
+ (0, import_react50.useEffect)(() => {
7139
7411
  if (!registry || !enabled) return;
7140
7412
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
7141
7413
  if (!eventTarget) return;
@@ -7153,14 +7425,14 @@ function useCommandShortcuts(registry, options = {}) {
7153
7425
  }, [registry, enabled, target]);
7154
7426
  }
7155
7427
  function useRegisterCommands(registry, specs) {
7156
- (0, import_react49.useEffect)(() => {
7428
+ (0, import_react50.useEffect)(() => {
7157
7429
  if (!registry || !specs || specs.length === 0) return;
7158
7430
  return registry.register(specs);
7159
7431
  }, [registry, specs]);
7160
7432
  }
7161
7433
 
7162
7434
  // src/persistence/useAutosave.ts
7163
- var import_react50 = require("react");
7435
+ var import_react51 = require("react");
7164
7436
  var import_persistence = require("@pixerate/editor/persistence");
7165
7437
  var IDLE = {
7166
7438
  status: "idle",
@@ -7171,18 +7443,18 @@ var IDLE = {
7171
7443
  ready: false
7172
7444
  };
7173
7445
  function useAutosave(options) {
7174
- const optionsRef = (0, import_react50.useRef)(options);
7446
+ const optionsRef = (0, import_react51.useRef)(options);
7175
7447
  optionsRef.current = options;
7176
7448
  const { storage, key, history, dirty } = options;
7177
7449
  const recover = options.recover !== false;
7178
7450
  const flushOnHide = options.flushOnHide !== false;
7179
7451
  const ready = options.ready !== false;
7180
- const [controller, setController] = (0, import_react50.useState)(null);
7181
- const [status, setStatus] = (0, import_react50.useState)(IDLE);
7182
- const [recovery, setRecovery] = (0, import_react50.useState)(null);
7183
- const [pendingRecovery, setPendingRecovery] = (0, import_react50.useState)(recover);
7184
- const revisionsRef = (0, import_react50.useRef)(null);
7185
- (0, import_react50.useEffect)(() => {
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)(() => {
7186
7458
  const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
7187
7459
  const o = optionsRef.current;
7188
7460
  const instance = (0, import_persistence.createAutosaveController)({
@@ -7225,10 +7497,10 @@ function useAutosave(options) {
7225
7497
  if (revisionsRef.current === revisions) revisionsRef.current = null;
7226
7498
  };
7227
7499
  }, [storage, key, history, dirty, recover]);
7228
- (0, import_react50.useEffect)(() => {
7500
+ (0, import_react51.useEffect)(() => {
7229
7501
  if (controller && ready && !pendingRecovery) controller.ready();
7230
7502
  }, [controller, ready, pendingRecovery]);
7231
- (0, import_react50.useEffect)(() => {
7503
+ (0, import_react51.useEffect)(() => {
7232
7504
  if (!controller || !flushOnHide || typeof window === "undefined") return;
7233
7505
  const flush = () => void controller.flushNow();
7234
7506
  const onVisibility = () => {
@@ -7241,31 +7513,31 @@ function useAutosave(options) {
7241
7513
  document.removeEventListener("visibilitychange", onVisibility);
7242
7514
  };
7243
7515
  }, [controller, flushOnHide]);
7244
- const restore = (0, import_react50.useCallback)(() => {
7516
+ const restore = (0, import_react51.useCallback)(() => {
7245
7517
  const snapshot = recovery?.snapshot;
7246
7518
  setRecovery(null);
7247
7519
  setPendingRecovery(false);
7248
7520
  return snapshot;
7249
7521
  }, [recovery]);
7250
- const discard = (0, import_react50.useCallback)(async () => {
7522
+ const discard = (0, import_react51.useCallback)(async () => {
7251
7523
  if (controller) await controller.discardRecovery();
7252
7524
  setRecovery(null);
7253
7525
  setPendingRecovery(false);
7254
7526
  }, [controller]);
7255
- const flushNow = (0, import_react50.useCallback)(async () => {
7527
+ const flushNow = (0, import_react51.useCallback)(async () => {
7256
7528
  await controller?.flushNow();
7257
7529
  }, [controller]);
7258
- const markClean = (0, import_react50.useCallback)(async () => {
7530
+ const markClean = (0, import_react51.useCallback)(async () => {
7259
7531
  revisionsRef.current?.markSaved();
7260
7532
  await controller?.markClean();
7261
7533
  }, [controller]);
7262
- const notifyChange = (0, import_react50.useCallback)(() => revisionsRef.current?.bump(), []);
7534
+ const notifyChange = (0, import_react51.useCallback)(() => revisionsRef.current?.bump(), []);
7263
7535
  return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
7264
7536
  }
7265
7537
 
7266
7538
  // src/persistence/RecoveryPrompt.tsx
7267
7539
  var import_persistence2 = require("@pixerate/editor/persistence");
7268
- var import_jsx_runtime32 = require("react/jsx-runtime");
7540
+ var import_jsx_runtime33 = require("react/jsx-runtime");
7269
7541
  var RecoveryPrompt = ({
7270
7542
  recovery,
7271
7543
  onRestore,
@@ -7277,7 +7549,7 @@ var RecoveryPrompt = ({
7277
7549
  }) => {
7278
7550
  if (!recovery) return null;
7279
7551
  const { name } = recovery.meta;
7280
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7552
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7281
7553
  "div",
7282
7554
  {
7283
7555
  role: "alertdialog",
@@ -7285,15 +7557,15 @@ var RecoveryPrompt = ({
7285
7557
  "data-recovery-prompt": "",
7286
7558
  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}`,
7287
7559
  children: [
7288
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "min-w-0 flex-1", children: [
7560
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "min-w-0 flex-1", children: [
7289
7561
  (0, import_persistence2.formatRecoveryMessage)(recovery.meta, formatTime),
7290
- name ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7562
+ name ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7291
7563
  "(",
7292
7564
  name,
7293
7565
  ")"
7294
7566
  ] }) : null
7295
7567
  ] }),
7296
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7568
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7297
7569
  "button",
7298
7570
  {
7299
7571
  type: "button",
@@ -7303,7 +7575,7 @@ var RecoveryPrompt = ({
7303
7575
  children: restoreLabel
7304
7576
  }
7305
7577
  ),
7306
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7578
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7307
7579
  "button",
7308
7580
  {
7309
7581
  type: "button",
@@ -7319,17 +7591,17 @@ var RecoveryPrompt = ({
7319
7591
  };
7320
7592
 
7321
7593
  // src/generation/useGenerationPlan.ts
7322
- var import_react51 = require("react");
7594
+ var import_react52 = require("react");
7323
7595
  var import_generation = require("@pixerate/editor/generation");
7324
7596
  function useGenerationPlan(request, capabilities, options = {}) {
7325
7597
  const key = JSON.stringify([request, capabilities, options]);
7326
- return (0, import_react51.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7598
+ return (0, import_react52.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7327
7599
  }
7328
7600
  function useJobProgress(options) {
7329
7601
  const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
7330
- const [tick, setTick] = (0, import_react51.useState)(() => Date.now());
7602
+ const [tick, setTick] = (0, import_react52.useState)(() => Date.now());
7331
7603
  const ticking = !done && now === void 0;
7332
- (0, import_react51.useEffect)(() => {
7604
+ (0, import_react52.useEffect)(() => {
7333
7605
  if (!ticking) return;
7334
7606
  setTick(Date.now());
7335
7607
  const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
@@ -7339,9 +7611,9 @@ function useJobProgress(options) {
7339
7611
  }
7340
7612
 
7341
7613
  // src/generation/GenerationSettings.tsx
7342
- var import_react52 = require("react");
7614
+ var import_react53 = require("react");
7343
7615
  var import_generation2 = require("@pixerate/editor/generation");
7344
- var import_jsx_runtime33 = require("react/jsx-runtime");
7616
+ var import_jsx_runtime34 = require("react/jsx-runtime");
7345
7617
  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";
7346
7618
  function Control({
7347
7619
  control,
@@ -7351,7 +7623,7 @@ function Control({
7351
7623
  }) {
7352
7624
  const shown = value ?? control.defaultValue;
7353
7625
  if (control.kind === "checkbox") {
7354
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7626
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7355
7627
  "input",
7356
7628
  {
7357
7629
  id,
@@ -7363,7 +7635,7 @@ function Control({
7363
7635
  );
7364
7636
  }
7365
7637
  if (control.kind === "select") {
7366
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7638
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
7367
7639
  "select",
7368
7640
  {
7369
7641
  id,
@@ -7372,14 +7644,14 @@ function Control({
7372
7644
  value: shown === void 0 ? "" : String(shown),
7373
7645
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
7374
7646
  children: [
7375
- shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("option", { value: "", children: "Default" }),
7376
- control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
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)))
7377
7649
  ]
7378
7650
  }
7379
7651
  );
7380
7652
  }
7381
7653
  if (control.kind === "textarea") {
7382
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7654
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7383
7655
  "textarea",
7384
7656
  {
7385
7657
  id,
@@ -7393,8 +7665,8 @@ function Control({
7393
7665
  );
7394
7666
  }
7395
7667
  const numeric = typeof shown === "number" ? shown : void 0;
7396
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-2", children: [
7397
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7668
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2", children: [
7669
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7398
7670
  "input",
7399
7671
  {
7400
7672
  id,
@@ -7408,7 +7680,7 @@ function Control({
7408
7680
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
7409
7681
  }
7410
7682
  ),
7411
- control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
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" })
7412
7684
  ] });
7413
7685
  }
7414
7686
  var GenerationSettings = ({
@@ -7422,17 +7694,17 @@ var GenerationSettings = ({
7422
7694
  renderReference,
7423
7695
  className = ""
7424
7696
  }) => {
7425
- const baseId = (0, import_react52.useId)();
7426
- const controls = (0, import_react52.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7697
+ const baseId = (0, import_react53.useId)();
7698
+ const controls = (0, import_react53.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7427
7699
  const computed = useGenerationPlan(value, capabilities, { strategy });
7428
7700
  const plan = planProp ?? computed;
7429
7701
  const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
7430
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
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: [
7431
7703
  controls.map((control) => {
7432
7704
  const id = `${baseId}-${control.key}`;
7433
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
7434
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
7435
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
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)(
7436
7708
  Control,
7437
7709
  {
7438
7710
  control,
@@ -7443,23 +7715,23 @@ var GenerationSettings = ({
7443
7715
  )
7444
7716
  ] }, control.key);
7445
7717
  }),
7446
- slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
7447
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
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: [
7448
7720
  slot.label,
7449
7721
  " ",
7450
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7722
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7451
7723
  "(",
7452
7724
  slot.references.length,
7453
7725
  "/",
7454
7726
  slot.max,
7455
7727
  ")"
7456
7728
  ] }),
7457
- slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-destructive", children: " *" })
7729
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-destructive", children: " *" })
7458
7730
  ] }),
7459
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
7460
- slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
7461
- renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
7462
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
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)(
7463
7735
  "button",
7464
7736
  {
7465
7737
  type: "button",
@@ -7470,7 +7742,7 @@ var GenerationSettings = ({
7470
7742
  }
7471
7743
  )
7472
7744
  ] }, ref.id)),
7473
- onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7745
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7474
7746
  "button",
7475
7747
  {
7476
7748
  type: "button",
@@ -7481,21 +7753,21 @@ var GenerationSettings = ({
7481
7753
  ) })
7482
7754
  ] })
7483
7755
  ] }, slot.role)),
7484
- showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.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_runtime33.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
7485
- showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.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_runtime33.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
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)) })
7486
7758
  ] });
7487
7759
  };
7488
7760
 
7489
7761
  // src/generation/JobProgress.tsx
7490
- var import_jsx_runtime34 = require("react/jsx-runtime");
7762
+ var import_jsx_runtime35 = require("react/jsx-runtime");
7491
7763
  var JobProgress = ({ title, className = "", ...options }) => {
7492
7764
  const progress = useJobProgress(options);
7493
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
7494
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
7495
- title && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "truncate text-foreground", children: title }),
7496
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
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 })
7497
7769
  ] }),
7498
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7770
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7499
7771
  "div",
7500
7772
  {
7501
7773
  role: "progressbar",
@@ -7505,7 +7777,7 @@ var JobProgress = ({ title, className = "", ...options }) => {
7505
7777
  "aria-valuenow": progress.percent,
7506
7778
  "aria-valuetext": `${progress.percent}%, ${progress.label}`,
7507
7779
  className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
7508
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7780
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7509
7781
  "div",
7510
7782
  {
7511
7783
  className: "h-full rounded-full bg-primary transition-[width] duration-500",
@@ -7518,9 +7790,9 @@ var JobProgress = ({ title, className = "", ...options }) => {
7518
7790
  };
7519
7791
 
7520
7792
  // src/generation/AssetMentionChips.tsx
7521
- var import_react53 = require("react");
7793
+ var import_react54 = require("react");
7522
7794
  var import_generation3 = require("@pixerate/editor/generation");
7523
- var import_jsx_runtime35 = require("react/jsx-runtime");
7795
+ var import_jsx_runtime36 = require("react/jsx-runtime");
7524
7796
  var AssetMentionChips = ({
7525
7797
  content,
7526
7798
  onChange,
@@ -7530,14 +7802,14 @@ var AssetMentionChips = ({
7530
7802
  renderAsset,
7531
7803
  className = ""
7532
7804
  }) => {
7533
- const [open, setOpen] = (0, import_react53.useState)(null);
7534
- const rootRef = (0, import_react53.useRef)(null);
7535
- const chips = (0, import_react53.useMemo)(
7805
+ const [open, setOpen] = (0, import_react54.useState)(null);
7806
+ const rootRef = (0, import_react54.useRef)(null);
7807
+ const chips = (0, import_react54.useMemo)(
7536
7808
  () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
7537
7809
  [content, assets, capabilities]
7538
7810
  );
7539
7811
  const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
7540
- (0, import_react53.useEffect)(() => {
7812
+ (0, import_react54.useEffect)(() => {
7541
7813
  if (open === null) return;
7542
7814
  const onPointer = (event) => {
7543
7815
  if (!rootRef.current?.contains(event.target)) setOpen(null);
@@ -7545,19 +7817,19 @@ var AssetMentionChips = ({
7545
7817
  document.addEventListener("mousedown", onPointer);
7546
7818
  return () => document.removeEventListener("mousedown", onPointer);
7547
7819
  }, [open]);
7548
- const pick = (chip2, role) => {
7820
+ const pick = (chip3, role) => {
7549
7821
  setOpen(null);
7550
- if (chip2.start === void 0) return;
7551
- onChange((0, import_generation3.setMentionRoleInText)(content, chip2.start, role));
7822
+ if (chip3.start === void 0) return;
7823
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip3.start, role));
7552
7824
  };
7553
7825
  if (chips.length === 0) return null;
7554
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip2) => {
7555
- const error = chip2.issues.find((issue) => issue.severity === "error");
7556
- const warning = chip2.issues.find((issue) => issue.severity === "warning");
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");
7557
7829
  const problem = error ?? warning;
7558
- const isOpen = open === chip2.index;
7559
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip2.asset.id, children: [
7560
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
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)(
7561
7833
  "button",
7562
7834
  {
7563
7835
  type: "button",
@@ -7565,82 +7837,82 @@ var AssetMentionChips = ({
7565
7837
  "aria-expanded": isOpen,
7566
7838
  title: problem?.message,
7567
7839
  "data-issue": problem?.code,
7568
- onClick: () => setOpen(isOpen ? null : chip2.index),
7840
+ onClick: () => setOpen(isOpen ? null : chip3.index),
7569
7841
  onKeyDown: (e) => {
7570
7842
  if (e.key === "Escape") setOpen(null);
7571
7843
  },
7572
7844
  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`,
7573
7845
  children: [
7574
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: renderAsset ? renderAsset(chip2) : `@${chip2.asset.label ?? chip2.handle}` }),
7575
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7846
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: renderAsset ? renderAsset(chip3) : `@${chip3.asset.label ?? chip3.handle}` }),
7847
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7576
7848
  "span",
7577
7849
  {
7578
- className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip2.role ? "bg-primary/15" : "opacity-60"}`,
7579
- "data-role-badge": chip2.role ?? "",
7580
- children: chip2.roleLabel ?? "No role"
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"
7581
7853
  }
7582
7854
  )
7583
7855
  ]
7584
7856
  }
7585
7857
  ),
7586
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
7858
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7587
7859
  "div",
7588
7860
  {
7589
7861
  role: "listbox",
7590
- "aria-label": `Role for ${chip2.asset.label ?? chip2.handle}`,
7862
+ "aria-label": `Role for ${chip3.asset.label ?? chip3.handle}`,
7591
7863
  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",
7592
7864
  "data-role-picker": "",
7593
7865
  onKeyDown: (e) => {
7594
7866
  if (e.key === "Escape") setOpen(null);
7595
7867
  },
7596
7868
  children: [
7597
- options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
7869
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7598
7870
  "button",
7599
7871
  {
7600
7872
  type: "button",
7601
7873
  role: "option",
7602
- "aria-selected": chip2.role === option.role,
7874
+ "aria-selected": chip3.role === option.role,
7603
7875
  "data-role-option": option.role,
7604
7876
  title: option.description,
7605
- onClick: () => pick(chip2, option.role),
7877
+ onClick: () => pick(chip3, option.role),
7606
7878
  className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
7607
7879
  children: [
7608
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: option.label }),
7609
- option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
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
7610
7882
  ]
7611
7883
  },
7612
7884
  option.role
7613
7885
  )),
7614
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7886
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7615
7887
  "button",
7616
7888
  {
7617
7889
  type: "button",
7618
7890
  role: "option",
7619
- "aria-selected": !chip2.role,
7891
+ "aria-selected": !chip3.role,
7620
7892
  "data-role-option": "",
7621
- onClick: () => pick(chip2, null),
7893
+ onClick: () => pick(chip3, null),
7622
7894
  className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
7623
7895
  children: "No role"
7624
7896
  }
7625
7897
  ),
7626
- chip2.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "mt-1 border-t border-border px-2 pt-1 text-[10px]", "data-chip-issues": "", children: chip2.issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
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)) })
7627
7899
  ]
7628
7900
  }
7629
7901
  )
7630
- ] }, `${chip2.start}-${chip2.index}`);
7902
+ ] }, `${chip3.start}-${chip3.index}`);
7631
7903
  }) });
7632
7904
  };
7633
7905
 
7634
7906
  // src/generation/GenerationHistory.tsx
7635
- var import_react54 = require("react");
7907
+ var import_react55 = require("react");
7636
7908
  var import_generation4 = require("@pixerate/editor/generation");
7637
- var import_jsx_runtime36 = require("react/jsx-runtime");
7909
+ var import_jsx_runtime37 = require("react/jsx-runtime");
7638
7910
  function useGenerationRecords(store, filter) {
7639
- const [records, setRecords] = (0, import_react54.useState)([]);
7640
- const [loading, setLoading] = (0, import_react54.useState)(!!store);
7641
- const [error, setError] = (0, import_react54.useState)(null);
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);
7642
7914
  const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
7643
- const refresh = (0, import_react54.useCallback)(async () => {
7915
+ const refresh = (0, import_react55.useCallback)(async () => {
7644
7916
  if (!store) {
7645
7917
  setRecords([]);
7646
7918
  setLoading(false);
@@ -7657,7 +7929,7 @@ function useGenerationRecords(store, filter) {
7657
7929
  setLoading(false);
7658
7930
  }
7659
7931
  }, [store, filterKey]);
7660
- (0, import_react54.useEffect)(() => {
7932
+ (0, import_react55.useEffect)(() => {
7661
7933
  void refresh();
7662
7934
  if (!store) return;
7663
7935
  return store.subscribe(() => void refresh());
@@ -7683,21 +7955,21 @@ var GenerationHistory = ({
7683
7955
  emptyText = "No generations yet.",
7684
7956
  className = ""
7685
7957
  }) => {
7686
- const [innerMode, setInnerMode] = (0, import_react54.useState)("exact");
7958
+ const [innerMode, setInnerMode] = (0, import_react55.useState)("exact");
7687
7959
  const mode = modeProp ?? innerMode;
7688
7960
  const setMode = (next) => {
7689
7961
  if (modeProp === void 0) setInnerMode(next);
7690
7962
  onModeChange?.(next);
7691
7963
  };
7692
- const options = (0, import_react54.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
7693
- const results = (0, import_react54.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
7694
- const models = (0, import_react54.useMemo)(
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)(
7695
7967
  () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
7696
7968
  [capabilities]
7697
7969
  );
7698
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
7699
- /* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
7700
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
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)(
7701
7973
  "input",
7702
7974
  {
7703
7975
  type: "radio",
@@ -7710,34 +7982,34 @@ var GenerationHistory = ({
7710
7982
  ),
7711
7983
  value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
7712
7984
  ] }, value)) }),
7713
- records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
7714
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
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) => {
7715
7987
  const result = results[i];
7716
7988
  const model = models.find((m) => m.id === record.provenance.modelId);
7717
7989
  const blocked = !result.ok;
7718
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7990
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
7719
7991
  "li",
7720
7992
  {
7721
7993
  className: "rounded-md border border-border p-2",
7722
7994
  "data-record": record.id,
7723
7995
  "data-drift": result.drift.length,
7724
7996
  children: [
7725
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
7726
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
7727
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "text-muted-foreground", children: [
7728
- record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { "data-kind": "", 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: [
7729
8001
  record.kind,
7730
8002
  " \xB7 "
7731
8003
  ] }),
7732
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
7733
- record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
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: [
7734
8006
  " \xB7 seed ",
7735
8007
  record.seed
7736
8008
  ] })
7737
8009
  ] })
7738
8010
  ] }),
7739
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
7740
- record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
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)(
7741
8013
  "span",
7742
8014
  {
7743
8015
  className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
@@ -7751,16 +8023,16 @@ var GenerationHistory = ({
7751
8023
  `${asset.role}:${asset.id}`
7752
8024
  )) }),
7753
8025
  renderPreview?.(record),
7754
- result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
7755
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("strong", { children: [
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: [
7756
8028
  import_generation4.DRIFT_TYPE_LABELS[item.type],
7757
8029
  ":"
7758
8030
  ] }),
7759
8031
  " ",
7760
8032
  item.message
7761
8033
  ] }, j)) }),
7762
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "mt-2 flex gap-2", children: [
7763
- onRecreate && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8034
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-2 flex gap-2", children: [
8035
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7764
8036
  "button",
7765
8037
  {
7766
8038
  type: "button",
@@ -7772,7 +8044,7 @@ var GenerationHistory = ({
7772
8044
  children: "Recreate"
7773
8045
  }
7774
8046
  ),
7775
- onVariation && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8047
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7776
8048
  "button",
7777
8049
  {
7778
8050
  type: "button",
@@ -7782,7 +8054,7 @@ var GenerationHistory = ({
7782
8054
  children: "Variation"
7783
8055
  }
7784
8056
  ),
7785
- onRemove && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8057
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7786
8058
  "button",
7787
8059
  {
7788
8060
  type: "button",
@@ -7802,19 +8074,19 @@ var GenerationHistory = ({
7802
8074
  };
7803
8075
 
7804
8076
  // src/find-replace/useFindReplace.ts
7805
- var import_react55 = require("react");
8077
+ var import_react56 = require("react");
7806
8078
  var import_editor16 = require("@pixerate/editor");
7807
8079
  var noopUnsubscribe2 = () => {
7808
8080
  };
7809
8081
  function useFindReplace(editor) {
7810
8082
  const store = (0, import_editor16.getFindReplaceStore)(editor ?? null);
7811
- const subscribe = (0, import_react55.useCallback)(
8083
+ const subscribe = (0, import_react56.useCallback)(
7812
8084
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
7813
8085
  [store]
7814
8086
  );
7815
8087
  const getSnapshot = () => store?.getSnapshot() ?? import_editor16.EMPTY_FIND_REPLACE_SNAPSHOT;
7816
- const snapshot = (0, import_react55.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7817
- return (0, import_react55.useMemo)(() => {
8088
+ const snapshot = (0, import_react56.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
8089
+ return (0, import_react56.useMemo)(() => {
7818
8090
  const run = (fn) => {
7819
8091
  if (editor && !editor.isDestroyed && store) fn(editor);
7820
8092
  };
@@ -7838,9 +8110,9 @@ function useFindReplace(editor) {
7838
8110
  }
7839
8111
 
7840
8112
  // src/find-replace/FindReplaceBar.tsx
7841
- var import_react56 = require("react");
8113
+ var import_react57 = require("react");
7842
8114
  var import_editor17 = require("@pixerate/editor");
7843
- var import_jsx_runtime37 = require("react/jsx-runtime");
8115
+ var import_jsx_runtime38 = require("react/jsx-runtime");
7844
8116
  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";
7845
8117
  var buttonClass5 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
7846
8118
  var toggleClass = (on) => `${buttonClass5} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
@@ -7853,10 +8125,10 @@ var FindReplaceBar = ({
7853
8125
  onClose
7854
8126
  }) => {
7855
8127
  const find = useFindReplace(editor);
7856
- const findInput = (0, import_react56.useRef)(null);
7857
- const [moreOpen, setMoreOpen] = (0, import_react56.useState)(false);
8128
+ const findInput = (0, import_react57.useRef)(null);
8129
+ const [moreOpen, setMoreOpen] = (0, import_react57.useState)(false);
7858
8130
  const visible = find.available && (alwaysOpen || find.open);
7859
- (0, import_react56.useEffect)(() => {
8131
+ (0, import_react57.useEffect)(() => {
7860
8132
  if (!visible || find.focusRequest === 0) return;
7861
8133
  findInput.current?.focus();
7862
8134
  findInput.current?.select();
@@ -7894,9 +8166,9 @@ var FindReplaceBar = ({
7894
8166
  if (isMod(e)) find.replaceAll();
7895
8167
  else find.replace();
7896
8168
  };
7897
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
7898
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-1", children: [
7899
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
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)(
7900
8172
  "button",
7901
8173
  {
7902
8174
  type: "button",
@@ -7907,7 +8179,7 @@ var FindReplaceBar = ({
7907
8179
  children: showReplace ? "\u25BE" : "\u25B8"
7908
8180
  }
7909
8181
  ),
7910
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8182
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7911
8183
  "input",
7912
8184
  {
7913
8185
  ref: findInput,
@@ -7921,7 +8193,7 @@ var FindReplaceBar = ({
7921
8193
  onKeyDown: onFindKeyDown
7922
8194
  }
7923
8195
  ),
7924
- import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8196
+ import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7925
8197
  "button",
7926
8198
  {
7927
8199
  type: "button",
@@ -7934,7 +8206,7 @@ var FindReplaceBar = ({
7934
8206
  },
7935
8207
  t.key
7936
8208
  )),
7937
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8209
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7938
8210
  "span",
7939
8211
  {
7940
8212
  className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
@@ -7944,9 +8216,9 @@ var FindReplaceBar = ({
7944
8216
  children: status
7945
8217
  }
7946
8218
  ),
7947
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
7948
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
7949
- showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
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)(
7950
8222
  "button",
7951
8223
  {
7952
8224
  type: "button",
@@ -7957,10 +8229,10 @@ var FindReplaceBar = ({
7957
8229
  children: "\u2026"
7958
8230
  }
7959
8231
  ),
7960
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
8232
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
7961
8233
  ] }),
7962
- showReplace && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
7963
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
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)(
7964
8236
  "input",
7965
8237
  {
7966
8238
  type: "text",
@@ -7972,7 +8244,7 @@ var FindReplaceBar = ({
7972
8244
  onKeyDown: onReplaceKeyDown
7973
8245
  }
7974
8246
  ),
7975
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
8247
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7976
8248
  "button",
7977
8249
  {
7978
8250
  type: "button",
@@ -7982,11 +8254,11 @@ var FindReplaceBar = ({
7982
8254
  children: "Replace"
7983
8255
  }
7984
8256
  ),
7985
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
7986
- find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
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` })
7987
8259
  ] }),
7988
- showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime37.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_runtime37.jsxs)("label", { className: "flex items-center gap-1", children: [
7989
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
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)(
7990
8262
  "input",
7991
8263
  {
7992
8264
  type: "checkbox",
@@ -8000,12 +8272,12 @@ var FindReplaceBar = ({
8000
8272
  };
8001
8273
 
8002
8274
  // src/tables/useTableMenu.ts
8003
- var import_react57 = require("react");
8275
+ var import_react58 = require("react");
8004
8276
  var import_editor18 = require("@pixerate/editor");
8005
8277
  function useTableMenu(editor) {
8006
- const store = (0, import_react57.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
8007
- const snapshot = (0, import_react57.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
8008
- return (0, import_react57.useMemo)(
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)(
8009
8281
  () => ({
8010
8282
  ...snapshot,
8011
8283
  run: (action, params) => (0, import_editor18.runTableAction)(editor, action, params, { focus: true }),
@@ -8016,9 +8288,9 @@ function useTableMenu(editor) {
8016
8288
  }
8017
8289
 
8018
8290
  // src/tables/TableToolbar.tsx
8019
- var import_react58 = __toESM(require("react"), 1);
8291
+ var import_react59 = __toESM(require("react"), 1);
8020
8292
  var import_editor19 = require("@pixerate/editor");
8021
- var import_jsx_runtime38 = require("react/jsx-runtime");
8293
+ var import_jsx_runtime39 = require("react/jsx-runtime");
8022
8294
  var keepSelection2 = (event) => event.preventDefault();
8023
8295
  var TableToolbar = ({
8024
8296
  editor,
@@ -8032,14 +8304,14 @@ var TableToolbar = ({
8032
8304
  }) => {
8033
8305
  const table = useTableMenu(editor);
8034
8306
  if (!editor || !table.inTable && !showWhenOutside) return null;
8035
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
8307
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
8036
8308
  const status = table.check(item.action, item.params);
8037
8309
  const enabled = status === true;
8038
8310
  const active = item.active?.(table);
8039
8311
  const separator = index > 0 && items[index - 1].group !== item.group;
8040
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_react58.default.Fragment, { children: [
8041
- separator && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
8042
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
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)(
8043
8315
  "button",
8044
8316
  {
8045
8317
  type: "button",
@@ -8061,8 +8333,8 @@ var TableToolbar = ({
8061
8333
  };
8062
8334
 
8063
8335
  // src/tables/InsertTableGrid.tsx
8064
- var import_react59 = require("react");
8065
- var import_jsx_runtime39 = require("react/jsx-runtime");
8336
+ var import_react60 = require("react");
8337
+ var import_jsx_runtime40 = require("react/jsx-runtime");
8066
8338
  var keepSelection3 = (event) => event.preventDefault();
8067
8339
  var InsertTableGrid = ({
8068
8340
  editor,
@@ -8075,14 +8347,14 @@ var InsertTableGrid = ({
8075
8347
  onInsert
8076
8348
  }) => {
8077
8349
  const table = useTableMenu(editor);
8078
- const [hover, setHover] = (0, import_react59.useState)(null);
8350
+ const [hover, setHover] = (0, import_react60.useState)(null);
8079
8351
  const status = table.actions.insertTable;
8080
8352
  const disabled = !editor || !status.enabled;
8081
8353
  const insert = (size) => {
8082
8354
  if (table.run("insertTable", { ...size, withHeaderRow })) onInsert?.(size);
8083
8355
  setHover(null);
8084
8356
  };
8085
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
8357
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8086
8358
  "div",
8087
8359
  {
8088
8360
  className,
@@ -8092,7 +8364,7 @@ var InsertTableGrid = ({
8092
8364
  "data-insert-table-grid": "",
8093
8365
  onMouseLeave: () => setHover(null),
8094
8366
  children: [
8095
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8367
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8096
8368
  "div",
8097
8369
  {
8098
8370
  role: "grid",
@@ -8101,7 +8373,7 @@ var InsertTableGrid = ({
8101
8373
  children: Array.from({ length: rows * cols }, (_, i) => {
8102
8374
  const size = { rows: Math.floor(i / cols) + 1, cols: i % cols + 1 };
8103
8375
  const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols;
8104
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8376
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8105
8377
  "button",
8106
8378
  {
8107
8379
  type: "button",
@@ -8121,7 +8393,7 @@ var InsertTableGrid = ({
8121
8393
  })
8122
8394
  }
8123
8395
  ),
8124
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { "aria-live": "polite", "data-testid": "insert-table-size", children: disabled ? status.reason : hover ? `${hover.rows} \xD7 ${hover.cols}` : "Insert table" })
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" })
8125
8397
  ]
8126
8398
  }
8127
8399
  );
@@ -8129,31 +8401,31 @@ var InsertTableGrid = ({
8129
8401
 
8130
8402
  // src/tables/TableBubbleMenu.tsx
8131
8403
  var import_editor20 = require("@pixerate/editor");
8132
- var import_jsx_runtime40 = require("react/jsx-runtime");
8404
+ var import_jsx_runtime41 = require("react/jsx-runtime");
8133
8405
  var TableBubbleMenu = ({
8134
8406
  editor,
8135
8407
  children,
8136
8408
  toolbarProps,
8137
8409
  pluginKey = "tableBubbleMenu",
8138
8410
  ...rest
8139
- }) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(BubbleMenu, { editor, pluginKey, shouldShow: import_editor20.shouldShowTableBubbleMenu, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TableToolbar, { editor, ...toolbarProps }) });
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 }) });
8140
8412
 
8141
8413
  // src/chart-node/ChartNodeView.tsx
8142
8414
  var import_client = require("react-dom/client");
8143
8415
 
8144
8416
  // src/chart/ChartCanvas.tsx
8145
- var import_react61 = require("react");
8417
+ var import_react62 = require("react");
8146
8418
  var import_chart2 = require("@pixerate/editor/chart");
8147
8419
 
8148
8420
  // src/chart/useChartEditor.ts
8149
- var import_react60 = require("react");
8421
+ var import_react61 = require("react");
8150
8422
  var import_chart = require("@pixerate/editor/chart");
8151
8423
  function useChartState(controller) {
8152
- return (0, import_react60.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8424
+ return (0, import_react61.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
8153
8425
  }
8154
8426
 
8155
8427
  // src/chart/ChartCanvas.tsx
8156
- var import_jsx_runtime41 = require("react/jsx-runtime");
8428
+ var import_jsx_runtime42 = require("react/jsx-runtime");
8157
8429
  function renderChartMark(mark, fontFamily, interactive) {
8158
8430
  const common = {
8159
8431
  "data-role": mark.role,
@@ -8165,9 +8437,9 @@ function renderChartMark(mark, fontFamily, interactive) {
8165
8437
  };
8166
8438
  switch (mark.kind) {
8167
8439
  case "rect":
8168
- return /* @__PURE__ */ (0, import_jsx_runtime41.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);
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);
8169
8441
  case "path":
8170
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8442
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8171
8443
  "path",
8172
8444
  {
8173
8445
  ...common,
@@ -8180,11 +8452,11 @@ function renderChartMark(mark, fontFamily, interactive) {
8180
8452
  mark.key
8181
8453
  );
8182
8454
  case "circle":
8183
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
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);
8184
8456
  case "line":
8185
- return /* @__PURE__ */ (0, import_jsx_runtime41.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);
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);
8186
8458
  case "text":
8187
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8459
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8188
8460
  "text",
8189
8461
  {
8190
8462
  ...common,
@@ -8201,23 +8473,23 @@ function renderChartMark(mark, fontFamily, interactive) {
8201
8473
  }
8202
8474
  }
8203
8475
  function ChartPresenceLayer({ presence }) {
8204
- const { actors } = (0, import_react61.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
8205
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("g", { "data-chart-presence": "", pointerEvents: "none", children: actors.map((a) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("g", { transform: `translate(${a.x} ${a.y})`, "data-actor": a.id, children: [
8206
- /* @__PURE__ */ (0, import_jsx_runtime41.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 }),
8207
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("g", { transform: "translate(13 16)", children: [
8208
- /* @__PURE__ */ (0, import_jsx_runtime41.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 } }),
8209
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("text", { x: 6, y: 9, dominantBaseline: "central", style: { fill: "#ffffff", fontSize: 11, fontWeight: 600, fontFamily: "inherit" }, children: a.message ?? a.name })
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 })
8210
8482
  ] })
8211
8483
  ] }, a.id)) });
8212
8484
  }
8213
8485
  function ChartCanvas({ controller, width = 640, height = 400, responsive = true, theme, editable = true, measureText, emptyMessage, className, presence, sceneRef }) {
8214
8486
  const state = useChartState(controller);
8215
- const wrapper = (0, import_react61.useRef)(null);
8216
- const svg = (0, import_react61.useRef)(null);
8217
- const drag = (0, import_react61.useRef)(null);
8218
- const [measured, setMeasured] = (0, import_react61.useState)(null);
8219
- const [frozen, setFrozen] = (0, import_react61.useState)(null);
8220
- (0, import_react61.useEffect)(() => {
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)(() => {
8221
8493
  const el = wrapper.current;
8222
8494
  if (!responsive || !el || typeof ResizeObserver === "undefined") return;
8223
8495
  const observer = new ResizeObserver(([entry]) => {
@@ -8228,8 +8500,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8228
8500
  return () => observer.disconnect();
8229
8501
  }, [responsive]);
8230
8502
  const sceneWidth = responsive && measured || width;
8231
- const fullTheme = (0, import_react61.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
8232
- const scene = (0, import_react61.useMemo)(
8503
+ const fullTheme = (0, import_react62.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
8504
+ const scene = (0, import_react62.useMemo)(
8233
8505
  () => (0, import_chart2.layoutChart)(state.spec, {
8234
8506
  width: sceneWidth,
8235
8507
  height,
@@ -8245,8 +8517,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8245
8517
  [state.spec, state.selection, sceneWidth, height, fullTheme, editable, measureText, emptyMessage, frozen]
8246
8518
  );
8247
8519
  if (sceneRef) sceneRef.current = scene;
8248
- const byKey = (0, import_react61.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
8249
- (0, import_react61.useEffect)(() => () => drag.current?.end(), []);
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(), []);
8250
8522
  const scenePoint = (e) => (0, import_chart2.chartClientToScene)(scene, svg.current.getBoundingClientRect(), e.clientX, e.clientY);
8251
8523
  const onPointerDown = (e) => {
8252
8524
  if (!editable || e.button !== 0) return;
@@ -8279,7 +8551,7 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8279
8551
  if (editable && (0, import_chart2.handleChartKey)(controller, scene, e)) e.preventDefault();
8280
8552
  };
8281
8553
  const label = state.spec.title || "Chart";
8282
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ref: wrapper, className: `w-full ${className ?? ""}`, "data-chart-canvas": "", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
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)(
8283
8555
  "svg",
8284
8556
  {
8285
8557
  ref: svg,
@@ -8297,14 +8569,14 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
8297
8569
  onKeyDown,
8298
8570
  children: [
8299
8571
  scene.marks.map((m) => renderChartMark(m, scene.theme.fontFamily, editable)),
8300
- presence && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ChartPresenceLayer, { presence })
8572
+ presence && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartPresenceLayer, { presence })
8301
8573
  ]
8302
8574
  }
8303
8575
  ) });
8304
8576
  }
8305
8577
 
8306
8578
  // src/chart/ChartDataGrid.tsx
8307
- var import_react62 = require("react");
8579
+ var import_react63 = require("react");
8308
8580
  var import_chart3 = require("@pixerate/editor/chart");
8309
8581
 
8310
8582
  // src/chart/styles.ts
@@ -8317,11 +8589,11 @@ var chartSectionClass = "space-y-2 border-b border-border pb-3 last:border-b-0";
8317
8589
  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";
8318
8590
 
8319
8591
  // src/chart/ChartDataGrid.tsx
8320
- var import_jsx_runtime42 = require("react/jsx-runtime");
8592
+ var import_jsx_runtime43 = require("react/jsx-runtime");
8321
8593
  function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
8322
- const [draft, setDraft] = (0, import_react62.useState)(value);
8323
- const typing = (0, import_react62.useRef)(false);
8324
- (0, import_react62.useEffect)(() => {
8594
+ const [draft, setDraft] = (0, import_react63.useState)(value);
8595
+ const typing = (0, import_react63.useRef)(false);
8596
+ (0, import_react63.useEffect)(() => {
8325
8597
  if (!typing.current) setDraft(value);
8326
8598
  }, [value]);
8327
8599
  const commit = () => {
@@ -8330,7 +8602,7 @@ function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
8330
8602
  if (draft === value) return;
8331
8603
  if (onCommit(draft) === false) setDraft(value);
8332
8604
  };
8333
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8605
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8334
8606
  "input",
8335
8607
  {
8336
8608
  ...rest,
@@ -8365,15 +8637,15 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8365
8637
  e.preventDefault();
8366
8638
  controller.pasteCells(row, column, text);
8367
8639
  };
8368
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
8369
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
8370
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("tr", { children: [
8371
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("th", { className: "border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground", children: categoryHeader }),
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 }),
8372
8644
  spec.series.map((s, si) => {
8373
8645
  const color = (0, import_chart3.chartSeriesColor)(spec, si);
8374
8646
  const selected = selection?.kind === "series" && selection.seriesId === s.id;
8375
- return /* @__PURE__ */ (0, import_jsx_runtime42.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_runtime42.jsxs)("div", { className: "flex items-center gap-1", children: [
8376
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
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)(
8377
8649
  "input",
8378
8650
  {
8379
8651
  type: "color",
@@ -8386,7 +8658,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8386
8658
  className: "h-5 w-5 shrink-0 cursor-pointer rounded border-0 bg-transparent p-0"
8387
8659
  }
8388
8660
  ),
8389
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8661
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8390
8662
  ChartCommitInput,
8391
8663
  {
8392
8664
  value: s.name,
@@ -8396,8 +8668,8 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8396
8668
  className: `${chartInputClass} h-6 min-w-[5rem] border-transparent bg-transparent font-medium ${s.hidden ? "text-muted-foreground line-through" : ""}`
8397
8669
  }
8398
8670
  ),
8399
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8400
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8671
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8672
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8401
8673
  "button",
8402
8674
  {
8403
8675
  type: "button",
@@ -8410,16 +8682,16 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8410
8682
  children: s.hidden ? "\u25CB" : "\u25CF"
8411
8683
  }
8412
8684
  ),
8413
- /* @__PURE__ */ (0, import_jsx_runtime42.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" })
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" })
8414
8686
  ] })
8415
8687
  ] }) }, s.id);
8416
8688
  }),
8417
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("th", { className: "w-8 border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Add series", "aria-label": "Add series", "data-action": "add-series", onClick: () => controller.addSeries(), children: "+" }) })
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: "+" }) })
8418
8690
  ] }) }),
8419
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("tbody", { children: spec.categories.map((category, i) => {
8691
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("tbody", { children: spec.categories.map((category, i) => {
8420
8692
  const rowSelected = selection?.kind === "category" && selection.index === i;
8421
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
8422
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("th", { className: "border-b border-r border-border p-0 text-left font-normal", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
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)(
8423
8695
  ChartCommitInput,
8424
8696
  {
8425
8697
  value: category,
@@ -8433,7 +8705,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8433
8705
  spec.series.map((s) => {
8434
8706
  const value = s.values[i];
8435
8707
  const selected = selection?.kind === "point" && selection.seriesId === s.id && selection.index === i;
8436
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("td", { className: `border-b border-r border-border p-0 ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
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)(
8437
8709
  ChartCommitInput,
8438
8710
  {
8439
8711
  value: value === null || value === void 0 ? "" : String(value),
@@ -8448,38 +8720,38 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
8448
8720
  }
8449
8721
  ) }, s.id);
8450
8722
  }),
8451
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("td", { className: "border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete category", "aria-label": `Delete ${category}`, "data-action": "remove-category", onClick: () => controller.removeCategory(i), children: "\xD7" }) })
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" }) })
8452
8724
  ] }, i);
8453
8725
  }) })
8454
8726
  ] }),
8455
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "p-1", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: `${chartButtonClass} h-6 border-dashed`, "data-action": "add-category", onClick: () => controller.addCategory(), children: "+ Add category" }) })
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" }) })
8456
8728
  ] });
8457
8729
  }
8458
8730
 
8459
8731
  // src/chart/ChartInspector.tsx
8460
- var import_react63 = require("react");
8732
+ var import_react64 = require("react");
8461
8733
  var import_chart4 = require("@pixerate/editor/chart");
8462
- var import_jsx_runtime43 = require("react/jsx-runtime");
8734
+ var import_jsx_runtime44 = require("react/jsx-runtime");
8463
8735
  var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
8464
8736
  function Field({ label, htmlFor, children }) {
8465
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-2", children: [
8466
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
8467
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "min-w-0 flex-1", 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 })
8468
8740
  ] });
8469
8741
  }
8470
8742
  function Toggle({ label, checked, onChange, name }) {
8471
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
8472
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("input", { type: "checkbox", className: "h-3.5 w-3.5 accent-primary", checked, "data-option": name, onChange: (e) => onChange(e.currentTarget.checked) }),
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) }),
8473
8745
  label
8474
8746
  ] });
8475
8747
  }
8476
8748
  function Select({ id, value, options, onChange, name, labels }) {
8477
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("select", { id, className: chartInputClass, value, "data-option": name, onChange: (e) => onChange(e.currentTarget.value), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: o, children: labels?.[o] ?? cap(o) }, o)) });
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)) });
8478
8750
  }
8479
8751
  function AxisSection({ controller, axis, value, idBase, horizontal, numeric = false, scales = false }) {
8480
8752
  const set = (patch) => controller.setAxis(axis, patch);
8481
8753
  const setFormat = (patch) => set({ format: { ...value.format, ...patch } });
8482
- const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8754
+ const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8483
8755
  ChartCommitInput,
8484
8756
  {
8485
8757
  id: `${idBase}-${axis}-${key2}`,
@@ -8494,26 +8766,26 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8494
8766
  const name = axis === "x" ? numeric ? "X axis" : "Category axis" : axis === "y" ? "Value axis" : "Secondary axis";
8495
8767
  const valueAxis = axis !== "x" || numeric;
8496
8768
  const key = axis === "y2" ? "yAxis2" : `${axis}Axis`;
8497
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
8498
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between", children: [
8499
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
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: [
8500
8772
  name,
8501
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8773
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8502
8774
  "(",
8503
8775
  axis === "x" ? horizontal ? "left" : "bottom" : axis === "y2" ? horizontal ? "top" : "right" : horizontal ? "bottom" : "left",
8504
8776
  ")"
8505
8777
  ] })
8506
8778
  ] }),
8507
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8779
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8508
8780
  ] }),
8509
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Title", htmlFor: `${idBase}-${axis}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-title`, value: value.title, "data-option": `${axis}Axis.title`, className: chartInputClass, onCommit: (title) => void set({ title }) }) }),
8510
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8511
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
8512
- axis === "x" && !numeric && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Dates", name: "xAxis.kind", checked: value.kind === "date", onChange: (dates) => set({ kind: dates ? "date" : void 0 }) }),
8513
- scales && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
8514
- scales && valueAxis && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Log scale", name: `${key}.scale`, checked: value.scale === "log", onChange: (log) => set({ scale: log ? "log" : "linear" }) })
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" }) })
8515
8787
  ] }),
8516
- scales && valueAxis && value.scale === "log" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Log base", htmlFor: `${idBase}-${axis}-log-base`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8517
8789
  ChartCommitInput,
8518
8790
  {
8519
8791
  id: `${idBase}-${axis}-log-base`,
@@ -8524,7 +8796,7 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8524
8796
  onCommit: (text) => set({ logBase: text.trim() === "" ? void 0 : Number(text) }).ok
8525
8797
  }
8526
8798
  ) }),
8527
- valueAxis && value.scale !== "log" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Step", htmlFor: `${idBase}-${axis}-step`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8528
8800
  ChartCommitInput,
8529
8801
  {
8530
8802
  id: `${idBase}-${axis}-step`,
@@ -8536,14 +8808,14 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8536
8808
  onCommit: (text) => set({ step: text.trim() === "" ? null : Number(text) }).ok
8537
8809
  }
8538
8810
  ) }),
8539
- valueAxis && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8540
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex gap-1", children: [
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: [
8541
8813
  bound("min"),
8542
8814
  bound("max")
8543
8815
  ] }) }),
8544
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Format", htmlFor: `${idBase}-${axis}-format`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex gap-1", children: [
8545
- /* @__PURE__ */ (0, import_jsx_runtime43.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 }) }),
8546
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8547
8819
  ChartCommitInput,
8548
8820
  {
8549
8821
  value: value.format.decimals === void 0 ? "" : String(value.format.decimals),
@@ -8562,8 +8834,8 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
8562
8834
  }
8563
8835
  )
8564
8836
  ] }) }),
8565
- value.format.style === "currency" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Currency", htmlFor: `${idBase}-${axis}-currency`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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() }) }) }),
8566
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8567
8839
  ChartCommitInput,
8568
8840
  {
8569
8841
  id: `${idBase}-${axis}-code`,
@@ -8589,15 +8861,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8589
8861
  const values = which === "xErrorBars" ? series.x ?? [] : series.values;
8590
8862
  const set = (next) => controller.updateSeries(series.id, { [which]: next });
8591
8863
  const patch = (p) => bars && set({ ...bars, ...p });
8592
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
8593
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: which === "errorBars" ? "Error bars" : "X error bars", htmlFor: `${id}-type`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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: [
8594
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "None" }),
8595
- import_chart4.CHART_ERROR_BAR_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: t, children: import_chart4.CHART_ERROR_BAR_LABELS[t] }, t))
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))
8596
8868
  ] }) }),
8597
- bars && (bars.type === "fixed" || bars.type === "percent" || bars.type === "stddev") && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: bars.type === "percent" ? "Percent" : bars.type === "stddev" ? "Deviations" : "Amount", htmlFor: `${id}-value`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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 }) }),
8598
- bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8599
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Plus", htmlFor: `${id}-plus`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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 }) }),
8600
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8601
8873
  ChartCommitInput,
8602
8874
  {
8603
8875
  id: `${id}-minus`,
@@ -8614,15 +8886,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
8614
8886
  }
8615
8887
  ) })
8616
8888
  ] }),
8617
- bars && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-2", children: [
8618
- /* @__PURE__ */ (0, import_jsx_runtime43.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_runtime43.jsx)("option", { value: d, children: d === "both" ? "Both ways" : d === "plus" ? "Plus only" : "Minus only" }, d)) }),
8619
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
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 }) })
8620
8892
  ] })
8621
8893
  ] });
8622
8894
  }
8623
8895
  function ChartInspector({ controller, sections, className }) {
8624
8896
  const { spec, selectedSeries } = useChartState(controller);
8625
- const idBase = (0, import_react63.useId)();
8897
+ const idBase = (0, import_react64.useId)();
8626
8898
  const show = (section) => !sections || sections.includes(section);
8627
8899
  const cartesian = (0, import_chart4.isCartesianChart)(spec.type);
8628
8900
  const family = (0, import_chart4.chartFamily)(spec);
@@ -8634,29 +8906,29 @@ function ChartInspector({ controller, sections, className }) {
8634
8906
  const hasLines = cartesian && types.some((t) => t === "line" || t === "area");
8635
8907
  const seriesIndex = selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1;
8636
8908
  const scales = family === "cartesian" || family === "xy";
8637
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
8638
- show("type") && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: chartSectionClass, "data-section": "type", children: /* @__PURE__ */ (0, import_jsx_runtime43.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_runtime43.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)) }) }),
8639
- show("style") && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
8640
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Layout", htmlFor: `${idBase}-layout`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("select", { id: `${idBase}-layout`, className: chartInputClass, value: "", "data-option": "preset.layout", onChange: (e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value }), children: [
8641
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "Quick layout\u2026" }),
8642
- import_chart4.CHART_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: p.id, title: p.description, children: p.label }, p.id))
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))
8643
8915
  ] }) }),
8644
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Colours", htmlFor: `${idBase}-colors`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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: [
8645
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "Custom" }),
8646
- import_chart4.CHART_COLOR_SCHEMES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: c.id, title: c.description, children: c.label }, c.id))
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))
8647
8919
  ] }) }),
8648
- !colorCheck.ok && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", "data-chart-color-warning": "", children: colorCheck.issues[0] }),
8649
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
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" })
8650
8922
  ] }),
8651
- show("titles") && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
8652
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Title", htmlFor: `${idBase}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCommitInput, { id: `${idBase}-title`, value: spec.title, "data-option": "title", className: chartInputClass, onCommit: (title) => void controller.setTitle(title) }) }),
8653
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Subtitle", htmlFor: `${idBase}-subtitle`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCommitInput, { id: `${idBase}-subtitle`, value: spec.subtitle, "data-option": "subtitle", className: chartInputClass, onCommit: (subtitle) => void controller.setSubtitle(subtitle) }) })
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) }) })
8654
8926
  ] }),
8655
- show("options") && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
8656
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Stacking", htmlFor: `${idBase}-stacking`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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 }) }) }),
8657
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Bars", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: ["vertical", "horizontal"].map((o) => /* @__PURE__ */ (0, import_jsx_runtime43.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)) }) }),
8658
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Lines", htmlFor: `${idBase}-curve`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Select, { id: `${idBase}-curve`, name: "curve", value: spec.curve, options: import_chart4.CHART_CURVES, onChange: (curve) => controller.update({ curve }) }) }),
8659
- spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8660
8932
  "input",
8661
8933
  {
8662
8934
  id: `${idBase}-hole`,
@@ -8672,7 +8944,7 @@ function ChartInspector({ controller, sections, className }) {
8672
8944
  onChange: (e) => controller.update({ innerRadius: Number(e.currentTarget.value) })
8673
8945
  }
8674
8946
  ) }),
8675
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8947
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8676
8948
  "input",
8677
8949
  {
8678
8950
  id: `${idBase}-gap`,
@@ -8688,31 +8960,31 @@ function ChartInspector({ controller, sections, className }) {
8688
8960
  onChange: (e) => controller.update({ gapWidth: Number(e.currentTarget.value) })
8689
8961
  }
8690
8962
  ) }),
8691
- spec.dataLabels && hasBars && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Labels", htmlFor: `${idBase}-label-position`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Select, { id: `${idBase}-label-position`, name: "labelPosition", value: spec.labelPosition, options: import_chart4.CHART_LABEL_POSITIONS, onChange: (labelPosition) => controller.update({ labelPosition }) }) }),
8692
- spec.type === "histogram" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Bins", htmlFor: `${idBase}-bins`, children: /* @__PURE__ */ (0, import_jsx_runtime43.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 }) }),
8693
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8694
- spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
8695
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
8696
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
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 }) })
8697
8969
  ] })
8698
8970
  ] }),
8699
- show("legend") && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
8700
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between", children: [
8701
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
8702
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
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 }) })
8703
8975
  ] }),
8704
- spec.legend.show && /* @__PURE__ */ (0, import_jsx_runtime43.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_runtime43.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)) })
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)) })
8705
8977
  ] }),
8706
- show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8707
- family !== "box" && family !== "histogram" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AxisSection, { controller, axis: "x", value: spec.xAxis, idBase, horizontal: spec.orientation === "horizontal", numeric: family === "xy", scales }),
8708
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
8709
- usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
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 })
8710
8982
  ] }),
8711
- show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
8712
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
8713
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Name", htmlFor: `${idBase}-series-name`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCommitInput, { id: `${idBase}-series-name`, value: selectedSeries.name, "data-option": "series.name", className: chartInputClass, onCommit: (name) => void controller.updateSeries(selectedSeries.id, { name }) }) }),
8714
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Colour", htmlFor: `${idBase}-series-color`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-1", children: [
8715
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
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)(
8716
8988
  "input",
8717
8989
  {
8718
8990
  id: `${idBase}-series-color`,
@@ -8725,9 +8997,9 @@ function ChartInspector({ controller, sections, className }) {
8725
8997
  onChange: (e) => controller.updateSeries(selectedSeries.id, { color: e.currentTarget.value })
8726
8998
  }
8727
8999
  ),
8728
- selectedSeries.color && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "reset-color", onClick: () => controller.updateSeries(selectedSeries.id, { color: null }), children: "Palette" })
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" })
8729
9001
  ] }) }),
8730
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9002
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
8731
9003
  "select",
8732
9004
  {
8733
9005
  id: `${idBase}-series-type`,
@@ -8736,12 +9008,12 @@ function ChartInspector({ controller, sections, className }) {
8736
9008
  "data-option": "series.type",
8737
9009
  onChange: (e) => controller.updateSeries(selectedSeries.id, { type: e.currentTarget.value || null }),
8738
9010
  children: [
8739
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "Chart type" }),
8740
- import_chart4.CHART_SERIES_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: t, children: import_chart4.CHART_TYPE_LABELS[t] }, t))
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))
8741
9013
  ]
8742
9014
  }
8743
9015
  ) }),
8744
- (cartesian || family === "xy") && ["line", "area", "scatter"].includes((0, import_chart4.chartSeriesType)(spec, selectedSeries)) && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Field, { label: "Marker", htmlFor: `${idBase}-series-marker`, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
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)(
8745
9017
  "select",
8746
9018
  {
8747
9019
  id: `${idBase}-series-marker`,
@@ -8750,20 +9022,20 @@ function ChartInspector({ controller, sections, className }) {
8750
9022
  "data-option": "series.marker",
8751
9023
  onChange: (e) => controller.updateSeries(selectedSeries.id, { marker: e.currentTarget.value || null }),
8752
9024
  children: [
8753
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "Default" }),
8754
- import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: m, children: cap(m) }, m))
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))
8755
9027
  ]
8756
9028
  }
8757
9029
  ) }),
8758
- scales && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
8759
- family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
8760
- (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
8761
- (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
8762
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
8763
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "R\xB2", name: `trendline.${i}.showR2`, checked: !!t.showR2, onChange: (showR2) => controller.updateTrendline(selectedSeries.id, i, { showR2 }) }),
8764
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartButtonClass, "aria-label": "Delete trendline", "data-action": "trendline-delete", onClick: () => controller.removeTrendline(selectedSeries.id, i), children: "\xD7" })
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" })
8765
9037
  ] }, i)),
8766
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9038
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
8767
9039
  "select",
8768
9040
  {
8769
9041
  className: chartInputClass,
@@ -8772,32 +9044,32 @@ function ChartInspector({ controller, sections, className }) {
8772
9044
  "data-option": "trendline.add",
8773
9045
  onChange: (e) => e.currentTarget.value && controller.addTrendline(selectedSeries.id, { type: e.currentTarget.value }),
8774
9046
  children: [
8775
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "Add trendline\u2026" }),
8776
- import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
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))
8777
9049
  ]
8778
9050
  }
8779
9051
  )
8780
9052
  ] }),
8781
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
8782
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
8783
- family === "cartesian" && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Toggle, { label: "Secondary axis", name: "series.axis", checked: selectedSeries.axis === "secondary", onChange: (secondary) => controller.updateSeries(selectedSeries.id, { axis: secondary ? "secondary" : null }) }),
8784
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex-1" }),
8785
- /* @__PURE__ */ (0, import_jsx_runtime43.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" }),
8786
- /* @__PURE__ */ (0, import_jsx_runtime43.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" }),
8787
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: `${chartButtonClass} text-destructive`, "data-action": "series-delete", onClick: () => controller.removeSeries(selectedSeries.id), children: "Delete" })
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" })
8788
9060
  ] })
8789
9061
  ] })
8790
9062
  ] });
8791
9063
  }
8792
9064
 
8793
9065
  // src/chart-node/ChartNodeView.tsx
8794
- var import_jsx_runtime44 = require("react/jsx-runtime");
9066
+ var import_jsx_runtime45 = require("react/jsx-runtime");
8795
9067
  function ChartNodeView({ state, theme, showDataGrid = true }) {
8796
9068
  const { controller, editing, editable, selected, width, height, setEditing } = state;
8797
9069
  const open = () => {
8798
9070
  if (editable && !editing) setEditing(true);
8799
9071
  };
8800
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
9072
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
8801
9073
  "div",
8802
9074
  {
8803
9075
  className: `not-prose my-2 rounded-md border bg-background p-1 ${selected ? "border-primary ring-1 ring-primary" : "border-border"}`,
@@ -8810,24 +9082,24 @@ function ChartNodeView({ state, theme, showDataGrid = true }) {
8810
9082
  }
8811
9083
  },
8812
9084
  children: [
8813
- editing && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "mb-1 flex items-center justify-between gap-2 px-1", "data-chart-node-toolbar": "", children: [
8814
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
8815
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
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" })
8816
9088
  ] }),
8817
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9089
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8818
9090
  "div",
8819
9091
  {
8820
9092
  className: editable && !editing ? "cursor-pointer" : void 0,
8821
9093
  onClick: open,
8822
9094
  title: editable && !editing ? "Click to edit the chart" : void 0,
8823
9095
  "data-chart-node-canvas": "",
8824
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
9096
+ children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
8825
9097
  }
8826
9098
  ),
8827
9099
  editing && // Wraps by the document's width, not the viewport's: side by side when there is room.
8828
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
8829
- showDataGrid && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "min-w-0 flex-[1_1_20rem] overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartDataGrid, { controller }) }),
8830
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChartInspector, { controller, className: "max-h-96 min-w-0 flex-[1_1_16rem] overflow-y-auto rounded-md border border-border p-3" })
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" })
8831
9103
  ] })
8832
9104
  ]
8833
9105
  }
@@ -8845,7 +9117,7 @@ function createReactChartNodeView(options = {}) {
8845
9117
  scheduled = true;
8846
9118
  queueMicrotask(() => {
8847
9119
  scheduled = false;
8848
- if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Component, { ...props, state: latest }));
9120
+ if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Component, { ...props, state: latest }));
8849
9121
  });
8850
9122
  };
8851
9123
  schedule();
@@ -8879,6 +9151,7 @@ function createReactChartNodeView(options = {}) {
8879
9151
  ExportDocxButton,
8880
9152
  FindReplaceBar,
8881
9153
  FormulaHints,
9154
+ FreeTransformOptionsBar,
8882
9155
  GenerationHistory,
8883
9156
  GenerationSettings,
8884
9157
  Histogram,