@pixerate/editor-react 0.58.0 → 0.60.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
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AdjustmentLayersPanel: () => AdjustmentLayersPanel,
34
34
  AssetMentionChips: () => AssetMentionChips,
35
+ BrushOptionsBar: () => BrushOptionsBar,
35
36
  BubbleMenu: () => BubbleMenu,
36
37
  ChartNodeView: () => ChartNodeView,
37
38
  CommandPalette: () => CommandPalette,
@@ -52,6 +53,7 @@ __export(src_exports, {
52
53
  ImageEditor: () => ImageEditor,
53
54
  InsertTableGrid: () => InsertTableGrid,
54
55
  JobProgress: () => JobProgress,
56
+ LayersPanel: () => LayersPanel,
55
57
  MergePreview: () => MergePreview,
56
58
  NameManager: () => NameManager,
57
59
  OutlinePanel: () => OutlinePanel,
@@ -3718,11 +3720,11 @@ function useImageEditor(options = {}) {
3718
3720
  [controller]
3719
3721
  );
3720
3722
  const applyInpaintedImage = (0, import_react34.useCallback)(
3721
- (newDataUrl) => controller.applyInpaintedImage(newDataUrl),
3723
+ (newDataUrl, options2) => controller.applyInpaintedImage(newDataUrl, options2),
3722
3724
  [controller]
3723
3725
  );
3724
3726
  const applyBackgroundRemovedImage = (0, import_react34.useCallback)(
3725
- (newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
3727
+ (newDataUrl, options2) => controller.applyBackgroundRemovedImage(newDataUrl, options2),
3726
3728
  [controller]
3727
3729
  );
3728
3730
  return (0, import_react34.useMemo)(
@@ -3781,8 +3783,8 @@ function useImageEditor(options = {}) {
3781
3783
  }
3782
3784
 
3783
3785
  // src/image-editor/ImageEditor.tsx
3784
- var import_react40 = __toESM(require("react"), 1);
3785
- var import_image_editor8 = require("@pixerate/editor/image-editor");
3786
+ var import_react42 = __toESM(require("react"), 1);
3787
+ var import_image_editor10 = require("@pixerate/editor/image-editor");
3786
3788
 
3787
3789
  // src/image-editor/ControlSlider.tsx
3788
3790
  var import_image_editor2 = require("@pixerate/editor/image-editor");
@@ -4213,10 +4215,492 @@ var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
4213
4215
  ] });
4214
4216
  };
4215
4217
 
4216
- // src/image-editor/SelectionOptionsBar.tsx
4218
+ // src/image-editor/LayersPanel.tsx
4217
4219
  var import_react38 = require("react");
4218
4220
  var import_image_editor6 = require("@pixerate/editor/image-editor");
4219
4221
  var import_jsx_runtime21 = require("react/jsx-runtime");
4222
+ var iconButton = "px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 hover:text-white disabled:opacity-40";
4223
+ var rowClass = (active) => `flex items-center gap-1.5 px-1.5 py-1 rounded cursor-pointer select-none ${active ? "bg-indigo-600/30 ring-1 ring-indigo-500" : "hover:bg-slate-800"}`;
4224
+ var Thumbnail = ({
4225
+ pixels,
4226
+ size,
4227
+ label,
4228
+ onClick,
4229
+ selected,
4230
+ testId
4231
+ }) => {
4232
+ const ref = (0, import_react38.useRef)(null);
4233
+ (0, import_react38.useEffect)(() => {
4234
+ const canvas = ref.current;
4235
+ const ctx = canvas?.getContext("2d");
4236
+ if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== "function") return;
4237
+ canvas.width = pixels.width;
4238
+ canvas.height = pixels.height;
4239
+ const img = ctx.createImageData(pixels.width, pixels.height);
4240
+ img.data.set(pixels.data);
4241
+ ctx.putImageData(img, 0, 0);
4242
+ }, [pixels]);
4243
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4244
+ "canvas",
4245
+ {
4246
+ ref,
4247
+ role: onClick ? "button" : "img",
4248
+ "aria-label": label,
4249
+ "data-testid": testId,
4250
+ onClick,
4251
+ style: { width: size, height: size },
4252
+ className: `shrink-0 rounded bg-[repeating-conic-gradient(#334155_0%_25%,#1e293b_0%_50%)] [background-size:8px_8px] object-contain ${selected ? "ring-2 ring-white" : "ring-1 ring-slate-700"}`
4253
+ }
4254
+ );
4255
+ };
4256
+ var LayersPanel = ({ controller, thumbnailSize = 32, psd = true, psdFileName = "image", className }) => {
4257
+ const [, setTick] = (0, import_react38.useState)(0);
4258
+ (0, import_react38.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
4259
+ const [error, setError] = (0, import_react38.useState)(null);
4260
+ const [renaming, setRenaming] = (0, import_react38.useState)(null);
4261
+ const [menu, setMenu] = (0, import_react38.useState)(null);
4262
+ const [drag, setDrag] = (0, import_react38.useState)(null);
4263
+ const [psdNotes, setPsdNotes] = (0, import_react38.useState)([]);
4264
+ const fileInput = (0, import_react38.useRef)(null);
4265
+ const psdTask = async (fn) => {
4266
+ try {
4267
+ setError(null);
4268
+ setPsdNotes(await fn());
4269
+ } catch (err) {
4270
+ setError(err instanceof Error ? err.message : String(err));
4271
+ }
4272
+ };
4273
+ const commitNext = (0, import_react38.useRef)(true);
4274
+ const state = controller.getState();
4275
+ const rows = (0, import_image_editor6.layerPanelRows)(state.layers, state.activeLayerId);
4276
+ const active = controller.getActiveLayer();
4277
+ const attempt = (fn) => {
4278
+ try {
4279
+ setError(null);
4280
+ fn();
4281
+ } catch (err) {
4282
+ setError(err instanceof Error ? err.message : String(err));
4283
+ }
4284
+ };
4285
+ const run = async (action) => {
4286
+ setMenu(null);
4287
+ setError(await (0, import_image_editor6.runLayerMenuAction)(controller, action));
4288
+ };
4289
+ const prop = (key, value) => attempt(() => {
4290
+ controller.setLayerProperties(active.id, { [key]: value }, commitNext.current);
4291
+ commitNext.current = false;
4292
+ });
4293
+ const sliderEvents = {
4294
+ onPointerDown: () => commitNext.current = true,
4295
+ onPointerUp: () => commitNext.current = true,
4296
+ onKeyDown: () => commitNext.current = true
4297
+ };
4298
+ const onDrop = (e, row) => {
4299
+ e.preventDefault();
4300
+ const id = e.dataTransfer.getData("text/x-pixerate-layer") || drag;
4301
+ setDrag(null);
4302
+ if (!id) return;
4303
+ const rect = e.currentTarget.getBoundingClientRect();
4304
+ const fraction = rect.height ? (e.clientY - rect.top) / rect.height : 0.5;
4305
+ const placement = (0, import_image_editor6.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor6.dropZone)(fraction, row.layer.type === "group"));
4306
+ if (placement) attempt(() => controller.moveLayer(id, placement));
4307
+ };
4308
+ const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
4309
+ const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
4310
+ const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
4311
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "layers-panel", onClick: () => menu && setMenu(null), children: [
4312
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
4313
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
4314
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
4315
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
4316
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
4317
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
4318
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4319
+ "button",
4320
+ {
4321
+ type: "button",
4322
+ className: iconButton,
4323
+ "aria-label": "Layer menu",
4324
+ "aria-haspopup": "menu",
4325
+ onClick: (e) => {
4326
+ e.stopPropagation();
4327
+ const r = e.currentTarget.getBoundingClientRect();
4328
+ setMenu(menu ? null : { x: r.left, y: r.bottom });
4329
+ },
4330
+ children: "\u22EF"
4331
+ }
4332
+ ),
4333
+ psd && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
4334
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => fileInput.current?.click(), children: "Open PSD\u2026" }),
4335
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => psdTask(async () => (await (0, import_image_editor6.downloadPsd)(controller, psdFileName)).warnings), children: "Export PSD" }),
4336
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4337
+ "input",
4338
+ {
4339
+ ref: fileInput,
4340
+ type: "file",
4341
+ accept: import_image_editor6.PSD_FILE_ACCEPT,
4342
+ className: "hidden",
4343
+ "data-testid": "psd-file-input",
4344
+ "aria-label": "Open a PSD file",
4345
+ onChange: (e) => {
4346
+ const file = e.currentTarget.files?.[0];
4347
+ e.currentTarget.value = "";
4348
+ if (file) psdTask(() => (0, import_image_editor6.openPsdFile)(controller, file));
4349
+ }
4350
+ }
4351
+ )
4352
+ ] })
4353
+ ] }),
4354
+ psdNotes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("ul", { className: "rounded bg-amber-900/30 text-amber-200 px-2 py-1 space-y-0.5", "data-testid": "psd-warnings", "aria-label": "PSD warnings", children: [
4355
+ psdNotes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { children: n }, n)),
4356
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: "underline", onClick: () => setPsdNotes([]), children: "Dismiss" }) })
4357
+ ] }),
4358
+ active && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "grid grid-cols-2 gap-x-2 gap-y-1 items-center", "data-testid": "layer-properties", children: [
4359
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
4360
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-slate-400", children: [
4361
+ "Opacity ",
4362
+ Math.round(active.opacity * 100),
4363
+ "%"
4364
+ ] }),
4365
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4366
+ "input",
4367
+ {
4368
+ type: "range",
4369
+ min: 0,
4370
+ max: 100,
4371
+ "aria-label": "Layer opacity",
4372
+ value: Math.round(active.opacity * 100),
4373
+ ...sliderEvents,
4374
+ onChange: (e) => prop("opacity", Number(e.target.value) / 100),
4375
+ className: "accent-indigo-500"
4376
+ }
4377
+ )
4378
+ ] }),
4379
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
4380
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-slate-400", children: [
4381
+ "Fill ",
4382
+ Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
4383
+ "%"
4384
+ ] }),
4385
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4386
+ "input",
4387
+ {
4388
+ type: "range",
4389
+ min: 0,
4390
+ max: 100,
4391
+ "aria-label": "Layer fill",
4392
+ disabled: active.type !== "pixel",
4393
+ value: Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
4394
+ ...sliderEvents,
4395
+ onChange: (e) => prop("fillOpacity", Number(e.target.value) / 100),
4396
+ className: "accent-indigo-500 disabled:opacity-40"
4397
+ }
4398
+ )
4399
+ ] }),
4400
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4401
+ "select",
4402
+ {
4403
+ "aria-label": "Layer blend mode",
4404
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
4405
+ value: active.blend,
4406
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
4407
+ children: [
4408
+ active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "pass-through", children: "Pass Through" }),
4409
+ import_image_editor6.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: m.id, children: m.label }, m.id))
4410
+ ]
4411
+ }
4412
+ ),
4413
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
4414
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4415
+ "input",
4416
+ {
4417
+ type: "checkbox",
4418
+ "aria-label": "Clip to layer below",
4419
+ checked: Boolean(active.clipped),
4420
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { clipped: e.target.checked })),
4421
+ className: "accent-indigo-500"
4422
+ }
4423
+ ),
4424
+ "Clip to below"
4425
+ ] }),
4426
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "col-span-2 flex flex-wrap gap-2 text-slate-400", role: "group", "aria-label": "Layer locks", children: ["pixels", "transparency", "position", "all"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-1", children: [
4427
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4428
+ "input",
4429
+ {
4430
+ type: "checkbox",
4431
+ "aria-label": `Lock ${k}`,
4432
+ checked: Boolean(active.locks?.[k]),
4433
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { locks: { ...active.locks, [k]: e.target.checked } })),
4434
+ className: "accent-indigo-500"
4435
+ }
4436
+ ),
4437
+ k
4438
+ ] }, k)) })
4439
+ ] }),
4440
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
4441
+ const { layer } = row;
4442
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4443
+ "li",
4444
+ {
4445
+ role: "treeitem",
4446
+ "aria-selected": row.active,
4447
+ "aria-level": row.depth + 1,
4448
+ "data-layer-id": layer.id,
4449
+ draggable: !layer.locks?.all,
4450
+ onDragStart: (e) => {
4451
+ e.dataTransfer.setData("text/x-pixerate-layer", layer.id);
4452
+ setDrag(layer.id);
4453
+ },
4454
+ onDragOver: (e) => e.preventDefault(),
4455
+ onDrop: (e) => onDrop(e, row),
4456
+ tabIndex: 0,
4457
+ onClick: () => attempt(() => controller.setActiveLayer(layer.id, "pixels")),
4458
+ onKeyDown: (e) => {
4459
+ if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
4460
+ e.preventDefault();
4461
+ attempt(() => controller.setActiveLayer(layer.id, "pixels"));
4462
+ }
4463
+ },
4464
+ onContextMenu: (e) => {
4465
+ e.preventDefault();
4466
+ controller.setActiveLayer(layer.id, state.activeLayerId === layer.id ? state.activeTarget : "pixels");
4467
+ setMenu({ x: e.clientX, y: e.clientY });
4468
+ },
4469
+ className: rowClass(row.active),
4470
+ style: { paddingLeft: 6 + row.depth * 14 },
4471
+ children: [
4472
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4473
+ "button",
4474
+ {
4475
+ type: "button",
4476
+ "aria-label": layer.visible ? `Hide ${row.label}` : `Show ${row.label}`,
4477
+ "aria-pressed": layer.visible,
4478
+ className: "w-4 text-center text-slate-300",
4479
+ onClick: (e) => {
4480
+ e.stopPropagation();
4481
+ attempt(() => controller.setLayerProperties(layer.id, { visible: !layer.visible }));
4482
+ },
4483
+ children: layer.visible ? "\u25CF" : "\u25CB"
4484
+ }
4485
+ ),
4486
+ layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4487
+ "button",
4488
+ {
4489
+ type: "button",
4490
+ "aria-label": layer.collapsed ? `Expand ${row.label}` : `Collapse ${row.label}`,
4491
+ className: "w-3 text-slate-400",
4492
+ onClick: (e) => {
4493
+ e.stopPropagation();
4494
+ attempt(() => controller.setLayerProperties(layer.id, { collapsed: !layer.collapsed }));
4495
+ },
4496
+ children: layer.collapsed ? "\u25B8" : "\u25BE"
4497
+ }
4498
+ ),
4499
+ row.clipped && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
4500
+ layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4501
+ Thumbnail,
4502
+ {
4503
+ pixels: thumb(layer),
4504
+ size: thumbnailSize,
4505
+ label: `${row.label} pixels`,
4506
+ selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
4507
+ }
4508
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4509
+ "span",
4510
+ {
4511
+ className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
4512
+ style: { width: thumbnailSize, height: thumbnailSize },
4513
+ children: (0, import_image_editor6.layerBadge)(layer)
4514
+ }
4515
+ ),
4516
+ layer.mask && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4517
+ Thumbnail,
4518
+ {
4519
+ pixels: maskThumb(layer),
4520
+ size: thumbnailSize,
4521
+ label: `${row.label} mask${layer.mask.enabled === false ? " (disabled)" : ""}`,
4522
+ testId: "layer-mask-thumbnail",
4523
+ selected: row.active && state.activeTarget === "mask",
4524
+ onClick: (e) => {
4525
+ e.stopPropagation();
4526
+ if (e.shiftKey) attempt(() => controller.setLayerMaskProps(layer.id, { enabled: layer.mask.enabled === false }));
4527
+ else attempt(() => controller.setActiveLayer(layer.id, "mask"));
4528
+ }
4529
+ }
4530
+ ),
4531
+ renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4532
+ "input",
4533
+ {
4534
+ autoFocus: true,
4535
+ "aria-label": "Layer name",
4536
+ defaultValue: layer.name || row.label,
4537
+ className: "flex-1 min-w-0 bg-slate-900 border border-slate-600 rounded px-1",
4538
+ onClick: (e) => e.stopPropagation(),
4539
+ onBlur: (e) => {
4540
+ setRenaming(null);
4541
+ if (e.target.value.trim() && e.target.value !== layer.name) attempt(() => controller.setLayerProperties(layer.id, { name: e.target.value }));
4542
+ },
4543
+ onKeyDown: (e) => {
4544
+ if (e.key === "Enter") e.target.blur();
4545
+ if (e.key === "Escape") setRenaming(null);
4546
+ }
4547
+ }
4548
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4549
+ "span",
4550
+ {
4551
+ className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
4552
+ onDoubleClick: (e) => {
4553
+ e.stopPropagation();
4554
+ setRenaming(layer.id);
4555
+ },
4556
+ children: row.label
4557
+ }
4558
+ ),
4559
+ locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
4560
+ layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
4561
+ ]
4562
+ },
4563
+ layer.id
4564
+ );
4565
+ }) }),
4566
+ error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
4567
+ menu && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4568
+ "div",
4569
+ {
4570
+ role: "menu",
4571
+ "aria-label": "Layer menu",
4572
+ className: "fixed z-50 min-w-44 rounded border border-slate-700 bg-slate-900 py-1 shadow-xl",
4573
+ style: { left: menu.x, top: menu.y },
4574
+ onClick: (e) => e.stopPropagation(),
4575
+ onKeyDown: (e) => e.key === "Escape" && setMenu(null),
4576
+ children: (0, import_image_editor6.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4577
+ "button",
4578
+ {
4579
+ type: "button",
4580
+ role: "menuitem",
4581
+ disabled: !item.enabled,
4582
+ className: "block w-full px-3 py-1 text-left hover:bg-slate-800 disabled:opacity-40",
4583
+ onClick: () => run(item.action),
4584
+ children: item.label
4585
+ },
4586
+ item.action
4587
+ ))
4588
+ }
4589
+ )
4590
+ ] });
4591
+ };
4592
+
4593
+ // src/image-editor/BrushOptionsBar.tsx
4594
+ var import_react39 = require("react");
4595
+ var import_image_editor7 = require("@pixerate/editor/image-editor");
4596
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4597
+ var chip = (on) => `px-2 py-1 rounded text-[11px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-300 hover:text-white"}`;
4598
+ var BrushOptionsBar = ({ controller, className }) => {
4599
+ const [, setTick] = (0, import_react39.useState)(0);
4600
+ (0, import_react39.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
4601
+ const [error, setError] = (0, import_react39.useState)(null);
4602
+ const state = controller.getState();
4603
+ const { brush, foreground, background } = state.paint;
4604
+ const attempt = (fn) => {
4605
+ try {
4606
+ setError(null);
4607
+ fn();
4608
+ } catch (err) {
4609
+ setError(err instanceof Error ? err.message : String(err));
4610
+ }
4611
+ };
4612
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `flex flex-col gap-2 text-xs text-slate-200 ${className ?? ""}`, "data-testid": "brush-options", children: [
4613
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex gap-1", role: "toolbar", "aria-label": "Paint tools", children: import_image_editor7.PAINT_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4614
+ "button",
4615
+ {
4616
+ type: "button",
4617
+ "aria-pressed": state.activeTool === t.id,
4618
+ title: `${t.label} (${t.shortcut})`,
4619
+ className: chip(state.activeTool === t.id),
4620
+ onClick: () => controller.setTool(t.id),
4621
+ children: t.label
4622
+ },
4623
+ t.id
4624
+ )) }),
4625
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
4626
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1", children: [
4627
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4628
+ "input",
4629
+ {
4630
+ type: "color",
4631
+ "aria-label": "Foreground colour",
4632
+ value: foreground,
4633
+ onChange: (e) => controller.setPaintOptions({ foreground: e.target.value }),
4634
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
4635
+ }
4636
+ ),
4637
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-slate-400", children: "FG" })
4638
+ ] }),
4639
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1", children: [
4640
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4641
+ "input",
4642
+ {
4643
+ type: "color",
4644
+ "aria-label": "Background colour",
4645
+ value: background,
4646
+ onChange: (e) => controller.setPaintOptions({ background: e.target.value }),
4647
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
4648
+ }
4649
+ ),
4650
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-slate-400", children: "BG" })
4651
+ ] }),
4652
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
4653
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
4654
+ ] }),
4655
+ import_image_editor7.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4656
+ ControlSlider,
4657
+ {
4658
+ spec,
4659
+ value: brush[spec.id],
4660
+ onChange: (v) => controller.setPaintOptions({ brush: { [spec.id]: v } })
4661
+ },
4662
+ spec.id
4663
+ )),
4664
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
4665
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4666
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4667
+ "input",
4668
+ {
4669
+ type: "checkbox",
4670
+ "aria-label": "Pressure controls size",
4671
+ checked: brush.pressureSize,
4672
+ onChange: (e) => controller.setPaintOptions({ brush: { pressureSize: e.target.checked } }),
4673
+ className: "accent-indigo-500"
4674
+ }
4675
+ ),
4676
+ "Pressure size"
4677
+ ] }),
4678
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4679
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4680
+ "input",
4681
+ {
4682
+ type: "checkbox",
4683
+ "aria-label": "Pressure controls opacity",
4684
+ checked: brush.pressureOpacity,
4685
+ onChange: (e) => controller.setPaintOptions({ brush: { pressureOpacity: e.target.checked } }),
4686
+ className: "accent-indigo-500"
4687
+ }
4688
+ ),
4689
+ "Pressure opacity"
4690
+ ] })
4691
+ ] }),
4692
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex gap-1", children: [
4693
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
4694
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
4695
+ ] }),
4696
+ error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
4697
+ ] });
4698
+ };
4699
+
4700
+ // src/image-editor/SelectionOptionsBar.tsx
4701
+ var import_react40 = require("react");
4702
+ var import_image_editor8 = require("@pixerate/editor/image-editor");
4703
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4220
4704
  var MODIFY_OPS = [
4221
4705
  { op: "grow", label: "Grow" },
4222
4706
  { op: "shrink", label: "Shrink" },
@@ -4233,20 +4717,20 @@ var SelectionOptionsBar = ({
4233
4717
  quickMask,
4234
4718
  className = ""
4235
4719
  }) => {
4236
- const [radius, setRadius] = (0, import_react38.useState)(2);
4720
+ const [radius, setRadius] = (0, import_react40.useState)(2);
4237
4721
  const set = (patch) => onOptionsChange({ ...options, ...patch });
4238
4722
  const sel = selection === void 0 ? controller.getSelection() : selection;
4239
4723
  const qm = quickMask ?? Boolean(controller.getState().quickMask);
4240
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4241
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor6.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
4242
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor6.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor6.SELECTION_MODE_LABELS[m] }, m)) }),
4243
- options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-2", children: [
4244
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex flex-col gap-1", children: [
4245
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4246
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Tolerance" }),
4247
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "font-mono", children: options.tolerance })
4724
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4725
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "group", "aria-label": "Selection tool", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_TOOLS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", "aria-pressed": options.tool === t.id, className: btn(options.tool === t.id), onClick: () => set({ tool: t.id }), children: t.label }, t.id)) }),
4726
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "group", "aria-label": "Selection mode", className: "flex flex-wrap gap-1", children: import_image_editor8.SELECTION_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", "aria-pressed": options.mode === m, className: btn(options.mode === m), onClick: () => set({ mode: m }), children: import_image_editor8.SELECTION_MODE_LABELS[m] }, m)) }),
4727
+ options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-2", children: [
4728
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex flex-col gap-1", children: [
4729
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4730
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Tolerance" }),
4731
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-mono", children: options.tolerance })
4248
4732
  ] }),
