@pixerate/editor-react 0.58.0 → 0.59.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,
@@ -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,458 @@ 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, 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 commitNext = (0, import_react38.useRef)(true);
4264
+ const state = controller.getState();
4265
+ const rows = (0, import_image_editor6.layerPanelRows)(state.layers, state.activeLayerId);
4266
+ const active = controller.getActiveLayer();
4267
+ const attempt = (fn) => {
4268
+ try {
4269
+ setError(null);
4270
+ fn();
4271
+ } catch (err) {
4272
+ setError(err instanceof Error ? err.message : String(err));
4273
+ }
4274
+ };
4275
+ const run = async (action) => {
4276
+ setMenu(null);
4277
+ setError(await (0, import_image_editor6.runLayerMenuAction)(controller, action));
4278
+ };
4279
+ const prop = (key, value) => attempt(() => {
4280
+ controller.setLayerProperties(active.id, { [key]: value }, commitNext.current);
4281
+ commitNext.current = false;
4282
+ });
4283
+ const sliderEvents = {
4284
+ onPointerDown: () => commitNext.current = true,
4285
+ onPointerUp: () => commitNext.current = true,
4286
+ onKeyDown: () => commitNext.current = true
4287
+ };
4288
+ const onDrop = (e, row) => {
4289
+ e.preventDefault();
4290
+ const id = e.dataTransfer.getData("text/x-pixerate-layer") || drag;
4291
+ setDrag(null);
4292
+ if (!id) return;
4293
+ const rect = e.currentTarget.getBoundingClientRect();
4294
+ const fraction = rect.height ? (e.clientY - rect.top) / rect.height : 0.5;
4295
+ const placement = (0, import_image_editor6.dropPlacement)(state.layers, id, row.layer.id, (0, import_image_editor6.dropZone)(fraction, row.layer.type === "group"));
4296
+ if (placement) attempt(() => controller.moveLayer(id, placement));
4297
+ };
4298
+ const thumb = (layer) => layer.type === "pixel" ? controller.getLayerThumbnail(layer.id, { maxSide: 64 }) : null;
4299
+ const maskThumb = (layer) => layer.mask && !layer.mask.source ? controller.getLayerThumbnail(layer.id, { maxSide: 64, mask: true }) : null;
4300
+ const locked = (layer) => Boolean(layer.locks?.all || layer.locks?.pixels || layer.locks?.position || layer.locks?.transparency);
4301
+ 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: [
4302
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "toolbar", "aria-label": "Layer actions", children: [
4303
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-layer"), children: "New Layer" }),
4304
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, onClick: () => run("new-group"), children: "New Group" }),
4305
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("duplicate"), children: "Duplicate" }),
4306
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("add-mask"), children: "Add Mask" }),
4307
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: iconButton, disabled: !active, onClick: () => run("delete"), children: "Delete" }),
4308
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4309
+ "button",
4310
+ {
4311
+ type: "button",
4312
+ className: iconButton,
4313
+ "aria-label": "Layer menu",
4314
+ "aria-haspopup": "menu",
4315
+ onClick: (e) => {
4316
+ e.stopPropagation();
4317
+ const r = e.currentTarget.getBoundingClientRect();
4318
+ setMenu(menu ? null : { x: r.left, y: r.bottom });
4319
+ },
4320
+ children: "\u22EF"
4321
+ }
4322
+ )
4323
+ ] }),
4324
+ 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: [
4325
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
4326
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-slate-400", children: [
4327
+ "Opacity ",
4328
+ Math.round(active.opacity * 100),
4329
+ "%"
4330
+ ] }),
4331
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4332
+ "input",
4333
+ {
4334
+ type: "range",
4335
+ min: 0,
4336
+ max: 100,
4337
+ "aria-label": "Layer opacity",
4338
+ value: Math.round(active.opacity * 100),
4339
+ ...sliderEvents,
4340
+ onChange: (e) => prop("opacity", Number(e.target.value) / 100),
4341
+ className: "accent-indigo-500"
4342
+ }
4343
+ )
4344
+ ] }),
4345
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex flex-col gap-0.5", children: [
4346
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-slate-400", children: [
4347
+ "Fill ",
4348
+ Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
4349
+ "%"
4350
+ ] }),
4351
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4352
+ "input",
4353
+ {
4354
+ type: "range",
4355
+ min: 0,
4356
+ max: 100,
4357
+ "aria-label": "Layer fill",
4358
+ disabled: active.type !== "pixel",
4359
+ value: Math.round(((active.type === "pixel" ? active.fillOpacity : void 0) ?? 1) * 100),
4360
+ ...sliderEvents,
4361
+ onChange: (e) => prop("fillOpacity", Number(e.target.value) / 100),
4362
+ className: "accent-indigo-500 disabled:opacity-40"
4363
+ }
4364
+ )
4365
+ ] }),
4366
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4367
+ "select",
4368
+ {
4369
+ "aria-label": "Layer blend mode",
4370
+ className: "bg-slate-800 border border-slate-700 rounded px-1.5 py-1",
4371
+ value: active.blend,
4372
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { blend: e.target.value })),
4373
+ children: [
4374
+ active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "pass-through", children: "Pass Through" }),
4375
+ import_image_editor6.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: m.id, children: m.label }, m.id))
4376
+ ]
4377
+ }
4378
+ ),
4379
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-1.5 text-slate-300", children: [
4380
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4381
+ "input",
4382
+ {
4383
+ type: "checkbox",
4384
+ "aria-label": "Clip to layer below",
4385
+ checked: Boolean(active.clipped),
4386
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { clipped: e.target.checked })),
4387
+ className: "accent-indigo-500"
4388
+ }
4389
+ ),
4390
+ "Clip to below"
4391
+ ] }),
4392
+ /* @__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: [
4393
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4394
+ "input",
4395
+ {
4396
+ type: "checkbox",
4397
+ "aria-label": `Lock ${k}`,
4398
+ checked: Boolean(active.locks?.[k]),
4399
+ onChange: (e) => attempt(() => controller.setLayerProperties(active.id, { locks: { ...active.locks, [k]: e.target.checked } })),
4400
+ className: "accent-indigo-500"
4401
+ }
4402
+ ),
4403
+ k
4404
+ ] }, k)) })
4405
+ ] }),
4406
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5", role: "tree", "aria-label": "Layers", children: rows.map((row) => {
4407
+ const { layer } = row;
4408
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4409
+ "li",
4410
+ {
4411
+ role: "treeitem",
4412
+ "aria-selected": row.active,
4413
+ "aria-level": row.depth + 1,
4414
+ "data-layer-id": layer.id,
4415
+ draggable: !layer.locks?.all,
4416
+ onDragStart: (e) => {
4417
+ e.dataTransfer.setData("text/x-pixerate-layer", layer.id);
4418
+ setDrag(layer.id);
4419
+ },
4420
+ onDragOver: (e) => e.preventDefault(),
4421
+ onDrop: (e) => onDrop(e, row),
4422
+ tabIndex: 0,
4423
+ onClick: () => attempt(() => controller.setActiveLayer(layer.id, "pixels")),
4424
+ onKeyDown: (e) => {
4425
+ if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
4426
+ e.preventDefault();
4427
+ attempt(() => controller.setActiveLayer(layer.id, "pixels"));
4428
+ }
4429
+ },
4430
+ onContextMenu: (e) => {
4431
+ e.preventDefault();
4432
+ controller.setActiveLayer(layer.id, state.activeLayerId === layer.id ? state.activeTarget : "pixels");
4433
+ setMenu({ x: e.clientX, y: e.clientY });
4434
+ },
4435
+ className: rowClass(row.active),
4436
+ style: { paddingLeft: 6 + row.depth * 14 },
4437
+ children: [
4438
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4439
+ "button",
4440
+ {
4441
+ type: "button",
4442
+ "aria-label": layer.visible ? `Hide ${row.label}` : `Show ${row.label}`,
4443
+ "aria-pressed": layer.visible,
4444
+ className: "w-4 text-center text-slate-300",
4445
+ onClick: (e) => {
4446
+ e.stopPropagation();
4447
+ attempt(() => controller.setLayerProperties(layer.id, { visible: !layer.visible }));
4448
+ },
4449
+ children: layer.visible ? "\u25CF" : "\u25CB"
4450
+ }
4451
+ ),
4452
+ layer.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4453
+ "button",
4454
+ {
4455
+ type: "button",
4456
+ "aria-label": layer.collapsed ? `Expand ${row.label}` : `Collapse ${row.label}`,
4457
+ className: "w-3 text-slate-400",
4458
+ onClick: (e) => {
4459
+ e.stopPropagation();
4460
+ attempt(() => controller.setLayerProperties(layer.id, { collapsed: !layer.collapsed }));
4461
+ },
4462
+ children: layer.collapsed ? "\u25B8" : "\u25BE"
4463
+ }
4464
+ ),
4465
+ row.clipped && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-slate-500", "aria-label": "Clipped", children: "\u21B3" }),
4466
+ layer.type === "pixel" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4467
+ Thumbnail,
4468
+ {
4469
+ pixels: thumb(layer),
4470
+ size: thumbnailSize,
4471
+ label: `${row.label} pixels`,
4472
+ selected: row.active && state.activeTarget === "pixels" && Boolean(layer.mask)
4473
+ }
4474
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4475
+ "span",
4476
+ {
4477
+ className: "shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700",
4478
+ style: { width: thumbnailSize, height: thumbnailSize },
4479
+ children: (0, import_image_editor6.layerBadge)(layer)
4480
+ }
4481
+ ),
4482
+ layer.mask && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4483
+ Thumbnail,
4484
+ {
4485
+ pixels: maskThumb(layer),
4486
+ size: thumbnailSize,
4487
+ label: `${row.label} mask${layer.mask.enabled === false ? " (disabled)" : ""}`,
4488
+ testId: "layer-mask-thumbnail",
4489
+ selected: row.active && state.activeTarget === "mask",
4490
+ onClick: (e) => {
4491
+ e.stopPropagation();
4492
+ if (e.shiftKey) attempt(() => controller.setLayerMaskProps(layer.id, { enabled: layer.mask.enabled === false }));
4493
+ else attempt(() => controller.setActiveLayer(layer.id, "mask"));
4494
+ }
4495
+ }
4496
+ ),
4497
+ renaming === layer.id ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4498
+ "input",
4499
+ {
4500
+ autoFocus: true,
4501
+ "aria-label": "Layer name",
4502
+ defaultValue: layer.name || row.label,
4503
+ className: "flex-1 min-w-0 bg-slate-900 border border-slate-600 rounded px-1",
4504
+ onClick: (e) => e.stopPropagation(),
4505
+ onBlur: (e) => {
4506
+ setRenaming(null);
4507
+ if (e.target.value.trim() && e.target.value !== layer.name) attempt(() => controller.setLayerProperties(layer.id, { name: e.target.value }));
4508
+ },
4509
+ onKeyDown: (e) => {
4510
+ if (e.key === "Enter") e.target.blur();
4511
+ if (e.key === "Escape") setRenaming(null);
4512
+ }
4513
+ }
4514
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4515
+ "span",
4516
+ {
4517
+ className: `flex-1 min-w-0 truncate ${layer.visible ? "" : "text-slate-500"}`,
4518
+ onDoubleClick: (e) => {
4519
+ e.stopPropagation();
4520
+ setRenaming(layer.id);
4521
+ },
4522
+ children: row.label
4523
+ }
4524
+ ),
4525
+ locked(layer) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-label": "Locked", className: "text-slate-400", children: "\u{1F512}" }),
4526
+ layer.blend !== "normal" && layer.blend !== "pass-through" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[9px] text-slate-500", children: layer.blend })
4527
+ ]
4528
+ },
4529
+ layer.id
4530
+ );
4531
+ }) }),
4532
+ error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
4533
+ menu && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4534
+ "div",
4535
+ {
4536
+ role: "menu",
4537
+ "aria-label": "Layer menu",
4538
+ className: "fixed z-50 min-w-44 rounded border border-slate-700 bg-slate-900 py-1 shadow-xl",
4539
+ style: { left: menu.x, top: menu.y },
4540
+ onClick: (e) => e.stopPropagation(),
4541
+ onKeyDown: (e) => e.key === "Escape" && setMenu(null),
4542
+ children: (0, import_image_editor6.layerMenu)(controller).map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4543
+ "button",
4544
+ {
4545
+ type: "button",
4546
+ role: "menuitem",
4547
+ disabled: !item.enabled,
4548
+ className: "block w-full px-3 py-1 text-left hover:bg-slate-800 disabled:opacity-40",
4549
+ onClick: () => run(item.action),
4550
+ children: item.label
4551
+ },
4552
+ item.action
4553
+ ))
4554
+ }
4555
+ )
4556
+ ] });
4557
+ };
4558
+
4559
+ // src/image-editor/BrushOptionsBar.tsx
4560
+ var import_react39 = require("react");
4561
+ var import_image_editor7 = require("@pixerate/editor/image-editor");
4562
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4563
+ 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"}`;
4564
+ var BrushOptionsBar = ({ controller, className }) => {
4565
+ const [, setTick] = (0, import_react39.useState)(0);
4566
+ (0, import_react39.useEffect)(() => controller.subscribe(() => setTick((n) => n + 1)), [controller]);
4567
+ const [error, setError] = (0, import_react39.useState)(null);
4568
+ const state = controller.getState();
4569
+ const { brush, foreground, background } = state.paint;
4570
+ const attempt = (fn) => {
4571
+ try {
4572
+ setError(null);
4573
+ fn();
4574
+ } catch (err) {
4575
+ setError(err instanceof Error ? err.message : String(err));
4576
+ }
4577
+ };
4578
+ 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: [
4579
+ /* @__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)(
4580
+ "button",
4581
+ {
4582
+ type: "button",
4583
+ "aria-pressed": state.activeTool === t.id,
4584
+ title: `${t.label} (${t.shortcut})`,
4585
+ className: chip(state.activeTool === t.id),
4586
+ onClick: () => controller.setTool(t.id),
4587
+ children: t.label
4588
+ },
4589
+ t.id
4590
+ )) }),
4591
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", role: "group", "aria-label": "Colours", children: [
4592
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1", children: [
4593
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4594
+ "input",
4595
+ {
4596
+ type: "color",
4597
+ "aria-label": "Foreground colour",
4598
+ value: foreground,
4599
+ onChange: (e) => controller.setPaintOptions({ foreground: e.target.value }),
4600
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
4601
+ }
4602
+ ),
4603
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-slate-400", children: "FG" })
4604
+ ] }),
4605
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1", children: [
4606
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4607
+ "input",
4608
+ {
4609
+ type: "color",
4610
+ "aria-label": "Background colour",
4611
+ value: background,
4612
+ onChange: (e) => controller.setPaintOptions({ background: e.target.value }),
4613
+ className: "h-6 w-8 rounded border border-slate-700 bg-transparent"
4614
+ }
4615
+ ),
4616
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-slate-400", children: "BG" })
4617
+ ] }),
4618
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", title: "Swap colours (X)", className: chip(false), onClick: () => controller.swapPaintColors(), children: "Swap" }),
4619
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", title: "Default colours (D)", className: chip(false), onClick: () => controller.resetPaintColors(), children: "Default" })
4620
+ ] }),
4621
+ import_image_editor7.BRUSH_OPTION_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4622
+ ControlSlider,
4623
+ {
4624
+ spec,
4625
+ value: brush[spec.id],
4626
+ onChange: (v) => controller.setPaintOptions({ brush: { [spec.id]: v } })
4627
+ },
4628
+ spec.id
4629
+ )),
4630
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-wrap gap-3 text-slate-300", role: "group", "aria-label": "Pressure", children: [
4631
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4632
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4633
+ "input",
4634
+ {
4635
+ type: "checkbox",
4636
+ "aria-label": "Pressure controls size",
4637
+ checked: brush.pressureSize,
4638
+ onChange: (e) => controller.setPaintOptions({ brush: { pressureSize: e.target.checked } }),
4639
+ className: "accent-indigo-500"
4640
+ }
4641
+ ),
4642
+ "Pressure size"
4643
+ ] }),
4644
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "flex items-center gap-1.5", children: [
4645
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4646
+ "input",
4647
+ {
4648
+ type: "checkbox",
4649
+ "aria-label": "Pressure controls opacity",
4650
+ checked: brush.pressureOpacity,
4651
+ onChange: (e) => controller.setPaintOptions({ brush: { pressureOpacity: e.target.checked } }),
4652
+ className: "accent-indigo-500"
4653
+ }
4654
+ ),
4655
+ "Pressure opacity"
4656
+ ] })
4657
+ ] }),
4658
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex gap-1", children: [
4659
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.fillPixels()), children: "Fill" }),
4660
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: chip(false), onClick: () => attempt(() => controller.clearPixels()), children: "Clear" })
4661
+ ] }),
4662
+ error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", className: "text-rose-400", children: error })
4663
+ ] });
4664
+ };
4665
+
4666
+ // src/image-editor/SelectionOptionsBar.tsx
4667
+ var import_react40 = require("react");
4668
+ var import_image_editor8 = require("@pixerate/editor/image-editor");
4669
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4220
4670
  var MODIFY_OPS = [
4221
4671
  { op: "grow", label: "Grow" },
4222
4672
  { op: "shrink", label: "Shrink" },
@@ -4233,20 +4683,20 @@ var SelectionOptionsBar = ({
4233
4683
  quickMask,
4234
4684
  className = ""
4235
4685
  }) => {
4236
- const [radius, setRadius] = (0, import_react38.useState)(2);
4686
+ const [radius, setRadius] = (0, import_react40.useState)(2);
4237
4687
  const set = (patch) => onOptionsChange({ ...options, ...patch });
4238
4688
  const sel = selection === void 0 ? controller.getSelection() : selection;
4239
4689
  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 })
4690
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { "data-testid": "selection-options-bar", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4691
+ /* @__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)) }),
4692
+ /* @__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)) }),
4693
+ options.tool === "wand" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-2", children: [
4694
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex flex-col gap-1", children: [
4695
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4696
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Tolerance" }),
4697
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-mono", children: options.tolerance })
4248
4698
  ] }),
4249
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4699
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4250
4700
  "input",
4251
4701
  {
4252
4702
  type: "range",
@@ -4260,29 +4710,29 @@ var SelectionOptionsBar = ({
4260
4710
  }
4261
4711
  )
4262
4712
  ] }),
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 }) }),
4713
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4714
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.contiguous, onChange: (e) => set({ contiguous: e.target.checked }) }),
4265
4715
  "Contiguous"
4266
4716
  ] }),
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 }) }),
4717
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4718
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.sampleMerged, onChange: (e) => set({ sampleMerged: e.target.checked }) }),
4269
4719
  "Sample adjusted image"
4270
4720
  ] })
4271
4721
  ] }),
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 }) }),
4722
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4723
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { type: "checkbox", checked: options.antiAlias, onChange: (e) => set({ antiAlias: e.target.checked }) }),
4274
4724
  "Anti-alias"
4275
4725
  ] }),
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" })
4726
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4727
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.selectAll(), children: "Select All" }),
4728
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), disabled: !sel, onClick: () => controller.deselect(), children: "Deselect" }),
4729
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: btn(false), onClick: () => controller.invertSelection(), children: "Inverse" }),
4730
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", "aria-pressed": qm, className: btn(qm), onClick: () => controller.setQuickMask(!qm), children: "Quick Mask" })
4281
4731
  ] }),
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: [
4732
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
4733
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-1 text-slate-400", children: [
4284
4734
  "Radius",
4285
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4735
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4286
4736
  "input",
4287
4737
  {
4288
4738
  type: "number",
@@ -4296,24 +4746,24 @@ var SelectionOptionsBar = ({
4296
4746
  }
4297
4747
  )
4298
4748
  ] }),
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))
4749
+ 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
4750
  ] }),
4301
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor6.describeSelection)(sel) })
4751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { "data-testid": "selection-status", className: "text-slate-400", children: (0, import_image_editor8.describeSelection)(sel) })
4302
4752
  ] });
4303
4753
  };
4304
4754
 
4305
4755
  // 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");
4756
+ var import_react41 = require("react");
4757
+ var import_image_editor9 = require("@pixerate/editor/image-editor");
4758
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4309
4759
  var DEFAULT_PARAMS = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
4310
4760
  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
4761
  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");
4762
+ const [params, setParams] = (0, import_react41.useState)(DEFAULT_PARAMS);
4763
+ const [busy, setBusy] = (0, import_react41.useState)(false);
4764
+ const [error, setError] = (0, import_react41.useState)(null);
4765
+ const [layerId, setLayerId] = (0, import_react41.useState)("");
4766
+ const [newKind, setNewKind] = (0, import_react41.useState)("hueSaturation");
4317
4767
  const sel = selection === void 0 ? controller.getSelection() : selection;
4318
4768
  const list = layers ?? controller.getAdjustmentLayers();
4319
4769
  const target = list.find((l) => l.id === layerId) ?? list[list.length - 1];
@@ -4328,17 +4778,17 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4328
4778
  setBusy(false);
4329
4779
  }
4330
4780
  };
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: [
4781
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { "data-testid": "refine-edge-panel", className: `flex flex-col gap-3 text-xs ${className}`, children: [
4782
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Refine Edge" }),
4783
+ import_image_editor9.REFINE_EDGE_CONTROLS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4784
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4785
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: c.label }),
4786
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4337
4787
  params[c.id],
4338
4788
  c.unit
4339
4789
  ] })
4340
4790
  ] }),
4341
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4791
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4342
4792
  "input",
4343
4793
  {
4344
4794
  type: "range",
@@ -4352,67 +4802,67 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4352
4802
  }
4353
4803
  )
4354
4804
  ] }, 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 }) }),
4805
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
4806
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("input", { type: "checkbox", checked: params.smartRadius, onChange: (e) => setParams({ ...params, smartRadius: e.target.checked }) }),
4357
4807
  "Smart Radius"
4358
4808
  ] }),
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" })
4809
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex gap-1", children: [
4810
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !sel || busy, onClick: refine, children: "Refine Edge" }),
4811
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, onClick: () => setParams(DEFAULT_PARAMS), children: "Reset" })
4362
4812
  ] }),
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)(
4813
+ error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { role: "alert", className: "text-rose-400", children: error }),
4814
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2", children: "Layer Mask" }),
4815
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex gap-1 items-center", children: [
4816
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4367
4817
  "select",
4368
4818
  {
4369
4819
  "aria-label": "New masked layer kind",
4370
4820
  value: newKind,
4371
4821
  onChange: (e) => setNewKind(e.target.value),
4372
4822
  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))
4823
+ children: import_image_editor9.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: k.kind, children: k.label }, k.kind))
4374
4824
  }
4375
4825
  ),
4376
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4826
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4377
4827
  "button",
4378
4828
  {
4379
4829
  type: "button",
4380
4830
  className: button,
4381
4831
  disabled: !sel,
4382
- onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor7.layerMaskFromSelection)(sel) })),
4832
+ onClick: () => sel && setLayerId(controller.addAdjustmentLayer({ kind: newKind, mask: (0, import_image_editor9.layerMaskFromSelection)(sel) })),
4383
4833
  children: "New Masked Layer"
4384
4834
  }
4385
4835
  )
4386
4836
  ] }),
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)(
4837
+ list.length > 0 && target && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-2", children: [
4838
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4389
4839
  "select",
4390
4840
  {
4391
4841
  "aria-label": "Mask layer",
4392
4842
  value: target.id,
4393
4843
  onChange: (e) => setLayerId(e.target.value),
4394
4844
  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),
4845
+ children: list.map((l) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("option", { value: l.id, children: [
4846
+ l.name || (0, import_image_editor9.adjustmentKindLabel)(l.kind),
4397
4847
  l.mask ? " (masked)" : ""
4398
4848
  ] }, l.id))
4399
4849
  }
4400
4850
  ),
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" })
4851
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-wrap gap-1", children: [
4852
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !sel, onClick: () => controller.applySelectionAsLayerMask(target.id), children: "Mask with Selection" }),
4853
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.selectionFromLayerMask(target.id), children: "Load as Selection" }),
4854
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: button, disabled: !target.mask, onClick: () => controller.setAdjustmentLayerMask(target.id, null), children: "Remove Mask" })
4405
4855
  ] }),
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: [
4856
+ target.mask && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4857
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4858
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4859
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Density" }),
4860
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4411
4861
  Math.round((target.mask.density ?? 1) * 100),
4412
4862
  "%"
4413
4863
  ] })
4414
4864
  ] }),
4415
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4865
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4416
4866
  "input",
4417
4867
  {
4418
4868
  type: "range",
@@ -4426,15 +4876,15 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4426
4876
  }
4427
4877
  )
4428
4878
  ] }),
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: [
4879
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className: "flex flex-col gap-1", children: [
4880
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex justify-between text-slate-400", children: [
4881
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Mask Feather" }),
4882
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "font-mono", children: [
4433
4883
  target.mask.feather ?? 0,
4434
4884
  "px"
4435
4885
  ] })
4436
4886
  ] }),
4437
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4887
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4438
4888
  "input",
4439
4889
  {
4440
4890
  type: "range",
@@ -4454,7 +4904,7 @@ var RefineEdgePanel = ({ controller, selection, layers, className = "" }) => {
4454
4904
  };
4455
4905
 
4456
4906
  // src/image-editor/ImageEditor.tsx
4457
- var import_jsx_runtime23 = require("react/jsx-runtime");
4907
+ var import_jsx_runtime25 = require("react/jsx-runtime");
4458
4908
  var ImageEditor = ({
4459
4909
  editor: externalEditor,
4460
4910
  src,
@@ -4469,26 +4919,34 @@ var ImageEditor = ({
4469
4919
  const internalEditor = useImageEditor({ image: src });
4470
4920
  const editor = externalEditor || internalEditor;
4471
4921
  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);
4922
+ const legacyProcess = (0, import_image_editor10.normalizeProcessVersion)(state.adjustments.process) < import_image_editor10.LATEST_PROCESS_VERSION;
4923
+ const canvasRef = (0, import_react42.useRef)(null);
4924
+ const containerRef = (0, import_react42.useRef)(null);
4925
+ const [activeTab, setActiveTab] = (0, import_react42.useState)("crop");
4926
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react42.useState)(null);
4927
+ const [selectionOptions, setSelectionOptions] = (0, import_react42.useState)(import_image_editor10.DEFAULT_SELECTION_TOOL_OPTIONS);
4928
+ const selectionOptionsRef = (0, import_react42.useRef)(selectionOptions);
4479
4929
  selectionOptionsRef.current = selectionOptions;
4480
- const selectionGestureRef = (0, import_react40.useRef)(null);
4930
+ const selectionGestureRef = (0, import_react42.useRef)(null);
4481
4931
  if (!selectionGestureRef.current || selectionGestureRef.current.controller !== controller) {
4482
- selectionGestureRef.current = new import_image_editor8.SelectionGesture(controller, () => selectionOptionsRef.current);
4932
+ selectionGestureRef.current = new import_image_editor10.SelectionGesture(controller, () => selectionOptionsRef.current);
4933
+ }
4934
+ const selectionDraftRef = (0, import_react42.useRef)(null);
4935
+ const [selectionError, setSelectionError] = (0, import_react42.useState)(null);
4936
+ const paintGestureRef = (0, import_react42.useRef)(null);
4937
+ const paintControllerRef = (0, import_react42.useRef)(controller);
4938
+ if (!paintGestureRef.current || paintControllerRef.current !== controller) {
4939
+ paintGestureRef.current = new import_image_editor10.PaintGesture(controller);
4940
+ paintControllerRef.current = controller;
4483
4941
  }
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);
4942
+ const brushCursorRef = (0, import_react42.useRef)(null);
4943
+ const [paintError, setPaintError] = (0, import_react42.useState)(null);
4944
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react42.useState)("");
4945
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react42.useState)("annotations");
4946
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react42.useState)(false);
4947
+ const [isInpainting, setIsInpainting] = (0, import_react42.useState)(false);
4948
+ const [aiError, setAiError] = (0, import_react42.useState)(null);
4949
+ const [aiSuccess, setAiSuccess] = (0, import_react42.useState)(null);
4492
4950
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
4493
4951
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
4494
4952
  const handleRemoveBackground = async () => {
@@ -4550,18 +5008,18 @@ var ImageEditor = ({
4550
5008
  setIsInpainting(false);
4551
5009
  }
4552
5010
  };
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)(
5011
+ const [activeColor, setActiveColor] = (0, import_react42.useState)("#ef4444");
5012
+ const [strokeWidth, setStrokeWidth] = (0, import_react42.useState)(3);
5013
+ const [fontSize, setFontSize] = (0, import_react42.useState)(24);
5014
+ const [textInput, setTextInput] = (0, import_react42.useState)("");
5015
+ const draftAnnotationRef = (0, import_react42.useRef)(null);
5016
+ const draftCropRef = (0, import_react42.useRef)(null);
5017
+ const cropDragInfoRef = (0, import_react42.useRef)(null);
5018
+ const annotationDragInfoRef = (0, import_react42.useRef)(null);
5019
+ const isDrawingRef = (0, import_react42.useRef)(false);
5020
+ const currentPathRef = (0, import_react42.useRef)([]);
5021
+ const dragStartPointRef = (0, import_react42.useRef)(null);
5022
+ const renderCanvas = (0, import_react42.useCallback)(
4565
5023
  async (draftAnnotation, draftCrop) => {
4566
5024
  const canvas = canvasRef.current;
4567
5025
  const container = containerRef.current;
@@ -4576,12 +5034,13 @@ var ImageEditor = ({
4576
5034
  interactive: true,
4577
5035
  draftAnnotation: draftAnnotation !== void 0 ? draftAnnotation : draftAnnotationRef.current,
4578
5036
  draftCrop: draftCrop !== void 0 ? draftCrop : draftCropRef.current,
4579
- draftSelectionPath: selectionDraftRef.current
5037
+ draftSelectionPath: selectionDraftRef.current,
5038
+ brushCursor: activeTab === "paint" && brushCursorRef.current && controller.getState().activeTool !== "move" ? { ...brushCursorRef.current, diameter: controller.getState().paint.brush.size } : null
4580
5039
  });
4581
5040
  },
4582
5041
  [controller, activeTab]
4583
5042
  );
4584
- (0, import_react40.useEffect)(() => {
5043
+ (0, import_react42.useEffect)(() => {
4585
5044
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
4586
5045
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
4587
5046
  const animId = raf(() => {
@@ -4589,12 +5048,12 @@ var ImageEditor = ({
4589
5048
  });
4590
5049
  return () => caf(animId);
4591
5050
  }, [renderCanvas, state]);
4592
- (0, import_react40.useEffect)(() => {
5051
+ (0, import_react42.useEffect)(() => {
4593
5052
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
4594
5053
  editor.setTool("crop");
4595
5054
  }
4596
5055
  }, [activeTab, editor]);
4597
- (0, import_react40.useEffect)(() => {
5056
+ (0, import_react42.useEffect)(() => {
4598
5057
  const container = containerRef.current;
4599
5058
  if (!container) return;
4600
5059
  if (typeof ResizeObserver !== "undefined") {
@@ -4620,13 +5079,60 @@ var ImageEditor = ({
4620
5079
  y: (e.clientY - rect.top) * scaleY
4621
5080
  };
4622
5081
  };
5082
+ const paintSamples = (e) => {
5083
+ const canvas = canvasRef.current;
5084
+ const native = e.nativeEvent;
5085
+ const events = typeof native.getCoalescedEvents === "function" ? native.getCoalescedEvents() : [];
5086
+ const list = events.length ? events : [native];
5087
+ const rect = canvas.getBoundingClientRect();
5088
+ const sx = rect.width > 0 ? canvas.width / rect.width : 1;
5089
+ const sy = rect.height > 0 ? canvas.height / rect.height : 1;
5090
+ const s = controller.getState();
5091
+ return list.map((ev) => ({
5092
+ ...(0, import_image_editor10.canvasToImagePoint)({ x: (ev.clientX - rect.left) * sx, y: (ev.clientY - rect.top) * sy }, s, canvas.width, canvas.height, false),
5093
+ pressure: (0, import_image_editor10.pointerPressure)(ev)
5094
+ }));
5095
+ };
5096
+ const handlePaintPointerDown = (e) => {
5097
+ if (activeTab !== "paint" || e.button !== 0) return;
5098
+ e.preventDefault();
5099
+ try {
5100
+ e.currentTarget.setPointerCapture?.(e.pointerId);
5101
+ } catch {
5102
+ }
5103
+ const [first] = paintSamples(e);
5104
+ setPaintError(paintGestureRef.current.down(first));
5105
+ };
5106
+ const handlePaintPointerMove = (e) => {
5107
+ if (activeTab !== "paint") return;
5108
+ const samples = paintSamples(e);
5109
+ brushCursorRef.current = samples[samples.length - 1] ?? null;
5110
+ if (paintGestureRef.current.active) paintGestureRef.current.moveTo(samples);
5111
+ else void renderCanvas();
5112
+ };
5113
+ const handlePaintPointerUp = () => {
5114
+ if (activeTab !== "paint") return;
5115
+ const g = paintGestureRef.current;
5116
+ if (g.active) {
5117
+ g.up();
5118
+ if (g.error) setPaintError(g.error);
5119
+ }
5120
+ };
5121
+ (0, import_react42.useEffect)(() => {
5122
+ if (activeTab !== "paint" || typeof window === "undefined") return;
5123
+ const onKey = (e) => {
5124
+ if ((0, import_image_editor10.handlePaintShortcut)(controller, e)) e.preventDefault();
5125
+ };
5126
+ window.addEventListener("keydown", onKey);
5127
+ return () => window.removeEventListener("keydown", onKey);
5128
+ }, [activeTab, controller]);
4623
5129
  const handleMouseDown = (e) => {
4624
5130
  const canvas = canvasRef.current;
4625
5131
  if (!canvas) return;
4626
5132
  const canvasPt = getCanvasEventPoint(e);
4627
5133
  if (activeTab === "select") {
4628
5134
  const gesture = selectionGestureRef.current;
4629
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5135
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4630
5136
  void gesture.begin(imgPt, e).then(() => setSelectionError(gesture.error));
4631
5137
  return;
4632
5138
  }
@@ -4637,8 +5143,8 @@ var ImageEditor = ({
4637
5143
  width: state.imageDimensions.width,
4638
5144
  height: state.imageDimensions.height
4639
5145
  };
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);
5146
+ const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5147
+ const startImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
4642
5148
  if (handle) {
4643
5149
  cropDragInfoRef.current = {
4644
5150
  handle,
@@ -4657,12 +5163,12 @@ var ImageEditor = ({
4657
5163
  return;
4658
5164
  }
4659
5165
  if (activeTab === "annotate") {
4660
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5166
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4661
5167
  dragStartPointRef.current = imgPt;
4662
5168
  if (state.activeTool === "select") {
4663
5169
  for (let i = state.annotations.length - 1; i >= 0; i--) {
4664
5170
  const ann = state.annotations[i];
4665
- if ((0, import_image_editor8.hitTestAnnotation)(imgPt, ann)) {
5171
+ if ((0, import_image_editor10.hitTestAnnotation)(imgPt, ann)) {
4666
5172
  editor.selectAnnotation(ann.id);
4667
5173
  annotationDragInfoRef.current = {
4668
5174
  annId: ann.id,
@@ -4698,7 +5204,7 @@ var ImageEditor = ({
4698
5204
  const canvasPt = getCanvasEventPoint(e);
4699
5205
  if (activeTab === "select") {
4700
5206
  const gesture = selectionGestureRef.current;
4701
- if (gesture.active && gesture.move((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
5207
+ if (gesture.active && gesture.move((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false))) {
4702
5208
  selectionDraftRef.current = gesture.draftPath;
4703
5209
  renderCanvas();
4704
5210
  }
@@ -4707,7 +5213,7 @@ var ImageEditor = ({
4707
5213
  if (activeTab === "crop") {
4708
5214
  const drag = cropDragInfoRef.current;
4709
5215
  if (drag) {
4710
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
5216
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
4711
5217
  let newCrop;
4712
5218
  if (drag.handle === "new") {
4713
5219
  const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
@@ -4721,7 +5227,7 @@ var ImageEditor = ({
4721
5227
  height: Math.round(Math.max(20, maxY - minY))
4722
5228
  };
4723
5229
  } else {
4724
- newCrop = (0, import_image_editor8.calculateCropDrag)(
5230
+ newCrop = (0, import_image_editor10.calculateCropDrag)(
4725
5231
  drag.startCrop,
4726
5232
  drag.handle,
4727
5233
  drag.startImgPt,
@@ -4741,15 +5247,15 @@ var ImageEditor = ({
4741
5247
  width: state.imageDimensions.width,
4742
5248
  height: state.imageDimensions.height
4743
5249
  };
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);
5250
+ const handle = (0, import_image_editor10.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
5251
+ canvas.style.cursor = (0, import_image_editor10.getCropCursor)(handle, state.transform);
4746
5252
  }
4747
5253
  return;
4748
5254
  }
4749
5255
  if (activeTab === "annotate") {
4750
5256
  if (annotationDragInfoRef.current) {
4751
5257
  const drag = annotationDragInfoRef.current;
4752
- const currentImgPt2 = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5258
+ const currentImgPt2 = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4753
5259
  const dx = currentImgPt2.x - drag.startImgPt.x;
4754
5260
  const dy = currentImgPt2.y - drag.startImgPt.y;
4755
5261
  editor.updateAnnotation(drag.annId, {
@@ -4761,10 +5267,10 @@ var ImageEditor = ({
4761
5267
  const startPt = dragStartPointRef.current;
4762
5268
  if (!startPt) {
4763
5269
  if (state.activeTool === "select") {
4764
- const imgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5270
+ const imgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4765
5271
  let hovered = false;
4766
5272
  for (let i = state.annotations.length - 1; i >= 0; i--) {
4767
- if ((0, import_image_editor8.hitTestAnnotation)(imgPt, state.annotations[i])) {
5273
+ if ((0, import_image_editor10.hitTestAnnotation)(imgPt, state.annotations[i])) {
4768
5274
  hovered = true;
4769
5275
  break;
4770
5276
  }
@@ -4775,7 +5281,7 @@ var ImageEditor = ({
4775
5281
  }
4776
5282
  return;
4777
5283
  }
4778
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5284
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4779
5285
  if (state.activeTool === "pen" && isDrawingRef.current) {
4780
5286
  currentPathRef.current.push(currentImgPt);
4781
5287
  const draft = {
@@ -4855,7 +5361,7 @@ var ImageEditor = ({
4855
5361
  if (activeTab === "select") {
4856
5362
  const gesture = selectionGestureRef.current;
4857
5363
  if (gesture.active) {
4858
- gesture.end((0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
5364
+ gesture.end((0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false), e);
4859
5365
  selectionDraftRef.current = null;
4860
5366
  renderCanvas();
4861
5367
  }
@@ -4879,7 +5385,7 @@ var ImageEditor = ({
4879
5385
  }
4880
5386
  const startPt = dragStartPointRef.current;
4881
5387
  if (startPt) {
4882
- const currentImgPt = (0, import_image_editor8.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
5388
+ const currentImgPt = (0, import_image_editor10.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
4883
5389
  if (state.activeTool === "pen" && isDrawingRef.current) {
4884
5390
  if (currentPathRef.current.length > 1) {
4885
5391
  editor.addAnnotation({
@@ -4975,15 +5481,15 @@ var ImageEditor = ({
4975
5481
  link.click();
4976
5482
  }
4977
5483
  };
4978
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5484
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4979
5485
  "div",
4980
5486
  {
4981
5487
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
4982
5488
  style,
4983
5489
  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)(
5490
+ /* @__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: [
5491
+ /* @__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: [
5492
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4987
5493
  "button",
4988
5494
  {
4989
5495
  type: "button",
@@ -4995,7 +5501,7 @@ var ImageEditor = ({
4995
5501
  children: "Transform & Crop"
4996
5502
  }
4997
5503
  ),
4998
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5504
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4999
5505
  "button",
5000
5506
  {
5001
5507
  type: "button",
@@ -5007,7 +5513,31 @@ var ImageEditor = ({
5007
5513
  children: "Adjustments"
5008
5514
  }
5009
5515
  ),
5010
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5516
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5517
+ "button",
5518
+ {
5519
+ type: "button",
5520
+ onClick: () => {
5521
+ setActiveTab("layers");
5522
+ editor.setTool("select");
5523
+ },
5524
+ 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"}`,
5525
+ children: "Layers"
5526
+ }
5527
+ ),
5528
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5529
+ "button",
5530
+ {
5531
+ type: "button",
5532
+ onClick: () => {
5533
+ setActiveTab("paint");
5534
+ editor.setTool("brush");
5535
+ },
5536
+ 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"}`,
5537
+ children: "Paint"
5538
+ }
5539
+ ),
5540
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5011
5541
  "button",
5012
5542
  {
5013
5543
  type: "button",
@@ -5019,7 +5549,7 @@ var ImageEditor = ({
5019
5549
  children: "Select & Mask"
5020
5550
  }
5021
5551
  ),
5022
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5552
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5023
5553
  "button",
5024
5554
  {
5025
5555
  type: "button",
@@ -5031,7 +5561,7 @@ var ImageEditor = ({
5031
5561
  children: "Annotations"
5032
5562
  }
5033
5563
  ),
5034
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5564
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5035
5565
  "button",
5036
5566
  {
5037
5567
  type: "button",
@@ -5043,7 +5573,7 @@ var ImageEditor = ({
5043
5573
  children: "Depth Mask"
5044
5574
  }
5045
5575
  ),
5046
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5576
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5047
5577
  "button",
5048
5578
  {
5049
5579
  type: "button",
@@ -5053,14 +5583,14 @@ var ImageEditor = ({
5053
5583
  },
5054
5584
  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
5585
  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" }) }),
5586
+ /* @__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
5587
  "AI Tools"
5058
5588
  ]
5059
5589
  }
5060
5590
  )
5061
5591
  ] }),
5062
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
5063
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5592
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
5593
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5064
5594
  "button",
5065
5595
  {
5066
5596
  type: "button",
@@ -5071,7 +5601,7 @@ var ImageEditor = ({
5071
5601
  children: "\u21A9"
5072
5602
  }
5073
5603
  ),
5074
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5604
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5075
5605
  "button",
5076
5606
  {
5077
5607
  type: "button",
@@ -5082,7 +5612,7 @@ var ImageEditor = ({
5082
5612
  children: "\u21AA"
5083
5613
  }
5084
5614
  ),
5085
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5615
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5086
5616
  "button",
5087
5617
  {
5088
5618
  type: "button",
@@ -5091,8 +5621,8 @@ var ImageEditor = ({
5091
5621
  children: "Reset"
5092
5622
  }
5093
5623
  ),
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)(
5624
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5625
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5096
5626
  "button",
5097
5627
  {
5098
5628
  type: "button",
@@ -5102,11 +5632,11 @@ var ImageEditor = ({
5102
5632
  children: "-"
5103
5633
  }
5104
5634
  ),
5105
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
5635
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
5106
5636
  Math.round(state.zoom * 100),
5107
5637
  "%"
5108
5638
  ] }),
5109
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5639
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5110
5640
  "button",
5111
5641
  {
5112
5642
  type: "button",
@@ -5116,8 +5646,8 @@ var ImageEditor = ({
5116
5646
  children: "+"
5117
5647
  }
5118
5648
  ),
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)(
5649
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
5650
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5121
5651
  "button",
5122
5652
  {
5123
5653
  type: "button",
@@ -5128,7 +5658,7 @@ var ImageEditor = ({
5128
5658
  children: "Hold Compare"
5129
5659
  }
5130
5660
  ),
5131
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5661
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5132
5662
  "button",
5133
5663
  {
5134
5664
  type: "button",
@@ -5139,13 +5669,13 @@ var ImageEditor = ({
5139
5669
  )
5140
5670
  ] })
5141
5671
  ] }),
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)(
5672
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
5673
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5144
5674
  "div",
5145
5675
  {
5146
5676
  ref: containerRef,
5147
5677
  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)(
5678
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5149
5679
  "canvas",
5150
5680
  {
5151
5681
  ref: canvasRef,
@@ -5153,16 +5683,21 @@ var ImageEditor = ({
5153
5683
  onMouseMove: handleMouseMove,
5154
5684
  onMouseUp: handleMouseUp,
5155
5685
  onMouseLeave: handleMouseUp,
5156
- className: "absolute inset-0 w-full h-full block"
5686
+ onPointerDown: handlePaintPointerDown,
5687
+ onPointerMove: handlePaintPointerMove,
5688
+ onPointerUp: handlePaintPointerUp,
5689
+ onPointerCancel: () => paintGestureRef.current?.cancel(),
5690
+ "data-testid": "image-editor-canvas",
5691
+ className: `absolute inset-0 w-full h-full block ${activeTab === "paint" ? "touch-none cursor-crosshair" : ""}`
5157
5692
  }
5158
5693
  )
5159
5694
  }
5160
5695
  ),
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)(
5696
+ /* @__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: [
5697
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
5698
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
5699
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
5700
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5166
5701
  "button",
5167
5702
  {
5168
5703
  type: "button",
@@ -5174,7 +5709,7 @@ var ImageEditor = ({
5174
5709
  children: "Freeform"
5175
5710
  }
5176
5711
  ),
5177
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5712
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5178
5713
  "button",
5179
5714
  {
5180
5715
  type: "button",
@@ -5186,7 +5721,7 @@ var ImageEditor = ({
5186
5721
  children: "1:1 Square"
5187
5722
  }
5188
5723
  ),
5189
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5724
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5190
5725
  "button",
5191
5726
  {
5192
5727
  type: "button",
@@ -5198,7 +5733,7 @@ var ImageEditor = ({
5198
5733
  children: "4:3 Standard"
5199
5734
  }
5200
5735
  ),
5201
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5736
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5202
5737
  "button",
5203
5738
  {
5204
5739
  type: "button",
@@ -5210,7 +5745,7 @@ var ImageEditor = ({
5210
5745
  children: "16:9 Wide"
5211
5746
  }
5212
5747
  ),
5213
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5748
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5214
5749
  "button",
5215
5750
  {
5216
5751
  type: "button",
@@ -5222,7 +5757,7 @@ var ImageEditor = ({
5222
5757
  children: "3:2 Photo"
5223
5758
  }
5224
5759
  ),
5225
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5760
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5226
5761
  "button",
5227
5762
  {
5228
5763
  type: "button",
@@ -5235,10 +5770,10 @@ var ImageEditor = ({
5235
5770
  }
5236
5771
  )
5237
5772
  ] }),
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)(
5773
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5774
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
5775
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
5776
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5242
5777
  "button",
5243
5778
  {
5244
5779
  type: "button",
@@ -5247,7 +5782,7 @@ var ImageEditor = ({
5247
5782
  children: "Rotate -90\xB0"
5248
5783
  }
5249
5784
  ),
5250
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5785
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5251
5786
  "button",
5252
5787
  {
5253
5788
  type: "button",
@@ -5256,7 +5791,7 @@ var ImageEditor = ({
5256
5791
  children: "Rotate +90\xB0"
5257
5792
  }
5258
5793
  ),
5259
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5794
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5260
5795
  "button",
5261
5796
  {
5262
5797
  type: "button",
@@ -5265,7 +5800,7 @@ var ImageEditor = ({
5265
5800
  children: "Flip Horizontal"
5266
5801
  }
5267
5802
  ),
5268
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5803
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5269
5804
  "button",
5270
5805
  {
5271
5806
  type: "button",
@@ -5276,10 +5811,10 @@ var ImageEditor = ({
5276
5811
  )
5277
5812
  ] })
5278
5813
  ] }),
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)(
5814
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5815
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
5816
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
5817
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5283
5818
  "button",
5284
5819
  {
5285
5820
  type: "button",
@@ -5289,25 +5824,25 @@ var ImageEditor = ({
5289
5824
  }
5290
5825
  )
5291
5826
  ] }),
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)(
5827
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Histogram, { histogram: editor.histogram }),
5828
+ import_image_editor10.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react42.default.Fragment, { children: [
5829
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5295
5830
  ControlSlider,
5296
5831
  {
5297
5832
  spec,
5298
- value: (0, import_image_editor8.readAdjustmentControls)(state.adjustments)[spec.id],
5833
+ value: (0, import_image_editor10.readAdjustmentControls)(state.adjustments)[spec.id],
5299
5834
  disabled: spec.requiresProcess !== void 0 && legacyProcess,
5300
5835
  onChange: (v) => editor.setAdjustments({ [spec.id]: v })
5301
5836
  }
5302
5837
  ),
5303
- spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5838
+ spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5304
5839
  "div",
5305
5840
  {
5306
5841
  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
5842
  "data-testid": "image-editor-process-notice",
5308
5843
  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)(
5844
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
5845
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5311
5846
  "button",
5312
5847
  {
5313
5848
  type: "button",
@@ -5320,7 +5855,7 @@ var ImageEditor = ({
5320
5855
  }
5321
5856
  )
5322
5857
  ] }, 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)(
5858
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5324
5859
  AdjustmentLayersPanel,
5325
5860
  {
5326
5861
  controller,
@@ -5329,9 +5864,19 @@ var ImageEditor = ({
5329
5864
  }
5330
5865
  ) })
5331
5866
  ] }),
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)(
5867
+ activeTab === "layers" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5868
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Layers" }),
5869
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LayersPanel, { controller })
5870
+ ] }),
5871
+ activeTab === "paint" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5872
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Paint" }),
5873
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(BrushOptionsBar, { controller }),
5874
+ paintError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-rose-400", "data-testid": "paint-error", children: paintError }),
5875
+ /* @__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 }) })
5876
+ ] }),
5877
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5878
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
5879
+ /* @__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
5880
  "button",
5336
5881
  {
5337
5882
  type: "button",
@@ -5341,9 +5886,9 @@ var ImageEditor = ({
5341
5886
  },
5342
5887
  t
5343
5888
  )) }),
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)(
5889
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
5890
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { className: "text-slate-400", children: "Color:" }),
5891
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5347
5892
  "input",
5348
5893
  {
5349
5894
  type: "color",
@@ -5352,15 +5897,15 @@ var ImageEditor = ({
5352
5897
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
5353
5898
  }
5354
5899
  ),
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: [
5900
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex-1 ml-2", children: [
5901
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
5902
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Width:" }),
5903
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono", children: [
5359
5904
  strokeWidth,
5360
5905
  "px"
5361
5906
  ] })
5362
5907
  ] }),
5363
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5908
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5364
5909
  "input",
5365
5910
  {
5366
5911
  type: "range",
@@ -5373,10 +5918,10 @@ var ImageEditor = ({
5373
5918
  )
5374
5919
  ] })
5375
5920
  ] }),
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)(
5921
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5922
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
5923
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex gap-2", children: [
5924
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5380
5925
  "input",
5381
5926
  {
5382
5927
  type: "text",
@@ -5387,7 +5932,7 @@ var ImageEditor = ({
5387
5932
  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
5933
  }
5389
5934
  ),
5390
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5935
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5391
5936
  "button",
5392
5937
  {
5393
5938
  type: "button",
@@ -5397,14 +5942,14 @@ var ImageEditor = ({
5397
5942
  }
5398
5943
  )
5399
5944
  ] }),
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: [
5945
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
5946
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Font Size:" }),
5947
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "font-mono", children: [
5403
5948
  fontSize,
5404
5949
  "px"
5405
5950
  ] })
5406
5951
  ] }),
5407
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5952
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5408
5953
  "input",
5409
5954
  {
5410
5955
  type: "range",
@@ -5415,14 +5960,14 @@ var ImageEditor = ({
5415
5960
  className: "w-full accent-indigo-500"
5416
5961
  }
5417
5962
  ),
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: [
5963
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
5964
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
5965
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "text-slate-400", children: [
5421
5966
  "Layers (",
5422
5967
  state.annotations.length,
5423
5968
  ")"
5424
5969
  ] }),
5425
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5970
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5426
5971
  "button",
5427
5972
  {
5428
5973
  type: "button",
@@ -5431,7 +5976,7 @@ var ImageEditor = ({
5431
5976
  children: "Delete Selected"
5432
5977
  }
5433
5978
  ),
5434
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5979
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5435
5980
  "button",
5436
5981
  {
5437
5982
  type: "button",
@@ -5442,10 +5987,10 @@ var ImageEditor = ({
5442
5987
  )
5443
5988
  ] })
5444
5989
  ] }),
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)(
5990
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
5991
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
5992
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
5993
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5449
5994
  "button",
5450
5995
  {
5451
5996
  type: "button",
@@ -5455,8 +6000,8 @@ var ImageEditor = ({
5455
6000
  }
5456
6001
  )
5457
6002
  ] }),
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)(
6003
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
6004
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5460
6005
  "input",
5461
6006
  {
5462
6007
  type: "checkbox",
@@ -5465,12 +6010,12 @@ var ImageEditor = ({
5465
6010
  className: "rounded accent-indigo-500"
5466
6011
  }
5467
6012
  ),
5468
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Enable Depth / Alpha Mask" })
6013
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Enable Depth / Alpha Mask" })
5469
6014
  ] }),
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)(
6015
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6016
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6017
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
6018
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5474
6019
  "input",
5475
6020
  {
5476
6021
  type: "text",
@@ -5481,8 +6026,8 @@ var ImageEditor = ({
5481
6026
  }
5482
6027
  )
5483
6028
  ] }),
5484
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex gap-2", children: [
5485
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6029
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex gap-2", children: [
6030
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5486
6031
  "button",
5487
6032
  {
5488
6033
  type: "button",
@@ -5491,7 +6036,7 @@ var ImageEditor = ({
5491
6036
  children: "Threshold Mode"
5492
6037
  }
5493
6038
  ),
5494
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6039
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5495
6040
  "button",
5496
6041
  {
5497
6042
  type: "button",
@@ -5501,12 +6046,12 @@ var ImageEditor = ({
5501
6046
  }
5502
6047
  )
5503
6048
  ] }),
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] })
6049
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6050
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6051
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Depth Start (Lower):" }),
6052
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
5508
6053
  ] }),
5509
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6054
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5510
6055
  "input",
5511
6056
  {
5512
6057
  type: "range",
@@ -5520,12 +6065,12 @@ var ImageEditor = ({
5520
6065
  }
5521
6066
  )
5522
6067
  ] }),
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] })
6068
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6069
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6070
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Depth Stop (Upper):" }),
6071
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
5527
6072
  ] }),
5528
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6073
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5529
6074
  "input",
5530
6075
  {
5531
6076
  type: "range",
@@ -5539,12 +6084,12 @@ var ImageEditor = ({
5539
6084
  }
5540
6085
  )
5541
6086
  ] }),
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 })
6087
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { children: [
6088
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
6089
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Softness:" }),
6090
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
5546
6091
  ] }),
5547
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6092
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5548
6093
  "input",
5549
6094
  {
5550
6095
  type: "range",
@@ -5556,8 +6101,8 @@ var ImageEditor = ({
5556
6101
  }
5557
6102
  )
5558
6103
  ] }),
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)(
6104
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
6105
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5561
6106
  "input",
5562
6107
  {
5563
6108
  type: "checkbox",
@@ -5566,12 +6111,12 @@ var ImageEditor = ({
5566
6111
  className: "rounded accent-indigo-500"
5567
6112
  }
5568
6113
  ),
5569
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Invert Mask" })
6114
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Invert Mask" })
5570
6115
  ] })
5571
6116
  ] })
5572
6117
  ] }),
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)(
6118
+ activeTab === "select" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6119
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5575
6120
  SelectionOptionsBar,
5576
6121
  {
5577
6122
  controller,
@@ -5581,51 +6126,51 @@ var ImageEditor = ({
5581
6126
  quickMask: Boolean(state.quickMask)
5582
6127
  }
5583
6128
  ),
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 })
6129
+ selectionError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-rose-400", children: selectionError }),
6130
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(RefineEdgePanel, { controller, selection: state.selection ?? null, layers: state.adjustments.layers })
5586
6131
  ] }),
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" }) }),
6132
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
6133
+ /* @__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: [
6134
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6135
+ /* @__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: [
6136
+ /* @__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
6137
  "Background Removal"
5593
6138
  ] }),
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..." })
6139
+ 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
6140
  ] }),
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)(
6141
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
6142
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5598
6143
  "button",
5599
6144
  {
5600
6145
  type: "button",
5601
6146
  onClick: handleRemoveBackground,
5602
6147
  disabled: isRemovingBg || isInpainting,
5603
6148
  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" }),
6149
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6150
+ /* @__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
6151
  "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" }) }),
6152
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6153
+ /* @__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
6154
  "Remove Background"
5610
6155
  ] })
5611
6156
  }
5612
6157
  )
5613
6158
  ] }),
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" })
6159
+ /* @__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: [
6160
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center justify-between", children: [
6161
+ /* @__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: [
6162
+ /* @__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: [
6163
+ /* @__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" }),
6164
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "m14 7 3 3" })
5620
6165
  ] }),
5621
6166
  "Generative Inpainting"
5622
6167
  ] }),
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..." })
6168
+ 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
6169
  ] }),
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)(
6170
+ /* @__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." }),
6171
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-1", children: [
6172
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
6173
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5629
6174
  "textarea",
5630
6175
  {
5631
6176
  id: "ai-inpaint-prompt-react",
@@ -5637,10 +6182,10 @@ var ImageEditor = ({
5637
6182
  }
5638
6183
  )
5639
6184
  ] }),
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)(
6185
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-1", children: [
6186
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
6187
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
6188
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5644
6189
  "button",
5645
6190
  {
5646
6191
  type: "button",
@@ -5653,7 +6198,7 @@ var ImageEditor = ({
5653
6198
  ]
5654
6199
  }
5655
6200
  ),
5656
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6201
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5657
6202
  "button",
5658
6203
  {
5659
6204
  type: "button",
@@ -5668,25 +6213,25 @@ var ImageEditor = ({
5668
6213
  )
5669
6214
  ] })
5670
6215
  ] }),
5671
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6216
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5672
6217
  "button",
5673
6218
  {
5674
6219
  type: "button",
5675
6220
  onClick: handleInpaint,
5676
6221
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
5677
6222
  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" }),
6223
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6224
+ /* @__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
6225
  "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" }) }),
6226
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
6227
+ /* @__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
6228
  "Apply Inpainting"
5684
6229
  ] })
5685
6230
  }
5686
6231
  )
5687
6232
  ] }),
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 })
6233
+ 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 }),
6234
+ 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
6235
  ] })
5691
6236
  ] })
5692
6237
  ] })
@@ -5696,7 +6241,7 @@ var ImageEditor = ({
5696
6241
  };
5697
6242
 
5698
6243
  // src/review/useReview.ts
5699
- var import_react41 = require("react");
6244
+ var import_react43 = require("react");
5700
6245
  var import_editor12 = require("@pixerate/editor");
5701
6246
  var EMPTY_COMMENTS = Object.freeze({
5702
6247
  threads: [],
@@ -5715,23 +6260,23 @@ function isCommentStore(value) {
5715
6260
  }
5716
6261
  function useComments(source) {
5717
6262
  const store = isCommentStore(source) ? source : (0, import_editor12.getCommentStore)(source);
5718
- const subscribe = (0, import_react41.useCallback)(
6263
+ const subscribe = (0, import_react43.useCallback)(
5719
6264
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
5720
6265
  [store]
5721
6266
  );
5722
6267
  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]);
6268
+ const snapshot = (0, import_react43.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6269
+ return (0, import_react43.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
5725
6270
  }
5726
6271
  function useTrackChanges(editor) {
5727
6272
  const store = (0, import_editor12.getTrackChangesStore)(editor ?? null);
5728
- const subscribe = (0, import_react41.useCallback)(
6273
+ const subscribe = (0, import_react43.useCallback)(
5729
6274
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
5730
6275
  [store]
5731
6276
  );
5732
6277
  const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
5733
- const snapshot = (0, import_react41.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
5734
- return (0, import_react41.useMemo)(() => {
6278
+ const snapshot = (0, import_react43.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
6279
+ return (0, import_react43.useMemo)(() => {
5735
6280
  const run = (fn) => () => {
5736
6281
  if (editor && !editor.isDestroyed) fn(editor);
5737
6282
  };
@@ -5754,9 +6299,9 @@ function useTrackChanges(editor) {
5754
6299
  }
5755
6300
 
5756
6301
  // src/review/CommentsPanel.tsx
5757
- var import_react42 = require("react");
6302
+ var import_react44 = require("react");
5758
6303
  var import_editor13 = require("@pixerate/editor");
5759
- var import_jsx_runtime24 = require("react/jsx-runtime");
6304
+ var import_jsx_runtime26 = require("react/jsx-runtime");
5760
6305
  var buttonClass2 = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
5761
6306
  var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
5762
6307
  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 +6315,18 @@ var CommentsPanel = ({
5770
6315
  emptyMessage = "No comments yet. Select text and add a comment."
5771
6316
  }) => {
5772
6317
  const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
5773
- const [showResolved, setShowResolved] = (0, import_react42.useState)(showResolvedInitial);
6318
+ const [showResolved, setShowResolved] = (0, import_react44.useState)(showResolvedInitial);
5774
6319
  const author = authorProp ?? (0, import_editor13.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
5775
6320
  const visible = threads.filter((t) => showResolved || !t.resolved);
5776
6321
  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: [
6322
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("aside", { className, "aria-label": "Comments", children: [
6323
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
6324
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
5780
6325
  threads.length - resolvedCount,
5781
6326
  " open",
5782
6327
  resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
5783
6328
  ] }),
5784
- resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6329
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5785
6330
  "button",
5786
6331
  {
5787
6332
  type: "button",
@@ -5792,7 +6337,7 @@ var CommentsPanel = ({
5792
6337
  }
5793
6338
  )
5794
6339
  ] }),
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)(
6340
+ 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
6341
  CommentThreadCard,
5797
6342
  {
5798
6343
  thread,
@@ -5814,7 +6359,7 @@ var CommentThreadCard = ({
5814
6359
  author,
5815
6360
  formatTime
5816
6361
  }) => {
5817
- const [draft, setDraft] = (0, import_react42.useState)("");
6362
+ const [draft, setDraft] = (0, import_react44.useState)("");
5818
6363
  const isDraft = thread.body === "";
5819
6364
  const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
5820
6365
  const live = editor && !editor.isDestroyed ? editor : null;
@@ -5840,7 +6385,7 @@ var CommentThreadCard = ({
5840
6385
  setDraft("");
5841
6386
  };
5842
6387
  const stop = (e) => e.stopPropagation();
5843
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6388
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5844
6389
  "li",
5845
6390
  {
5846
6391
  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 +6401,24 @@ var CommentThreadCard = ({
5856
6401
  }
5857
6402
  },
5858
6403
  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) })
6404
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
6405
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-medium", children: thread.author.name }),
6406
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
5862
6407
  ] }),
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 }),
6408
+ 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 }),
6409
+ thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
6410
+ thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
6411
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
6412
+ 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: [
6413
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "text-xs", children: [
6414
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "font-medium", children: reply.author.name }),
5870
6415
  " ",
5871
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
6416
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
5872
6417
  ] }),
5873
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
6418
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
5874
6419
  ] }, 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)(
6420
+ (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
6421
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5877
6422
  "textarea",
5878
6423
  {
5879
6424
  className: textareaClass,
@@ -5891,9 +6436,9 @@ var CommentThreadCard = ({
5891
6436
  }
5892
6437
  }
5893
6438
  ),
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)(
6439
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-end gap-1", children: [
6440
+ isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass2, onClick: remove, children: "Cancel" }),
6441
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5897
6442
  "button",
5898
6443
  {
5899
6444
  type: "button",
@@ -5905,9 +6450,9 @@ var CommentThreadCard = ({
5905
6450
  )
5906
6451
  ] })
5907
6452
  ] }),
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)(
6453
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
6454
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: buttonClass2, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
6455
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5911
6456
  "button",
5912
6457
  {
5913
6458
  type: "button",
@@ -5923,7 +6468,7 @@ var CommentThreadCard = ({
5923
6468
  };
5924
6469
 
5925
6470
  // src/review/ReviewToolbar.tsx
5926
- var import_jsx_runtime25 = require("react/jsx-runtime");
6471
+ var import_jsx_runtime27 = require("react/jsx-runtime");
5927
6472
  var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
5928
6473
  var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
5929
6474
  var ReviewToolbar = ({
@@ -5936,8 +6481,8 @@ var ReviewToolbar = ({
5936
6481
  const count = review.changes.length;
5937
6482
  const current = review.currentChange;
5938
6483
  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)(
6484
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
6485
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5941
6486
  "button",
5942
6487
  {
5943
6488
  type: "button",
@@ -5948,8 +6493,8 @@ var ReviewToolbar = ({
5948
6493
  children: review.enabled ? "Tracking on" : "Track changes"
5949
6494
  }
5950
6495
  ),
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)(
6496
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6497
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5953
6498
  "button",
5954
6499
  {
5955
6500
  type: "button",
@@ -5960,8 +6505,8 @@ var ReviewToolbar = ({
5960
6505
  children: "\u2039"
5961
6506
  }
5962
6507
  ),
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)(
6508
+ /* @__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` }),
6509
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5965
6510
  "button",
5966
6511
  {
5967
6512
  type: "button",
@@ -5972,7 +6517,7 @@ var ReviewToolbar = ({
5972
6517
  children: "\u203A"
5973
6518
  }
5974
6519
  ),
5975
- showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6520
+ showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5976
6521
  "span",
5977
6522
  {
5978
6523
  className: descriptionClassName,
@@ -5984,8 +6529,8 @@ var ReviewToolbar = ({
5984
6529
  ]
5985
6530
  }
5986
6531
  ),
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)(
6532
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
6533
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5989
6534
  "button",
5990
6535
  {
5991
6536
  type: "button",
@@ -5995,7 +6540,7 @@ var ReviewToolbar = ({
5995
6540
  children: "Accept"
5996
6541
  }
5997
6542
  ),
5998
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6543
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5999
6544
  "button",
6000
6545
  {
6001
6546
  type: "button",
@@ -6005,18 +6550,18 @@ var ReviewToolbar = ({
6005
6550
  children: "Reject"
6006
6551
  }
6007
6552
  ),
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" })
6553
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
6554
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: buttonClass3, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
6010
6555
  ] });
6011
6556
  };
6012
6557
 
6013
6558
  // src/review/CommentButton.tsx
6014
- var import_jsx_runtime26 = require("react/jsx-runtime");
6559
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6015
6560
  var CommentButton = ({
6016
6561
  editor,
6017
6562
  className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
6018
6563
  children = "Comment"
6019
- }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6564
+ }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6020
6565
  "button",
6021
6566
  {
6022
6567
  type: "button",
@@ -6028,13 +6573,13 @@ var CommentButton = ({
6028
6573
  );
6029
6574
 
6030
6575
  // src/review/useDocumentCompare.ts
6031
- var import_react43 = require("react");
6576
+ var import_react45 = require("react");
6032
6577
  var import_editor14 = require("@pixerate/editor");
6033
6578
  function useDocumentCompare(editor, options) {
6034
- const [summary, setSummary] = (0, import_react43.useState)(null);
6035
- const defaults = (0, import_react43.useRef)(options);
6579
+ const [summary, setSummary] = (0, import_react45.useState)(null);
6580
+ const defaults = (0, import_react45.useRef)(options);
6036
6581
  defaults.current = options;
6037
- const compare = (0, import_react43.useCallback)(
6582
+ const compare = (0, import_react45.useCallback)(
6038
6583
  (original, revised, overrides) => {
6039
6584
  if (!editor || editor.isDestroyed) return null;
6040
6585
  const result = (0, import_editor14.applyDocumentComparison)(editor, original, revised, {
@@ -6046,13 +6591,13 @@ function useDocumentCompare(editor, options) {
6046
6591
  },
6047
6592
  [editor]
6048
6593
  );
6049
- const clear = (0, import_react43.useCallback)(() => setSummary(null), []);
6050
- return (0, import_react43.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
6594
+ const clear = (0, import_react45.useCallback)(() => setSummary(null), []);
6595
+ return (0, import_react45.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
6051
6596
  }
6052
6597
 
6053
6598
  // src/review/TrackedChangesList.tsx
6054
6599
  var import_editor15 = require("@pixerate/editor");
6055
- var import_jsx_runtime27 = require("react/jsx-runtime");
6600
+ var import_jsx_runtime29 = require("react/jsx-runtime");
6056
6601
  var buttonClass4 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
6057
6602
  var TrackedChangesList = ({
6058
6603
  editor,
@@ -6063,18 +6608,18 @@ var TrackedChangesList = ({
6063
6608
  }) => {
6064
6609
  const review = useTrackChanges(editor);
6065
6610
  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 }) });
6611
+ 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
6612
  }
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) => {
6613
+ 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
6614
  const active = change.id === review.currentChangeId;
6070
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6615
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6071
6616
  "li",
6072
6617
  {
6073
6618
  className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
6074
6619
  "data-change-type": change.type,
6075
6620
  "data-change-id": change.id,
6076
6621
  children: [
6077
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6622
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6078
6623
  "button",
6079
6624
  {
6080
6625
  type: "button",
@@ -6082,14 +6627,14 @@ var TrackedChangesList = ({
6082
6627
  title: `${change.author.name}: ${change.description}`,
6083
6628
  onClick: () => review.select(change.id),
6084
6629
  children: [
6085
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
6630
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-medium", children: (0, import_editor15.trackedChangeLabel)(change) }),
6086
6631
  change.author.name ? ` \xB7 ${change.author.name}` : "",
6087
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
6632
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "block truncate text-muted-foreground", children: change.description })
6088
6633
  ]
6089
6634
  }
6090
6635
  ),
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" })
6636
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.accept(change.id), children: "Accept" }),
6637
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: buttonClass4, onClick: () => review.reject(change.id), children: "Reject" })
6093
6638
  ]
6094
6639
  },
6095
6640
  `${change.type}:${change.id}`
@@ -6098,12 +6643,12 @@ var TrackedChangesList = ({
6098
6643
  };
6099
6644
 
6100
6645
  // src/commands/useCommandPalette.ts
6101
- var import_react44 = require("react");
6646
+ var import_react46 = require("react");
6102
6647
  var import_commands2 = require("@pixerate/editor/commands");
6103
6648
  function useCommandPalette(registry, options = {}) {
6104
- const optionsRef = (0, import_react44.useRef)(options);
6649
+ const optionsRef = (0, import_react46.useRef)(options);
6105
6650
  optionsRef.current = options;
6106
- const controller = (0, import_react44.useMemo)(
6651
+ const controller = (0, import_react46.useMemo)(
6107
6652
  () => (0, import_commands2.createCommandPaletteController)(registry, {
6108
6653
  context: () => {
6109
6654
  const c = optionsRef.current.context;
@@ -6124,9 +6669,9 @@ function useCommandPalette(registry, options = {}) {
6124
6669
  // eslint-disable-next-line react-hooks/exhaustive-deps
6125
6670
  [registry]
6126
6671
  );
6127
- const state = (0, import_react44.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
6672
+ const state = (0, import_react46.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
6128
6673
  const { hotkey, hotkeyTarget } = options;
6129
- (0, import_react44.useEffect)(() => {
6674
+ (0, import_react46.useEffect)(() => {
6130
6675
  if (!hotkey) return;
6131
6676
  const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
6132
6677
  if (!target) return;
@@ -6154,13 +6699,13 @@ function useCommandPalette(registry, options = {}) {
6154
6699
  }
6155
6700
 
6156
6701
  // src/commands/CommandPalette.tsx
6157
- var import_react45 = __toESM(require("react"), 1);
6158
- var import_jsx_runtime28 = require("react/jsx-runtime");
6702
+ var import_react47 = __toESM(require("react"), 1);
6703
+ var import_jsx_runtime30 = require("react/jsx-runtime");
6159
6704
  function HighlightedLabel({ item }) {
6160
- if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: item.label });
6705
+ if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: item.label });
6161
6706
  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)
6707
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: Array.from(item.label).map(
6708
+ (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
6709
  ) });
6165
6710
  }
6166
6711
  var CommandPalette = ({
@@ -6169,22 +6714,22 @@ var CommandPalette = ({
6169
6714
  emptyMessage = "No matching commands",
6170
6715
  className = ""
6171
6716
  }) => {
6172
- const inputRef = (0, import_react45.useRef)(null);
6173
- const listRef = (0, import_react45.useRef)(null);
6174
- const baseId = (0, import_react45.useId)();
6717
+ const inputRef = (0, import_react47.useRef)(null);
6718
+ const listRef = (0, import_react47.useRef)(null);
6719
+ const baseId = (0, import_react47.useId)();
6175
6720
  const listId = `${baseId}-list`;
6176
6721
  const optionId = (index) => `${baseId}-option-${index}`;
6177
6722
  const { open, query, items, activeIndex } = palette;
6178
- (0, import_react45.useEffect)(() => {
6723
+ (0, import_react47.useEffect)(() => {
6179
6724
  if (open) inputRef.current?.focus();
6180
6725
  }, [open]);
6181
- (0, import_react45.useEffect)(() => {
6726
+ (0, import_react47.useEffect)(() => {
6182
6727
  if (!open) return;
6183
6728
  const active = listRef.current?.querySelector('[aria-selected="true"]');
6184
6729
  active?.scrollIntoView?.({ block: "nearest" });
6185
6730
  }, [open, activeIndex]);
6186
6731
  if (!open) return null;
6187
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6732
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6188
6733
  "div",
6189
6734
  {
6190
6735
  className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
@@ -6192,7 +6737,7 @@ var CommandPalette = ({
6192
6737
  onMouseDown: (e) => {
6193
6738
  if (e.target === e.currentTarget) palette.setOpen(false);
6194
6739
  },
6195
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
6740
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
6196
6741
  "div",
6197
6742
  {
6198
6743
  role: "dialog",
@@ -6201,7 +6746,7 @@ var CommandPalette = ({
6201
6746
  className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
6202
6747
  style: { background: "var(--popover, var(--background, #fff))" },
6203
6748
  children: [
6204
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6749
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
6205
6750
  "input",
6206
6751
  {
6207
6752
  ref: inputRef,
@@ -6221,7 +6766,7 @@ var CommandPalette = ({
6221
6766
  className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
6222
6767
  }
6223
6768
  ),
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)(
6769
+ 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
6770
  "li",
6226
6771
  {
6227
6772
  id: optionId(index),
@@ -6236,12 +6781,12 @@ var CommandPalette = ({
6236
6781
  onClick: () => palette.run(item.id),
6237
6782
  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
6783
  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 })
6784
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
6785
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(HighlightedLabel, { item }),
6786
+ item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
6242
6787
  ] }),
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 })
6788
+ item.group && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
6789
+ 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
6790
  ]
6246
6791
  },
6247
6792
  item.id
@@ -6254,12 +6799,12 @@ var CommandPalette = ({
6254
6799
  };
6255
6800
 
6256
6801
  // src/commands/useCommandShortcuts.ts
6257
- var import_react46 = require("react");
6802
+ var import_react48 = require("react");
6258
6803
  function useCommandShortcuts(registry, options = {}) {
6259
- const optionsRef = (0, import_react46.useRef)(options);
6804
+ const optionsRef = (0, import_react48.useRef)(options);
6260
6805
  optionsRef.current = options;
6261
6806
  const { enabled = true, target } = options;
6262
- (0, import_react46.useEffect)(() => {
6807
+ (0, import_react48.useEffect)(() => {
6263
6808
  if (!registry || !enabled) return;
6264
6809
  const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
6265
6810
  if (!eventTarget) return;
@@ -6277,14 +6822,14 @@ function useCommandShortcuts(registry, options = {}) {
6277
6822
  }, [registry, enabled, target]);
6278
6823
  }
6279
6824
  function useRegisterCommands(registry, specs) {
6280
- (0, import_react46.useEffect)(() => {
6825
+ (0, import_react48.useEffect)(() => {
6281
6826
  if (!registry || !specs || specs.length === 0) return;
6282
6827
  return registry.register(specs);
6283
6828
  }, [registry, specs]);
6284
6829
  }
6285
6830
 
6286
6831
  // src/persistence/useAutosave.ts
6287
- var import_react47 = require("react");
6832
+ var import_react49 = require("react");
6288
6833
  var import_persistence = require("@pixerate/editor/persistence");
6289
6834
  var IDLE = {
6290
6835
  status: "idle",
@@ -6295,18 +6840,18 @@ var IDLE = {
6295
6840
  ready: false
6296
6841
  };
6297
6842
  function useAutosave(options) {
6298
- const optionsRef = (0, import_react47.useRef)(options);
6843
+ const optionsRef = (0, import_react49.useRef)(options);
6299
6844
  optionsRef.current = options;
6300
6845
  const { storage, key, history, dirty } = options;
6301
6846
  const recover = options.recover !== false;
6302
6847
  const flushOnHide = options.flushOnHide !== false;
6303
6848
  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)(() => {
6849
+ const [controller, setController] = (0, import_react49.useState)(null);
6850
+ const [status, setStatus] = (0, import_react49.useState)(IDLE);
6851
+ const [recovery, setRecovery] = (0, import_react49.useState)(null);
6852
+ const [pendingRecovery, setPendingRecovery] = (0, import_react49.useState)(recover);
6853
+ const revisionsRef = (0, import_react49.useRef)(null);
6854
+ (0, import_react49.useEffect)(() => {
6310
6855
  const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
6311
6856
  const o = optionsRef.current;
6312
6857
  const instance = (0, import_persistence.createAutosaveController)({
@@ -6349,10 +6894,10 @@ function useAutosave(options) {
6349
6894
  if (revisionsRef.current === revisions) revisionsRef.current = null;
6350
6895
  };
6351
6896
  }, [storage, key, history, dirty, recover]);
6352
- (0, import_react47.useEffect)(() => {
6897
+ (0, import_react49.useEffect)(() => {
6353
6898
  if (controller && ready && !pendingRecovery) controller.ready();
6354
6899
  }, [controller, ready, pendingRecovery]);
6355
- (0, import_react47.useEffect)(() => {
6900
+ (0, import_react49.useEffect)(() => {
6356
6901
  if (!controller || !flushOnHide || typeof window === "undefined") return;
6357
6902
  const flush = () => void controller.flushNow();
6358
6903
  const onVisibility = () => {
@@ -6365,31 +6910,31 @@ function useAutosave(options) {
6365
6910
  document.removeEventListener("visibilitychange", onVisibility);
6366
6911
  };
6367
6912
  }, [controller, flushOnHide]);
6368
- const restore = (0, import_react47.useCallback)(() => {
6913
+ const restore = (0, import_react49.useCallback)(() => {
6369
6914
  const snapshot = recovery?.snapshot;
6370
6915
  setRecovery(null);
6371
6916
  setPendingRecovery(false);
6372
6917
  return snapshot;
6373
6918
  }, [recovery]);
6374
- const discard = (0, import_react47.useCallback)(async () => {
6919
+ const discard = (0, import_react49.useCallback)(async () => {
6375
6920
  if (controller) await controller.discardRecovery();
6376
6921
  setRecovery(null);
6377
6922
  setPendingRecovery(false);
6378
6923
  }, [controller]);
6379
- const flushNow = (0, import_react47.useCallback)(async () => {
6924
+ const flushNow = (0, import_react49.useCallback)(async () => {
6380
6925
  await controller?.flushNow();
6381
6926
  }, [controller]);
6382
- const markClean = (0, import_react47.useCallback)(async () => {
6927
+ const markClean = (0, import_react49.useCallback)(async () => {
6383
6928
  revisionsRef.current?.markSaved();
6384
6929
  await controller?.markClean();
6385
6930
  }, [controller]);
6386
- const notifyChange = (0, import_react47.useCallback)(() => revisionsRef.current?.bump(), []);
6931
+ const notifyChange = (0, import_react49.useCallback)(() => revisionsRef.current?.bump(), []);
6387
6932
  return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
6388
6933
  }
6389
6934
 
6390
6935
  // src/persistence/RecoveryPrompt.tsx
6391
6936
  var import_persistence2 = require("@pixerate/editor/persistence");
6392
- var import_jsx_runtime29 = require("react/jsx-runtime");
6937
+ var import_jsx_runtime31 = require("react/jsx-runtime");
6393
6938
  var RecoveryPrompt = ({
6394
6939
  recovery,
6395
6940
  onRestore,
@@ -6401,7 +6946,7 @@ var RecoveryPrompt = ({
6401
6946
  }) => {
6402
6947
  if (!recovery) return null;
6403
6948
  const { name } = recovery.meta;
6404
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
6949
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
6405
6950
  "div",
6406
6951
  {
6407
6952
  role: "alertdialog",
@@ -6409,15 +6954,15 @@ var RecoveryPrompt = ({
6409
6954
  "data-recovery-prompt": "",
6410
6955
  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
6956
  children: [
6412
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { className: "min-w-0 flex-1", children: [
6957
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "min-w-0 flex-1", children: [
6413
6958
  (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: [
6959
+ name ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
6415
6960
  "(",
6416
6961
  name,
6417
6962
  ")"
6418
6963
  ] }) : null
6419
6964
  ] }),
6420
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6965
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6421
6966
  "button",
6422
6967
  {
6423
6968
  type: "button",
@@ -6427,7 +6972,7 @@ var RecoveryPrompt = ({
6427
6972
  children: restoreLabel
6428
6973
  }
6429
6974
  ),
6430
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
6975
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6431
6976
  "button",
6432
6977
  {
6433
6978
  type: "button",
@@ -6443,17 +6988,17 @@ var RecoveryPrompt = ({
6443
6988
  };
6444
6989
 
6445
6990
  // src/generation/useGenerationPlan.ts
6446
- var import_react48 = require("react");
6991
+ var import_react50 = require("react");
6447
6992
  var import_generation = require("@pixerate/editor/generation");
6448
6993
  function useGenerationPlan(request, capabilities, options = {}) {
6449
6994
  const key = JSON.stringify([request, capabilities, options]);
6450
- return (0, import_react48.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
6995
+ return (0, import_react50.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
6451
6996
  }
6452
6997
  function useJobProgress(options) {
6453
6998
  const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
6454
- const [tick, setTick] = (0, import_react48.useState)(() => Date.now());
6999
+ const [tick, setTick] = (0, import_react50.useState)(() => Date.now());
6455
7000
  const ticking = !done && now === void 0;
6456
- (0, import_react48.useEffect)(() => {
7001
+ (0, import_react50.useEffect)(() => {
6457
7002
  if (!ticking) return;
6458
7003
  setTick(Date.now());
6459
7004
  const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
@@ -6463,9 +7008,9 @@ function useJobProgress(options) {
6463
7008
  }
6464
7009
 
6465
7010
  // src/generation/GenerationSettings.tsx
6466
- var import_react49 = require("react");
7011
+ var import_react51 = require("react");
6467
7012
  var import_generation2 = require("@pixerate/editor/generation");
6468
- var import_jsx_runtime30 = require("react/jsx-runtime");
7013
+ var import_jsx_runtime32 = require("react/jsx-runtime");
6469
7014
  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
7015
  function Control({
6471
7016
  control,
@@ -6475,7 +7020,7 @@ function Control({
6475
7020
  }) {
6476
7021
  const shown = value ?? control.defaultValue;
6477
7022
  if (control.kind === "checkbox") {
6478
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7023
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6479
7024
  "input",
6480
7025
  {
6481
7026
  id,
@@ -6487,7 +7032,7 @@ function Control({
6487
7032
  );
6488
7033
  }
6489
7034
  if (control.kind === "select") {
6490
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
7035
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6491
7036
  "select",
6492
7037
  {
6493
7038
  id,
@@ -6496,14 +7041,14 @@ function Control({
6496
7041
  value: shown === void 0 ? "" : String(shown),
6497
7042
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
6498
7043
  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)))
7044
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: "", children: "Default" }),
7045
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
6501
7046
  ]
6502
7047
  }
6503
7048
  );
6504
7049
  }
6505
7050
  if (control.kind === "textarea") {
6506
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7051
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6507
7052
  "textarea",
6508
7053
  {
6509
7054
  id,
@@ -6517,8 +7062,8 @@ function Control({
6517
7062
  );
6518
7063
  }
6519
7064
  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)(
7065
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-2", children: [
7066
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6522
7067
  "input",
6523
7068
  {
6524
7069
  id,
@@ -6532,7 +7077,7 @@ function Control({
6532
7077
  onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
6533
7078
  }
6534
7079
  ),
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" })
7080
+ 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
7081
  ] });
6537
7082
  }
6538
7083
  var GenerationSettings = ({
@@ -6546,17 +7091,17 @@ var GenerationSettings = ({
6546
7091
  renderReference,
6547
7092
  className = ""
6548
7093
  }) => {
6549
- const baseId = (0, import_react49.useId)();
6550
- const controls = (0, import_react49.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
7094
+ const baseId = (0, import_react51.useId)();
7095
+ const controls = (0, import_react51.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
6551
7096
  const computed = useGenerationPlan(value, capabilities, { strategy });
6552
7097
  const plan = planProp ?? computed;
6553
7098
  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: [
7099
+ 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
7100
  controls.map((control) => {
6556
7101
  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)(
7102
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
7103
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
7104
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6560
7105
  Control,
6561
7106
  {
6562
7107
  control,
@@ -6567,23 +7112,23 @@ var GenerationSettings = ({
6567
7112
  )
6568
7113
  ] }, control.key);
6569
7114
  }),
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: [
7115
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
7116
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
6572
7117
  slot.label,
6573
7118
  " ",
6574
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
7119
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
6575
7120
  "(",
6576
7121
  slot.references.length,
6577
7122
  "/",
6578
7123
  slot.max,
6579
7124
  ")"
6580
7125
  ] }),
6581
- slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-destructive", children: " *" })
7126
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-destructive", children: " *" })
6582
7127
  ] }),
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)(
7128
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
7129
+ 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: [
7130
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
7131
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6587
7132
  "button",
6588
7133
  {
6589
7134
  type: "button",
@@ -6594,7 +7139,7 @@ var GenerationSettings = ({
6594
7139
  }
6595
7140
  )
6596
7141
  ] }, ref.id)),
6597
- onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
7142
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6598
7143
  "button",
6599
7144
  {
6600
7145
  type: "button",
@@ -6605,21 +7150,21 @@ var GenerationSettings = ({
6605
7150
  ) })
6606
7151
  ] })
6607
7152
  ] }, 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)) })
7153
+ 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)) }),
7154
+ 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
7155
  ] });
6611
7156
  };
6612
7157
 
6613
7158
  // src/generation/JobProgress.tsx
6614
- var import_jsx_runtime31 = require("react/jsx-runtime");
7159
+ var import_jsx_runtime33 = require("react/jsx-runtime");
6615
7160
  var JobProgress = ({ title, className = "", ...options }) => {
6616
7161
  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 })
7162
+ 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: [
7163
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
7164
+ title && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "truncate text-foreground", children: title }),
7165
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
6621
7166
  ] }),
6622
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7167
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6623
7168
  "div",
6624
7169
  {
6625
7170
  role: "progressbar",
@@ -6629,7 +7174,7 @@ var JobProgress = ({ title, className = "", ...options }) => {
6629
7174
  "aria-valuenow": progress.percent,
6630
7175
  "aria-valuetext": `${progress.percent}%, ${progress.label}`,
6631
7176
  className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
6632
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
7177
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6633
7178
  "div",
6634
7179
  {
6635
7180
  className: "h-full rounded-full bg-primary transition-[width] duration-500",
@@ -6642,9 +7187,9 @@ var JobProgress = ({ title, className = "", ...options }) => {
6642
7187
  };
6643
7188
 
6644
7189
  // src/generation/AssetMentionChips.tsx
6645
- var import_react50 = require("react");
7190
+ var import_react52 = require("react");
6646
7191
  var import_generation3 = require("@pixerate/editor/generation");
6647
- var import_jsx_runtime32 = require("react/jsx-runtime");
7192
+ var import_jsx_runtime34 = require("react/jsx-runtime");
6648
7193
  var AssetMentionChips = ({
6649
7194
  content,
6650
7195
  onChange,
@@ -6654,14 +7199,14 @@ var AssetMentionChips = ({
6654
7199
  renderAsset,
6655
7200
  className = ""
6656
7201
  }) => {
6657
- const [open, setOpen] = (0, import_react50.useState)(null);
6658
- const rootRef = (0, import_react50.useRef)(null);
6659
- const chips = (0, import_react50.useMemo)(
7202
+ const [open, setOpen] = (0, import_react52.useState)(null);
7203
+ const rootRef = (0, import_react52.useRef)(null);
7204
+ const chips = (0, import_react52.useMemo)(
6660
7205
  () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
6661
7206
  [content, assets, capabilities]
6662
7207
  );
6663
7208
  const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
6664
- (0, import_react50.useEffect)(() => {
7209
+ (0, import_react52.useEffect)(() => {
6665
7210
  if (open === null) return;
6666
7211
  const onPointer = (event) => {
6667
7212
  if (!rootRef.current?.contains(event.target)) setOpen(null);
@@ -6669,19 +7214,19 @@ var AssetMentionChips = ({
6669
7214
  document.addEventListener("mousedown", onPointer);
6670
7215
  return () => document.removeEventListener("mousedown", onPointer);
6671
7216
  }, [open]);
6672
- const pick = (chip, role) => {
7217
+ const pick = (chip2, role) => {
6673
7218
  setOpen(null);
6674
- if (chip.start === void 0) return;
6675
- onChange((0, import_generation3.setMentionRoleInText)(content, chip.start, role));
7219
+ if (chip2.start === void 0) return;
7220
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip2.start, role));
6676
7221
  };
6677
7222
  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");
7223
+ 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) => {
7224
+ const error = chip2.issues.find((issue) => issue.severity === "error");
7225
+ const warning = chip2.issues.find((issue) => issue.severity === "warning");
6681
7226
  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)(
7227
+ const isOpen = open === chip2.index;
7228
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip2.asset.id, children: [
7229
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6685
7230
  "button",
6686
7231
  {
6687
7232
  type: "button",
@@ -6689,82 +7234,82 @@ var AssetMentionChips = ({
6689
7234
  "aria-expanded": isOpen,
6690
7235
  title: problem?.message,
6691
7236
  "data-issue": problem?.code,
6692
- onClick: () => setOpen(isOpen ? null : chip.index),
7237
+ onClick: () => setOpen(isOpen ? null : chip2.index),
6693
7238
  onKeyDown: (e) => {
6694
7239
  if (e.key === "Escape") setOpen(null);
6695
7240
  },
6696
7241
  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
7242
  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)(
7243
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: renderAsset ? renderAsset(chip2) : `@${chip2.asset.label ?? chip2.handle}` }),
7244
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6700
7245
  "span",
6701
7246
  {
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"
7247
+ className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip2.role ? "bg-primary/15" : "opacity-60"}`,
7248
+ "data-role-badge": chip2.role ?? "",
7249
+ children: chip2.roleLabel ?? "No role"
6705
7250
  }
6706
7251
  )
6707
7252
  ]
6708
7253
  }
6709
7254
  ),
6710
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7255
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6711
7256
  "div",
6712
7257
  {
6713
7258
  role: "listbox",
6714
- "aria-label": `Role for ${chip.asset.label ?? chip.handle}`,
7259
+ "aria-label": `Role for ${chip2.asset.label ?? chip2.handle}`,
6715
7260
  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
7261
  "data-role-picker": "",
6717
7262
  onKeyDown: (e) => {
6718
7263
  if (e.key === "Escape") setOpen(null);
6719
7264
  },
6720
7265
  children: [
6721
- options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
7266
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
6722
7267
  "button",
6723
7268
  {
6724
7269
  type: "button",
6725
7270
  role: "option",
6726
- "aria-selected": chip.role === option.role,
7271
+ "aria-selected": chip2.role === option.role,
6727
7272
  "data-role-option": option.role,
6728
7273
  title: option.description,
6729
- onClick: () => pick(chip, option.role),
7274
+ onClick: () => pick(chip2, option.role),
6730
7275
  className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
6731
7276
  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
7277
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: option.label }),
7278
+ option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
6734
7279
  ]
6735
7280
  },
6736
7281
  option.role
6737
7282
  )),
6738
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7283
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6739
7284
  "button",
6740
7285
  {
6741
7286
  type: "button",
6742
7287
  role: "option",
6743
- "aria-selected": !chip.role,
7288
+ "aria-selected": !chip2.role,
6744
7289
  "data-role-option": "",
6745
- onClick: () => pick(chip, null),
7290
+ onClick: () => pick(chip2, null),
6746
7291
  className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
6747
7292
  children: "No role"
6748
7293
  }
6749
7294
  ),
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)) })
7295
+ 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
7296
  ]
6752
7297
  }
6753
7298
  )
6754
- ] }, `${chip.start}-${chip.index}`);
7299
+ ] }, `${chip2.start}-${chip2.index}`);
6755
7300
  }) });
6756
7301
  };
6757
7302
 
6758
7303
  // src/generation/GenerationHistory.tsx
6759
- var import_react51 = require("react");
7304
+ var import_react53 = require("react");
6760
7305
  var import_generation4 = require("@pixerate/editor/generation");
6761
- var import_jsx_runtime33 = require("react/jsx-runtime");
7306
+ var import_jsx_runtime35 = require("react/jsx-runtime");
6762
7307
  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);
7308
+ const [records, setRecords] = (0, import_react53.useState)([]);
7309
+ const [loading, setLoading] = (0, import_react53.useState)(!!store);
7310
+ const [error, setError] = (0, import_react53.useState)(null);
6766
7311
  const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
6767
- const refresh = (0, import_react51.useCallback)(async () => {
7312
+ const refresh = (0, import_react53.useCallback)(async () => {
6768
7313
  if (!store) {
6769
7314
  setRecords([]);
6770
7315
  setLoading(false);
@@ -6781,7 +7326,7 @@ function useGenerationRecords(store, filter) {
6781
7326
  setLoading(false);
6782
7327
  }
6783
7328
  }, [store, filterKey]);
6784
- (0, import_react51.useEffect)(() => {
7329
+ (0, import_react53.useEffect)(() => {
6785
7330
  void refresh();
6786
7331
  if (!store) return;
6787
7332
  return store.subscribe(() => void refresh());
@@ -6807,21 +7352,21 @@ var GenerationHistory = ({
6807
7352
  emptyText = "No generations yet.",
6808
7353
  className = ""
6809
7354
  }) => {
6810
- const [innerMode, setInnerMode] = (0, import_react51.useState)("exact");
7355
+ const [innerMode, setInnerMode] = (0, import_react53.useState)("exact");
6811
7356
  const mode = modeProp ?? innerMode;
6812
7357
  const setMode = (next) => {
6813
7358
  if (modeProp === void 0) setInnerMode(next);
6814
7359
  onModeChange?.(next);
6815
7360
  };
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)(
7361
+ const options = (0, import_react53.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
7362
+ const results = (0, import_react53.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
7363
+ const models = (0, import_react53.useMemo)(
6819
7364
  () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
6820
7365
  [capabilities]
6821
7366
  );
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)(
7367
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
7368
+ /* @__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: [
7369
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6825
7370
  "input",
6826
7371
  {
6827
7372
  type: "radio",
@@ -6834,34 +7379,34 @@ var GenerationHistory = ({
6834
7379
  ),
6835
7380
  value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
6836
7381
  ] }, 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) => {
7382
+ records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
7383
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
6839
7384
  const result = results[i];
6840
7385
  const model = models.find((m) => m.id === record.provenance.modelId);
6841
7386
  const blocked = !result.ok;
6842
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7387
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
6843
7388
  "li",
6844
7389
  {
6845
7390
  className: "rounded-md border border-border p-2",
6846
7391
  "data-record": record.id,
6847
7392
  "data-drift": result.drift.length,
6848
7393
  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: [
7394
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
7395
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
7396
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "text-muted-foreground", children: [
7397
+ record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { "data-kind": "", children: [
6853
7398
  record.kind,
6854
7399
  " \xB7 "
6855
7400
  ] }),
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: [
7401
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
7402
+ record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
6858
7403
  " \xB7 seed ",
6859
7404
  record.seed
6860
7405
  ] })
6861
7406
  ] })
6862
7407
  ] }),
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)(
7408
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
7409
+ 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
7410
  "span",
6866
7411
  {
6867
7412
  className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
@@ -6875,16 +7420,16 @@ var GenerationHistory = ({
6875
7420
  `${asset.role}:${asset.id}`
6876
7421
  )) }),
6877
7422
  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: [
7423
+ 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: [
7424
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("strong", { children: [
6880
7425
  import_generation4.DRIFT_TYPE_LABELS[item.type],
6881
7426
  ":"
6882
7427
  ] }),
6883
7428
  " ",
6884
7429
  item.message
6885
7430
  ] }, j)) }),
6886
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "mt-2 flex gap-2", children: [
6887
- onRecreate && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7431
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-2 flex gap-2", children: [
7432
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6888
7433
  "button",
6889
7434
  {
6890
7435
  type: "button",
@@ -6896,7 +7441,7 @@ var GenerationHistory = ({
6896
7441
  children: "Recreate"
6897
7442
  }
6898
7443
  ),
6899
- onVariation && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7444
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6900
7445
  "button",
6901
7446
  {
6902
7447
  type: "button",
@@ -6906,7 +7451,7 @@ var GenerationHistory = ({
6906
7451
  children: "Variation"
6907
7452
  }
6908
7453
  ),
6909
- onRemove && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7454
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6910
7455
  "button",
6911
7456
  {
6912
7457
  type: "button",
@@ -6926,19 +7471,19 @@ var GenerationHistory = ({
6926
7471
  };
6927
7472
 
6928
7473
  // src/find-replace/useFindReplace.ts
6929
- var import_react52 = require("react");
7474
+ var import_react54 = require("react");
6930
7475
  var import_editor16 = require("@pixerate/editor");
6931
7476
  var noopUnsubscribe2 = () => {
6932
7477
  };
6933
7478
  function useFindReplace(editor) {
6934
7479
  const store = (0, import_editor16.getFindReplaceStore)(editor ?? null);
6935
- const subscribe = (0, import_react52.useCallback)(
7480
+ const subscribe = (0, import_react54.useCallback)(
6936
7481
  (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
6937
7482
  [store]
6938
7483
  );
6939
7484
  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)(() => {
7485
+ const snapshot = (0, import_react54.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
7486
+ return (0, import_react54.useMemo)(() => {
6942
7487
  const run = (fn) => {
6943
7488
  if (editor && !editor.isDestroyed && store) fn(editor);
6944
7489
  };
@@ -6962,9 +7507,9 @@ function useFindReplace(editor) {
6962
7507
  }
6963
7508
 
6964
7509
  // src/find-replace/FindReplaceBar.tsx
6965
- var import_react53 = require("react");
7510
+ var import_react55 = require("react");
6966
7511
  var import_editor17 = require("@pixerate/editor");
6967
- var import_jsx_runtime34 = require("react/jsx-runtime");
7512
+ var import_jsx_runtime36 = require("react/jsx-runtime");
6968
7513
  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
7514
  var buttonClass5 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
6970
7515
  var toggleClass = (on) => `${buttonClass5} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
@@ -6977,10 +7522,10 @@ var FindReplaceBar = ({
6977
7522
  onClose
6978
7523
  }) => {
6979
7524
  const find = useFindReplace(editor);
6980
- const findInput = (0, import_react53.useRef)(null);
6981
- const [moreOpen, setMoreOpen] = (0, import_react53.useState)(false);
7525
+ const findInput = (0, import_react55.useRef)(null);
7526
+ const [moreOpen, setMoreOpen] = (0, import_react55.useState)(false);
6982
7527
  const visible = find.available && (alwaysOpen || find.open);
6983
- (0, import_react53.useEffect)(() => {
7528
+ (0, import_react55.useEffect)(() => {
6984
7529
  if (!visible || find.focusRequest === 0) return;
6985
7530
  findInput.current?.focus();
6986
7531
  findInput.current?.select();
@@ -7018,9 +7563,9 @@ var FindReplaceBar = ({
7018
7563
  if (isMod(e)) find.replaceAll();
7019
7564
  else find.replace();
7020
7565
  };
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)(
7566
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
7567
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-1", children: [
7568
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7024
7569
  "button",
7025
7570
  {
7026
7571
  type: "button",
@@ -7031,7 +7576,7 @@ var FindReplaceBar = ({
7031
7576
  children: showReplace ? "\u25BE" : "\u25B8"
7032
7577
  }
7033
7578
  ),
7034
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7579
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7035
7580
  "input",
7036
7581
  {
7037
7582
  ref: findInput,
@@ -7045,7 +7590,7 @@ var FindReplaceBar = ({
7045
7590
  onKeyDown: onFindKeyDown
7046
7591
  }
7047
7592
  ),
7048
- import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7593
+ import_editor17.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7049
7594
  "button",
7050
7595
  {
7051
7596
  type: "button",
@@ -7058,7 +7603,7 @@ var FindReplaceBar = ({
7058
7603
  },
7059
7604
  t.key
7060
7605
  )),
7061
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7606
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7062
7607
  "span",
7063
7608
  {
7064
7609
  className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
@@ -7068,9 +7613,9 @@ var FindReplaceBar = ({
7068
7613
  children: status
7069
7614
  }
7070
7615
  ),
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)(
7616
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
7617
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
7618
+ showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7074
7619
  "button",
7075
7620
  {
7076
7621
  type: "button",
@@ -7081,10 +7626,10 @@ var FindReplaceBar = ({
7081
7626
  children: "\u2026"
7082
7627
  }
7083
7628
  ),
7084
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
7629
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, "aria-label": "Close find", onClick: close, children: "\xD7" })
7085
7630
  ] }),
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)(
7631
+ showReplace && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
7632
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7088
7633
  "input",
7089
7634
  {
7090
7635
  type: "text",
@@ -7096,7 +7641,7 @@ var FindReplaceBar = ({
7096
7641
  onKeyDown: onReplaceKeyDown
7097
7642
  }
7098
7643
  ),
7099
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
7644
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7100
7645
  "button",
7101
7646
  {
7102
7647
  type: "button",
@@ -7106,11 +7651,11 @@ var FindReplaceBar = ({
7106
7651
  children: "Replace"
7107
7652
  }
7108
7653
  ),
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` })
7654
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: buttonClass5, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
7655
+ 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
7656
  ] }),
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)(
7657
+ 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: [
7658
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7114
7659
  "input",
7115
7660
  {
7116
7661
  type: "checkbox",
@@ -7124,12 +7669,12 @@ var FindReplaceBar = ({
7124
7669
  };
7125
7670
 
7126
7671
  // src/tables/useTableMenu.ts
7127
- var import_react54 = require("react");
7672
+ var import_react56 = require("react");
7128
7673
  var import_editor18 = require("@pixerate/editor");
7129
7674
  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)(
7675
+ const store = (0, import_react56.useMemo)(() => (0, import_editor18.createTableStore)(editor), [editor]);
7676
+ const snapshot = (0, import_react56.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
7677
+ return (0, import_react56.useMemo)(
7133
7678
  () => ({
7134
7679
  ...snapshot,
7135
7680
  run: (action, params) => (0, import_editor18.runTableAction)(editor, action, params, { focus: true }),
@@ -7140,9 +7685,9 @@ function useTableMenu(editor) {
7140
7685
  }
7141
7686
 
7142
7687
  // src/tables/TableToolbar.tsx
7143
- var import_react55 = __toESM(require("react"), 1);
7688
+ var import_react57 = __toESM(require("react"), 1);
7144
7689
  var import_editor19 = require("@pixerate/editor");
7145
- var import_jsx_runtime35 = require("react/jsx-runtime");
7690
+ var import_jsx_runtime37 = require("react/jsx-runtime");
7146
7691
  var keepSelection2 = (event) => event.preventDefault();
7147
7692
  var TableToolbar = ({
7148
7693
  editor,
@@ -7156,14 +7701,14 @@ var TableToolbar = ({
7156
7701
  }) => {
7157
7702
  const table = useTableMenu(editor);
7158
7703
  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) => {
7704
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className, role: "toolbar", "aria-label": "Table", "data-table-toolbar": "", children: items.map((item, index) => {
7160
7705
  const status = table.check(item.action, item.params);
7161
7706
  const enabled = status === true;
7162
7707
  const active = item.active?.(table);
7163
7708
  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)(
7709
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react57.default.Fragment, { children: [
7710
+ separator && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: separatorClassName, "aria-hidden": "true" }),
7711
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7167
7712
  "button",
7168
7713
  {
7169
7714
  type: "button",
@@ -7185,8 +7730,8 @@ var TableToolbar = ({
7185
7730
  };
7186
7731
 
7187
7732
  // src/tables/InsertTableGrid.tsx
7188
- var import_react56 = require("react");
7189
- var import_jsx_runtime36 = require("react/jsx-runtime");
7733
+ var import_react58 = require("react");
7734
+ var import_jsx_runtime38 = require("react/jsx-runtime");
7190
7735
  var keepSelection3 = (event) => event.preventDefault();
7191
7736
  var InsertTableGrid = ({
7192
7737
  editor,
@@ -7199,14 +7744,14 @@ var InsertTableGrid = ({
7199
7744
  onInsert
7200
7745
  }) => {
7201
7746
  const table = useTableMenu(editor);
7202
- const [hover, setHover] = (0, import_react56.useState)(null);
7747
+ const [hover, setHover] = (0, import_react58.useState)(null);
7203
7748
  const status = table.actions.insertTable;
7204
7749
  const disabled = !editor || !status.enabled;
7205
7750
  const insert = (size) => {
7206
7751
  if (table.run("insertTable", { ...size, withHeaderRow })) onInsert?.(size);
7207
7752
  setHover(null);
7208
7753
  };
7209
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7754
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7210
7755
  "div",
7211
7756
  {
7212
7757
  className,
@@ -7216,7 +7761,7 @@ var InsertTableGrid = ({
7216
7761
  "data-insert-table-grid": "",
7217
7762
  onMouseLeave: () => setHover(null),
7218
7763
  children: [
7219
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7764
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7220
7765
  "div",
7221
7766
  {
7222
7767
  role: "grid",
@@ -7225,7 +7770,7 @@ var InsertTableGrid = ({
7225
7770
  children: Array.from({ length: rows * cols }, (_, i) => {
7226
7771
  const size = { rows: Math.floor(i / cols) + 1, cols: i % cols + 1 };
7227
7772
  const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols;
7228
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7773
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7229
7774
  "button",
7230
7775
  {
7231
7776
  type: "button",
@@ -7245,7 +7790,7 @@ var InsertTableGrid = ({
7245
7790
  })
7246
7791
  }
7247
7792
  ),
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" })
7793
+ /* @__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
7794
  ]
7250
7795
  }
7251
7796
  );
@@ -7253,31 +7798,31 @@ var InsertTableGrid = ({
7253
7798
 
7254
7799
  // src/tables/TableBubbleMenu.tsx
7255
7800
  var import_editor20 = require("@pixerate/editor");
7256
- var import_jsx_runtime37 = require("react/jsx-runtime");
7801
+ var import_jsx_runtime39 = require("react/jsx-runtime");
7257
7802
  var TableBubbleMenu = ({
7258
7803
  editor,
7259
7804
  children,
7260
7805
  toolbarProps,
7261
7806
  pluginKey = "tableBubbleMenu",
7262
7807
  ...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 }) });
7808
+ }) => /* @__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
7809
 
7265
7810
  // src/chart-node/ChartNodeView.tsx
7266
7811
  var import_client = require("react-dom/client");
7267
7812
 
7268
7813
  // src/chart/ChartCanvas.tsx
7269
- var import_react58 = require("react");
7814
+ var import_react60 = require("react");
7270
7815
  var import_chart2 = require("@pixerate/editor/chart");
7271
7816
 
7272
7817
  // src/chart/useChartEditor.ts
7273
- var import_react57 = require("react");
7818
+ var import_react59 = require("react");
7274
7819
  var import_chart = require("@pixerate/editor/chart");
7275
7820
  function useChartState(controller) {
7276
- return (0, import_react57.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7821
+ return (0, import_react59.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
7277
7822
  }
7278
7823
 
7279
7824
  // src/chart/ChartCanvas.tsx
7280
- var import_jsx_runtime38 = require("react/jsx-runtime");
7825
+ var import_jsx_runtime40 = require("react/jsx-runtime");
7281
7826
  function renderChartMark(mark, fontFamily, interactive) {
7282
7827
  const common = {
7283
7828
  "data-role": mark.role,
@@ -7289,9 +7834,9 @@ function renderChartMark(mark, fontFamily, interactive) {
7289
7834
  };
7290
7835
  switch (mark.kind) {
7291
7836
  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);
7837
+ 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
7838
  case "path":
7294
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7839
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7295
7840
  "path",
7296
7841
  {
7297
7842
  ...common,
@@ -7304,11 +7849,11 @@ function renderChartMark(mark, fontFamily, interactive) {
7304
7849
  mark.key
7305
7850
  );
7306
7851
  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);
7852
+ 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
7853
  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);
7854
+ 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
7855
  case "text":
7311
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7856
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7312
7857
  "text",
7313
7858
  {
7314
7859
  ...common,
@@ -7325,23 +7870,23 @@ function renderChartMark(mark, fontFamily, interactive) {
7325
7870
  }
7326
7871
  }
7327
7872
  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 })
7873
+ const { actors } = (0, import_react60.useSyncExternalStore)(presence.subscribe, presence.getState, presence.getState);
7874
+ 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: [
7875
+ /* @__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 }),
7876
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("g", { transform: "translate(13 16)", children: [
7877
+ /* @__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 } }),
7878
+ /* @__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
7879
  ] })
7335
7880
  ] }, a.id)) });
7336
7881
  }
7337
7882
  function ChartCanvas({ controller, width = 640, height = 400, responsive = true, theme, editable = true, measureText, emptyMessage, className, presence, sceneRef }) {
7338
7883
  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)(() => {
7884
+ const wrapper = (0, import_react60.useRef)(null);
7885
+ const svg = (0, import_react60.useRef)(null);
7886
+ const drag = (0, import_react60.useRef)(null);
7887
+ const [measured, setMeasured] = (0, import_react60.useState)(null);
7888
+ const [frozen, setFrozen] = (0, import_react60.useState)(null);
7889
+ (0, import_react60.useEffect)(() => {
7345
7890
  const el = wrapper.current;
7346
7891
  if (!responsive || !el || typeof ResizeObserver === "undefined") return;
7347
7892
  const observer = new ResizeObserver(([entry]) => {
@@ -7352,8 +7897,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7352
7897
  return () => observer.disconnect();
7353
7898
  }, [responsive]);
7354
7899
  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)(
7900
+ const fullTheme = (0, import_react60.useMemo)(() => ({ ...import_chart2.CSS_VARIABLE_CHART_THEME, ...theme }), [theme]);
7901
+ const scene = (0, import_react60.useMemo)(
7357
7902
  () => (0, import_chart2.layoutChart)(state.spec, {
7358
7903
  width: sceneWidth,
7359
7904
  height,
@@ -7369,8 +7914,8 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7369
7914
  [state.spec, state.selection, sceneWidth, height, fullTheme, editable, measureText, emptyMessage, frozen]
7370
7915
  );
7371
7916
  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(), []);
7917
+ const byKey = (0, import_react60.useMemo)(() => new Map(scene.marks.map((m) => [m.key, m])), [scene]);
7918
+ (0, import_react60.useEffect)(() => () => drag.current?.end(), []);
7374
7919
  const scenePoint = (e) => (0, import_chart2.chartClientToScene)(scene, svg.current.getBoundingClientRect(), e.clientX, e.clientY);
7375
7920
  const onPointerDown = (e) => {
7376
7921
  if (!editable || e.button !== 0) return;
@@ -7403,7 +7948,7 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7403
7948
  if (editable && (0, import_chart2.handleChartKey)(controller, scene, e)) e.preventDefault();
7404
7949
  };
7405
7950
  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)(
7951
+ 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
7952
  "svg",
7408
7953
  {
7409
7954
  ref: svg,
@@ -7421,14 +7966,14 @@ function ChartCanvas({ controller, width = 640, height = 400, responsive = true,
7421
7966
  onKeyDown,
7422
7967
  children: [
7423
7968
  scene.marks.map((m) => renderChartMark(m, scene.theme.fontFamily, editable)),
7424
- presence && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ChartPresenceLayer, { presence })
7969
+ presence && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChartPresenceLayer, { presence })
7425
7970
  ]
7426
7971
  }
7427
7972
  ) });
7428
7973
  }
7429
7974
 
7430
7975
  // src/chart/ChartDataGrid.tsx
7431
- var import_react59 = require("react");
7976
+ var import_react61 = require("react");
7432
7977
  var import_chart3 = require("@pixerate/editor/chart");
7433
7978
 
7434
7979
  // src/chart/styles.ts
@@ -7441,11 +7986,11 @@ var chartSectionClass = "space-y-2 border-b border-border pb-3 last:border-b-0";
7441
7986
  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
7987
 
7443
7988
  // src/chart/ChartDataGrid.tsx
7444
- var import_jsx_runtime39 = require("react/jsx-runtime");
7989
+ var import_jsx_runtime41 = require("react/jsx-runtime");
7445
7990
  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)(() => {
7991
+ const [draft, setDraft] = (0, import_react61.useState)(value);
7992
+ const typing = (0, import_react61.useRef)(false);
7993
+ (0, import_react61.useEffect)(() => {
7449
7994
  if (!typing.current) setDraft(value);
7450
7995
  }, [value]);
7451
7996
  const commit = () => {
@@ -7454,7 +7999,7 @@ function ChartCommitInput({ value, onCommit, onKeyDown, onBlur, ...rest }) {
7454
7999
  if (draft === value) return;
7455
8000
  if (onCommit(draft) === false) setDraft(value);
7456
8001
  };
7457
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8002
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7458
8003
  "input",
7459
8004
  {
7460
8005
  ...rest,
@@ -7489,15 +8034,15 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7489
8034
  e.preventDefault();
7490
8035
  controller.pasteCells(row, column, text);
7491
8036
  };
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 }),
8037
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: `overflow-auto rounded-md border border-border ${className ?? ""}`, "data-chart-grid": "", children: [
8038
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("table", { className: "w-full border-collapse text-xs", children: [
8039
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("thead", { className: "bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("tr", { children: [
8040
+ /* @__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
8041
  spec.series.map((s, si) => {
7497
8042
  const color = (0, import_chart3.chartSeriesColor)(spec, si);
7498
8043
  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)(
8044
+ 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: [
8045
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7501
8046
  "input",
7502
8047
  {
7503
8048
  type: "color",
@@ -7510,7 +8055,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7510
8055
  className: "h-5 w-5 shrink-0 cursor-pointer rounded border-0 bg-transparent p-0"
7511
8056
  }
7512
8057
  ),
7513
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8058
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7514
8059
  ChartCommitInput,
7515
8060
  {
7516
8061
  value: s.name,
@@ -7520,8 +8065,8 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7520
8065
  className: `${chartInputClass} h-6 min-w-[5rem] border-transparent bg-transparent font-medium ${s.hidden ? "text-muted-foreground line-through" : ""}`
7521
8066
  }
7522
8067
  ),
7523
- !readOnly && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
7524
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8068
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
8069
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7525
8070
  "button",
7526
8071
  {
7527
8072
  type: "button",
@@ -7534,16 +8079,16 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7534
8079
  children: s.hidden ? "\u25CB" : "\u25CF"
7535
8080
  }
7536
8081
  ),
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" })
8082
+ /* @__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
8083
  ] })
7539
8084
  ] }) }, s.id);
7540
8085
  }),
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: "+" }) })
8086
+ !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
8087
  ] }) }),
7543
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tbody", { children: spec.categories.map((category, i) => {
8088
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("tbody", { children: spec.categories.map((category, i) => {
7544
8089
  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)(
8090
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("tr", { "data-category-index": i, className: rowSelected ? "bg-primary/10" : void 0, children: [
8091
+ /* @__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
8092
  ChartCommitInput,
7548
8093
  {
7549
8094
  value: category,
@@ -7557,7 +8102,7 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7557
8102
  spec.series.map((s) => {
7558
8103
  const value = s.values[i];
7559
8104
  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)(
8105
+ 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
8106
  ChartCommitInput,
7562
8107
  {
7563
8108
  value: value === null || value === void 0 ? "" : String(value),
@@ -7572,38 +8117,38 @@ function ChartDataGrid({ controller, categoryHeader = "Category", readOnly = fal
7572
8117
  }
7573
8118
  ) }, s.id);
7574
8119
  }),
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" }) })
8120
+ !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
8121
  ] }, i);
7577
8122
  }) })
7578
8123
  ] }),
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" }) })
8124
+ !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
8125
  ] });
7581
8126
  }
7582
8127
 
7583
8128
  // src/chart/ChartInspector.tsx
7584
- var import_react60 = require("react");
8129
+ var import_react62 = require("react");
7585
8130
  var import_chart4 = require("@pixerate/editor/chart");
7586
- var import_jsx_runtime40 = require("react/jsx-runtime");
8131
+ var import_jsx_runtime42 = require("react/jsx-runtime");
7587
8132
  var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
7588
8133
  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 })
8134
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
8135
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("label", { htmlFor, className: `${chartLabelClass} w-20 shrink-0`, children: label }),
8136
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "min-w-0 flex-1", children })
7592
8137
  ] });
7593
8138
  }
7594
8139
  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) }),
8140
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "flex cursor-pointer items-center gap-2 text-xs text-foreground", children: [
8141
+ /* @__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
8142
  label
7598
8143
  ] });
7599
8144
  }
7600
8145
  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)) });
8146
+ 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
8147
  }
7603
8148
  function AxisSection({ controller, axis, value, idBase, horizontal, numeric = false, scales = false }) {
7604
8149
  const set = (patch) => controller.setAxis(axis, patch);
7605
8150
  const setFormat = (patch) => set({ format: { ...value.format, ...patch } });
7606
- const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8151
+ const bound = (key2) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7607
8152
  ChartCommitInput,
7608
8153
  {
7609
8154
  id: `${idBase}-${axis}-${key2}`,
@@ -7618,26 +8163,26 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7618
8163
  const name = axis === "x" ? numeric ? "X axis" : "Category axis" : axis === "y" ? "Value axis" : "Secondary axis";
7619
8164
  const valueAxis = axis !== "x" || numeric;
7620
8165
  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: [
8166
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": `axis-${axis}`, children: [
8167
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
8168
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("h4", { className: "text-xs font-semibold text-foreground", children: [
7624
8169
  name,
7625
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
8170
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-1 font-normal text-muted-foreground", children: [
7626
8171
  "(",
7627
8172
  axis === "x" ? horizontal ? "left" : "bottom" : axis === "y2" ? horizontal ? "top" : "right" : horizontal ? "bottom" : "left",
7628
8173
  ")"
7629
8174
  ] })
7630
8175
  ] }),
7631
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
8176
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Show", name: `${axis}Axis.show`, checked: value.show, onChange: (show) => set({ show }) })
7632
8177
  ] }),
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" }) })
8178
+ /* @__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 }) }) }),
8179
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8180
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Grid lines", name: `${key}.gridlines`, checked: value.gridlines, onChange: (gridlines) => set({ gridlines }) }),
8181
+ 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 }) }),
8182
+ scales && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Reverse", name: `${key}.reverse`, checked: !!value.reverse, onChange: (reverse) => set({ reverse }) }),
8183
+ 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
8184
  ] }),
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)(
8185
+ 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
8186
  ChartCommitInput,
7642
8187
  {
7643
8188
  id: `${idBase}-${axis}-log-base`,
@@ -7648,7 +8193,7 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7648
8193
  onCommit: (text) => set({ logBase: text.trim() === "" ? void 0 : Number(text) }).ok
7649
8194
  }
7650
8195
  ) }),
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)(
8196
+ 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
8197
  ChartCommitInput,
7653
8198
  {
7654
8199
  id: `${idBase}-${axis}-step`,
@@ -7660,14 +8205,14 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7660
8205
  onCommit: (text) => set({ step: text.trim() === "" ? null : Number(text) }).ok
7661
8206
  }
7662
8207
  ) }),
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: [
8208
+ valueAxis && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8209
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Min / max", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex gap-1", children: [
7665
8210
  bound("min"),
7666
8211
  bound("max")
7667
8212
  ] }) }),
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)(
8213
+ /* @__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: [
8214
+ /* @__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 }) }),
8215
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7671
8216
  ChartCommitInput,
7672
8217
  {
7673
8218
  value: value.format.decimals === void 0 ? "" : String(value.format.decimals),
@@ -7686,8 +8231,8 @@ function AxisSection({ controller, axis, value, idBase, horizontal, numeric = fa
7686
8231
  }
7687
8232
  )
7688
8233
  ] }) }),
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)(
8234
+ 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() }) }) }),
8235
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Code", htmlFor: `${idBase}-${axis}-code`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7691
8236
  ChartCommitInput,
7692
8237
  {
7693
8238
  id: `${idBase}-${axis}-code`,
@@ -7713,15 +8258,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
7713
8258
  const values = which === "xErrorBars" ? series.x ?? [] : series.values;
7714
8259
  const set = (next) => controller.updateSeries(series.id, { [which]: next });
7715
8260
  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))
8261
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", "data-section": which === "errorBars" ? "error-bars" : "x-error-bars", children: [
8262
+ /* @__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: [
8263
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "None" }),
8264
+ 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
8265
  ] }) }),
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)(
8266
+ 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 }) }),
8267
+ bars?.type === "custom" && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8268
+ /* @__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 }) }),
8269
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Minus", htmlFor: `${id}-minus`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7725
8270
  ChartCommitInput,
7726
8271
  {
7727
8272
  id: `${id}-minus`,
@@ -7738,15 +8283,15 @@ function ErrorBarFields({ controller, series, which, idBase }) {
7738
8283
  }
7739
8284
  ) })
7740
8285
  ] }),
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 }) })
8286
+ bars && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
8287
+ /* @__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)) }),
8288
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Caps", name: `${key}.cap`, checked: bars.cap !== false, onChange: (cap2) => patch({ cap: cap2 }) })
7744
8289
  ] })
7745
8290
  ] });
7746
8291
  }
7747
8292
  function ChartInspector({ controller, sections, className }) {
7748
8293
  const { spec, selectedSeries } = useChartState(controller);
7749
- const idBase = (0, import_react60.useId)();
8294
+ const idBase = (0, import_react62.useId)();
7750
8295
  const show = (section) => !sections || sections.includes(section);
7751
8296
  const cartesian = (0, import_chart4.isCartesianChart)(spec.type);
7752
8297
  const family = (0, import_chart4.chartFamily)(spec);
@@ -7758,29 +8303,29 @@ function ChartInspector({ controller, sections, className }) {
7758
8303
  const hasLines = cartesian && types.some((t) => t === "line" || t === "area");
7759
8304
  const seriesIndex = selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1;
7760
8305
  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))
8306
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: `space-y-3 text-xs ${className ?? ""}`, "data-chart-inspector": "", children: [
8307
+ 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)) }) }),
8308
+ show("style") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "style", children: [
8309
+ /* @__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: [
8310
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Quick layout\u2026" }),
8311
+ 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
8312
  ] }) }),
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))
8313
+ /* @__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: [
8314
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Custom" }),
8315
+ 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
8316
  ] }) }),
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" })
8317
+ !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] }),
8318
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "transpose", onClick: () => controller.transpose(), children: "Switch rows and columns" })
7774
8319
  ] }),
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) }) })
8320
+ show("titles") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "titles", children: [
8321
+ /* @__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) }) }),
8322
+ /* @__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
8323
  ] }),
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)(
8324
+ show("options") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "options", children: [
8325
+ 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 }) }) }),
8326
+ 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)) }) }),
8327
+ 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 }) }) }),
8328
+ spec.type === "donut" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Hole", htmlFor: `${idBase}-hole`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7784
8329
  "input",
7785
8330
  {
7786
8331
  id: `${idBase}-hole`,
@@ -7796,7 +8341,7 @@ function ChartInspector({ controller, sections, className }) {
7796
8341
  onChange: (e) => controller.update({ innerRadius: Number(e.currentTarget.value) })
7797
8342
  }
7798
8343
  ) }),
7799
- hasBars && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
8344
+ hasBars && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Spacing", htmlFor: `${idBase}-gap`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7800
8345
  "input",
7801
8346
  {
7802
8347
  id: `${idBase}-gap`,
@@ -7812,31 +8357,31 @@ function ChartInspector({ controller, sections, className }) {
7812
8357
  onChange: (e) => controller.update({ gapWidth: Number(e.currentTarget.value) })
7813
8358
  }
7814
8359
  ) }),
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 }) })
8360
+ 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 }) }) }),
8361
+ 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 }) }),
8362
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: [
8363
+ spec.type === "waterfall" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Total bar", name: "showTotal", checked: spec.showTotal, onChange: (showTotal) => controller.update({ showTotal }) }),
8364
+ hasLines && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Points", name: "points", checked: spec.points, onChange: (points) => controller.update({ points }) }),
8365
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Data labels", name: "dataLabels", checked: spec.dataLabels, onChange: (dataLabels) => controller.update({ dataLabels }) })
7821
8366
  ] })
7822
8367
  ] }),
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 }) })
8368
+ show("legend") && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "legend", children: [
8369
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
8370
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Legend" }),
8371
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Show", name: "legend.show", checked: spec.legend.show, onChange: (v) => controller.setLegend({ show: v }) })
7827
8372
  ] }),
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)) })
8373
+ 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
8374
  ] }),
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 })
8375
+ show("axes") && hasAxes && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
8376
+ 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 }),
8377
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AxisSection, { controller, axis: "y", value: spec.yAxis, idBase, horizontal: spec.orientation === "horizontal", scales }),
8378
+ usesSecondary && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AxisSection, { controller, axis: "y2", value: spec.yAxis2, idBase, horizontal: spec.orientation === "horizontal", scales })
7834
8379
  ] }),
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)(
8380
+ show("series") && selectedSeries && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: chartSectionClass, "data-section": "series", "data-series-id": selectedSeries.id, children: [
8381
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h4", { className: "text-xs font-semibold text-foreground", children: "Series" }),
8382
+ /* @__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 }) }) }),
8383
+ /* @__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: [
8384
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7840
8385
  "input",
7841
8386
  {
7842
8387
  id: `${idBase}-series-color`,
@@ -7849,9 +8394,9 @@ function ChartInspector({ controller, sections, className }) {
7849
8394
  onChange: (e) => controller.updateSeries(selectedSeries.id, { color: e.currentTarget.value })
7850
8395
  }
7851
8396
  ),
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" })
8397
+ 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
8398
  ] }) }),
7854
- cartesian && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8399
+ cartesian && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Field, { label: "Draw as", htmlFor: `${idBase}-series-type`, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7855
8400
  "select",
7856
8401
  {
7857
8402
  id: `${idBase}-series-type`,
@@ -7860,12 +8405,12 @@ function ChartInspector({ controller, sections, className }) {
7860
8405
  "data-option": "series.type",
7861
8406
  onChange: (e) => controller.updateSeries(selectedSeries.id, { type: e.currentTarget.value || null }),
7862
8407
  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))
8408
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Chart type" }),
8409
+ 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
8410
  ]
7866
8411
  }
7867
8412
  ) }),
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)(
8413
+ (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
8414
  "select",
7870
8415
  {
7871
8416
  id: `${idBase}-series-marker`,
@@ -7874,20 +8419,20 @@ function ChartInspector({ controller, sections, className }) {
7874
8419
  "data-option": "series.marker",
7875
8420
  onChange: (e) => controller.updateSeries(selectedSeries.id, { marker: e.currentTarget.value || null }),
7876
8421
  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))
8422
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Default" }),
8423
+ import_chart4.CHART_MARKERS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: m, children: cap(m) }, m))
7879
8424
  ]
7880
8425
  }
7881
8426
  ) }),
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" })
8427
+ scales && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "errorBars", idBase }),
8428
+ family === "xy" && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ErrorBarFields, { controller, series: selectedSeries, which: "xErrorBars", idBase }),
8429
+ (0, import_chart4.chartSupportsTrendlines)(spec.type, spec.stacking) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1", "data-section": "trendlines", children: [
8430
+ (selectedSeries.trendlines ?? []).map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1", "data-trendline": i, children: [
8431
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-1 truncate text-muted-foreground", children: (0, import_chart4.chartTrendlineName)(t, selectedSeries.name) }),
8432
+ /* @__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 }) }),
8433
+ /* @__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
8434
  ] }, i)),
7890
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
8435
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7891
8436
  "select",
7892
8437
  {
7893
8438
  className: chartInputClass,
@@ -7896,32 +8441,32 @@ function ChartInspector({ controller, sections, className }) {
7896
8441
  "data-option": "trendline.add",
7897
8442
  onChange: (e) => e.currentTarget.value && controller.addTrendline(selectedSeries.id, { type: e.currentTarget.value }),
7898
8443
  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))
8444
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "Add trendline\u2026" }),
8445
+ import_chart4.CHART_TRENDLINE_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t, children: cap(t.replace("-", " ")) }, t))
7901
8446
  ]
7902
8447
  }
7903
8448
  )
7904
8449
  ] }),
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" })
8450
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
8451
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Toggle, { label: "Hidden", name: "series.hidden", checked: !!selectedSeries.hidden, onChange: (hidden) => controller.updateSeries(selectedSeries.id, { hidden }) }),
8452
+ 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 }) }),
8453
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex-1" }),
8454
+ /* @__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" }),
8455
+ /* @__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" }),
8456
+ /* @__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
8457
  ] })
7913
8458
  ] })
7914
8459
  ] });
7915
8460
  }
7916
8461
 
7917
8462
  // src/chart-node/ChartNodeView.tsx
7918
- var import_jsx_runtime41 = require("react/jsx-runtime");
8463
+ var import_jsx_runtime43 = require("react/jsx-runtime");
7919
8464
  function ChartNodeView({ state, theme, showDataGrid = true }) {
7920
8465
  const { controller, editing, editable, selected, width, height, setEditing } = state;
7921
8466
  const open = () => {
7922
8467
  if (editable && !editing) setEditing(true);
7923
8468
  };
7924
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8469
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7925
8470
  "div",
7926
8471
  {
7927
8472
  className: `not-prose my-2 rounded-md border bg-background p-1 ${selected ? "border-primary ring-1 ring-primary" : "border-border"}`,
@@ -7934,24 +8479,24 @@ function ChartNodeView({ state, theme, showDataGrid = true }) {
7934
8479
  }
7935
8480
  },
7936
8481
  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" })
8482
+ 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: [
8483
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-xs text-muted-foreground", children: "Editing chart" }),
8484
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: chartButtonClass, "data-action": "done", onClick: () => setEditing(false), children: "Done" })
7940
8485
  ] }),
7941
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8486
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7942
8487
  "div",
7943
8488
  {
7944
8489
  className: editable && !editing ? "cursor-pointer" : void 0,
7945
8490
  onClick: open,
7946
8491
  title: editable && !editing ? "Click to edit the chart" : void 0,
7947
8492
  "data-chart-node-canvas": "",
7948
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
8493
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChartCanvas, { controller, width: width ?? 640, height, responsive: width === null, editable: editing, theme })
7949
8494
  }
7950
8495
  ),
7951
8496
  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" })
8497
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "mt-2 flex flex-wrap items-start gap-2", "data-chart-node-panel": "", children: [
8498
+ 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 }) }),
8499
+ /* @__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
8500
  ] })
7956
8501
  ]
7957
8502
  }
@@ -7969,7 +8514,7 @@ function createReactChartNodeView(options = {}) {
7969
8514
  scheduled = true;
7970
8515
  queueMicrotask(() => {
7971
8516
  scheduled = false;
7972
- if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Component, { ...props, state: latest }));
8517
+ if (!destroyed) root.render(/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Component, { ...props, state: latest }));
7973
8518
  });
7974
8519
  };
7975
8520
  schedule();
@@ -7989,6 +8534,7 @@ function createReactChartNodeView(options = {}) {
7989
8534
  0 && (module.exports = {
7990
8535
  AdjustmentLayersPanel,
7991
8536
  AssetMentionChips,
8537
+ BrushOptionsBar,
7992
8538
  BubbleMenu,
7993
8539
  ChartNodeView,
7994
8540
  CommandPalette,
@@ -8009,6 +8555,7 @@ function createReactChartNodeView(options = {}) {
8009
8555
  ImageEditor,
8010
8556
  InsertTableGrid,
8011
8557
  JobProgress,
8558
+ LayersPanel,
8012
8559
  MergePreview,
8013
8560
  NameManager,
8014
8561
  OutlinePanel,