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