4249
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4733
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4250
4734
  "input",
4251
4735
  {
4252
4736
  type: "range",
@@ -4260,29 +4744,45 @@ var SelectionOptionsBar = ({
4260
4744
  }
4261
4745
  )
4262
4746
  ] }),
4263
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4264
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
4747
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4748
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
4265
4749
  "Contiguous"
4266
4750
  ] }),
4267
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4268
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
4751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4752
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
4269
4753
  "Sample adjusted image"
4754
+ ] }),
4755
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4756
+ "Sample",
4757
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4758
+ "select",
4759
+ {
4760
+ "aria-label": "Sample from",
4761
+ value: options.sample ?? "composite",
4762
+ onChange: (e) => set({ sample: e.target.value }),
4763
+ className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5",
4764
+ children: [
4765
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "composite", children: "All layers" }),
4766
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "active-layer", children: "Active layer" })
4767
+ ]
4768
+ }
4769
+ )
4270
4770
  ] })
4271
4771
  ] }),
4272
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4273
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
4772
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4773
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
4274
4774
  "Anti-alias"
4275
4775
  ] }),
4276
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4277
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
4278
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
4279
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
4280
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
4776
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4777
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
4778
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
4779
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
4780
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
4281
4781
  ] }),
4282
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
4283
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
4782
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
4783
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
4284
4784
  "Radius",
4285
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4785
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4286
4786
  "input",
4287
4787
  {
4288
4788
  type: "number",
@@ -4296,24 +4796,24 @@ var SelectionOptionsBar = ({
4296
4796
  }
4297
4797
  )
4298
4798
  ] }),
4299
- MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
4799
+ MODIFY_OPS.map(({ op, label }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.modifySelection(op, radius), children: label }, op))
4300
4800
  ] }),
4301
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor6.describeSelection)(sel) })
4801
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor8.describeSelection)(sel) })
4302
4802
  ] });
4303
4803
  };
4304
4804
 
4305
4805
  // src/image-editor/RefineEdgePanel.tsx
4306
- var import_react39 = require("react");
4307
- var import_image_editor7 = require("@pixerate/editor/image-editor");
4308
- var import_jsx_runtime22 = require("react/jsx-runtime");
4806
+ var import_react41 = require("react");
4807
+ var import_image_editor9 = require("@pixerate/editor/image-editor");
4808
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4309
4809
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
4310
4810
  var button = "px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40";
4311
4811
  var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4312
- const [params, setParams] = (0, import_react39.useState)(DEFAULT_PARAMS);
4313
- const [busy, setBusy] = (0, import_react39.useState)(false);
4314
- const [error, setError] = (0, import_react39.useState)(null);
4315
- const [layerId, setLayerId] = (0, import_react39.useState)("");
4316
- const [newKind, setNewKind] = (0, import_react39.useState)("hueSaturation");
4812
+ const [params, setParams] = (0, import_react41.useState)(DEFAULT_PARAMS);
4813
+ const [busy, setBusy] = (0, import_react41.useState)(false);
4814
+ const [error, setError] = (0, import_react41.useState)(null);
4815
+ const [layerId, setLayerId] = (0, import_react41.useState)("");
4816
+ const [newKind, setNewKind] = (0, import_react41.useState)("hueSaturation");
4317
4817
  const sel = selection === void 0 ? controller.getSelection() : selection;
4318
4818
  const list = layers ?? controller.getAdjustmentLayers();
4319
4819
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -4328,17 +4828,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4328
4828
  setBusy(false);
4329
4829
  }
4330
4830
  };
4331
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4332
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
4333
- import_image_editor7.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex flex-col gap-1", children: [
4334
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4335
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: c.label }),
4336
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "font-mono", children: [
4831
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4832
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
4833
+ import_image_editor9.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4834
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4835
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: c.label }),
4836
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4337
4837
  params[c.id],
4338
4838
  c.unit
4339
4839
  ] })
4340
4840
  ] }),
4341
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4841
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4342
4842
  "input",
4343
4843
  {
4344
4844
  type: "range",
@@ -4352,67 +4852,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4352
4852
  }
4353
4853
  )
4354
4854
  ] }, c.id)),
4355
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4356
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
4855
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4856
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
4357
4857
  "Smart Radius"
4358
4858
  ] }),
4359
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex gap-1", children: [
4360
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
4361
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
4859
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex gap-1", children: [
4860
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
4861
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
4362
4862
  ] }),
4363
- error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
4364
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
4365
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex gap-1 items-center", children: [
4366
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4863
+ error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
4864
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
4865
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex gap-1 items-center", children: [
4866
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4367
4867
  "select",
4368
4868
  {
4369
4869
  "aria-label": "New masked layer kind",
4370
4870
  value: newKind,
4371
4871
  onChange: (e) => setNewKind(e.target.value),
4372
4872
  className: "flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
4373
- children: import_image_editor7.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: k.kind, children: k.label }, k.kind))
4873
+ children: import_image_editor9.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: k.kind, children: k.label }, k.kind))
4374
4874
  }
4375
4875
  ),
4376
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4876
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4377
4877
  "button",
4378
4878
  {
4379
4879
  type: "button",
4380
4880
  className: button,
4381
4881
  disabled: !sel,
4382
- onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor7.layerMaskFromSelection)(sel) })),
4882
+ onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor9.layerMaskFromSelection)(sel) })),
4383
4883
  children: "New Masked Layer"
4384
4884
  }
4385
4885
  )
4386
4886
  ] }),
4387
- list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-2", children: [
4388
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4887
+ list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-2", children: [
4888
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4389
4889
  "select",
4390
4890
  {
4391
4891
  "aria-label": "Mask layer",
4392
4892
  value: target.id,
4393
4893
  onChange: (e) => setLayerId(e.target.value),
4394
4894
  className: "bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200",
4395
- children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("option", { value: l.id, children: [
4396
- l.name || (0, import_image_editor7.adjustmentKindLabel)(l.kind),
4895
+ children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("option", { value: l.id, children: [
4896
+ l.name || (0, import_image_editor9.adjustmentKindLabel)(l.kind),
4397
4897
  l.mask ? " (masked)" : ""
4398
4898
  ] }, l.id))
4399
4899
  }
4400
4900
  ),
4401
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4402
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
4403
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
4404
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
4901
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4902
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
4903
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
4904
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
4405
4905
  ] }),
4406
- target.mask && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4407
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex flex-col gap-1", children: [
4408
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4409
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: "Density" }),
4410
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "font-mono", children: [
4906
+ target.mask && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4907
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4908
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4909
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Density" }),
4910
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4411
4911
  Math.round((target.mask.density ?? 1) * 100),
4412
4912
  "%"
4413
4913
  ] })
4414
4914
  ] }),
4415
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4915
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4416
4916
  "input",
4417
4917
  {
4418
4918
  type: "range",
@@ -4426,15 +4926,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4426
4926
  }
4427
4927
  )
4428
4928
  ] }),
4429
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex flex-col gap-1", children: [
4430
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4431
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: "Mask Feather" }),
4432
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "font-mono", children: [
4929
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4930
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4931
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Mask Feather" }),
4932
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4433
4933
  target.mask.feather ?? 0,
4434
4934
  "px"
4435
4935
  ] })
4436
4936
  ] }),
4437
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4937
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4438
4938
  "input",
4439
4939
  {
4440
4940
  type: "range",
@@ -4454,7 +4954,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4454
4954
  };
4455
4955
 
4456
4956
  // src/image-editor/ImageEditor.tsx
4457
- var import_jsx_runtime23 = require("react/jsx-runtime");
4957
+ var import_jsx_runtime25 = require("react/jsx-runtime");
4458
4958
  var ImageEditor = ({
4459
4959
  editor: externalEditor,
4460
4960
  src,
@@ -4469,26 +4969,36 @@ var ImageEditor = ({
4469
4969
  const internalEditor = useImageEditor({ image: src });
4470
4970
  const editor = externalEditor || internalEditor;
4471
4971
  const { state, controller } = editor;
4472
- const legacyProcess = (0, import_image_editor8.normalizeProcessVersion)(state.adjustments.process) < import_image_editor8.LATEST_PROCESS_VERSION;
4473
- const canvasRef = (0, import_react40.useRef)(null);
4474
- const containerRef = (0, import_react40.useRef)(null);
4475
- const [activeTab, setActiveTab] = (0, import_react40.useState)("crop");
4476
- const [activeCropRatio, setActiveCropRatio] = (0, import_react40.useState)(null);
4477
- const [selectionOptions, setSelectionOptions] = (0, import_react40.useState)(import_image_editor8.DEFAULT_SELECTION_TOOL_OPTIONS);
4478
- const selectionOptionsRef = (0, import_react40.useRef)(selectionOptions);
4972
+ const legacyProcess = (0, import_image_editor10.normalizeProcessVersion)(state.adjustments.process) < import_image_editor10.LATEST_PROCESS_VERSION;
4973
+ const canvasRef = (0, import_react42.useRef)(null);
4974
+ const containerRef = (0, import_react42.useRef)(null);
4975
+ const [activeTab, setActiveTab] = (0, import_react42.useState)("crop");
4976
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react42.useState)(null);
4977
+ const [selectionOptions, setSelectionOptions] = (0, import_react42.useState)(import_image_editor10.DEFAULT_SELECTION_TOOL_OPTIONS);
4978
+ const selectionOptionsRef = (0, import_react42.useRef)(selectionOptions);
4479
4979
  selectionOptionsRef.current = selectionOptions;
4480
- const selectionGestureRef = (0, import_react40.useRef)(null);
4980
+ const selectionGestureRef = (0, import_react42.useRef)(null);
4481
4981
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
4482
- selectionGestureRef.current = new import_image_editor8.SelectionGesture(controller, () => selectionOptionsRef.current);
4982
+ selectionGestureRef.current = new import_image_editor10.SelectionGesture(controller, () => selectionOptionsRef.current);
4483
4983
  }
4484
- const selectionDraftRef = (0, import_react40.useRef)(null);
4485
- const [selectionError, setSelectionError] = (0, import_react40.useState)(null);
4486
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react40.useState)("");
4487
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react40.useState)("annotations");
4488
- const [isRemovingBg, setIsRemovingBg] = (0, import_react40.useState)(false);
4489
- const [isInpainting, setIsInpainting] = (0, import_react40.useState)(false);
4490
- const [aiError, setAiError] = (0, import_react40.useState)(null);
4491
- const [aiSuccess, setAiSuccess] = (0, import_react40.useState)(null);
4984
+ const selectionDraftRef = (0, import_react42.useRef)(null);
4985
+ const [selectionError, setSelectionError] = (0, import_react42.useState)(null);
4986
+ const paintGestureRef = (0, import_react42.useRef)(null);
4987
+ const paintControllerRef = (0, import_react42.useRef)(controller);
4988
+ if (!paintGestureRef.current || paintControllerRef.current !== controller) {
4989
+ paintGestureRef.current = new import_image_editor10.PaintGesture(controller);
4990
+ paintControllerRef.current = controller;
4991
+ }
4992
+ const brushCursorRef = (0, import_react42.useRef)(null);
4993
+ const [paintError, setPaintError] = (0, import_react42.useState)(null);
4994
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react42.useState)("");
4995
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react42.useState)("annotations");
4996
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react42.useState)(false);
4997
+ const [isInpainting, setIsInpainting] = (0, import_react42.useState)(false);
4998
+ const [aiError, setAiError] = (0, import_react42.useState)(null);
4999
+ const [aiSuccess, setAiSuccess] = (0, import_react42.useState)(null);
5000
+ const [aiTarget, setAiTarget] = (0, import_react42.useState)("auto");
5001
+ const aiOptions = aiTarget === "auto" ? {} : { target: aiTarget };
4492
5002
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
4493
5003
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
4494
5004
  const handleRemoveBackground = async () => {
@@ -4500,10 +5010,10 @@ var ImageEditor = ({
4500
5010
  setAiSuccess(null);
4501
5011
  setIsRemovingBg(true);
4502
5012
  try {
4503
- const imageDataUrl = await editor.toSourceDataURL();
5013
+ const imageDataUrl = await controller.toAIInputDataURL(aiOptions);
4504
5014
  const result = await effectiveOnRemoveBg({ imageDataUrl });
4505
5015
  if (typeof result === "string") {
4506
- await editor.applyBackgroundRemovedImage(result);
5016
+ await editor.applyBackgroundRemovedImage(result, aiOptions);
4507
5017
  setAiSuccess("Background removed successfully!");
4508
5018
  } else {
4509
5019
  setAiSuccess("Background removal complete.");
@@ -4527,7 +5037,7 @@ var ImageEditor = ({
4527
5037
  setAiSuccess(null);
4528
5038
  setIsInpainting(true);
4529
5039
  try {
4530
- const imageDataUrl = await editor.toSourceDataURL();
5040
+ const imageDataUrl = await controller.toAIInputDataURL(aiOptions);
4531
5041
  const maskDataUrl = await editor.toMaskDataURL({
4532
5042
  useAnnotations: inpaintMaskMode === "annotations",
4533
5043
  useCrop: inpaintMaskMode === "crop"
@@ -4539,7 +5049,7 @@ var ImageEditor = ({
4539
5049
  cropBox: inpaintMaskMode === "crop" ? editor.state.crop : null
4540
5050
  });
4541
5051
  if (typeof result === "string") {
4542
- await editor.applyInpaintedImage(result);
5052
+ await editor.applyInpaintedImage(result, aiOptions);
4543
5053
  setAiSuccess("Inpainting applied successfully!");
4544
5054
  } else {
4545
5055
  setAiSuccess("Inpainting complete.");
@@ -4550,18 +5060,18 @@ var ImageEditor = ({
4550
5060
  setIsInpainting(false);
4551
5061
  }
4552
5062
  };
4553
- const [activeColor, setActiveColor] = (0, import_react40.useState)("#ef4444");
4554
- const [strokeWidth, setStrokeWidth] = (0, import_react40.useState)(3);
4555
- const [fontSize, setFontSize] = (0, import_react40.useState)(24);
4556
- const [textInput, setTextInput] = (0, import_react40.useState)("");
4557
- const draftAnnotationRef = (0, import_react40.useRef)(null);
4558
- const draftCropRef = (0, import_react40.useRef)(null);
4559
- const cropDragInfoRef = (0, import_react40.useRef)(null);
4560
- const annotationDragInfoRef = (0, import_react40.useRef)(null);
4561
- const isDrawingRef = (0, import_react40.useRef)(false);
4562
- const currentPathRef = (0, import_react40.useRef)([]);
4563
- const dragStartPointRef = (0, import_react40.useRef)(null);
4564
- const renderCanvas = (0, import_react40.useCallback)(
5063
+ const [activeColor, setActiveColor] = (0, import_react42.useState)("#ef4444");
5064
+ const [strokeWidth, setStrokeWidth] = (0, import_react42.useState)(3);
5065
+ const [fontSize, setFontSize] = (0, import_react42.useState)(24);
5066
+ const [textInput, setTextInput] = (0, import_react42.useState)("");
5067
+ const draftAnnotationRef = (0, import_react42.useRef)(null);
5068
+ const draftCropRef = (0, import_react42.useRef)(null);
5069
+ const cropDragInfoRef = (0, import_react42.useRef)(null);
5070
+ const annotationDragInfoRef = (0, import_react42.useRef)(null);
5071
+ const isDrawingRef = (0, import_react42.useRef)(false);
5072
+ const currentPathRef = (0, import_react42.useRef)([]);
5073
+ const dragStartPointRef = (0, import_react42.useRef)(null);
5074
+ const renderCanvas = (0, import_react42.useCallback)(
4565
5075
  async (draftAnnotation, draftCrop) => {
4566
5076
  const canvas = canvasRef.current;
4567
5077
  const container = containerRef.current;
@@ -4576,12 +5086,13 @@ var ImageEditor = ({
4576
5086
  interactive: true,
4577
5087
  draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
4578
5088
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
4579
- draftSelectionPath: selectionDraftRef.current
5089
+ draftSelectionPath: selectionDraftRef.current,
5090
+ brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null
4580
5091
  });
4581
5092
  },
4582
5093
  [controller, activeTab]
4583
5094
  );
4584
- (0, import_react40.useEffect)(() => {
5095
+ (0, import_react42.useEffect)(() => {
4585
5096
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
4586
5097
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
4587
5098
  const animId = raf(() => {
@@ -4589,12 +5100,12 @@ var ImageEditor = ({
4589
5100
  });
4590
5101
  return () => caf(animId);
4591
5102
  }, [renderCanvas, state]);
4592
- (0, import_react40.useEffect)(() => {
5103
+ (0, import_react42.useEffect)(() => {
4593
5104
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
4594
5105
  editor.setTool("crop");
4595
5106
  }
4596
5107
  }, [activeTab, editor]);
4597
- (0, import_react40.useEffect)(() => {
5108
+ (0, import_react42.useEffect)(() => {
4598
5109
  const container = containerRef.current;
4599
5110
  if (!container) return;
4600
5111
  if (typeof ResizeObserver !== "undefined") {
@@ -4620,13 +5131,60 @@ var ImageEditor = ({
4620
5131
  y: (e.clientY - rect.top) * scaleY
4621
5132
  };
4622
5133
  };
5134
+ const paintSamples = (e) => {
5135
+ const canvas = canvasRef.current;
5136
+ const native = e.nativeEvent;
5137
+ const events = typeof native.getCoalescedEvents === "function" ? native.getCoalescedEvents() : [];
5138
+ const list = events.length ? events : [native];
5139
+ const rect = canvas.getBoundingClientRect();
5140
+ const sx = rect.width > 0 ? canvas.width / rect.width : 1;
5141
+ const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5142
+ const s = controller.getState();
5143
+ return list.map((ev) => ({
5144
+ ...(0, import_image_editor10.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5145
+ pressure: (0, import_image_editor10.pointerPressure)(ev)
5146
+ }));
5147
+ };
5148
+ const handlePaintPointerDown = (e) => {
5149
+ if (activeTab !== "paint" || e.button !== 0) return;
5150
+ e.preventDefault();
5151
+ try {
5152
+ e.currentTarget.setPointerCapture?.(e.pointerId);
5153
+ } catch {
5154
+ }
5155
+ const [first] = paintSamples(e);
5156
+ setPaintError(paintGestureRef.current.down(first));
5157
+ };
5158
+ const handlePaintPointerMove = (e) => {
5159
+ if (activeTab !== "paint") return;
5160
+ const samples = paintSamples(e);
5161
+ brushCursorRef.current = samples[samples.length - 1] ?? null;
5162
+ if (paintGestureRef.current.active) paintGestureRef.current.moveTo(samples);
5163
+ else void renderCanvas();
5164
+ };
5165
+ const handlePaintPointerUp = () => {
5166
+ if (activeTab !== "paint") return;
5167
+ const g = paintGestureRef.current;
5168
+ if (g.active) {
5169
+ g.up();
5170
+ if (g.error) setPaintError(g.error);
5171
+ }
5172
+ };
5173
+ (0, import_react42.useEffect)(() => {
5174
+ if (activeTab !== "paint" || typeof window === "undefined") return;
5175
+ const onKey = (e) => {
5176
+ if ((0, import_image_editor10.handlePaintShortcut)(controller, e)) e.preventDefault();
5177
+ };
5178
+ window.addEventListener("keydown", onKey);
5179
+ return () => window.removeEventListener("keydown", onKey);
5180
+ }, [activeTab, controller]);
4623
5181
  const handleMouseDown = (e) => {
4624
5182
  const canvas = canvasRef.current;
4625
5183
  if (!canvas) return;
4626
5184
  const canvasPt = getCanvasEventPoint(e);
4627
5185
  if (activeTab === "select") {
4628
5186
  const gesture = selectionGestureRef.current;
4629
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5187
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4630
5188
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
4631
5189
  return;
4632
5190
  }
@@ -4637,8 +5195,8 @@ var ImageEditor = ({
4637
5195
  width: state.imageDimensions.width,
4638
5196
  height: state.imageDimensions.height
4639
5197
  };
4640
- const handle = (0, import_image_editor8.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
4641
- const startImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5198
+ const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5199
+ const startImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
4642
5200
  if (handle) {
4643
5201
  cropDragInfoRef.current = {
4644
5202
  handle,
@@ -4657,12 +5215,12 @@ var ImageEditor = ({
4657
5215
  return;
4658
5216
  }
4659
5217
  if (activeTab === "annotate") {
4660
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5218
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4661
5219
  dragStartPointRef.current = imgPt;
4662
5220
  if (state.activeTool === "select") {
4663
5221
  for (let i = state.annotations.length - 1; i >= 0; i--) {
4664
5222
  const ann = state.annotations[i];
4665
- if ((0, import_image_editor8.hitTestAnnotation)(imgPt, ann)) {
5223
+ if ((0, import_image_editor10.hitTestAnnotation)(imgPt, ann)) {
4666
5224
  editor.selectAnnotation(ann.id);
4667
5225
  annotationDragInfoRef.current = {
4668
5226
  annId: ann.id,
@@ -4698,7 +5256,7 @@ var ImageEditor = ({
4698
5256
  const canvasPt = getCanvasEventPoint(e);
4699
5257
  if (activeTab === "select") {
4700
5258
  const gesture = selectionGestureRef.current;
4701
- if (gesture.active && gesture.move((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5259
+ if (gesture.active && gesture.move((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
4702
5260
  selectionDraftRef.current = gesture.draftPath;
4703
5261
  renderCanvas();
4704
5262
  }
@@ -4707,7 +5265,7 @@ var ImageEditor = ({
4707
5265
  if (activeTab === "crop") {
4708
5266
  const drag = cropDragInfoRef.current;
4709
5267
  if (drag) {
4710
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5268
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
4711
5269
  let newCrop;
4712
5270
  if (drag.handle === "new") {
4713
5271
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -4721,7 +5279,7 @@ var ImageEditor = ({
4721
5279
  height: Math.round(Math.max(20, maxY - minY))
4722
5280
  };
4723
5281
  } else {
4724
- newCrop = (0, import_image_editor8.calculateCropDrag)(
5282
+ newCrop = (0, import_image_editor10.calculateCropDrag)(
4725
5283
  drag.startCrop,
4726
5284
  drag.handle,
4727
5285
  drag.startImgPt,
@@ -4741,15 +5299,15 @@ var ImageEditor = ({
4741
5299
  width: state.imageDimensions.width,
4742
5300
  height: state.imageDimensions.height
4743
5301
  };
4744
- const handle = (0, import_image_editor8.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
4745
- canvas.style.cursor = (0, import_image_editor8.getCropCursor)(handle, state.transform);
5302
+ const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5303
+ canvas.style.cursor = (0, import_image_editor10.getCropCursor)(handle, state.transform);
4746
5304
  }
4747
5305
  return;
4748
5306
  }
4749
5307
  if (activeTab === "annotate") {
4750
5308
  if (annotationDragInfoRef.current) {
4751
5309
  const drag = annotationDragInfoRef.current;
4752
- const currentImgPt2 = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5310
+ const currentImgPt2 = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4753
5311
  const dx = currentImgPt2.x - drag.startImgPt.x;
4754
5312
  const dy = currentImgPt2.y - drag.startImgPt.y;
4755
5313
  editor.updateAnnotation(drag.annId, {
@@ -4761,10 +5319,10 @@ var ImageEditor = ({
4761
5319
  const startPt = dragStartPointRef.current;
4762
5320
  if (!startPt) {
4763
5321
  if (state.activeTool === "select") {
4764
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5322
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4765
5323
  let hovered = false;
4766
5324
  for (let i = state.annotations.length - 1; i >= 0; i--) {
4767
- if ((0, import_image_editor8.hitTestAnnotation)(imgPt, state.annotations[i])) {
5325
+ if ((0, import_image_editor10.hitTestAnnotation)(imgPt, state.annotations[i])) {
4768
5326
  hovered = true;
4769
5327
  break;
4770
5328
  }
@@ -4775,7 +5333,7 @@ var ImageEditor = ({
4775
5333
  }
4776
5334
  return;
4777
5335
  }
4778
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5336
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4779
5337
  if (state.activeTool === "pen" && isDrawingRef.current) {
4780
5338
  currentPathRef.current.push(currentImgPt);
4781
5339
  const draft = {
@@ -4855,7 +5413,7 @@ var ImageEditor = ({
4855
5413
  if (activeTab === "select") {
4856
5414
  const gesture = selectionGestureRef.current;
4857
5415
  if (gesture.active) {
4858
- gesture.end((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5416
+ gesture.end((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
4859
5417
  selectionDraftRef.current = null;
4860
5418
  renderCanvas();
4861
5419
  }
@@ -4879,7 +5437,7 @@ var ImageEditor = ({
4879
5437
  }
4880
5438
  const startPt = dragStartPointRef.current;
4881
5439
  if (startPt) {
4882
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5440
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4883
5441
  if (state.activeTool === "pen" && isDrawingRef.current) {
4884
5442
  if (currentPathRef.current.length > 1) {
4885
5443
  editor.addAnnotation({
@@ -4975,15 +5533,15 @@ var ImageEditor = ({
4975
5533
  link.click();
4976
5534
  }
4977
5535
  };
4978
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5536
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4979
5537
  "div",
4980
5538
  {
4981
5539
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
4982
5540
  style,
4983
5541
  children: [
4984
- /* @__PURE__ */ (0, import_jsx_runtime23.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: [
4985
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
4986
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5542
+ /* @__PURE__ */ (0, import_jsx_runtime25.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: [
5543
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
5544
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4987
5545
  "button",
4988
5546
  {
4989
5547
  type: "button",
@@ -4995,7 +5553,7 @@ var ImageEditor = ({
4995
5553
  children: "Transform & Crop"
4996
5554
  }
4997
5555
  ),
4998
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5556
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4999
5557
  "button",
5000
5558
  {
5001
5559
  type: "button",
@@ -5007,7 +5565,31 @@ var ImageEditor = ({
5007
5565
  children: "Adjustments"
5008
5566
  }
5009
5567
  ),
5010
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5568
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5569
+ "button",
5570
+ {
5571
+ type: "button",
5572
+ onClick: () => {
5573
+ setActiveTab("layers");
5574
+ editor.setTool("select");
5575
+ },
5576
+ className: `px-3 py-1.5 rounded-md font-medium transition-colors ${activeTab === "layers" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
5577
+ children: "Layers"
5578
+ }
5579
+ ),
5580
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5581
+ "button",
5582
+ {
5583
+ type: "button",
5584
+ onClick: () => {
5585
+ setActiveTab("paint");
5586
+ editor.setTool("brush");
5587
+ },
5588
+ className: `px-3 py-1.5 rounded-md font-medium transition-colors ${activeTab === "paint" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
5589
+ children: "Paint"
5590
+ }
5591
+ ),
5592
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5011
5593
  "button",
5012
5594
  {
5013
5595
  type: "button",
@@ -5019,7 +5601,7 @@ var ImageEditor = ({
5019
5601
  children: "Select & Mask"
5020
5602
  }
5021
5603
  ),
5022
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5604
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5023
5605
  "button",
5024
5606
  {
5025
5607
  type: "button",
@@ -5031,7 +5613,7 @@ var ImageEditor = ({
5031
5613
  children: "Annotations"
5032
5614
  }
5033
5615
  ),
5034
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5616
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5035
5617
  "button",
5036
5618
  {
5037
5619
  type: "button",
@@ -5043,7 +5625,7 @@ var ImageEditor = ({
5043
5625
  children: "Depth Mask"
5044
5626
  }
5045
5627
  ),
5046
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5628
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5047
5629
  "button",
5048
5630
  {
5049
5631
  type: "button",
@@ -5053,14 +5635,14 @@ var ImageEditor = ({
5053
5635
  },
5054
5636
  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"}`,
5055
5637
  children: [
5056
- /* @__PURE__ */ (0, import_jsx_runtime23.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_runtime23.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" }) }),
5638
+ /* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.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" }) }),
5057
5639
  "AI Tools"
5058
5640
  ]
5059
5641
  }
5060
5642
  )
5061
5643
  ] }),
5062
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
5063
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5644
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
5645
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5064
5646
  "button",
5065
5647
  {
5066
5648
  type: "button",
@@ -5071,7 +5653,7 @@ var ImageEditor = ({
5071
5653
  children: "\u21A9"
5072
5654
  }
5073
5655
  ),
5074
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5656
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5075
5657
  "button",
5076
5658
  {
5077
5659
  type: "button",
@@ -5082,7 +5664,7 @@ var ImageEditor = ({
5082
5664
  children: "\u21AA"
5083
5665
  }
5084
5666
  ),
5085
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5667
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5086
5668
  "button",
5087
5669
  {
5088
5670
  type: "button",
@@ -5091,8 +5673,8 @@ var ImageEditor = ({
5091
5673
  children: "Reset"
5092
5674
  }
5093
5675
  ),
5094
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5095
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5676
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5677
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5096
5678
  "button",
5097
5679
  {
5098
5680
  type: "button",
@@ -5102,11 +5684,11 @@ var ImageEditor = ({
5102
5684
  children: "-"
5103
5685
  }
5104
5686
  ),
5105
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
5687
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
5106
5688
  Math.round(state.zoom * 100),
5107
5689
  "%"
5108
5690
  ] }),
5109
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5691
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5110
5692
  "button",
5111
5693
  {
5112
5694
  type: "button",
@@ -5116,8 +5698,8 @@ var ImageEditor = ({
5116
5698
  children: "+"
5117
5699
  }
5118
5700
  ),
5119
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5120
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5701
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5702
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5121
5703
  "button",
5122
5704
  {
5123
5705
  type: "button",
@@ -5128,7 +5710,7 @@ var ImageEditor = ({
5128
5710
  children: "Hold Compare"
5129
5711
  }
5130
5712
  ),
5131
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5713
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5132
5714
  "button",
5133
5715
  {
5134
5716
  type: "button",
@@ -5139,13 +5721,13 @@ var ImageEditor = ({
5139
5721
  )
5140
5722
  ] })
5141
5723
  ] }),
5142
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
5143
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5724
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
5725
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5144
5726
  "div",
5145
5727
  {
5146
5728
  ref: containerRef,
5147
5729
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
5148
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5730
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5149
5731
  "canvas",
5150
5732
  {
5151
5733
  ref: canvasRef,
@@ -5153,16 +5735,21 @@ var ImageEditor = ({
5153
5735
  onMouseMove: handleMouseMove,
5154
5736
  onMouseUp: handleMouseUp,
5155
5737
  onMouseLeave: handleMouseUp,
5156
- className: "absolute inset-0 w-full h-full block"
5738
+ onPointerDown: handlePaintPointerDown,
5739
+ onPointerMove: handlePaintPointerMove,
5740
+ onPointerUp: handlePaintPointerUp,
5741
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
5742
+ "data-testid": "image-editor-canvas",
5743
+ className: `absolute inset-0 w-full h-full block ${activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
5157
5744
  }
5158
5745
  )
5159
5746
  }
5160
5747
  ),
5161
- /* @__PURE__ */ (0, import_jsx_runtime23.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: [
5162
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
5163
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
5164
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
5165
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5748
+ /* @__PURE__ */ (0, import_jsx_runtime25.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: [
5749
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
5750
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
5751
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
5752
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5166
5753
  "button",
5167
5754
  {
5168
5755
  type: "button",
@@ -5174,7 +5761,7 @@ var ImageEditor = ({
5174
5761
  children: "Freeform"
5175
5762
  }
5176
5763
  ),
5177
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5764
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5178
5765
  "button",
5179
5766
  {
5180
5767
  type: "button",
@@ -5186,7 +5773,7 @@ var ImageEditor = ({
5186
5773
  children: "1:1 Square"
5187
5774
  }
5188
5775
  ),
5189
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5776
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5190
5777
  "button",
5191
5778
  {
5192
5779
  type: "button",
@@ -5198,7 +5785,7 @@ var ImageEditor = ({
5198
5785
  children: "4:3 Standard"
5199
5786
  }
5200
5787
  ),
5201
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5788
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5202
5789
  "button",
5203
5790
  {
5204
5791
  type: "button",
@@ -5210,7 +5797,7 @@ var ImageEditor = ({
5210
5797
  children: "16:9 Wide"
5211
5798
  }
5212
5799
  ),
5213
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5800
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5214
5801
  "button",
5215
5802
  {
5216
5803
  type: "button",
@@ -5222,7 +5809,7 @@ var ImageEditor = ({
5222
5809
  children: "3:2 Photo"
5223
5810
  }
5224
5811
  ),
5225
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5812
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5226
5813
  "button",
5227
5814
  {
5228
5815
  type: "button",
@@ -5235,10 +5822,10 @@ var ImageEditor = ({
5235
5822
  }
5236
5823
  )
5237
5824
  ] }),
5238
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5239
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
5240
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
5241
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5825
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5826
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
5827
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
5828
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5242
5829
  "button",
5243
5830
  {
5244
5831
  type: "button",
@@ -5247,7 +5834,7 @@ var ImageEditor = ({
5247
5834
  children: "Rotate -90\xB0"
5248
5835
  }
5249
5836
  ),
5250
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5837
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5251
5838
  "button",
5252
5839
  {
5253
5840
  type: "button",
@@ -5256,7 +5843,7 @@ var ImageEditor = ({
5256
5843
  children: "Rotate +90\xB0"
5257
5844
  }
5258
5845
  ),
5259
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5846
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5260
5847
  "button",
5261
5848
  {
5262
5849
  type: "button",
@@ -5265,7 +5852,7 @@ var ImageEditor = ({
5265
5852
  children: "Flip Horizontal"
5266
5853
  }
5267
5854
  ),
5268
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5855
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5269
5856
  "button",
5270
5857
  {
5271
5858
  type: "button",
@@ -5276,10 +5863,10 @@ var ImageEditor = ({
5276
5863
  )
5277
5864
  ] })
5278
5865
  ] }),
5279
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5280
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between", children: [
5281
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
5282
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5866
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5867
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
5868
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
5869
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5283
5870
  "button",
5284
5871
  {
5285
5872
  type: "button",
@@ -5289,25 +5876,25 @@ var ImageEditor = ({
5289
5876
  }
5290
5877
  )
5291
5878
  ] }),
5292
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Histogram, { histogram: editor.histogram }),
5293
- import_image_editor8.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react40.default.Fragment, { children: [
5294
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5879
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Histogram, { histogram: editor.histogram }),
5880
+ import_image_editor10.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react42.default.Fragment, { children: [
5881
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5295
5882
  ControlSlider,
5296
5883
  {
5297
5884
  spec,
5298
- value: (0, import_image_editor8.readAdjustmentControls)(state.adjustments)[spec.id],
5885
+ value: (0, import_image_editor10.readAdjustmentControls)(state.adjustments)[spec.id],
5299
5886
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
5300
5887
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
5301
5888
  }
5302
5889
  ),
5303
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5890
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5304
5891
  "div",
5305
5892
  {
5306
5893
  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",
5307
5894
  "data-testid": "image-editor-process-notice",
5308
5895
  children: [
5309
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
5310
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5896
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
5897
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5311
5898
  "button",
5312
5899
  {
5313
5900
  type: "button",
@@ -5320,7 +5907,7 @@ var ImageEditor = ({
5320
5907
  }
5321
5908
  )
5322
5909
  ] }, spec.id)),
5323
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5910
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5324
5911
  AdjustmentLayersPanel,
5325
5912
  {
5326
5913
  controller,
@@ -5329,9 +5916,19 @@ var ImageEditor = ({
5329
5916
  }
5330
5917
  ) })
5331
5918
  ] }),
5332
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5333
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
5334
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5919
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5920
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
5921
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LayersPanel, { controller })
5922
+ ] }),
5923
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5924
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
5925
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(BrushOptionsBar, { controller }),
5926
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
5927
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LayersPanel, { controller }) })
5928
+ ] }),
5929
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5930
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
5931
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5335
5932
  "button",
5336
5933
  {
5337
5934
  type: "button",
@@ -5341,9 +5938,9 @@ var ImageEditor = ({
5341
5938
  },
5342
5939
  t
5343
5940
  )) }),
5344
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
5345
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { className: "text-slate-400", children: "Color:" }),
5346
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5941
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
5942
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { className: "text-slate-400", children: "Color:" }),
5943
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5347
5944
  "input",
5348
5945
  {
5349
5946
  type: "color",
@@ -5352,15 +5949,15 @@ var ImageEditor = ({
5352
5949
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
5353
5950
  }
5354
5951
  ),
5355
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex-1 ml-2", children: [
5356
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
5357
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Width:" }),
5358
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-mono", children: [
5952
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex-1 ml-2", children: [
5953
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
5954
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Width:" }),
5955
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono", children: [
5359
5956
  strokeWidth,
5360
5957
  "px"
5361
5958
  ] })
5362
5959
  ] }),
5363
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5960
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5364
5961
  "input",
5365
5962
  {
5366
5963
  type: "range",
@@ -5373,10 +5970,10 @@ var ImageEditor = ({
5373
5970
  )
5374
5971
  ] })
5375
5972
  ] }),
5376
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5377
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
5378
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex gap-2", children: [
5379
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5973
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5974
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
5975
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex gap-2", children: [
5976
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5380
5977
  "input",
5381
5978
  {
5382
5979
  type: "text",
@@ -5387,7 +5984,7 @@ var ImageEditor = ({
5387
5984
  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"
5388
5985
  }
5389
5986
  ),
5390
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5987
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5391
5988
  "button",
5392
5989
  {
5393
5990
  type: "button",
@@ -5397,14 +5994,14 @@ var ImageEditor = ({
5397
5994
  }
5398
5995
  )
5399
5996
  ] }),
5400
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
5401
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Font Size:" }),
5402
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-mono", children: [
5997
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
5998
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Font Size:" }),
5999
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono", children: [
5403
6000
  fontSize,
5404
6001
  "px"
5405
6002
  ] })
5406
6003
  ] }),
5407
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6004
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5408
6005
  "input",
5409
6006
  {
5410
6007
  type: "range",
@@ -5415,14 +6012,14 @@ var ImageEditor = ({
5415
6012
  className: "w-full accent-indigo-500"
5416
6013
  }
5417
6014
  ),
5418
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5419
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between", children: [
5420
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "text-slate-400", children: [
6015
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
6016
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6017
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "text-slate-400", children: [
5421
6018
  "Layers (",
5422
6019
  state.annotations.length,
5423
6020
  ")"
5424
6021
  ] }),
5425
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6022
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5426
6023
  "button",
5427
6024
  {
5428
6025
  type: "button",
@@ -5431,7 +6028,7 @@ var ImageEditor = ({
5431
6028
  children: "Delete Selected"
5432
6029
  }
5433
6030
  ),
5434
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6031
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5435
6032
  "button",
5436
6033
  {
5437
6034
  type: "button",
@@ -5442,10 +6039,10 @@ var ImageEditor = ({
5442
6039
  )
5443
6040
  ] })
5444
6041
  ] }),
5445
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5446
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between", children: [
5447
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
5448
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6042
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
6043
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6044
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
6045
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5449
6046
  "button",
5450
6047
  {
5451
6048
  type: "button",
@@ -5455,8 +6052,8 @@ var ImageEditor = ({
5455
6052
  }
5456
6053
  )
5457
6054
  ] }),
5458
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
5459
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6055
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6056
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5460
6057
  "input",
5461
6058
  {
5462
6059
  type: "checkbox",
@@ -5465,12 +6062,12 @@ var ImageEditor = ({
5465
6062
  className: "rounded accent-indigo-500"
5466
6063
  }
5467
6064
  ),
5468
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6065
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Enable Depth / Alpha Mask" })
5469
6066
  ] }),
5470
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5471
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
5472
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
5473
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6067
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6068
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6069
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6070
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5474
6071
  "input",
5475
6072
  {
5476
6073
  type: "text",
@@ -5481,8 +6078,8 @@ var ImageEditor = ({
5481
6078
  }
5482
6079
  )
5483
6080
  ] }),
5484
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex gap-2", children: [
5485
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6081
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex gap-2", children: [
6082
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5486
6083
  "button",
5487
6084
  {
5488
6085
  type: "button",
@@ -5491,7 +6088,7 @@ var ImageEditor = ({
5491
6088
  children: "Threshold Mode"
5492
6089
  }
5493
6090
  ),
5494
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6091
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5495
6092
  "button",
5496
6093
  {
5497
6094
  type: "button",
@@ -5501,12 +6098,12 @@ var ImageEditor = ({
5501
6098
  }
5502
6099
  )
5503
6100
  ] }),
5504
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
5505
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
5506
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Depth Start (Lower):" }),
5507
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
6101
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6102
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6103
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Depth Start (Lower):" }),
6104
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
5508
6105
  ] }),
5509
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6106
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5510
6107
  "input",
5511
6108
  {
5512
6109
  type: "range",
@@ -5520,12 +6117,12 @@ var ImageEditor = ({
5520
6117
  }
5521
6118
  )
5522
6119
  ] }),
5523
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
5524
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
5525
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Depth Stop (Upper):" }),
5526
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
6120
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6121
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6122
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Depth Stop (Upper):" }),
6123
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
5527
6124
  ] }),
5528
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6125
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5529
6126
  "input",
5530
6127
  {
5531
6128
  type: "range",
@@ -5539,12 +6136,12 @@ var ImageEditor = ({
5539
6136
  }
5540
6137
  )
5541
6138
  ] }),
5542
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
5543
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
5544
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Softness:" }),
5545
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
6139
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6140
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6141
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Softness:" }),
6142
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
5546
6143
  ] }),
5547
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6144
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5548
6145
  "input",
5549
6146
  {
5550
6147
  type: "range",
@@ -5556,8 +6153,8 @@ var ImageEditor = ({
5556
6153
  }
5557
6154
  )
5558
6155
  ] }),
5559
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
5560
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6156
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
6157
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5561
6158
  "input",
5562
6159
  {
5563
6160
  type: "checkbox",
@@ -5566,12 +6163,12 @@ var ImageEditor = ({
5566
6163
  className: "rounded accent-indigo-500"
5567
6164
  }
5568
6165
  ),
5569
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Invert Mask" })
6166
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Invert Mask" })
5570
6167
  ] })
5571
6168
  ] })
5572
6169
  ] }),
5573
- activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
5574
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6170
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6171
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5575
6172
  SelectionOptionsBar,
5576
6173
  {
5577
6174
  controller,
@@ -5581,51 +6178,68 @@ var ImageEditor = ({
5581
6178
  quickMask: Boolean(state.quickMask)
5582
6179
  }
5583
6180
  ),
5584
- selectionError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
5585
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
6181
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
6182
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
5586
6183
  ] }),
5587
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
5588
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
5589
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between", children: [
5590
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
5591
- /* @__PURE__ */ (0, import_jsx_runtime23.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_runtime23.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" }) }),
6184
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6185
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className: "flex items-center justify-between gap-2 text-slate-300", children: [
6186
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Results go to" }),
6187
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6188
+ "select",
6189
+ {
6190
+ "aria-label": "AI result target",
6191
+ value: aiTarget,
6192
+ onChange: (e) => setAiTarget(e.target.value),
6193
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
6194
+ children: [
6195
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "auto", children: controller.isMultiLayer ? "Auto (new layer)" : "Auto (replace image)" }),
6196
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "new-layer", children: "New layer / mask" }),
6197
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "replace", children: "Replace image" })
6198
+ ]
6199
+ }
6200
+ )
6201
+ ] }),
6202
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6203
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6204
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6205
+ /* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.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" }) }),
5592
6206
  "Background Removal"
5593
6207
  ] }),
5594
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime23.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..." })
6208
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime25.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..." })
5595
6209
  ] }),
5596
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
5597
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6210
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
6211
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5598
6212
  "button",
5599
6213
  {
5600
6214
  type: "button",
5601
6215
  onClick: handleRemoveBackground,
5602
6216
  disabled: isRemovingBg || isInpainting,
5603
6217
  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",
5604
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5605
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
6218
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6219
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
5606
6220
  "Removing Background..."
5607
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5608
- /* @__PURE__ */ (0, import_jsx_runtime23.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_runtime23.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" }) }),
6221
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6222
+ /* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.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" }) }),
5609
6223
  "Remove Background"
5610
6224
  ] })
5611
6225
  }
5612
6226
  )
5613
6227
  ] }),
5614
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
5615
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between", children: [
5616
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
5617
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
5618
- /* @__PURE__ */ (0, import_jsx_runtime23.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" }),
5619
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "m14 7 3 3" })
6228
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
6229
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6230
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
6231
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
6232
+ /* @__PURE__ */ (0, import_jsx_runtime25.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" }),
6233
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "m14 7 3 3" })
5620
6234
  ] }),
5621
6235
  "Generative Inpainting"
5622
6236
  ] }),
5623
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime23.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..." })
6237
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime25.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..." })
5624
6238
  ] }),
5625
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
5626
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
5627
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
5628
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6239
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
6240
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-1", children: [
6241
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
6242
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5629
6243
  "textarea",
5630
6244
  {
5631
6245
  id: "ai-inpaint-prompt-react",
@@ -5637,10 +6251,10 @@ var ImageEditor = ({
5637
6251
  }
5638
6252
  )
5639
6253
  ] }),
5640
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", children: [
5641
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
5642
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
5643
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6254
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-1", children: [
6255
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
6256
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
6257
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5644
6258
  "button",
5645
6259
  {
5646
6260
  type: "button",
@@ -5653,7 +6267,7 @@ var ImageEditor = ({
5653
6267
  ]
5654
6268
  }
5655
6269
  ),
5656
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6270
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5657
6271
  "button",
5658
6272
  {
5659
6273
  type: "button",
@@ -5668,25 +6282,25 @@ var ImageEditor = ({
5668
6282
  )
5669
6283
  ] })
5670
6284
  ] }),
5671
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6285
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5672
6286
  "button",
5673
6287
  {
5674
6288
  type: "button",
5675
6289
  onClick: handleInpaint,
5676
6290
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
5677
6291
  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",
5678
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5679
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
6292
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6293
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
5680
6294
  "Generating Inpaint..."
5681
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5682
- /* @__PURE__ */ (0, import_jsx_runtime23.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_runtime23.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" }) }),
6295
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6296
+ /* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.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" }) }),
5683
6297
  "Apply Inpainting"
5684
6298
  ] })
5685
6299
  }
5686
6300
  )
5687
6301
  ] }),
5688
- aiError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
5689
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
6302
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
6303
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
5690
6304
  ] })
5691
6305
  ] })
5692
6306
  ] })
@@ -5696,7 +6310,7 @@ var ImageEditor = ({
5696
6310
  };
5697
6311
 
5698
6312
  // src/review/useReview.ts
5699
- var import_react41 = require("react");
6313
+ var import_react43 = require("react");
5700
6314
  var import_editor12 = require("@pixerate/editor");
5701
6315
  var EMPTY_COMMENTS = Object.freeze({
5702
6316
  threads: [],
@@ -5715,23 +6329,23 @@ function isCommentStore(value) {
5715
6329
  }
5716
6330
  function useComments(source) {
5717
6331
  const store = isCommentStore(source) ? source : (0, import_editor12.getCommentStore)(source);
5718
- const subscribe = (0, import_react41.useCallback)(
6332
+ const subscribe = (0, import_react43.useCallback)(
5719
6333
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
5720
6334
  [store]
5721
6335
  );
5722
6336
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
5723
- const snapshot = (0, import_react41.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
5724
- return (0, import_react41.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
6337
+ const snapshot = (0, import_react43.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6338
+ return (0, import_react43.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
5725
6339
  }
5726
6340
  function useTrackChanges(editor) {
5727
6341
  const store = (0, import_editor12.getTrackChangesStore)(editor ?? null);
5728
- const subscribe = (0, import_react41.useCallback)(
6342
+ const subscribe = (0, import_react43.useCallback)(
5729
6343
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
5730
6344
  [store]
5731
6345
  );
5732
6346
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
5733
- const snapshot = (0, import_react41.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
5734
- return (0, import_react41.useMemo)(() => {
6347
+ const snapshot = (0, import_react43.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6348
+ return (0, import_react43.useMemo)(() => {
5735
6349
  const run = (fn) => () => {
5736
6350
  if (editor && !editor.isDestroyed) fn(editor);
5737
6351
  };
@@ -5754,9 +6368,9 @@ function useTrackChanges(editor) {
5754
6368
  }
5755
6369
 
5756
6370
  // src/review/CommentsPanel.tsx
5757
- var import_react42 = require("react");
6371
+ var import_react44 = require("react");
5758
6372
  var import_editor13 = require("@pixerate/editor");
5759
- var import_jsx_runtime24 = require("react/jsx-runtime");
6373
+ var import_jsx_runtime26 = require("react/jsx-runtime");
5760
6374
  var buttonClass2 = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
5761
6375
  var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
5762
6376
  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";
@@ -5770,18 +6384,18 @@ var CommentsPanel = ({
5770
6384
  emptyMessage = "No comments yet. Select text and add a comment."
5771
6385
  }) => {
5772
6386
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
5773
- const [showResolved, setShowResolved] = (0, import_react42.useState)(showResolvedInitial);
6387
+ const [showResolved, setShowResolved] = (0, import_react44.useState)(showResolvedInitial);
5774
6388
  const author = authorProp ?? (0, import_editor13.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
5775
6389
  const visible = threads.filter((t) => showResolved || !t.resolved);
5776
6390
  const resolvedCount = threads.filter((t) => t.resolved).length;
5777
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("aside", { className, "aria-label": "Comments", children: [
5778
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
5779
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
6391
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("aside", { className, "aria-label": "Comments", children: [
6392
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
6393
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
5780
6394
  threads.length - resolvedCount,
5781
6395
  " open",
5782
6396
  resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
5783
6397
  ] }),
5784
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6398
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5785
6399
  "button",
5786
6400
  {
5787
6401
  type: "button",
@@ -5792,7 +6406,7 @@ var CommentsPanel = ({
5792
6406
  }
5793
6407
  )
5794
6408
  ] }),
5795
- visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6409
+ visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5796
6410
  CommentThreadCard,
5797
6411
  {
5798
6412
  thread,
@@ -5814,7 +6428,7 @@ var CommentThreadCard = ({
5814
6428
  author,
5815
6429
  formatTime
5816
6430
  }) => {
5817
- const [draft, setDraft] = (0, import_react42.useState)("");
6431
+ const [draft, setDraft] = (0, import_react44.useState)("");
5818
6432
  const isDraft = thread.body === "";
5819
6433
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
5820
6434
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -5840,7 +6454,7 @@ var CommentThreadCard = ({
5840
6454
  setDraft("");
5841
6455
  };
5842
6456
  const stop = (e) => e.stopPropagation();
5843
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6457
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5844
6458
  "li",
5845
6459
  {
5846
6460
  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" : ""}`,
@@ -5856,24 +6470,24 @@ var CommentThreadCard = ({
5856
6470
  }
5857
6471
  },
5858
6472
  children: [
5859
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
5860
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-medium", children: thread.author.name }),
5861
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
6473
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
6474
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-medium", children: thread.author.name }),
6475
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
5862
6476
  ] }),
5863
- quote && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
5864
- thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
5865
- thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
5866
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
5867
- thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
5868
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "text-xs", children: [
5869
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-medium", children: reply.author.name }),
6477
+ quote && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
6478
+ thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
6479
+ thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
6480
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
6481
+ thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.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_runtime26.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
6482
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-xs", children: [
6483
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-medium", children: reply.author.name }),
5870
6484
  " ",
5871
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
6485
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
5872
6486
  ] }),
5873
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
6487
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
5874
6488
  ] }, reply.id)) }),
5875
- (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
5876
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6489
+ (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
6490
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5877
6491
  "textarea",
5878
6492
  {
5879
6493
  className: textareaClass,
@@ -5891,9 +6505,9 @@ var CommentThreadCard = ({
5891
6505
  }
5892
6506
  }
5893
6507
  ),
5894
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex justify-end gap-1", children: [
5895
- isDraft && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
5896
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6508
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-end gap-1", children: [
6509
+ isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
6510
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5897
6511
  "button",
5898
6512
  {
5899
6513
  type: "button",
@@ -5905,9 +6519,9 @@ var CommentThreadCard = ({
5905
6519
  )
5906
6520
  ] })
5907
6521
  ] }),
5908
- !isDraft && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
5909
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
5910
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6522
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
6523
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
6524
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5911
6525
  "button",
5912
6526
  {
5913
6527
  type: "button",
@@ -5923,7 +6537,7 @@ var CommentThreadCard = ({
5923
6537
  };
5924
6538
 
5925
6539
  // src/review/ReviewToolbar.tsx
5926
- var import_jsx_runtime25 = require("react/jsx-runtime");
6540
+ var import_jsx_runtime27 = require("react/jsx-runtime");
5927
6541
  var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
5928
6542
  var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
5929
6543
  var ReviewToolbar = ({
@@ -5936,8 +6550,8 @@ var ReviewToolbar = ({
5936
6550
  const count = review.changes.length;
5937
6551
  const current = review.currentChange;
5938
6552
  const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
5939
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
5940
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6553
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
6554
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5941
6555
  "button",
5942
6556
  {
5943
6557
  type: "button",
@@ -5948,8 +6562,8 @@ var ReviewToolbar = ({
5948
6562
  children: review.enabled ? "Tracking on" : "Track changes"
5949
6563
  }
5950
6564
  ),
5951
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
5952
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6565
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6566
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5953
6567
  "button",
5954
6568
  {
5955
6569
  type: "button",
@@ -5960,8 +6574,8 @@ var ReviewToolbar = ({
5960
6574
  children: "\u2039"
5961
6575
  }
5962
6576
  ),
5963
- /* @__PURE__ */ (0, import_jsx_runtime25.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` }),
5964
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6577
+ /* @__PURE__ */ (0, import_jsx_runtime27.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` }),
6578
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5965
6579
  "button",
5966
6580
  {
5967
6581
  type: "button",
@@ -5972,7 +6586,7 @@ var ReviewToolbar = ({
5972
6586
  children: "\u203A"
5973
6587
  }
5974
6588
  ),
5975
- showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6589
+ showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5976
6590
  "span",
5977
6591
  {
5978
6592
  className: descriptionClassName,
@@ -5984,8 +6598,8 @@ var ReviewToolbar = ({
5984
6598
  ]
5985
6599
  }
5986
6600
  ),
5987
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
5988
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6601
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6602
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5989
6603
  "button",
5990
6604
  {
5991
6605
  type: "button",
@@ -5995,7 +6609,7 @@ var ReviewToolbar = ({
5995
6609
  children: "Accept"
5996
6610
  }
5997
6611
  ),
5998
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6612
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5999
6613
  "button",
6000
6614
  {
6001
6615
  type: "button",
@@ -6005,18 +6619,18 @@ var ReviewToolbar = ({
6005
6619
  children: "Reject"
6006
6620
  }
6007
6621
  ),
6008
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
6009
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
6622
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
6623
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
6010
6624
  ] });
6011
6625
  };
6012
6626
 
6013
6627
  // src/review/CommentButton.tsx
6014
- var import_jsx_runtime26 = require("react/jsx-runtime");
6628
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6015
6629
  var CommentButton = ({
6016
6630
  editor,
6017
6631
  className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
6018
6632
  children = "Comment"
6019
- }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6633
+ }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6020
6634
  "button",
6021
6635
  {
6022
6636
  type: "button",
@@ -6028,13 +6642,13 @@ var CommentButton = ({
6028
6642
  );
6029
6643
 
6030
6644
  // src/review/useDocumentCompare.ts
6031
- var import_react43 = require("react");
6645
+ var import_react45 = require("react");
6032
6646
  var import_editor14 = require("@pixerate/editor");
6033
6647
  function useDocumentCompare(editor, options) {
6034
- const [summary, setSummary] = (0, import_react43.useState)(null);
6035
- const defaults = (0, import_react43.useRef)(options);
6648
+ const [summary, setSummary] = (0, import_react45.useState)(null);
6649
+ const defaults = (0, import_react45.useRef)(options);
6036
6650
  defaults.current = options;
6037
- const compare = (0, import_react43.useCallback)(
6651
+ const compare = (0, import_react45.useCallback)(
6038
6652
  (original, revised, overrides) => {
6039
6653
  if (!editor || editor.isDestroyed) return null;
6040
6654
  const result = (0, import_editor14.applyDocumentComparison)(editor, original, revised, {
@@ -6046,13 +6660,13 @@ function useDocumentCompare(editor, options) {
6046
6660
  },
6047
6661
  [editor]
6048
6662
  );
6049
- const clear = (0, import_react43.useCallback)(() => setSummary(null), []);
6050
- return (0, import_react43.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
6663
+ const clear = (0, import_react45.useCallback)(() => setSummary(null), []);
6664
+ return (0, import_react45.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
6051
6665
  }
6052
6666
 
6053
6667
  // src/review/TrackedChangesList.tsx
6054
6668
  var import_editor15 = require("@pixerate/editor");
6055
- var import_jsx_runtime27 = require("react/jsx-runtime");
6669
+ var import_jsx_runtime29 = require("react/jsx-runtime");
6056
6670
  var buttonClass4 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
6057
6671
  var TrackedChangesList = ({
6058
6672
  editor,
@@ -6063,18 +6677,18 @@ var TrackedChangesList = ({
6063
6677
  }) => {
6064
6678
  const review = useTrackChanges(editor);
6065
6679
  if (review.changes.length === 0) {
6066
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
6680
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
6067
6681
  }
6068
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
6682
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
6069
6683
  const active = change.id === review.currentChangeId;
6070
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6684
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6071
6685
  "li",
6072
6686
  {
6073
6687
  className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
6074
6688
  "data-change-type": change.type,
6075
6689
  "data-change-id": change.id,
6076
6690
  children: [
6077
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6691
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6078
6692
  "button",
6079
6693
  {
6080
6694
  type: "button",
@@ -6082,14 +6696,14 @@ var TrackedChangesList = ({
6082
6696
  title: `${change.author.name}: ${change.description}`,
6083
6697
  onClick: () => review.select(change.id),
6084
6698
  children: [
6085
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
6699
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
6086
6700
  change.author.name ? ` \xB7 ${change.author.name}` : "",
6087
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
6701
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
6088
6702
  ]
6089
6703
  }
6090
6704
  ),
6091
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
6092
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
6705
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
6706
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
6093
6707
  ]
6094
6708
  },
6095
6709
  `${change.type}:${change.id}`
@@ -6098,12 +6712,12 @@ var TrackedChangesList = ({
6098
6712
  };
6099
6713
 
6100
6714
  // src/commands/useCommandPalette.ts
6101
- var import_react44 = require("react");
6715
+ var import_react46 = require("react");
6102
6716
  var import_commands2 = require("@pixerate/editor/commands");
6103
6717
  function useCommandPalette(registry, options = {}) {
6104
- const optionsRef = (0, import_react44.useRef)(options);
6718
+ const optionsRef = (0, import_react46.useRef)(options);
6105
6719
  optionsRef.current = options;
6106
- const controller = (0, import_react44.useMemo)(
6720
+ const controller = (0, import_react46.useMemo)(
6107
6721
  () => (0, import_commands2.createCommandPaletteController)(registry, {
6108
6722
  context: () => {
6109
6723
  const c = optionsRef.current.context;
@@ -6124,9 +6738,9 @@ function useCommandPalette(registry, options = {}) {
6124
6738
  // eslint-disable-next-line react-hooks/exhaustive-deps
6125
6739
  [registry]
6126
6740
  );
6127
- const state = (0, import_react44.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
6741
+ const state = (0, import_react46.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
6128
6742
  const { hotkey, hotkeyTarget } = options;
6129
- (0, import_react44.useEffect)(() => {
6743
+ (0, import_react46.useEffect)(() => {
6130
6744
  if (!hotkey) return;
6131
6745
  const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
6132
6746
  if (!target) return;
@@ -6154,13 +6768,13 @@ function useCommandPalette(registry, options = {}) {
6154
6768
  }
6155
6769
 
6156
6770
  // src/commands/CommandPalette.tsx
6157
- var import_react45 = __toESM(require("react"), 1);
6158
- var import_jsx_runtime28 = require("react/jsx-runtime");
6771
+ var import_react47 = __toESM(require("react"), 1);
6772
+ var import_jsx_runtime30 = require("react/jsx-runtime");
6159
6773
  function HighlightedLabel({ item }) {
6160
- if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: item.label });
6774
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: item.label });
6161
6775
  const marked = new Set(item.labelIndices);
6162
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: Array.from(item.label).map(
6163
- (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react45.default.Fragment, { children: ch }, i)
6776
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: Array.from(item.label).map(
6777
+ (ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react47.default.Fragment, { children: ch }, i)
6164
6778
  ) });
6165
6779
  }
6166
6780
  var CommandPalette = ({
@@ -6169,22 +6783,22 @@ var CommandPalette = ({
6169
6783
  emptyMessage = "No matching commands",
6170
6784
  className = ""
6171
6785
  }) => {
6172
- const inputRef = (0, import_react45.useRef)(null);
6173
- const listRef = (0, import_react45.useRef)(null);
6174
- const baseId = (0, import_react45.useId)();
6786
+ const inputRef = (0, import_react47.useRef)(null);
6787
+ const listRef = (0, import_react47.useRef)(null);
6788
+ const baseId = (0, import_react47.useId)();
6175
6789
  const listId = `${baseId}-list`;
6176
6790
  const optionId = (index) => `${baseId}-option-${index}`;
6177
6791
  const { open, query, items, activeIndex } = palette;
6178
- (0, import_react45.useEffect)(() => {
6792
+ (0, import_react47.useEffect)(() => {
6179
6793
  if (open) inputRef.current?.focus();
6180
6794
  }, [open]);
6181
- (0, import_react45.useEffect)(() => {
6795
+ (0, import_react47.useEffect)(() => {
6182
6796
  if (!open) return;
6183
6797
  const active = listRef.current?.querySelector('[aria-selected="true"]');
6184
6798
  active?.scrollIntoView?.({ block: "nearest" });
6185
6799
  }, [open, activeIndex]);
6186
6800
  if (!open) return null;
6187
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6801
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6188
6802
  "div",
6189
6803
  {
6190
6804
  className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
@@ -6192,7 +6806,7 @@ var CommandPalette = ({
6192
6806
  onMouseDown: (e) => {
6193
6807
  if (e.target === e.currentTarget) palette.setOpen(false);
6194
6808
  },
6195
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
6809
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
6196
6810
  "div",
6197
6811
  {
6198
6812
  role: "dialog",
@@ -6201,7 +6815,7 @@ var CommandPalette = ({
6201
6815
  className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
6202
6816
  style: { background: "var(--popover, var(--background, #fff))" },
6203
6817
  children: [
6204
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6818
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6205
6819
  "input",
6206
6820
  {
6207
6821
  ref: inputRef,
@@ -6221,7 +6835,7 @@ var CommandPalette = ({
6221
6835
  className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
6222
6836
  }
6223
6837
  ),
6224
- items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime28.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_runtime28.jsxs)(
6838
+ items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime30.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_runtime30.jsxs)(
6225
6839
  "li",
6226
6840
  {
6227
6841
  id: optionId(index),
@@ -6236,12 +6850,12 @@ var CommandPalette = ({
6236
6850
  onClick: () => palette.run(item.id),
6237
6851
  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"}`,
6238
6852
  children: [
6239
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
6240
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(HighlightedLabel, { item }),
6241
- item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
6853
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
6854
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(HighlightedLabel, { item }),
6855
+ item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
6242
6856
  ] }),
6243
- item.group && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
6244
- item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
6857
+ item.group && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
6858
+ item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
6245
6859
  ]
6246
6860
  },
6247
6861
  item.id
@@ -6254,12 +6868,12 @@ var CommandPalette = ({
6254
6868
  };
6255
6869
 
6256
6870
  // src/commands/useCommandShortcuts.ts
6257
- var import_react46 = require("react");
6871
+ var import_react48 = require("react");
6258
6872
  function useCommandShortcuts(registry, options = {}) {
6259
- const optionsRef = (0, import_react46.useRef)(options);
6873
+ const optionsRef = (0, import_react48.useRef)(options);
6260
6874
  optionsRef.current = options;
6261
6875
  const { enabled = true, target } = options;
6262
- (0, import_react46.useEffect)(() => {
6876
+ (0, import_react48.useEffect)(() => {
6263
6877
  if (!registry || !enabled) return;
6264
6878
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
6265
6879
  if (!eventTarget) return;
@@ -6277,14 +6891,14 @@ function useCommandShortcuts(registry, options = {}) {
6277
6891
  }, [registry, enabled, target]);
6278
6892
  }
6279
6893
  function useRegisterCommands(registry, specs) {
6280
- (0, import_react46.useEffect)(() => {
6894
+ (0, import_react48.useEffect)(() => {
6281
6895
  if (!registry || !specs || specs.length === 0) return;
6282
6896
  return registry.register(specs);
6283
6897
  }, [registry, specs]);
6284
6898
  }
6285
6899
 
6286
6900
  // src/persistence/useAutosave.ts
6287
- var import_react47 = require("react");
6901
+ var import_react49 = require("react");
6288
6902
  var import_persistence = require("@pixerate/editor/persistence");
6289
6903
  var IDLE = {
6290
6904
  status: "idle",
@@ -6295,18 +6909,18 @@ var IDLE = {
6295
6909
  ready: false
6296
6910
  };
6297
6911
  function useAutosave(options) {
6298
- const optionsRef = (0, import_react47.useRef)(options);
6912
+ const optionsRef = (0, import_react49.useRef)(options);
6299
6913
  optionsRef.current = options;
6300
6914
  const { storage, key, history, dirty } = options;
6301
6915
  const recover = options.recover !== false;
6302
6916
  const flushOnHide = options.flushOnHide !== false;
6303
6917
  const ready = options.ready !== false;
6304
- const [controller, setController] = (0, import_react47.useState)(null);
6305
- const [status, setStatus] = (0, import_react47.useState)(IDLE);
6306
- const [recovery, setRecovery] = (0, import_react47.useState)(null);
6307
- const [pendingRecovery, setPendingRecovery] = (0, import_react47.useState)(recover);
6308
- const revisionsRef = (0, import_react47.useRef)(null);
6309
- (0, import_react47.useEffect)(() => {
6918
+ const [controller, setController] = (0, import_react49.useState)(null);
6919
+ const [status, setStatus] = (0, import_react49.useState)(IDLE);
6920
+ const [recovery, setRecovery] = (0, import_react49.useState)(null);
6921
+ const [pendingRecovery, setPendingRecovery] = (0, import_react49.useState)(recover);
6922
+ const revisionsRef = (0, import_react49.useRef)(null);
6923
+ (0, import_react49.useEffect)(() => {
6310
6924
  const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
6311
6925
  const o = optionsRef.current;
6312
6926
  const instance = (0, import_persistence.createAutosaveController)({
@@ -6349,10 +6963,10 @@ function useAutosave(options) {
6349
6963
  if (revisionsRef.current === revisions) revisionsRef.current = null;
6350
6964
  };
6351
6965
  }, [storage, key, history, dirty, recover]);
6352
- (0, import_react47.useEffect)(() => {
6966
+ (0, import_react49.useEffect)(() => {
6353
6967
  if (controller && ready && !pendingRecovery) controller.ready();
6354
6968
  }, [controller, ready, pendingRecovery]);
6355
- (0, import_react47.useEffect)(() => {
6969
+ (0, import_react49.useEffect)(() => {
6356
6970
  if (!controller || !flushOnHide || typeof window === "undefined") return;
6357
6971
  const flush = () => void controller.flushNow();
6358
6972
  const onVisibility = () => {
@@ -6365,31 +6979,31 @@ function useAutosave(options) {
6365
6979
  document.removeEventListener("visibilitychange", onVisibility);
6366
6980
  };
6367
6981
  }, [controller, flushOnHide]);
6368
- const restore = (0, import_react47.useCallback)(() => {
6982
+ const restore = (0, import_react49.useCallback)(() => {
6369
6983
  const snapshot = recovery?.snapshot;
6370
6984
  setRecovery(null);
6371
6985
  setPendingRecovery(false);
6372
6986
  return snapshot;
6373
6987
  }, [recovery]);
6374
- const discard = (0, import_react47.useCallback)(async () => {
6988
+ const discard = (0, import_react49.useCallback)(async () => {
6375
6989
  if (controller) await controller.discardRecovery();
6376
6990
  setRecovery(null);
6377
6991
  setPendingRecovery(false);
6378
6992
  }, [controller]);
6379
- const flushNow = (0, import_react47.useCallback)(async () => {
6993
+ const flushNow = (0, import_react49.useCallback)(async () => {
6380
6994
  await controller?.flushNow();
6381
6995
  }, [controller]);
6382
- const markClean = (0, import_react47.useCallback)(async () => {
6996
+ const markClean = (0, import_react49.useCallback)(async () => {
6383
6997
  revisionsRef.current?.markSaved();
6384
6998
  await controller?.markClean();
6385
6999
  }, [controller]);
6386
- const notifyChange = (0, import_react47.useCallback)(() => revisionsRef.current?.bump(), []);
7000
+ const notifyChange = (0, import_react49.useCallback)(() => revisionsRef.current?.bump(), []);
6387
7001
  return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
6388
7002
  }
6389
7003
 
6390
7004
  // src/persistence/RecoveryPrompt.tsx
6391
7005
  var import_persistence2 = require("@pixerate/editor/persistence");
6392
- var import_jsx_runtime29 = require("react/jsx-runtime");
7006
+ var import_jsx_runtime31 = require("react/jsx-runtime");
6393
7007
  var RecoveryPrompt = ({
6394
7008
  recovery,
6395
7009
  onRestore,
@@ -6401,7 +7015,7 @@ var RecoveryPrompt = ({
6401
7015
  }) => {
6402
7016
  if (!recovery) return null;
6403
7017
  const { name } = recovery.meta;
6404
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7018
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
6405
7019
  "div",
6406
7020
  {
6407
7021
  role: "alertdialog",
@@ -6409,15 +7023,15 @@ var RecoveryPrompt = ({
6409
7023
  "data-recovery-prompt": "",
6410
7024
  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}`,
6411
7025
  children: [
6412
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "min-w-0 flex-1", children: [
7026
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "min-w-0 flex-1", children: [
6413
7027
  (0, import_persistence2.formatRecoveryMessage)(recovery.meta, formatTime),
6414
- name ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
7028
+ name ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
6415
7029
  "(",
6416
7030
  name,
6417
7031
  ")"
6418
7032
  ] }) : null
6419
7033
  ] }),
6420
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7034
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6421
7035
  "button",
6422
7036
  {
6423
7037
  type: "button",
@@ -6427,7 +7041,7 @@ var RecoveryPrompt = ({
6427
7041
  children: restoreLabel
6428
7042
  }
6429
7043
  ),
6430
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7044
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6431
7045
  "button",
6432
7046
  {
6433
7047
  type: "button",
@@ -6443,17 +7057,17 @@ var RecoveryPrompt = ({
6443
7057
  };
6444
7058
 
6445
7059
  // src/generation/useGenerationPlan.ts
6446
- var import_react48 = require("react");
7060
+ var import_react50 = require("react");
6447
7061
  var import_generation = require("@pixerate/editor/generation");
6448
7062
  function useGenerationPlan(request, capabilities, options = {}) {
6449
7063
  const key = JSON.stringify([request, capabilities, options]);
6450
- return (0, import_react48.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
7064
+ return (0, import_react50.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
6451
7065
  }
6452
7066
  function useJobProgress(options) {
6453
7067
  const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
6454
- const [tick, setTick] = (0, import_react48.useState)(() => Date.now());
7068
+ const [tick, setTick] = (0, import_react50.useState)(() => Date.now());
6455
7069
  const ticking = !done && now === void 0;
6456
- (0, import_react48.useEffect)(() => {
7070
+ (0, import_react50.useEffect)(() => {
6457
7071
  if (!ticking) return;
6458
7072
  setTick(Date.now());
6459
7073
  const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
@@ -6463,9 +7077,9 @@ function useJobProgress(options) {
6463
7077
  }
6464
7078
 
6465
7079
  // src/generation/GenerationSettings.tsx
6466
- var import_react49 = require("react");
7080
+ var import_react51 = require("react");
6467
7081
  var import_generation2 = require("@pixerate/editor/generation");
6468
- var import_jsx_runtime30 = require("react/jsx-runtime");
7082
+ var import_jsx_runtime32 = require("react/jsx-runtime");
6469
7083
  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";
6470
7084
  function Control({
6471
7085
  control,
@@ -6475,7 +7089,7 @@ function Control({
6475
7089
  }) {
6476
7090
  const shown = value ?? control.defaultValue;
6477
7091
  if (control.kind === "checkbox") {
6478
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7092
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6479
7093
  "input",
6480
7094
  {
6481
7095
  id,
@@ -6487,7 +7101,7 @@ function Control({
6487
7101
  );
6488
7102
  }
6489
7103
  if (control.kind === "select") {
6490
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
7104
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6491
7105
  "select",
6492
7106
  {
6493
7107
  id,
@@ -6496,14 +7110,14 @@ function Control({
6496
7110
  value: shown === void 0 ? "" : String(shown),
6497
7111
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
6498
7112
  children: [
6499
- shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("option", { value: "", children: "Default" }),
6500
- control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
7113
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: "", children: "Default" }),
7114
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
6501
7115
  ]
6502
7116
  }
6503
7117
  );
6504
7118
  }
6505
7119
  if (control.kind === "textarea") {
6506
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7120
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6507
7121
  "textarea",
6508
7122
  {
6509
7123
  id,
@@ -6517,8 +7131,8 @@ function Control({
6517
7131
  );
6518
7132
  }
6519
7133
  const numeric = typeof shown === "number" ? shown : void 0;
6520
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center gap-2", children: [
6521
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7134
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-2", children: [
7135
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6522
7136
  "input",
6523
7137
  {
6524
7138
  id,
@@ -6532,7 +7146,7 @@ function Control({
6532
7146
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
6533
7147
  }
6534
7148
  ),
6535
- control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
7149
+ control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
6536
7150
  ] });
6537
7151
  }
6538
7152
  var GenerationSettings = ({
@@ -6546,17 +7160,17 @@ var GenerationSettings = ({
6546
7160
  renderReference,
6547
7161
  className = ""
6548
7162
  }) => {
6549
- const baseId = (0, import_react49.useId)();
6550
- const controls = (0, import_react49.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7163
+ const baseId = (0, import_react51.useId)();
7164
+ const controls = (0, import_react51.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
6551
7165
  const computed = useGenerationPlan(value, capabilities, { strategy });
6552
7166
  const plan = planProp ?? computed;
6553
7167
  const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
6554
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
7168
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
6555
7169
  controls.map((control) => {
6556
7170
  const id = `${baseId}-${control.key}`;
6557
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
6558
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
6559
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7171
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
7172
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
7173
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6560
7174
  Control,
6561
7175
  {
6562
7176
  control,
@@ -6567,23 +7181,23 @@ var GenerationSettings = ({
6567
7181
  )
6568
7182
  ] }, control.key);
6569
7183
  }),
6570
- slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
6571
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
7184
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
7185
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
6572
7186
  slot.label,
6573
7187
  " ",
6574
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7188
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
6575
7189
  "(",
6576
7190
  slot.references.length,
6577
7191
  "/",
6578
7192
  slot.max,
6579
7193
  ")"
6580
7194
  ] }),
6581
- slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-destructive", children: " *" })
7195
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-destructive", children: " *" })
6582
7196
  ] }),
6583
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
6584
- slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
6585
- renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
6586
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7197
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
7198
+ slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
7199
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
7200
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6587
7201
  "button",
6588
7202
  {
6589
7203
  type: "button",
@@ -6594,7 +7208,7 @@ var GenerationSettings = ({
6594
7208
  }
6595
7209
  )
6596
7210
  ] }, ref.id)),
6597
- onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7211
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6598
7212
  "button",
6599
7213
  {
6600
7214
  type: "button",
@@ -6605,21 +7219,21 @@ var GenerationSettings = ({
6605
7219
  ) })
6606
7220
  ] })
6607
7221
  ] }, slot.role)),
6608
- showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.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_runtime30.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
6609
- showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.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_runtime30.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
7222
+ showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.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_runtime32.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
7223
+ showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.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_runtime32.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
6610
7224
  ] });
6611
7225
  };
6612
7226
 
6613
7227
  // src/generation/JobProgress.tsx
6614
- var import_jsx_runtime31 = require("react/jsx-runtime");
7228
+ var import_jsx_runtime33 = require("react/jsx-runtime");
6615
7229
  var JobProgress = ({ title, className = "", ...options }) => {
6616
7230
  const progress = useJobProgress(options);
6617
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
6618
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
6619
- title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "truncate text-foreground", children: title }),
6620
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
7231
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
7232
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
7233
+ title && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "truncate text-foreground", children: title }),
7234
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
6621
7235
  ] }),
6622
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7236
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6623
7237
  "div",
6624
7238
  {
6625
7239
  role: "progressbar",
@@ -6629,7 +7243,7 @@ var JobProgress = ({ title, className = "", ...options }) => {
6629
7243
  "aria-valuenow": progress.percent,
6630
7244
  "aria-valuetext": `${progress.percent}%, ${progress.label}`,
6631
7245
  className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
6632
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7246
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6633
7247
  "div",
6634
7248
  {
6635
7249
  className: "h-full rounded-full bg-primary transition-[width] duration-500",
@@ -6642,9 +7256,9 @@ var JobProgress = ({ title, className = "", ...options }) => {
6642
7256
  };
6643
7257
 
6644
7258
  // src/generation/AssetMentionChips.tsx
6645
- var import_react50 = require("react");
7259
+ var import_react52 = require("react");
6646
7260
  var import_generation3 = require("@pixerate/editor/generation");
6647
- var import_jsx_runtime32 = require("react/jsx-runtime");
7261
+ var import_jsx_runtime34 = require("react/jsx-runtime");
6648
7262
  var AssetMentionChips = ({
6649
7263
  content,
6650
7264
  onChange,
@@ -6654,14 +7268,14 @@ var AssetMentionChips = ({
6654
7268
  renderAsset,
6655
7269
  className = ""
6656
7270
  }) => {
6657
- const [open, setOpen] = (0, import_react50.useState)(null);
6658
- const rootRef = (0, import_react50.useRef)(null);
6659
- const chips = (0, import_react50.useMemo)(
7271
+ const [open, setOpen] = (0, import_react52.useState)(null);
7272
+ const rootRef = (0, import_react52.useRef)(null);
7273
+ const chips = (0, import_react52.useMemo)(
6660
7274
  () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
6661
7275
  [content, assets, capabilities]
6662
7276
  );
6663
7277
  const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
6664
- (0, import_react50.useEffect)(() => {
7278
+ (0, import_react52.useEffect)(() => {
6665
7279
  if (open === null) return;
6666
7280
  const onPointer = (event) => {
6667
7281
  if (!rootRef.current?.contains(event.target)) setOpen(null);
@@ -6669,19 +7283,19 @@ var AssetMentionChips = ({
6669
7283
  document.addEventListener("mousedown", onPointer);
6670
7284
  return () => document.removeEventListener("mousedown", onPointer);
6671
7285
  }, [open]);
6672
- const pick = (chip, role) => {
7286
+ const pick = (chip2, role) => {
6673
7287
  setOpen(null);
6674
- if (chip.start === void 0) return;
6675
- onChange((0, import_generation3.setMentionRoleInText)(content, chip.start, role));
7288
+ if (chip2.start === void 0) return;
7289
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip2.start, role));
6676
7290
  };
6677
7291
  if (chips.length === 0) return null;
6678
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip) => {
6679
- const error = chip.issues.find((issue) => issue.severity === "error");
6680
- const warning = chip.issues.find((issue) => issue.severity === "warning");
7292
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip2) => {
7293
+ const error = chip2.issues.find((issue) => issue.severity === "error");
7294
+ const warning = chip2.issues.find((issue) => issue.severity === "warning");
6681
7295
  const problem = error ?? warning;
6682
- const isOpen = open === chip.index;
6683
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip.asset.id, children: [
6684
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7296
+ const isOpen = open === chip2.index;
7297
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip2.asset.id, children: [
7298
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6685
7299
  "button",
6686
7300
  {
6687
7301
  type: "button",
@@ -6689,82 +7303,82 @@ var AssetMentionChips = ({
6689
7303
  "aria-expanded": isOpen,
6690
7304
  title: problem?.message,
6691
7305
  "data-issue": problem?.code,
6692
- onClick: () => setOpen(isOpen ? null : chip.index),
7306
+ onClick: () => setOpen(isOpen ? null : chip2.index),
6693
7307
  onKeyDown: (e) => {
6694
7308
  if (e.key === "Escape") setOpen(null);
6695
7309
  },
6696
7310
  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`,
6697
7311
  children: [
6698
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: renderAsset ? renderAsset(chip) : `@${chip.asset.label ?? chip.handle}` }),
6699
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7312
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: renderAsset ? renderAsset(chip2) : `@${chip2.asset.label ?? chip2.handle}` }),
7313
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6700
7314
  "span",
6701
7315
  {
6702
- className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip.role ? "bg-primary/15" : "opacity-60"}`,
6703
- "data-role-badge": chip.role ?? "",
6704
- children: chip.roleLabel ?? "No role"
7316
+ className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip2.role ? "bg-primary/15" : "opacity-60"}`,
7317
+ "data-role-badge": chip2.role ?? "",
7318
+ children: chip2.roleLabel ?? "No role"
6705
7319
  }
6706
7320
  )
6707
7321
  ]
6708
7322
  }
6709
7323
  ),
6710
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7324
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6711
7325
  "div",
6712
7326
  {
6713
7327
  role: "listbox",
6714
- "aria-label": `Role for ${chip.asset.label ?? chip.handle}`,
7328
+ "aria-label": `Role for ${chip2.asset.label ?? chip2.handle}`,
6715
7329
  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",
6716
7330
  "data-role-picker": "",
6717
7331
  onKeyDown: (e) => {
6718
7332
  if (e.key === "Escape") setOpen(null);
6719
7333
  },
6720
7334
  children: [
6721
- options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7335
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6722
7336
  "button",
6723
7337
  {
6724
7338
  type: "button",
6725
7339
  role: "option",
6726
- "aria-selected": chip.role === option.role,
7340
+ "aria-selected": chip2.role === option.role,
6727
7341
  "data-role-option": option.role,
6728
7342
  title: option.description,
6729
- onClick: () => pick(chip, option.role),
7343
+ onClick: () => pick(chip2, option.role),
6730
7344
  className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
6731
7345
  children: [
6732
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: option.label }),
6733
- option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
7346
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: option.label }),
7347
+ option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
6734
7348
  ]
6735
7349
  },
6736
7350
  option.role
6737
7351
  )),
6738
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7352
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6739
7353
  "button",
6740
7354
  {
6741
7355
  type: "button",
6742
7356
  role: "option",
6743
- "aria-selected": !chip.role,
7357
+ "aria-selected": !chip2.role,
6744
7358
  "data-role-option": "",
6745
- onClick: () => pick(chip, null),
7359
+ onClick: () => pick(chip2, null),
6746
7360
  className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
6747
7361
  children: "No role"
6748
7362
  }
6749
7363
  ),
6750
- chip.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { className: "mt-1 border-t border-border px-2 pt-1 text-[10px]", "data-chip-issues": "", children: chip.issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
7364
+ chip2.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.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_runtime34.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
6751
7365
  ]
6752
7366
  }
6753
7367
  )
6754
- ] }, `${chip.start}-${chip.index}`);
7368
+ ] }, `${chip2.start}-${chip2.index}`);
6755
7369
  }) });
6756
7370
  };
6757
7371
 
6758
7372
  // src/generation/GenerationHistory.tsx
6759
- var import_react51 = require("react");
7373
+ var import_react53 = require("react");
6760
7374
  var import_generation4 = require("@pixerate/editor/generation");
6761
- var import_jsx_runtime33 = require("react/jsx-runtime");
7375
+ var import_jsx_runtime35 = require("react/jsx-runtime");
6762
7376
  function useGenerationRecords(store, filter) {
6763
- const [records, setRecords] = (0, import_react51.useState)([]);
6764
- const [loading, setLoading] = (0, import_react51.useState)(!!store);
6765
- const [error, setError] = (0, import_react51.useState)(null);
7377
+ const [records, setRecords] = (0, import_react53.useState)([]);
7378
+ const [loading, setLoading] = (0, import_react53.useState)(!!store);
7379
+ const [error, setError] = (0, import_react53.useState)(null);
6766
7380
  const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
6767
- const refresh = (0, import_react51.useCallback)(async () => {
7381
+ const refresh = (0, import_react53.useCallback)(async () => {
6768
7382
  if (!store) {
6769
7383
  setRecords([]);
6770
7384
  setLoading(false);
@@ -6781,7 +7395,7 @@ function useGenerationRecords(store, filter) {
6781
7395
  setLoading(false);
6782
7396
  }
6783
7397
  }, [store, filterKey]);
6784
- (0, import_react51.useEffect)(() => {
7398
+ (0, import_react53.useEffect)(() => {
6785
7399
  void refresh();
6786
7400
  if (!store) return;
6787
7401
  return store.subscribe(() => void refresh());
@@ -6807,21 +7421,21 @@ var GenerationHistory = ({
6807
7421
  emptyText = "No generations yet.",
6808
7422
  className = ""
6809
7423
  }) => {
6810
- const [innerMode, setInnerMode] = (0, import_react51.useState)("exact");
7424
+ const [innerMode, setInnerMode] = (0, import_react53.useState)("exact");
6811
7425
  const mode = modeProp ?? innerMode;
6812
7426
  const setMode = (next) => {
6813
7427
  if (modeProp === void 0) setInnerMode(next);
6814
7428
  onModeChange?.(next);
6815
7429
  };
6816
- const options = (0, import_react51.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
6817
- const results = (0, import_react51.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
6818
- const models = (0, import_react51.useMemo)(
7430
+ const options = (0, import_react53.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
7431
+ const results = (0, import_react53.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
7432
+ const models = (0, import_react53.useMemo)(
6819
7433
  () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
6820
7434
  [capabilities]
6821
7435
  );
6822
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
6823
- /* @__PURE__ */ (0, import_jsx_runtime33.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_runtime33.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
6824
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7436
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
7437
+ /* @__PURE__ */ (0, import_jsx_runtime35.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_runtime35.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
7438
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6825
7439
  "input",
6826
7440
  {
6827
7441
  type: "radio",
@@ -6834,34 +7448,34 @@ var GenerationHistory = ({
6834
7448
  ),
6835
7449
  value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
6836
7450
  ] }, value)) }),
6837
- records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
6838
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
7451
+ records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
7452
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
6839
7453
  const result = results[i];
6840
7454
  const model = models.find((m) => m.id === record.provenance.modelId);
6841
7455
  const blocked = !result.ok;
6842
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7456
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
6843
7457
  "li",
6844
7458
  {
6845
7459
  className: "rounded-md border border-border p-2",
6846
7460
  "data-record": record.id,
6847
7461
  "data-drift": result.drift.length,
6848
7462
  children: [
6849
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
6850
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
6851
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "text-muted-foreground", children: [
6852
- record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { "data-kind": "", children: [
7463
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
7464
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
7465
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "text-muted-foreground", children: [
7466
+ record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { "data-kind": "", children: [
6853
7467
  record.kind,
6854
7468
  " \xB7 "
6855
7469
  ] }),
6856
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
6857
- record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
7470
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
7471
+ record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
6858
7472
  " \xB7 seed ",
6859
7473
  record.seed
6860
7474
  ] })
6861
7475
  ] })
6862
7476
  ] }),
6863
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
6864
- record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7477
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
7478
+ record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
6865
7479
  "span",
6866
7480
  {
6867
7481
  className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
@@ -6875,16 +7489,16 @@ var GenerationHistory = ({
6875
7489
  `${asset.role}:${asset.id}`
6876
7490
  )) }),
6877
7491
  renderPreview?.(record),
6878
- result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.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_runtime33.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
6879
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("strong", { children: [
7492
+ result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.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_runtime35.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
7493
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("strong", { children: [
6880
7494
  import_generation4.DRIFT_TYPE_LABELS[item.type],
6881
7495
  ":"
6882
7496
  ] }),
6883
7497
  " ",
6884
7498
  item.message
6885
7499
  ] }, j)) }),
6886
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "mt-2 flex gap-2", children: [
6887
- onRecreate && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7500
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-2 flex gap-2", children: [
7501
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6888
7502
  "button",
6889
7503
  {
6890
7504
  type: "button",
@@ -6896,7 +7510,7 @@ var GenerationHistory = ({
6896
7510
  children: "Recreate"
6897
7511
  }
6898
7512
  ),
6899
- onVariation && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7513
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6900
7514
  "button",
6901
7515
  {
6902
7516
  type: "button",
@@ -6906,7 +7520,7 @@ var GenerationHistory = ({
6906
7520
  children: "Variation"
6907
7521
  }
6908
7522
  ),
6909
- onRemove && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7523
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6910
7524
  "button",
6911
7525
  {
6912
7526
  type: "button",
@@ -6926,19 +7540,19 @@ var GenerationHistory = ({
6926
7540
  };
6927
7541
 
6928
7542
  // src/find-replace/useFindReplace.ts
6929
- var import_react52 = require("react");
7543
+ var import_react54 = require("react");
6930
7544
  var import_editor16 = require("@pixerate/editor");
6931
7545
  var noopUnsubscribe2 = () => {
6932
7546
  };
6933
7547
  function useFindReplace(editor) {
6934
7548
  const store = (0, import_editor16.getFindReplaceStore)(editor ?? null);
6935
- const subscribe = (0, import_react52.useCallback)(
7549
+ const subscribe = (0, import_react54.useCallback)(
6936
7550
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
6937
7551
  [store]
6938
7552
  );
6939
7553
  const getSnapshot = () => store?.getSnapshot() ?? import_editor16.EMPTY_FIND_REPLACE_SNAPSHOT;
6940
- const snapshot = (0, import_react52.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6941
- return (0, import_react52.useMemo)(() => {
7554
+ const snapshot = (0, import_react54.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7555
+ return (0, import_react54.useMemo)(() => {
6942
7556
  const run = (fn) => {
6943
7557
  if (editor && !editor.isDestroyed && store) fn(editor);
6944
7558
  };
@@ -6962,9 +7576,9 @@ function useFindReplace(editor) {
6962
7576
  }
6963
7577
 
6964
7578
  // src/find-replace/FindReplaceBar.tsx
6965
- var import_react53 = require("react");
7579
+ var import_react55 = require("react");
6966
7580
  var import_editor17 = require("@pixerate/editor");
6967
- var import_jsx_runtime34 = require("react/jsx-runtime");
7581
+ var import_jsx_runtime36 = require("react/jsx-runtime");
6968
7582
  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";
6969
7583
  var buttonClass5 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
6970
7584
  var toggleClass = (on) => `${buttonClass5} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
@@ -6977,10 +7591,10 @@ var FindReplaceBar = ({
6977
7591
  onClose
6978
7592
  }) => {
6979
7593
  const find = useFindReplace(editor);
6980
- const findInput = (0, import_react53.useRef)(null);
6981
- const [moreOpen, setMoreOpen] = (0, import_react53.useState)(false);
7594
+ const findInput = (0, import_react55.useRef)(null);
7595
+ const [moreOpen, setMoreOpen] = (0, import_react55.useState)(false);
6982
7596
  const visible = find.available && (alwaysOpen || find.open);
6983
- (0, import_react53.useEffect)(() => {
7597
+ (0, import_react55.useEffect)(() => {
6984
7598
  if (!visible || find.focusRequest === 0) return;
6985
7599
  findInput.current?.focus();
6986
7600
  findInput.current?.select();
@@ -7018,9 +7632,9 @@ var FindReplaceBar = ({
7018
7632
  if (isMod(e)) find.replaceAll();
7019
7633
  else find.replace();
7020
7634
  };
7021
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
7022
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-1", children: [
7023
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7635
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
7636
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-1", children: [
7637
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7024
7638
  "button",
7025
7639
  {
7026
7640
  type: "button",
@@ -7031,7 +7645,7 @@ var FindReplaceBar = ({
7031
7645
  children: showReplace ? "\u25BE" : "\u25B8"
7032
7646
  }
7033
7647
  ),
7034
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7648
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7035
7649
  "input",
7036
7650
  {
7037
7651
  ref: findInput,
@@ -7045,7 +7659,7 @@ var FindReplaceBar = ({
7045
7659
  onKeyDown: onFindKeyDown
7046
7660
  }
7047
7661
  ),
7048
- import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7662
+ import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7049
7663
  "button",
7050
7664
  {
7051
7665
  type: "button",
@@ -7058,7 +7672,7 @@ var FindReplaceBar = ({
7058
7672
  },
7059
7673
  t.key
7060
7674
  )),
7061
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7675
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7062
7676
  "span",
7063
7677
  {
7064
7678
  className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
@@ -7068,9 +7682,9 @@ var FindReplaceBar = ({
7068
7682
  children: status
7069
7683
  }
7070
7684
  ),
7071
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
7072
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
7073
- showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7685
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
7686
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
7687
+ showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7074
7688
  "button",
7075
7689
  {
7076
7690
  type: "button",
@@ -7081,10 +7695,10 @@ var FindReplaceBar = ({
7081
7695
  children: "\u2026"
7082
7696
  }
7083
7697
  ),
7084
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
7698
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
7085
7699
  ] }),
7086
- showReplace && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
7087
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7700
+ showReplace && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
7701
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7088
7702
  "input",
7089
7703
  {
7090
7704
  type: "text",
@@ -7096,7 +7710,7 @@ var FindReplaceBar = ({
7096
7710
  onKeyDown: onReplaceKeyDown
7097
7711
  }
7098
7712
  ),
7099
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7713
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7100
7714
  "button",
7101
7715
  {
7102
7716
  type: "button",
@@ -7106,11 +7720,11 @@ var FindReplaceBar = ({
7106
7720
  children: "Replace"
7107
7721
  }
7108
7722
  ),
7109
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
7110
- find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
7723
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
7724
+ find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
7111
7725
  ] }),
7112
- showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime34.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_runtime34.jsxs)("label", { className: "flex items-center gap-1", children: [
7113
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7726
+ showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsxs)("label", { className: "flex items-center gap-1", children: [
7727
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7114
7728
  "input",
7115
7729
  {
7116
7730
  type: "checkbox",
@@ -7124,12 +7738,12 @@ var FindReplaceBar = ({
7124
7738
  };
7125
7739
 
7126
7740
  // src/tables/useTableMenu.ts
7127
- var import_react54 = require("react");
7741
+ var import_react56 = require("react");
7128
7742
  var import_editor18 = require("@pixerate/editor");
7129
7743
  function useTableMenu(editor) {
7130
- const store = (0, import_react54.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
7131
- const snapshot = (0, import_react54.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
7132
- return (0, import_react54.useMemo)(
7744
+ const store = (0, import_react56.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
7745
+ const snapshot = (0, import_react56.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
7746
+ return (0, import_react56.useMemo)(
7133
7747
  () => ({
7134
7748
  ...snapshot,
7135
7749
  run: (action, params) => (0, import_editor18.runTableAction)(editor, action, params, { focus: true }),
@@ -7140,9 +7754,9 @@ function useTableMenu(editor) {
7140
7754
  }
7141
7755
 
7142
7756
  // src/tables/TableToolbar.tsx
7143
- var import_react55 = __toESM(require("react"), 1);
7757
+ var import_react57 = __toESM(require("react"), 1);
7144
7758
  var import_editor19 = require("@pixerate/editor");
7145
- var import_jsx_runtime35 = require("react/jsx-runtime");
7759
+ var import_jsx_runtime37 = require("react/jsx-runtime");
7146
7760
  var keepSelection2 = (event) => event.preventDefault();
7147
7761
  var TableToolbar = ({
7148
7762
  editor,
@@ -7156,14 +7770,14 @@ var TableToolbar = ({
7156
7770
  }) => {
7157
7771
  const table = useTableMenu(editor);
7158
7772
  if (!editor || !table.inTable && !showWhenOutside) return null;
7159
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
7773
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
7160
7774
  const status = table.check(item.action, item.params);
7161
7775
  const enabled = status === true;
7162
7776
  const active = item.active?.(table);
7163
7777
  const separator = index > 0 && items[index - 1].group !== item.group;
7164
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_react55.default.Fragment, { children: [
7165
- separator && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
7166
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
7778
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react57.default.Fragment, { children: [
7779
+ separator && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
7780
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7167
7781
  "button",
7168
7782
  {
7169
7783
  type: "button",
@@ -7185,8 +7799,8 @@ var TableToolbar = ({
7185
7799
  };
7186
7800
 
7187
7801
  // src/tables/InsertTableGrid.tsx
7188
- var import_react56 = require("react");
7189
- var import_jsx_runtime36 = require("react/jsx-runtime");
7802
+ var import_react58 = require("react");
7803
+ var import_jsx_runtime38 = require("react/jsx-runtime");
7190
7804
  var keepSelection3 = (event) => event.preventDefault();
7191
7805
  var InsertTableGrid = ({
7192
7806
  editor,
@@ -7199,14 +7813,14 @@ var InsertTableGrid = ({
7199
7813
  onInsert
7200
7814
  }) => {
7201
7815
  const table = useTableMenu(editor);
7202
- const [hover, setHover] = (0, import_react56.useState)(null);
7816
+ const [hover, setHover] = (0, import_react58.useState)(null);
7203
7817
  const status = table.actions.insertTable;
7204
7818
  const disabled = !editor || !status.enabled;
7205
7819
  const insert = (size) => {
7206
7820
  if (table.run("insertTable", { ...size, withHeaderRow })) onInsert?.(size);
7207
7821
  setHover(null);
7208
7822
  };
7209
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7823
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7210
7824
  "div",
7211
7825
  {
7212
7826
  className,
@@ -7216,7 +7830,7 @@ var InsertTableGrid = ({
7216
7830
  "data-insert-table-grid": "",
7217
7831
  onMouseLeave: () => setHover(null),
7218
7832
  children: [
7219
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7833
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7220
7834
  "div",
7221
7835
  {
7222
7836
  role: "grid",
@@ -7225,7 +7839,7 @@ var InsertTableGrid = ({
7225
7839
  children: Array.from({ length: rows * cols }, (_, i) => {
7226
7840
  const size = { rows: Math.floor(i / cols) + 1, cols: i % cols + 1 };
7227
7841
  const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols;
7228
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7842
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7229
7843
  "button",
7230
7844
  {
7231
7845
  type: "button",
@@ -7245,7 +7859,7 @@ var InsertTableGrid = ({
7245
7859
  })
7246
7860
  }
7247
7861
  ),
7248
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { "aria-live": "polite", "data-testid": "insert-table-size", children: disabled ? status.reason : hover ? `${hover.rows} \xD7 ${hover.cols}` : "Insert table" })
7862
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { "aria-live": "polite", "data-testid": "insert-table-size", children: disabled ? status.reason : hover ? `${hover.rows} \xD7 ${hover.cols}` : "Insert table" })
7249
7863
  ]
7250
7864
  }
7251
7865
  );
@@ -7253,31 +7867,31 @@ var InsertTableGrid = ({
7253
7867
 
7254
7868
  // src/tables/TableBubbleMenu.tsx
7255
7869
  var import_editor20 = require("@pixerate/editor");
7256
- var import_jsx_runtime37 = require("react/jsx-runtime");
7870
+ var import_jsx_runtime39 = require("react/jsx-runtime");
7257
7871
  var TableBubbleMenu = ({
7258
7872
  editor,
7259
7873
  children,
7260
7874
  toolbarProps,
7261
7875
  pluginKey = "tableBubbleMenu",
7262
7876
  ...rest
7263
- }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(BubbleMenu, { editor, pluginKey, shouldShow: import_editor20.shouldShowTableBubbleMenu, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TableToolbar, { editor, ...toolbarProps }) });
7877
+ }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(BubbleMenu, { editor, pluginKey, shouldShow: import_editor20.shouldShowTableBubbleMenu, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TableToolbar, { editor, ...toolbarProps }) });
7264
7878
 
7265
7879
  // src/chart-node/ChartNodeView.tsx
7266
7880
  var import_client = require("react-dom/client");
7267
7881
 
7268
7882
  // src/chart/ChartCanvas.tsx
7269
- var import_react58 = require("react");
7883
+ var import_react60 = require("react");
7270
7884
  var import_chart2 = require("@pixerate/editor/chart");
7271
7885
 
7272
7886
  // src/chart/useChartEditor.ts
7273
- var import_react57 = require("react");
7887
+ var import_react59 = require("react");
7274
7888
  var import_chart = require("@pixerate/editor/chart");
7275
7889
  function useChartState(controller) {
7276
- return (0, import_react57.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7890
+ return (0, import_react59.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7277
7891
  }
7278
7892
 
7279
7893
  // src/chart/ChartCanvas.tsx
7280
- var import_jsx_runtime38 = require("react/jsx-runtime");
7894
+ var import_jsx_runtime40 = require("react/jsx-runtime");
7281
7895
  function renderChartMark(mark, fontFamily, interactive) {
7282
7896
  const common = {
7283
7897
  "data-role": mark.role,
@@ -7289,9 +7903,9 @@ function renderChartMark(mark, fontFamily, interactive) {
7289
7903
  };
7290
7904
  switch (mark.kind) {
7291
7905
  case "rect":
7292
- return /* @__PURE__ */ (0, import_jsx_runtime38.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);
7906
+ return /* @__PURE__ */ (0, import_jsx_runtime40.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);
7293
7907
  case "path":
7294
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7908
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7295
7909
  "path",
7296
7910
  {
7297
7911
  ...common,
@@ -7304,11 +7918,11 @@ function renderChartMark(mark, fontFamily, interactive) {
7304
7918
  mark.key
7305
7919
  );
7306
7920
  case "circle":
7307
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
7921
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, stroke: mark.stroke, strokeWidth: mark.strokeWidth } }, mark.key);
7308
7922
  case "line":
7309
- return /* @__PURE__ */ (0, import_jsx_runtime38.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);
7923
+ return /* @__PURE__ */ (0, import_jsx_runtime40.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);
7310
7924
  case "text":
7311
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7925
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7312
7926
  "text",
7313
7927
  {
7314
7928
  ...common,
@@ -7325,23 +7939,23 @@ function renderChartMark(mark, fontFamily, interactive) {
7325
7939
  }
7326
7940
  }
7327
7941
  function ChartPresenceLayer({ presence }) {
7328
- const { actors } = (0, import_react58.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
7329
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("g", { "data-chart-presence": "", pointerEvents: "none", children: actors.map((a) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("g", { transform: `translate(${a.x} ${a.y})`, "data-actor": a.id, children: [
7330
- /* @__PURE__ */ (0, import_jsx_runtime38.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 }),
7331
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("g", { transform: "translate(13 16)", children: [
7332
- /* @__PURE__ */ (0, import_jsx_runtime38.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 } }),
7333
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("text", { x: 6, y: 9, dominantBaseline: "central", style: { fill: "#ffffff", fontSize: 11, fontWeight: 600, fontFamily: "inherit" }, children: a.message ?? a.name })
7942
+ const { actors } = (0, import_react60.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
7943
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("g", { "data-chart-presence": "", pointerEvents: "none", children: actors.map((a) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("g", { transform: `translate(${a.x} ${a.y})`, "data-actor": a.id, children: [
7944
+ /* @__PURE__ */ (0, import_jsx_runtime40.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 }),
7945
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("g", { transform: "translate(13 16)", children: [
7946
+ /* @__PURE__ */ (0, import_jsx_runtime40.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 } }),
7947
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("text", { x: 6, y: 9, dominantBaseline: "central", style: { fill: "#ffffff", fontSize: 11, fontWeight: 600, fontFamily: "inherit" }, children: a.message ?? a.name })
7334
7948
  ] })
7335
7949
  ] }, a.id)) });
7336
7950
  }
7337
7951
  function ChartCanvas({ controller, width = 640, height = 400, responsive = true, theme, editable = true, measureText, emptyMessage, className, presence, sceneRef }) {
7338
7952
  const state = useChartState(controller);
7339
- const wrapper = (0, import_react58.useRef)(null);
7340
- const svg = (0, import_react58.useRef)(null);
7341
- const drag = (0, import_react58.useRef)(null);
7342
- const [measured, setMeasured] = (0, import_react58.useState)(null);
7343
- const [frozen, setFrozen] = (0, import_react58.useState)(null);
7344
- (0, import_react58.useEffect)(() => {
7953
+ const wrapper = (0, import_react60.useRef)(null);
7954
+ const svg = (0, import_react60.useRef)(null);
7955
+ const drag = (0, import_react60.useRef)(null);
7956
+ const [measured, setMeasured] = (0, import_react60.useState)(null);
7957
+ const [frozen, setFrozen] = (0, import_react60.useState)(null);
7958
+ (0, import_react60.useEffect)(() => {
7345
7959
  const el = wrapper.current;
7346
7960
  if (!responsive || !el || typeof ResizeObserver === "undefined") return;
7347
7961
  const observer = new ResizeObserver(([entry]) => {
@@ -7352,8 +7966,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7352
7966
  return () => observer.disconnect();
7353
7967
  }, [responsive]);
7354
7968
  const sceneWidth = responsive && measured || width;
7355
- const fullTheme = (0, import_react58.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
7356
- const scene = (0, import_react58.useMemo)(
7969
+ const fullTheme = (0, import_react60.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
7970
+ const scene = (0, import_react60.useMemo)(
7357
7971
  () => (0, import_chart2.layoutChart)(state.spec, {
7358
7972
  width: sceneWidth,
7359
7973
  height,
@@ -7369,8 +7983,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7369
7983
  [state.spec, state.selection, sceneWidth, height, fullTheme, editable, measureText, emptyMessage, frozen]
7370
7984
  );
7371
7985
  if (sceneRef) sceneRef.current = scene;
7372
- const byKey = (0, import_react58.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
7373
- (0, import_react58.useEffect)(() => () => drag.current?.end(), []);
7986
+ const byKey = (0, import_react60.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
7987
+ (0, import_react60.useEffect)(() => () => drag.current?.end(), []);
7374
7988
  const scenePoint = (e) => (0, import_chart2.chartClientToScene)(scene, svg.current.getBoundingClientRect(), e.clientX, e.clientY);
7375
7989
  const onPointerDown = (e) => {
7376
7990
  if (!editable || e.button !== 0) return;
@@ -7403,7 +8017,7 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7403
8017
  if (editable && (0, import_chart2.handleChartKey)(controller, scene, e)) e.preventDefault();
7404
8018
  };
7405
8019
  const label = state.spec.title || "Chart";
7406
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ref: wrapper, className: `w-full ${className ?? ""}`, "data-chart-canvas": "", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
8020
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ref: wrapper, className: `w-full ${className ?? ""}`, "data-chart-canvas": "", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
7407
8021
  "svg",
7408
8022
  {
7409
8023
  ref: svg,
@@ -7421,14 +8035,14 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7421
8035
  onKeyDown,
7422
8036
  children: [
7423
8037
  scene.marks.map((m) => renderChartMark(m, scene.theme.fontFamily, editable)),
7424
- presence && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ChartPresenceLayer, { presence })
8038
+ presence && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartPresenceLayer, { presence })
7425
8039
  ]
7426
8040
  }
7427
8041
  ) });
7428
8042
  }
7429
8043
 
7430
8044
  // src/chart/ChartDataGrid.tsx
7431
- var import_react59 = require("react");
8045
+ var import_react61 = require("react");
7432
8046
  var import_chart3 = require("@pixerate/editor/chart");
7433
8047
 
7434
8048
  // src/chart/styles.ts
@@ -7441,11 +8055,11 @@ var chartSectionClass = "space-y-2 border-b border-border pb-3 last:border-b-0";
7441
8055
  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";
7442
8056
 
7443
8057
  // src/chart/ChartDataGrid.tsx
7444
- var import_jsx_runtime39 = require("react/jsx-runtime");
8058
+ var import_jsx_runtime41 = require("react/jsx-runtime");
7445
8059
  function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
7446
- const [draft, setDraft] = (0, import_react59.useState)(value);
7447
- const typing = (0, import_react59.useRef)(false);
7448
- (0, import_react59.useEffect)(() => {
8060
+ const [draft, setDraft] = (0, import_react61.useState)(value);
8061
+ const typing = (0, import_react61.useRef)(false);
8062
+ (0, import_react61.useEffect)(() => {
7449
8063
  if (!typing.current) setDraft(value);
7450
8064
  }, [value]);
7451
8065
  const commit = () => {
@@ -7454,7 +8068,7 @@ function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
7454
8068
  if (draft === value) return;
7455
8069
  if (onCommit(draft) === false) setDraft(value);
7456
8070
  };
7457
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8071
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7458
8072
  "input",
7459
8073
  {
7460
8074
  ...rest,
@@ -7489,15 +8103,15 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7489
8103
  e.preventDefault();
7490
8104
  controller.pasteCells(row, column, text);
7491
8105
  };
7492
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
7493
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
7494
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("tr", { children: [
7495
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { className: "border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground", children: categoryHeader }),
8106
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
8107
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
8108
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("tr", { children: [
8109
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("th", { className: "border-b border-r border-border px-2 py-1 text-left font-medium text-muted-foreground", children: categoryHeader }),
7496
8110
  spec.series.map((s, si) => {
7497
8111
  const color = (0, import_chart3.chartSeriesColor)(spec, si);
7498
8112
  const selected = selection?.kind === "series" && selection.seriesId === s.id;
7499
- return /* @__PURE__ */ (0, import_jsx_runtime39.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_runtime39.jsxs)("div", { className: "flex items-center gap-1", children: [
7500
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8113
+ return /* @__PURE__ */ (0, import_jsx_runtime41.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_runtime41.jsxs)("div", { className: "flex items-center gap-1", children: [
8114
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7501
8115
  "input",
7502
8116
  {
7503
8117
  type: "color",
@@ -7510,7 +8124,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7510
8124
  className: "h-5 w-5 shrink-0 cursor-pointer rounded border-0 bg-transparent p-0"
7511
8125
  }
7512
8126
  ),
7513
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8127
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7514
8128
  ChartCommitInput,
7515
8129
  {
7516
8130
  value: s.name,
@@ -7520,8 +8134,8 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7520
8134
  className: `${chartInputClass} h-6 min-w-[5rem] border-transparent bg-transparent font-medium ${s.hidden ? "text-muted-foreground line-through" : ""}`
7521
8135
  }
7522
8136
  ),
7523
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
7524
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8137
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
8138
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7525
8139
  "button",
7526
8140
  {
7527
8141
  type: "button",
@@ -7534,16 +8148,16 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7534
8148
  children: s.hidden ? "\u25CB" : "\u25CF"
7535
8149
  }
7536
8150
  ),
7537
- /* @__PURE__ */ (0, import_jsx_runtime39.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" })
8151
+ /* @__PURE__ */ (0, import_jsx_runtime41.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" })
7538
8152
  ] })
7539
8153
  ] }) }, s.id);
7540
8154
  }),
7541
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { className: "w-8 border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Add series", "aria-label": "Add series", "data-action": "add-series", onClick: () => controller.addSeries(), children: "+" }) })
8155
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("th", { className: "w-8 border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Add series", "aria-label": "Add series", "data-action": "add-series", onClick: () => controller.addSeries(), children: "+" }) })
7542
8156
  ] }) }),
7543
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tbody", { children: spec.categories.map((category, i) => {
8157
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("tbody", { children: spec.categories.map((category, i) => {
7544
8158
  const rowSelected = selection?.kind === "category" && selection.index === i;
7545
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
7546
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("th", { className: "border-b border-r border-border p-0 text-left font-normal", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8159
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
8160
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("th", { className: "border-b border-r border-border p-0 text-left font-normal", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7547
8161
  ChartCommitInput,
7548
8162
  {
7549
8163
  value: category,
@@ -7557,7 +8171,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7557
8171
  spec.series.map((s) => {
7558
8172
  const value = s.values[i];
7559
8173
  const selected = selection?.kind === "point" && selection.seriesId === s.id && selection.index === i;
7560
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: `border-b border-r border-border p-0 ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8174
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("td", { className: `border-b border-r border-border p-0 ${selected ? "bg-primary/10" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7561
8175
  ChartCommitInput,
7562
8176
  {
7563
8177
  value: value === null || value === void 0 ? "" : String(value),
@@ -7572,38 +8186,38 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7572
8186
  }
7573
8187
  ) }, s.id);
7574
8188
  }),
7575
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: "border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete category", "aria-label": `Delete ${category}`, "data-action": "remove-category", onClick: () => controller.removeCategory(i), children: "\xD7" }) })
8189
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("td", { className: "border-b border-border px-1", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: chartIconButtonClass, title: "Delete category", "aria-label": `Delete ${category}`, "data-action": "remove-category", onClick: () => controller.removeCategory(i), children: "\xD7" }) })
7576
8190
  ] }, i);
7577
8191
  }) })
7578
8192
  ] }),
7579
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "p-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("button", { type: "button", className: `${chartButtonClass} h-6 border-dashed`, "data-action": "add-category", onClick: () => controller.addCategory(), children: "+ Add category" }) })
8193
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "p-1", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: `${chartButtonClass} h-6 border-dashed`, "data-action": "add-category", onClick: () => controller.addCategory(), children: "+ Add category" }) })
7580
8194
  ] });
7581
8195
  }
7582
8196
 
7583
8197
  // src/chart/ChartInspector.tsx
7584
- var import_react60 = require("react");
8198
+ var import_react62 = require("react");
7585
8199
  var import_chart4 = require("@pixerate/editor/chart");
7586
- var import_jsx_runtime40 = require("react/jsx-runtime");
8200
+ var import_jsx_runtime42 = require("react/jsx-runtime");
7587
8201
  var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
7588
8202
  function Field({ label, htmlFor, children }) {
7589
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
7590
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
7591
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "min-w-0 flex-1", children })
8203
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
8204
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
8205
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "min-w-0 flex-1", children })
7592
8206
  ] });
7593
8207
  }
7594
8208
  function Toggle({ label, checked, onChange, name }) {
7595
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
7596
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("input", { type: "checkbox", className: "h-3.5 w-3.5 accent-primary", checked, "data-option": name, onChange: (e) => onChange(e.currentTarget.checked) }),
8209
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
8210
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("input", { type: "checkbox", className: "h-3.5 w-3.5 accent-primary", checked, "data-option": name, onChange: (e) => onChange(e.currentTarget.checked) }),
7597
8211
  label
7598
8212
  ] });
7599
8213
  }
7600
8214
  function Select({ id, value, options, onChange, name, labels }) {
7601
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("select", { id, className: chartInputClass, value, "data-option": name, onChange: (e) => onChange(e.currentTarget.value), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: o, children: labels?.[o] ?? cap(o) }, o)) });
8215
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("select", { id, className: chartInputClass, value, "data-option": name, onChange: (e) => onChange(e.currentTarget.value), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: o, children: labels?.[o] ?? cap(o) }, o)) });
7602
8216
  }
7603
8217
  function AxisSection({ controller, axis, value, idBase, horizontal, numeric = false, scales = false }) {
7604
8218
  const set = (patch) => controller.setAxis(axis, patch);
7605
8219
  const setFormat = (patch) => set({ format: { ...value.format, ...patch } });
7606
- const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8220
+ const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7607
8221
  ChartCommitInput,
7608
8222
  {
7609
8223
  id: `${idBase}-${axis}-${key2}`,
@@ -7618,26 +8232,26 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7618
8232
  const name = axis === "x" ? numeric ? "X axis" : "Category axis" : axis === "y" ? "Value axis" : "Secondary axis";
7619
8233
  const valueAxis = axis !== "x" || numeric;
7620
8234
  const key = axis === "y2" ? "yAxis2" : `${axis}Axis`;
7621
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
7622
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between", children: [
7623
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
8235
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
8236
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
8237
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
7624
8238
  name,
7625
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8239
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
7626
8240
  "(",
7627
8241
  axis === "x" ? horizontal ? "left" : "bottom" : axis === "y2" ? horizontal ? "top" : "right" : horizontal ? "bottom" : "left",
7628
8242
  ")"
7629
8243
  ] })
7630
8244
  ] }),
7631
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8245
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
7632
8246
  ] }),
7633
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Title", htmlFor: `${idBase}-${axis}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-title`, value: value.title, "data-option": `${axis}Axis.title`, className: chartInputClass, onCommit: (title) => void set({ title }) }) }),
7634
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
7635
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
7636
- axis === "x" && !numeric && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Dates", name: "xAxis.kind", checked: value.kind === "date", onChange: (dates) => set({ kind: dates ? "date" : void 0 }) }),
7637
- scales && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
7638
- scales && valueAxis && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Log scale", name: `${key}.scale`, checked: value.scale === "log", onChange: (log) => set({ scale: log ? "log" : "linear" }) })
8247
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Title", htmlFor: `${idBase}-${axis}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartCommitInput, { id: `${idBase}-${axis}-title`, value: value.title, "data-option": `${axis}Axis.title`, className: chartInputClass, onCommit: (title) => void set({ title }) }) }),
8248
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8249
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
8250
+ axis === "x" && !numeric && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Dates", name: "xAxis.kind", checked: value.kind === "date", onChange: (dates) => set({ kind: dates ? "date" : void 0 }) }),
8251
+ scales && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
8252
+ scales && valueAxis && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Log scale", name: `${key}.scale`, checked: value.scale === "log", onChange: (log) => set({ scale: log ? "log" : "linear" }) })
7639
8253
  ] }),
7640
- scales && valueAxis && value.scale === "log" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Log base", htmlFor: `${idBase}-${axis}-log-base`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8254
+ scales && valueAxis && value.scale === "log" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Log base", htmlFor: `${idBase}-${axis}-log-base`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7641
8255
  ChartCommitInput,
7642
8256
  {
7643
8257
  id: `${idBase}-${axis}-log-base`,
@@ -7648,7 +8262,7 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7648
8262
  onCommit: (text) => set({ logBase: text.trim() === "" ? void 0 : Number(text) }).ok
7649
8263
  }
7650
8264
  ) }),
7651
- valueAxis && value.scale !== "log" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Step", htmlFor: `${idBase}-${axis}-step`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8265
+ valueAxis && value.scale !== "log" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Step", htmlFor: `${idBase}-${axis}-step`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7652
8266
  ChartCommitInput,
7653
8267
  {
7654
8268
  id: `${idBase}-${axis}-step`,
@@ -7660,14 +8274,14 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7660
8274
  onCommit: (text) => set({ step: text.trim() === "" ? null : Number(text) }).ok
7661
8275
  }
7662
8276
  ) }),
7663
- valueAxis && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
7664
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex gap-1", children: [
8277
+ valueAxis && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8278
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex gap-1", children: [
7665
8279
  bound("min"),
7666
8280
  bound("max")
7667
8281
  ] }) }),
7668
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Format", htmlFor: `${idBase}-${axis}-format`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex gap-1", children: [
7669
- /* @__PURE__ */ (0, import_jsx_runtime40.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 }) }),
7670
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8282
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Format", htmlFor: `${idBase}-${axis}-format`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex gap-1", children: [
8283
+ /* @__PURE__ */ (0, import_jsx_runtime42.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 }) }),
8284
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7671
8285
  ChartCommitInput,
7672
8286
  {
7673
8287
  value: value.format.decimals === void 0 ? "" : String(value.format.decimals),
@@ -7686,8 +8300,8 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7686
8300
  }
7687
8301
  )
7688
8302
  ] }) }),
7689
- value.format.style === "currency" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Currency", htmlFor: `${idBase}-${axis}-currency`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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() }) }) }),
7690
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8303
+ value.format.style === "currency" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Currency", htmlFor: `${idBase}-${axis}-currency`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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() }) }) }),
8304
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7691
8305
  ChartCommitInput,
7692
8306
  {
7693
8307
  id: `${idBase}-${axis}-code`,
@@ -7713,15 +8327,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
7713
8327
  const values = which === "xErrorBars" ? series.x ?? [] : series.values;
7714
8328
  const set = (next) => controller.updateSeries(series.id, { [which]: next });
7715
8329
  const patch = (p) => bars && set({ ...bars, ...p });
7716
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
7717
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: which === "errorBars" ? "Error bars" : "X error bars", htmlFor: `${id}-type`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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: [
7718
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "None" }),
7719
- import_chart4.CHART_ERROR_BAR_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: t, children: import_chart4.CHART_ERROR_BAR_LABELS[t] }, t))
8330
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
8331
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: which === "errorBars" ? "Error bars" : "X error bars", htmlFor: `${id}-type`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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: [
8332
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "None" }),
8333
+ import_chart4.CHART_ERROR_BAR_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t, children: import_chart4.CHART_ERROR_BAR_LABELS[t] }, t))
7720
8334
  ] }) }),
7721
- bars && (bars.type === "fixed" || bars.type === "percent" || bars.type === "stddev") && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: bars.type === "percent" ? "Percent" : bars.type === "stddev" ? "Deviations" : "Amount", htmlFor: `${id}-value`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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 }) }),
7722
- bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
7723
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Plus", htmlFor: `${id}-plus`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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 }) }),
7724
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8335
+ bars && (bars.type === "fixed" || bars.type === "percent" || bars.type === "stddev") && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: bars.type === "percent" ? "Percent" : bars.type === "stddev" ? "Deviations" : "Amount", htmlFor: `${id}-value`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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 }) }),
8336
+ bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8337
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Plus", htmlFor: `${id}-plus`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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 }) }),
8338
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7725
8339
  ChartCommitInput,
7726
8340
  {
7727
8341
  id: `${id}-minus`,
@@ -7738,15 +8352,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
7738
8352
  }
7739
8353
  ) })
7740
8354
  ] }),
7741
- bars && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
7742
- /* @__PURE__ */ (0, import_jsx_runtime40.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_runtime40.jsx)("option", { value: d, children: d === "both" ? "Both ways" : d === "plus" ? "Plus only" : "Minus only" }, d)) }),
7743
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
8355
+ bars && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
8356
+ /* @__PURE__ */ (0, import_jsx_runtime42.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_runtime42.jsx)("option", { value: d, children: d === "both" ? "Both ways" : d === "plus" ? "Plus only" : "Minus only" }, d)) }),
8357
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
7744
8358
  ] })
7745
8359
  ] });
7746
8360
  }
7747
8361
  function ChartInspector({ controller, sections, className }) {
7748
8362
  const { spec, selectedSeries } = useChartState(controller);
7749
- const idBase = (0, import_react60.useId)();
8363
+ const idBase = (0, import_react62.useId)();
7750
8364
  const show = (section) => !sections || sections.includes(section);
7751
8365
  const cartesian = (0, import_chart4.isCartesianChart)(spec.type);
7752
8366
  const family = (0, import_chart4.chartFamily)(spec);
@@ -7758,29 +8372,29 @@ function ChartInspector({ controller, sections, className }) {
7758
8372
  const hasLines = cartesian && types.some((t) => t === "line" || t === "area");
7759
8373
  const seriesIndex = selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1;
7760
8374
  const scales = family === "cartesian" || family === "xy";
7761
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
7762
- show("type") && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: chartSectionClass, "data-section": "type", children: /* @__PURE__ */ (0, import_jsx_runtime40.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_runtime40.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)) }) }),
7763
- show("style") && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
7764
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Layout", htmlFor: `${idBase}-layout`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("select", { id: `${idBase}-layout`, className: chartInputClass, value: "", "data-option": "preset.layout", onChange: (e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value }), children: [
7765
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "Quick layout\u2026" }),
7766
- import_chart4.CHART_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: p.id, title: p.description, children: p.label }, p.id))
8375
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
8376
+ show("type") && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: chartSectionClass, "data-section": "type", children: /* @__PURE__ */ (0, import_jsx_runtime42.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_runtime42.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)) }) }),
8377
+ show("style") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
8378
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Layout", htmlFor: `${idBase}-layout`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("select", { id: `${idBase}-layout`, className: chartInputClass, value: "", "data-option": "preset.layout", onChange: (e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value }), children: [
8379
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Quick layout\u2026" }),
8380
+ import_chart4.CHART_LAYOUT_PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: p.id, title: p.description, children: p.label }, p.id))
7767
8381
  ] }) }),
7768
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Colours", htmlFor: `${idBase}-colors`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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: [
7769
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "Custom" }),
7770
- import_chart4.CHART_COLOR_SCHEMES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: c.id, title: c.description, children: c.label }, c.id))
8382
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Colours", htmlFor: `${idBase}-colors`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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: [
8383
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Custom" }),
8384
+ import_chart4.CHART_COLOR_SCHEMES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: c.id, title: c.description, children: c.label }, c.id))
7771
8385
  ] }) }),
7772
- !colorCheck.ok && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", "data-chart-color-warning": "", children: colorCheck.issues[0] }),
7773
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
8386
+ !colorCheck.ok && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", "data-chart-color-warning": "", children: colorCheck.issues[0] }),
8387
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
7774
8388
  ] }),
7775
- show("titles") && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
7776
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Title", htmlFor: `${idBase}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartCommitInput, { id: `${idBase}-title`, value: spec.title, "data-option": "title", className: chartInputClass, onCommit: (title) => void controller.setTitle(title) }) }),
7777
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Subtitle", htmlFor: `${idBase}-subtitle`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartCommitInput, { id: `${idBase}-subtitle`, value: spec.subtitle, "data-option": "subtitle", className: chartInputClass, onCommit: (subtitle) => void controller.setSubtitle(subtitle) }) })
8389
+ show("titles") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
8390
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Title", htmlFor: `${idBase}-title`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartCommitInput, { id: `${idBase}-title`, value: spec.title, "data-option": "title", className: chartInputClass, onCommit: (title) => void controller.setTitle(title) }) }),
8391
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Subtitle", htmlFor: `${idBase}-subtitle`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartCommitInput, { id: `${idBase}-subtitle`, value: spec.subtitle, "data-option": "subtitle", className: chartInputClass, onCommit: (subtitle) => void controller.setSubtitle(subtitle) }) })
7778
8392
  ] }),
7779
- show("options") && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
7780
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Stacking", htmlFor: `${idBase}-stacking`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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 }) }) }),
7781
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Bars", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: ["vertical", "horizontal"].map((o) => /* @__PURE__ */ (0, import_jsx_runtime40.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)) }) }),
7782
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Lines", htmlFor: `${idBase}-curve`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Select, { id: `${idBase}-curve`, name: "curve", value: spec.curve, options: import_chart4.CHART_CURVES, onChange: (curve) => controller.update({ curve }) }) }),
7783
- spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8393
+ show("options") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
8394
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Stacking", htmlFor: `${idBase}-stacking`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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 }) }) }),
8395
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Bars", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "flex gap-0.5 rounded-md bg-muted p-0.5", children: ["vertical", "horizontal"].map((o) => /* @__PURE__ */ (0, import_jsx_runtime42.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)) }) }),
8396
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Lines", htmlFor: `${idBase}-curve`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Select, { id: `${idBase}-curve`, name: "curve", value: spec.curve, options: import_chart4.CHART_CURVES, onChange: (curve) => controller.update({ curve }) }) }),
8397
+ spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7784
8398
  "input",
7785
8399
  {
7786
8400
  id: `${idBase}-hole`,
@@ -7796,7 +8410,7 @@ function ChartInspector({ controller, sections, className }) {
7796
8410
  onChange: (e) => controller.update({ innerRadius: Number(e.currentTarget.value) })
7797
8411
  }
7798
8412
  ) }),
7799
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8413
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7800
8414
  "input",
7801
8415
  {
7802
8416
  id: `${idBase}-gap`,
@@ -7812,31 +8426,31 @@ function ChartInspector({ controller, sections, className }) {
7812
8426
  onChange: (e) => controller.update({ gapWidth: Number(e.currentTarget.value) })
7813
8427
  }
7814
8428
  ) }),
7815
- spec.dataLabels && hasBars && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Labels", htmlFor: `${idBase}-label-position`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Select, { id: `${idBase}-label-position`, name: "labelPosition", value: spec.labelPosition, options: import_chart4.CHART_LABEL_POSITIONS, onChange: (labelPosition) => controller.update({ labelPosition }) }) }),
7816
- spec.type === "histogram" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Bins", htmlFor: `${idBase}-bins`, children: /* @__PURE__ */ (0, import_jsx_runtime40.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 }) }),
7817
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
7818
- spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
7819
- hasLines && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
7820
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
8429
+ spec.dataLabels && hasBars && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Labels", htmlFor: `${idBase}-label-position`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Select, { id: `${idBase}-label-position`, name: "labelPosition", value: spec.labelPosition, options: import_chart4.CHART_LABEL_POSITIONS, onChange: (labelPosition) => controller.update({ labelPosition }) }) }),
8430
+ spec.type === "histogram" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Bins", htmlFor: `${idBase}-bins`, children: /* @__PURE__ */ (0, import_jsx_runtime42.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 }) }),
8431
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8432
+ spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
8433
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
8434
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
7821
8435
  ] })
7822
8436
  ] }),
7823
- show("legend") && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
7824
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between", children: [
7825
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
7826
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
8437
+ show("legend") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
8438
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
8439
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
8440
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
7827
8441
  ] }),
7828
- spec.legend.show && /* @__PURE__ */ (0, import_jsx_runtime40.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_runtime40.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)) })
8442
+ spec.legend.show && /* @__PURE__ */ (0, import_jsx_runtime42.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_runtime42.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)) })
7829
8443
  ] }),
7830
- show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
7831
- family !== "box" && family !== "histogram" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AxisSection, { controller, axis: "x", value: spec.xAxis, idBase, horizontal: spec.orientation === "horizontal", numeric: family === "xy", scales }),
7832
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
7833
- usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
8444
+ show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8445
+ family !== "box" && family !== "histogram" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AxisSection, { controller, axis: "x", value: spec.xAxis, idBase, horizontal: spec.orientation === "horizontal", numeric: family === "xy", scales }),
8446
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
8447
+ usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
7834
8448
  ] }),
7835
- show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
7836
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
7837
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Name", htmlFor: `${idBase}-series-name`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartCommitInput, { id: `${idBase}-series-name`, value: selectedSeries.name, "data-option": "series.name", className: chartInputClass, onCommit: (name) => void controller.updateSeries(selectedSeries.id, { name }) }) }),
7838
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Colour", htmlFor: `${idBase}-series-color`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1", children: [
7839
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8449
+ show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
8450
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
8451
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Name", htmlFor: `${idBase}-series-name`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChartCommitInput, { id: `${idBase}-series-name`, value: selectedSeries.name, "data-option": "series.name", className: chartInputClass, onCommit: (name) => void controller.updateSeries(selectedSeries.id, { name }) }) }),
8452
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Colour", htmlFor: `${idBase}-series-color`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1", children: [
8453
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7840
8454
  "input",
7841
8455
  {
7842
8456
  id: `${idBase}-series-color`,
@@ -7849,9 +8463,9 @@ function ChartInspector({ controller, sections, className }) {
7849
8463
  onChange: (e) => controller.updateSeries(selectedSeries.id, { color: e.currentTarget.value })
7850
8464
  }
7851
8465
  ),
7852
- selectedSeries.color && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "reset-color", onClick: () => controller.updateSeries(selectedSeries.id, { color: null }), children: "Palette" })
8466
+ selectedSeries.color && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "reset-color", onClick: () => controller.updateSeries(selectedSeries.id, { color: null }), children: "Palette" })
7853
8467
  ] }) }),
7854
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8468
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7855
8469
  "select",
7856
8470
  {
7857
8471
  id: `${idBase}-series-type`,
@@ -7860,12 +8474,12 @@ function ChartInspector({ controller, sections, className }) {
7860
8474
  "data-option": "series.type",
7861
8475
  onChange: (e) => controller.updateSeries(selectedSeries.id, { type: e.currentTarget.value || null }),
7862
8476
  children: [
7863
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "Chart type" }),
7864
- import_chart4.CHART_SERIES_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: t, children: import_chart4.CHART_TYPE_LABELS[t] }, t))
8477
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Chart type" }),
8478
+ import_chart4.CHART_SERIES_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t, children: import_chart4.CHART_TYPE_LABELS[t] }, t))
7865
8479
  ]
7866
8480
  }
7867
8481
  ) }),
7868
- (cartesian || family === "xy") && ["line", "area", "scatter"].includes((0, import_chart4.chartSeriesType)(spec, selectedSeries)) && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Marker", htmlFor: `${idBase}-series-marker`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8482
+ (cartesian || family === "xy") && ["line", "area", "scatter"].includes((0, import_chart4.chartSeriesType)(spec, selectedSeries)) && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Marker", htmlFor: `${idBase}-series-marker`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7869
8483
  "select",
7870
8484
  {
7871
8485
  id: `${idBase}-series-marker`,
@@ -7874,20 +8488,20 @@ function ChartInspector({ controller, sections, className }) {
7874
8488
  "data-option": "series.marker",
7875
8489
  onChange: (e) => controller.updateSeries(selectedSeries.id, { marker: e.currentTarget.value || null }),
7876
8490
  children: [
7877
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "Default" }),
7878
- import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: m, children: cap(m) }, m))
8491
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Default" }),
8492
+ import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: m, children: cap(m) }, m))
7879
8493
  ]
7880
8494
  }
7881
8495
  ) }),
7882
- scales && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
7883
- family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
7884
- (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
7885
- (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
7886
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
7887
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "R\xB2", name: `trendline.${i}.showR2`, checked: !!t.showR2, onChange: (showR2) => controller.updateTrendline(selectedSeries.id, i, { showR2 }) }),
7888
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: chartButtonClass, "aria-label": "Delete trendline", "data-action": "trendline-delete", onClick: () => controller.removeTrendline(selectedSeries.id, i), children: "\xD7" })
8496
+ scales && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
8497
+ family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
8498
+ (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
8499
+ (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
8500
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
8501
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "R\xB2", name: `trendline.${i}.showR2`, checked: !!t.showR2, onChange: (showR2) => controller.updateTrendline(selectedSeries.id, i, { showR2 }) }),
8502
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartButtonClass, "aria-label": "Delete trendline", "data-action": "trendline-delete", onClick: () => controller.removeTrendline(selectedSeries.id, i), children: "\xD7" })
7889
8503
  ] }, i)),
7890
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8504
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7891
8505
  "select",
7892
8506
  {
7893
8507
  className: chartInputClass,
@@ -7896,32 +8510,32 @@ function ChartInspector({ controller, sections, className }) {
7896
8510
  "data-option": "trendline.add",
7897
8511
  onChange: (e) => e.currentTarget.value && controller.addTrendline(selectedSeries.id, { type: e.currentTarget.value }),
7898
8512
  children: [
7899
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: "", children: "Add trendline\u2026" }),
7900
- import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
8513
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Add trendline\u2026" }),
8514
+ import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
7901
8515
  ]
7902
8516
  }
7903
8517
  )
7904
8518
  ] }),
7905
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
7906
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
7907
- family === "cartesian" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Secondary axis", name: "series.axis", checked: selectedSeries.axis === "secondary", onChange: (secondary) => controller.updateSeries(selectedSeries.id, { axis: secondary ? "secondary" : null }) }),
7908
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "flex-1" }),
7909
- /* @__PURE__ */ (0, import_jsx_runtime40.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" }),
7910
- /* @__PURE__ */ (0, import_jsx_runtime40.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" }),
7911
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: `${chartButtonClass} text-destructive`, "data-action": "series-delete", onClick: () => controller.removeSeries(selectedSeries.id), children: "Delete" })
8519
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
8520
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
8521
+ family === "cartesian" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Secondary axis", name: "series.axis", checked: selectedSeries.axis === "secondary", onChange: (secondary) => controller.updateSeries(selectedSeries.id, { axis: secondary ? "secondary" : null }) }),
8522
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-1" }),
8523
+ /* @__PURE__ */ (0, import_jsx_runtime42.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" }),
8524
+ /* @__PURE__ */ (0, import_jsx_runtime42.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" }),
8525
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: `${chartButtonClass} text-destructive`, "data-action": "series-delete", onClick: () => controller.removeSeries(selectedSeries.id), children: "Delete" })
7912
8526
  ] })
7913
8527
  ] })
7914
8528
  ] });
7915
8529
  }
7916
8530
 
7917
8531
  // src/chart-node/ChartNodeView.tsx
7918
- var import_jsx_runtime41 = require("react/jsx-runtime");
8532
+ var import_jsx_runtime43 = require("react/jsx-runtime");
7919
8533
  function ChartNodeView({ state, theme, showDataGrid = true }) {
7920
8534
  const { controller, editing, editable, selected, width, height, setEditing } = state;
7921
8535
  const open = () => {
7922
8536
  if (editable && !editing) setEditing(true);
7923
8537
  };
7924
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8538
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7925
8539
  "div",
7926
8540
  {
7927
8541
  className: `not-prose my-2 rounded-md border bg-background p-1 ${selected ? "border-primary ring-1 ring-primary" : "border-border"}`,
@@ -7934,24 +8548,24 @@ function ChartNodeView({ state, theme, showDataGrid = true }) {
7934
8548
  }
7935
8549
  },
7936
8550
  children: [
7937
- editing && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "mb-1 flex items-center justify-between gap-2 px-1", "data-chart-node-toolbar": "", children: [
7938
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
7939
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
8551
+ editing && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "mb-1 flex items-center justify-between gap-2 px-1", "data-chart-node-toolbar": "", children: [
8552
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
8553
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
7940
8554
  ] }),
7941
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8555
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7942
8556
  "div",
7943
8557
  {
7944
8558
  className: editable && !editing ? "cursor-pointer" : void 0,
7945
8559
  onClick: open,
7946
8560
  title: editable && !editing ? "Click to edit the chart" : void 0,
7947
8561
  "data-chart-node-canvas": "",
7948
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
8562
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
7949
8563
  }
7950
8564
  ),
7951
8565
  editing && // Wraps by the document's width, not the viewport's: side by side when there is room.
7952
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
7953
- showDataGrid && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "min-w-0 flex-[1_1_20rem] overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ChartDataGrid, { controller }) }),
7954
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ChartInspector, { controller, className: "max-h-96 min-w-0 flex-[1_1_16rem] overflow-y-auto rounded-md border border-border p-3" })
8566
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
8567
+ showDataGrid && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "min-w-0 flex-[1_1_20rem] overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartDataGrid, { controller }) }),
8568
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartInspector, { controller, className: "max-h-96 min-w-0 flex-[1_1_16rem] overflow-y-auto rounded-md border border-border p-3" })
7955
8569
  ] })
7956
8570
  ]
7957
8571
  }
@@ -7969,7 +8583,7 @@ function createReactChartNodeView(options = {}) {
7969
8583
  scheduled = true;
7970
8584
  queueMicrotask(() => {
7971
8585
  scheduled = false;
7972
- if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Component, { ...props, state: latest }));
8586
+ if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Component, { ...props, state: latest }));
7973
8587
  });
7974
8588
  };
7975
8589
  schedule();
@@ -7989,6 +8603,7 @@ function createReactChartNodeView(options = {}) {
7989
8603
  0 && (module.exports = {
7990
8604
  AdjustmentLayersPanel,
7991
8605
  AssetMentionChips,
8606
+ BrushOptionsBar,
7992
8607
  BubbleMenu,
7993
8608
  ChartNodeView,
7994
8609
  CommandPalette,
@@ -8009,6 +8624,7 @@ function createReactChartNodeView(options = {}) {
8009
8624
  ImageEditor,
8010
8625
  InsertTableGrid,
8011
8626
  JobProgress,
8627
+ LayersPanel,
8012
8628
  MergePreview,
8013
8629
  NameManager,
8014
8630
  OutlinePanel,