@pixerate/editor-react 0.15.0 → 0.17.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.
Files changed (54) hide show
  1. package/README.md +6 -2
  2. package/dist/canvas/index.cjs +484 -119
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +122 -3
  5. package/dist/canvas/index.d.ts +122 -3
  6. package/dist/canvas/index.js +380 -0
  7. package/dist/canvas/index.js.map +1 -1
  8. package/dist/chunk-I3E4KSA2.js +515 -0
  9. package/dist/chunk-I3E4KSA2.js.map +1 -0
  10. package/dist/chunk-JR5ZBDR7.js +2012 -0
  11. package/dist/chunk-JR5ZBDR7.js.map +1 -0
  12. package/dist/chunk-XWFU2CSG.js +167 -0
  13. package/dist/chunk-XWFU2CSG.js.map +1 -0
  14. package/dist/chunk-ZU54BMDC.js +2128 -0
  15. package/dist/chunk-ZU54BMDC.js.map +1 -0
  16. package/dist/generation/index.cjs +525 -0
  17. package/dist/generation/index.cjs.map +1 -0
  18. package/dist/generation/index.d.cts +124 -0
  19. package/dist/generation/index.d.ts +124 -0
  20. package/dist/generation/index.js +19 -0
  21. package/dist/generation/index.js.map +1 -0
  22. package/dist/image-editor/index.cjs +988 -337
  23. package/dist/image-editor/index.cjs.map +1 -1
  24. package/dist/image-editor/index.d.cts +92 -2
  25. package/dist/image-editor/index.d.ts +92 -2
  26. package/dist/image-editor/index.js +17 -3
  27. package/dist/index.cjs +3628 -754
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +226 -5
  30. package/dist/index.d.ts +226 -5
  31. package/dist/index.js +868 -77
  32. package/dist/index.js.map +1 -1
  33. package/dist/persistence/index.cjs +191 -0
  34. package/dist/persistence/index.cjs.map +1 -0
  35. package/dist/persistence/index.d.cts +77 -0
  36. package/dist/persistence/index.d.ts +77 -0
  37. package/dist/persistence/index.js +9 -0
  38. package/dist/persistence/index.js.map +1 -0
  39. package/dist/spreadsheet/index.cjs +949 -111
  40. package/dist/spreadsheet/index.cjs.map +1 -1
  41. package/dist/spreadsheet/index.d.cts +121 -7
  42. package/dist/spreadsheet/index.d.ts +121 -7
  43. package/dist/spreadsheet/index.js +11 -1
  44. package/dist/tokens/index.cjs +395 -0
  45. package/dist/tokens/index.cjs.map +1 -0
  46. package/dist/tokens/index.d.cts +54 -0
  47. package/dist/tokens/index.d.ts +54 -0
  48. package/dist/tokens/index.js +375 -0
  49. package/dist/tokens/index.js.map +1 -0
  50. package/package.json +26 -2
  51. package/dist/chunk-LPFZMZ3L.js +0 -1461
  52. package/dist/chunk-LPFZMZ3L.js.map +0 -1
  53. package/dist/chunk-QVQYYHJ5.js +0 -1161
  54. package/dist/chunk-QVQYYHJ5.js.map +0 -1
@@ -0,0 +1,525 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/generation/index.ts
21
+ var generation_exports = {};
22
+ __export(generation_exports, {
23
+ AssetMentionChips: () => AssetMentionChips,
24
+ GenerationHistory: () => GenerationHistory,
25
+ GenerationSettings: () => GenerationSettings,
26
+ JobProgress: () => JobProgress,
27
+ useGenerationPlan: () => useGenerationPlan,
28
+ useGenerationRecords: () => useGenerationRecords,
29
+ useJobProgress: () => useJobProgress
30
+ });
31
+ module.exports = __toCommonJS(generation_exports);
32
+
33
+ // src/generation/useGenerationPlan.ts
34
+ var import_react = require("react");
35
+ var import_generation = require("@pixerate/editor/generation");
36
+ function useGenerationPlan(request, capabilities, options = {}) {
37
+ const key = JSON.stringify([request, capabilities, options]);
38
+ return (0, import_react.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
39
+ }
40
+ function useJobProgress(options) {
41
+ const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
42
+ const [tick, setTick] = (0, import_react.useState)(() => Date.now());
43
+ const ticking = !done && now === void 0;
44
+ (0, import_react.useEffect)(() => {
45
+ if (!ticking) return;
46
+ setTick(Date.now());
47
+ const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
48
+ return () => clearInterval(id);
49
+ }, [ticking, intervalMs]);
50
+ return (0, import_generation.estimateJobProgress)({ startedAt, expectedMs, done, now: now ?? tick });
51
+ }
52
+
53
+ // src/generation/GenerationSettings.tsx
54
+ var import_react2 = require("react");
55
+ var import_generation2 = require("@pixerate/editor/generation");
56
+ var import_jsx_runtime = require("react/jsx-runtime");
57
+ var inputClass = "w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring";
58
+ function Control({
59
+ control,
60
+ value,
61
+ id,
62
+ onValue
63
+ }) {
64
+ const shown = value ?? control.defaultValue;
65
+ if (control.kind === "checkbox") {
66
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
67
+ "input",
68
+ {
69
+ id,
70
+ type: "checkbox",
71
+ "data-field": control.key,
72
+ checked: Boolean(shown),
73
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.checked))
74
+ }
75
+ );
76
+ }
77
+ if (control.kind === "select") {
78
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
79
+ "select",
80
+ {
81
+ id,
82
+ "data-field": control.key,
83
+ className: inputClass,
84
+ value: shown === void 0 ? "" : String(shown),
85
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
86
+ children: [
87
+ shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "Default" }),
88
+ control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
89
+ ]
90
+ }
91
+ );
92
+ }
93
+ if (control.kind === "textarea") {
94
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
95
+ "textarea",
96
+ {
97
+ id,
98
+ "data-field": control.key,
99
+ className: inputClass,
100
+ rows: 2,
101
+ maxLength: control.maxLength,
102
+ value: typeof value === "string" ? value : "",
103
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
104
+ }
105
+ );
106
+ }
107
+ const numeric = typeof shown === "number" ? shown : void 0;
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
110
+ "input",
111
+ {
112
+ id,
113
+ type: control.kind === "range" ? "range" : "number",
114
+ "data-field": control.key,
115
+ className: control.kind === "range" ? "flex-1" : inputClass,
116
+ min: control.min,
117
+ max: control.max,
118
+ step: control.step ?? "any",
119
+ value: numeric ?? (control.kind === "range" ? control.min ?? 0 : ""),
120
+ onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
121
+ }
122
+ ),
123
+ control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
124
+ ] });
125
+ }
126
+ var GenerationSettings = ({
127
+ capabilities,
128
+ value,
129
+ onChange,
130
+ plan: planProp,
131
+ strategy,
132
+ showAdjustments = true,
133
+ onAddReference,
134
+ renderReference,
135
+ className = ""
136
+ }) => {
137
+ const baseId = (0, import_react2.useId)();
138
+ const controls = (0, import_react2.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
139
+ const computed = useGenerationPlan(value, capabilities, { strategy });
140
+ const plan = planProp ?? computed;
141
+ const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
142
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
143
+ controls.map((control) => {
144
+ const id = `${baseId}-${control.key}`;
145
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
148
+ Control,
149
+ {
150
+ control,
151
+ id,
152
+ value: (0, import_generation2.getRequestValue)(value, control.key),
153
+ onValue: (next) => onChange((0, import_generation2.setRequestValue)(value, control.key, next))
154
+ }
155
+ )
156
+ ] }, control.key);
157
+ }),
158
+ slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
159
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
160
+ slot.label,
161
+ " ",
162
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
163
+ "(",
164
+ slot.references.length,
165
+ "/",
166
+ slot.max,
167
+ ")"
168
+ ] }),
169
+ slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-destructive", children: " *" })
170
+ ] }),
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
172
+ slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
173
+ renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
175
+ "button",
176
+ {
177
+ type: "button",
178
+ "aria-label": `Remove ${slot.label} ${ref.id}`,
179
+ className: "text-muted-foreground hover:text-foreground",
180
+ onClick: () => onChange((0, import_generation2.removeReference)(value, slot.role, ref.id)),
181
+ children: "\xD7"
182
+ }
183
+ )
184
+ ] }, ref.id)),
185
+ onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
186
+ "button",
187
+ {
188
+ type: "button",
189
+ className: "rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground",
190
+ onClick: () => onAddReference(slot.role),
191
+ children: "Add"
192
+ }
193
+ ) })
194
+ ] })
195
+ ] }, slot.role)),
196
+ showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.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_runtime.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
197
+ showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.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_runtime.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
198
+ ] });
199
+ };
200
+
201
+ // src/generation/JobProgress.tsx
202
+ var import_jsx_runtime2 = require("react/jsx-runtime");
203
+ var JobProgress = ({ title, className = "", ...options }) => {
204
+ const progress = useJobProgress(options);
205
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
206
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
207
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-foreground", children: title }),
208
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
209
+ ] }),
210
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
211
+ "div",
212
+ {
213
+ role: "progressbar",
214
+ "aria-label": title ?? "Generation progress",
215
+ "aria-valuemin": 0,
216
+ "aria-valuemax": 100,
217
+ "aria-valuenow": progress.percent,
218
+ "aria-valuetext": `${progress.percent}%, ${progress.label}`,
219
+ className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
220
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
221
+ "div",
222
+ {
223
+ className: "h-full rounded-full bg-primary transition-[width] duration-500",
224
+ style: { width: `${progress.percent}%`, background: "var(--primary, currentColor)" }
225
+ }
226
+ )
227
+ }
228
+ )
229
+ ] });
230
+ };
231
+
232
+ // src/generation/AssetMentionChips.tsx
233
+ var import_react3 = require("react");
234
+ var import_generation3 = require("@pixerate/editor/generation");
235
+ var import_jsx_runtime3 = require("react/jsx-runtime");
236
+ var AssetMentionChips = ({
237
+ content,
238
+ onChange,
239
+ assets,
240
+ capabilities,
241
+ roles,
242
+ renderAsset,
243
+ className = ""
244
+ }) => {
245
+ const [open, setOpen] = (0, import_react3.useState)(null);
246
+ const rootRef = (0, import_react3.useRef)(null);
247
+ const chips = (0, import_react3.useMemo)(
248
+ () => (0, import_generation3.describeAssetMentions)((0, import_generation3.findTextMentions)(content), assets, capabilities),
249
+ [content, assets, capabilities]
250
+ );
251
+ const options = roles ?? (capabilities ? (0, import_generation3.getAssetRoleOptions)(capabilities) : (0, import_generation3.defaultAssetRoleOptions)());
252
+ (0, import_react3.useEffect)(() => {
253
+ if (open === null) return;
254
+ const onPointer = (event) => {
255
+ if (!rootRef.current?.contains(event.target)) setOpen(null);
256
+ };
257
+ document.addEventListener("mousedown", onPointer);
258
+ return () => document.removeEventListener("mousedown", onPointer);
259
+ }, [open]);
260
+ const pick = (chip, role) => {
261
+ setOpen(null);
262
+ if (chip.start === void 0) return;
263
+ onChange((0, import_generation3.setMentionRoleInText)(content, chip.start, role));
264
+ };
265
+ if (chips.length === 0) return null;
266
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: rootRef, className: `flex flex-wrap gap-1.5 ${className}`, "data-asset-mention-chips": "", children: chips.map((chip) => {
267
+ const error = chip.issues.find((issue) => issue.severity === "error");
268
+ const warning = chip.issues.find((issue) => issue.severity === "warning");
269
+ const problem = error ?? warning;
270
+ const isOpen = open === chip.index;
271
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "relative inline-flex", "data-asset-chip": chip.asset.id, children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
273
+ "button",
274
+ {
275
+ type: "button",
276
+ "aria-haspopup": "listbox",
277
+ "aria-expanded": isOpen,
278
+ title: problem?.message,
279
+ "data-issue": problem?.code,
280
+ onClick: () => setOpen(isOpen ? null : chip.index),
281
+ onKeyDown: (e) => {
282
+ if (e.key === "Escape") setOpen(null);
283
+ },
284
+ 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`,
285
+ children: [
286
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: renderAsset ? renderAsset(chip) : `@${chip.asset.label ?? chip.handle}` }),
287
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
288
+ "span",
289
+ {
290
+ className: `rounded px-1 text-[10px] uppercase tracking-wide ${chip.role ? "bg-primary/15" : "opacity-60"}`,
291
+ "data-role-badge": chip.role ?? "",
292
+ children: chip.roleLabel ?? "No role"
293
+ }
294
+ )
295
+ ]
296
+ }
297
+ ),
298
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
299
+ "div",
300
+ {
301
+ role: "listbox",
302
+ "aria-label": `Role for ${chip.asset.label ?? chip.handle}`,
303
+ className: "absolute left-0 top-full z-50 mt-1 flex min-w-[12rem] flex-col rounded-md border border-border bg-background p-1 text-xs shadow-lg",
304
+ "data-role-picker": "",
305
+ onKeyDown: (e) => {
306
+ if (e.key === "Escape") setOpen(null);
307
+ },
308
+ children: [
309
+ options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
310
+ "button",
311
+ {
312
+ type: "button",
313
+ role: "option",
314
+ "aria-selected": chip.role === option.role,
315
+ "data-role-option": option.role,
316
+ title: option.description,
317
+ onClick: () => pick(chip, option.role),
318
+ className: "flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted",
319
+ children: [
320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: option.label }),
321
+ option.accepts?.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[10px] opacity-60", children: option.accepts.join(", ") }) : null
322
+ ]
323
+ },
324
+ option.role
325
+ )),
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
327
+ "button",
328
+ {
329
+ type: "button",
330
+ role: "option",
331
+ "aria-selected": !chip.role,
332
+ "data-role-option": "",
333
+ onClick: () => pick(chip, null),
334
+ className: "rounded px-2 py-1 text-left opacity-70 hover:bg-muted",
335
+ children: "No role"
336
+ }
337
+ ),
338
+ chip.issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "mt-1 border-t border-border px-2 pt-1 text-[10px]", "data-chip-issues": "", children: chip.issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { className: issue.severity === "error" ? "text-red-500" : "text-amber-500", children: issue.message }, i)) })
339
+ ]
340
+ }
341
+ )
342
+ ] }, `${chip.start}-${chip.index}`);
343
+ }) });
344
+ };
345
+
346
+ // src/generation/GenerationHistory.tsx
347
+ var import_react4 = require("react");
348
+ var import_generation4 = require("@pixerate/editor/generation");
349
+ var import_jsx_runtime4 = require("react/jsx-runtime");
350
+ function useGenerationRecords(store, filter) {
351
+ const [records, setRecords] = (0, import_react4.useState)([]);
352
+ const [loading, setLoading] = (0, import_react4.useState)(!!store);
353
+ const [error, setError] = (0, import_react4.useState)(null);
354
+ const filterKey = (0, import_generation4.stableStringify)(filter ?? {});
355
+ const refresh = (0, import_react4.useCallback)(async () => {
356
+ if (!store) {
357
+ setRecords([]);
358
+ setLoading(false);
359
+ return;
360
+ }
361
+ setLoading(true);
362
+ try {
363
+ const next = await store.list(filter);
364
+ setRecords(next);
365
+ setError(null);
366
+ } catch (err) {
367
+ setError(err);
368
+ } finally {
369
+ setLoading(false);
370
+ }
371
+ }, [store, filterKey]);
372
+ (0, import_react4.useEffect)(() => {
373
+ void refresh();
374
+ if (!store) return;
375
+ return store.subscribe(() => void refresh());
376
+ }, [store, refresh]);
377
+ return { records, loading, error, refresh };
378
+ }
379
+ var severityClass = {
380
+ info: "text-sky-600 dark:text-sky-300",
381
+ warning: "text-amber-600 dark:text-amber-300",
382
+ error: "text-red-600 dark:text-red-400"
383
+ };
384
+ var GenerationHistory = ({
385
+ records,
386
+ templates,
387
+ capabilities,
388
+ assets,
389
+ mode: modeProp,
390
+ onModeChange,
391
+ onRecreate,
392
+ onVariation,
393
+ onRemove,
394
+ renderPreview,
395
+ emptyText = "No generations yet.",
396
+ className = ""
397
+ }) => {
398
+ const [innerMode, setInnerMode] = (0, import_react4.useState)("exact");
399
+ const mode = modeProp ?? innerMode;
400
+ const setMode = (next) => {
401
+ if (modeProp === void 0) setInnerMode(next);
402
+ onModeChange?.(next);
403
+ };
404
+ const options = (0, import_react4.useMemo)(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);
405
+ const results = (0, import_react4.useMemo)(() => records.map((record) => (0, import_generation4.recreateRequest)(record, options)), [records, options]);
406
+ const models = (0, import_react4.useMemo)(
407
+ () => capabilities ? Array.isArray(capabilities) ? capabilities : [capabilities] : [],
408
+ [capabilities]
409
+ );
410
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `flex flex-col gap-2 text-sm ${className}`, "data-generation-history": "", children: [
411
+ /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsxs)("label", { className: "inline-flex items-center gap-1", children: [
412
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
413
+ "input",
414
+ {
415
+ type: "radio",
416
+ name: "generation-history-mode",
417
+ value,
418
+ checked: mode === value,
419
+ onChange: () => setMode(value),
420
+ "data-mode": value
421
+ }
422
+ ),
423
+ value === "exact" ? "Exact (recorded versions)" : "Latest templates & settings"
424
+ ] }, value)) }),
425
+ records.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyText }),
426
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "flex flex-col gap-2", children: records.map((record, i) => {
427
+ const result = results[i];
428
+ const model = models.find((m) => m.id === record.provenance.modelId);
429
+ const blocked = !result.ok;
430
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
431
+ "li",
432
+ {
433
+ className: "rounded-md border border-border p-2",
434
+ "data-record": record.id,
435
+ "data-drift": result.drift.length,
436
+ children: [
437
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 text-xs", children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-medium", children: model?.name ?? record.provenance.modelId }),
439
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-muted-foreground", children: [
440
+ record.kind !== "generate" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { "data-kind": "", children: [
441
+ record.kind,
442
+ " \xB7 "
443
+ ] }),
444
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("time", { dateTime: record.createdAt, children: record.createdAt.replace("T", " ").slice(0, 16) }),
445
+ record.seed !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
446
+ " \xB7 seed ",
447
+ record.seed
448
+ ] })
449
+ ] })
450
+ ] }),
451
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mt-1 line-clamp-3 break-words text-xs", "data-record-prompt": "", children: record.provenance.resolvedPrompt }),
452
+ record.assets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-1 flex flex-wrap gap-1", children: record.assets.map((asset) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
453
+ "span",
454
+ {
455
+ className: "rounded-full bg-muted px-2 py-0.5 text-[10px]",
456
+ "data-asset-role": asset.role,
457
+ children: [
458
+ asset.id,
459
+ " \xB7 ",
460
+ (0, import_generation4.referenceRoleLabel)(asset.role, model)
461
+ ]
462
+ },
463
+ `${asset.role}:${asset.id}`
464
+ )) }),
465
+ renderPreview?.(record),
466
+ result.drift.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsxs)("li", { className: severityClass[item.severity], "data-drift-type": item.type, children: [
467
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { children: [
468
+ import_generation4.DRIFT_TYPE_LABELS[item.type],
469
+ ":"
470
+ ] }),
471
+ " ",
472
+ item.message
473
+ ] }, j)) }),
474
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-2 flex gap-2", children: [
475
+ onRecreate && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
476
+ "button",
477
+ {
478
+ type: "button",
479
+ disabled: blocked,
480
+ title: blocked ? "This generation cannot be recreated as recorded." : void 0,
481
+ onClick: () => onRecreate(result, record),
482
+ className: "rounded border border-border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-50",
483
+ "data-action": "recreate",
484
+ children: "Recreate"
485
+ }
486
+ ),
487
+ onVariation && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
488
+ "button",
489
+ {
490
+ type: "button",
491
+ onClick: () => onVariation((0, import_generation4.variationRequest)(record, {}, options), record),
492
+ className: "rounded border border-border px-2 py-0.5 text-xs hover:bg-muted",
493
+ "data-action": "variation",
494
+ children: "Variation"
495
+ }
496
+ ),
497
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
498
+ "button",
499
+ {
500
+ type: "button",
501
+ onClick: () => onRemove(record),
502
+ className: "ml-auto rounded px-2 py-0.5 text-xs text-muted-foreground hover:bg-muted",
503
+ "data-action": "remove",
504
+ children: "Remove"
505
+ }
506
+ )
507
+ ] })
508
+ ]
509
+ },
510
+ record.id
511
+ );
512
+ }) })
513
+ ] });
514
+ };
515
+ // Annotate the CommonJS export names for ESM import in node:
516
+ 0 && (module.exports = {
517
+ AssetMentionChips,
518
+ GenerationHistory,
519
+ GenerationSettings,
520
+ JobProgress,
521
+ useGenerationPlan,
522
+ useGenerationRecords,
523
+ useJobProgress
524
+ });
525
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/generation/index.ts","../../src/generation/useGenerationPlan.ts","../../src/generation/GenerationSettings.tsx","../../src/generation/JobProgress.tsx","../../src/generation/AssetMentionChips.tsx","../../src/generation/GenerationHistory.tsx"],"sourcesContent":["export * from './useGenerationPlan';\nexport * from './GenerationSettings';\nexport * from './JobProgress';\nexport * from './AssetMentionChips';\nexport * from './GenerationHistory';\n","import { useEffect, useMemo, useState } from 'react';\nimport {\n estimateJobProgress,\n planGenerationRequest,\n type GenerationPlan,\n type GenerationRequest,\n type JobProgressEstimate,\n type ModelCapabilities,\n type PlanOptions,\n} from '@pixerate/editor/generation';\n\n/**\n * Plans `request` against `capabilities` (see `planGenerationRequest`) and\n * returns the adjusted request, adjustments and errors. Recomputed only when\n * the request, capabilities or options change by value, so inline objects are fine.\n */\nexport function useGenerationPlan(\n request: GenerationRequest,\n capabilities: ModelCapabilities,\n options: PlanOptions = {},\n): GenerationPlan {\n const key = JSON.stringify([request, capabilities, options]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => planGenerationRequest(request, capabilities, options), [key]);\n}\n\nexport interface UseJobProgressOptions {\n startedAt: number | Date | string;\n expectedMs?: number;\n done?: boolean;\n /** Fixed current time (disables ticking; useful for SSR and tests). */\n now?: number | Date | string;\n /** Re-render interval while running in ms (default 1000). */\n intervalMs?: number;\n}\n\n/** Ticking `estimateJobProgress` for a running job; stops ticking when `done`. */\nexport function useJobProgress(options: UseJobProgressOptions): JobProgressEstimate {\n const { startedAt, expectedMs, done, now, intervalMs = 1000 } = options;\n const [tick, setTick] = useState(() => Date.now());\n const ticking = !done && now === undefined;\n useEffect(() => {\n if (!ticking) return;\n setTick(Date.now());\n const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));\n return () => clearInterval(id);\n }, [ticking, intervalMs]);\n return estimateJobProgress({ startedAt, expectedMs, done, now: now ?? tick });\n}\n","import React, { useId, useMemo } from 'react';\nimport {\n getGenerationControls,\n getReferenceSlots,\n getRequestValue,\n parseControlValue,\n removeReference,\n setRequestValue,\n type GenerationControl,\n type GenerationPlan,\n type GenerationReference,\n type GenerationRequest,\n type ModelCapabilities,\n type PlanStrategy,\n type ReferenceRole,\n} from '@pixerate/editor/generation';\nimport { useGenerationPlan } from './useGenerationPlan';\n\nexport interface GenerationSettingsProps {\n capabilities: ModelCapabilities;\n /** The request being edited (controlled). */\n value: GenerationRequest;\n onChange: (next: GenerationRequest) => void;\n /** A plan computed elsewhere; otherwise one is computed with `strategy`. */\n plan?: GenerationPlan;\n /** Strategy for the built-in plan (default `nearest`). */\n strategy?: PlanStrategy;\n /** List plan adjustments and errors under the controls (default `true`). */\n showAdjustments?: boolean;\n /** Shows an \"Add\" button per reference role; you pick the asset and call `onChange`. */\n onAddReference?: (role: ReferenceRole) => void;\n /** Custom rendering of a reference chip (default: its id). */\n renderReference?: (reference: GenerationReference) => React.ReactNode;\n className?: string;\n}\n\nconst inputClass =\n 'w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring';\n\nfunction Control({\n control,\n value,\n id,\n onValue,\n}: {\n control: GenerationControl;\n value: unknown;\n id: string;\n onValue: (value: unknown) => void;\n}) {\n const shown = value ?? control.defaultValue;\n if (control.kind === 'checkbox') {\n return (\n <input\n id={id}\n type=\"checkbox\"\n data-field={control.key}\n checked={Boolean(shown)}\n onChange={(e) => onValue(parseControlValue(control, e.target.checked))}\n />\n );\n }\n if (control.kind === 'select') {\n return (\n <select\n id={id}\n data-field={control.key}\n className={inputClass}\n value={shown === undefined ? '' : String(shown)}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n >\n {shown === undefined && <option value=\"\">Default</option>}\n {control.options!.map((option) => (\n <option key={String(option.value)} value={String(option.value)}>\n {option.label}\n </option>\n ))}\n </select>\n );\n }\n if (control.kind === 'textarea') {\n return (\n <textarea\n id={id}\n data-field={control.key}\n className={inputClass}\n rows={2}\n maxLength={control.maxLength}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n />\n );\n }\n const numeric = typeof shown === 'number' ? shown : undefined;\n return (\n <div className=\"flex items-center gap-2\">\n <input\n id={id}\n type={control.kind === 'range' ? 'range' : 'number'}\n data-field={control.key}\n className={control.kind === 'range' ? 'flex-1' : inputClass}\n min={control.min}\n max={control.max}\n step={control.step ?? 'any'}\n value={numeric ?? (control.kind === 'range' ? (control.min ?? 0) : '')}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n />\n {control.kind === 'range' && (\n <span className=\"w-10 text-right tabular-nums text-muted-foreground\" data-field-value=\"\">\n {numeric ?? '–'}\n </span>\n )}\n </div>\n );\n}\n\n/**\n * Headless-styled settings form generated from a model's capabilities:\n * selects for choices, sliders/number inputs for ranges, text areas for\n * negative/system prompts, checkboxes for boolean params, reference slots by\n * role, and the plan's adjustments and errors. Controlled via `value` / `onChange`.\n */\nexport const GenerationSettings: React.FC<GenerationSettingsProps> = ({\n capabilities,\n value,\n onChange,\n plan: planProp,\n strategy,\n showAdjustments = true,\n onAddReference,\n renderReference,\n className = '',\n}) => {\n const baseId = useId();\n const controls = useMemo(() => getGenerationControls(capabilities), [capabilities]);\n const computed = useGenerationPlan(value, capabilities, { strategy });\n const plan = planProp ?? computed;\n const slots = getReferenceSlots(capabilities, value);\n\n return (\n <div className={`flex flex-col gap-3 text-sm ${className}`} data-generation-settings=\"\" data-model={capabilities.id}>\n {controls.map((control) => {\n const id = `${baseId}-${control.key}`;\n return (\n <div key={control.key} className=\"flex flex-col gap-1\" data-control={control.key}>\n <label htmlFor={id} className=\"text-xs font-medium text-muted-foreground\" title={control.description}>\n {control.label}\n </label>\n <Control\n control={control}\n id={id}\n value={getRequestValue(value, control.key)}\n onValue={(next) => onChange(setRequestValue(value, control.key, next))}\n />\n </div>\n );\n })}\n\n {slots.map((slot) => (\n <fieldset key={slot.role} className=\"flex flex-col gap-1\" data-reference-role={slot.role}>\n <legend className=\"text-xs font-medium text-muted-foreground\" title={slot.description}>\n {slot.label}{' '}\n <span className=\"tabular-nums\" data-reference-count=\"\">\n ({slot.references.length}/{slot.max})\n </span>\n {slot.min > 0 && <span className=\"text-destructive\"> *</span>}\n </legend>\n <ul className=\"flex flex-wrap gap-1\">\n {slot.references.map((ref) => (\n <li key={ref.id} className=\"flex items-center gap-1 rounded border border-border px-1.5 py-0.5\" data-reference-id={ref.id}>\n {renderReference ? renderReference(ref) : <span className=\"max-w-[10rem] truncate\">{ref.id}</span>}\n <button\n type=\"button\"\n aria-label={`Remove ${slot.label} ${ref.id}`}\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => onChange(removeReference(value, slot.role, ref.id))}\n >\n ×\n </button>\n </li>\n ))}\n {onAddReference && slot.canAdd && (\n <li>\n <button\n type=\"button\"\n className=\"rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground\"\n onClick={() => onAddReference(slot.role)}\n >\n Add\n </button>\n </li>\n )}\n </ul>\n </fieldset>\n ))}\n\n {showAdjustments && plan.adjustments.length > 0 && (\n <ul role=\"status\" className=\"flex flex-col gap-0.5 text-xs text-muted-foreground\" data-generation-adjustments=\"\">\n {plan.adjustments.map((adjustment, index) => (\n <li key={index} data-adjustment-field={adjustment.field} data-adjustment-kind={adjustment.kind}>\n {adjustment.reason}\n </li>\n ))}\n </ul>\n )}\n {showAdjustments && plan.errors.length > 0 && (\n <ul role=\"alert\" className=\"flex flex-col gap-0.5 text-xs text-destructive\" data-generation-errors=\"\">\n {plan.errors.map((error, index) => (\n <li key={index} data-error-field={error.field}>\n {error.message}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { useJobProgress, type UseJobProgressOptions } from './useGenerationPlan';\n\nexport interface JobProgressProps extends UseJobProgressOptions {\n /** Text shown before the time label, e.g. the model name. */\n title?: string;\n /** Extra classes for the root. */\n className?: string;\n}\n\n/**\n * Headless-styled progress bar for a generation job that reports no progress\n * of its own: time-based percent (held at 95% until `done`) with a\n * \"~2m left\" / \"Almost done…\" label. Exposes `role=\"progressbar\"`.\n */\nexport const JobProgress: React.FC<JobProgressProps> = ({ title, className = '', ...options }) => {\n const progress = useJobProgress(options);\n return (\n <div className={`flex flex-col gap-1 text-sm ${className}`} data-job-progress=\"\" data-done={options.done ? '' : undefined}>\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n {title && <span className=\"truncate text-foreground\">{title}</span>}\n <span data-job-progress-label=\"\" aria-live=\"polite\">\n {progress.label}\n </span>\n </div>\n <div\n role=\"progressbar\"\n aria-label={title ?? 'Generation progress'}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress.percent}\n aria-valuetext={`${progress.percent}%, ${progress.label}`}\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n >\n <div\n className=\"h-full rounded-full bg-primary transition-[width] duration-500\"\n style={{ width: `${progress.percent}%`, background: 'var(--primary, currentColor)' }}\n />\n </div>\n </div>\n );\n};\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n defaultAssetRoleOptions,\n describeAssetMentions,\n findTextMentions,\n getAssetRoleOptions,\n setMentionRoleInText,\n type AssetInfo,\n type AssetMentionChip,\n type AssetRoleOption,\n type ModelCapabilities,\n} from '@pixerate/editor/generation';\n\nexport interface AssetMentionChipsProps {\n /** Prompt text containing `@asset` / `@asset:role` mentions. */\n content: string;\n /** Called with the text after a role is picked (`@fox` → `@fox:style_ref`). */\n onChange: (next: string) => void;\n /** Mentionable assets; mentions that match none (by id or label) are not shown. */\n assets: readonly AssetInfo[];\n /** The selected model: its roles are offered and mentions are checked against it. */\n capabilities?: ModelCapabilities;\n /** Role options (default: the model's roles, else the built-in roles). */\n roles?: readonly AssetRoleOption[];\n /** Custom chip content (default: the asset label). */\n renderAsset?: (chip: AssetMentionChip) => React.ReactNode;\n className?: string;\n}\n\n/**\n * The asset mentions of a prompt as chips with role badges. Clicking a chip\n * opens a role picker popover; picking a role rewrites the mention's `:role`\n * suffix in the text. Chips with problems for the model (unsupported role,\n * wrong media type, too many for the role) are flagged.\n */\nexport const AssetMentionChips: React.FC<AssetMentionChipsProps> = ({\n content,\n onChange,\n assets,\n capabilities,\n roles,\n renderAsset,\n className = '',\n}) => {\n const [open, setOpen] = useState<number | null>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const chips = useMemo(\n () => describeAssetMentions(findTextMentions(content), assets, capabilities),\n [content, assets, capabilities],\n );\n const options = roles ?? (capabilities ? getAssetRoleOptions(capabilities) : defaultAssetRoleOptions());\n\n useEffect(() => {\n if (open === null) return;\n const onPointer = (event: MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) setOpen(null);\n };\n document.addEventListener('mousedown', onPointer);\n return () => document.removeEventListener('mousedown', onPointer);\n }, [open]);\n\n const pick = (chip: AssetMentionChip, role: string | null) => {\n setOpen(null);\n if (chip.start === undefined) return;\n onChange(setMentionRoleInText(content, chip.start, role));\n };\n\n if (chips.length === 0) return null;\n return (\n <div ref={rootRef} className={`flex flex-wrap gap-1.5 ${className}`} data-asset-mention-chips=\"\">\n {chips.map((chip) => {\n const error = chip.issues.find((issue) => issue.severity === 'error');\n const warning = chip.issues.find((issue) => issue.severity === 'warning');\n const problem = error ?? warning;\n const isOpen = open === chip.index;\n return (\n <span key={`${chip.start}-${chip.index}`} className=\"relative inline-flex\" data-asset-chip={chip.asset.id}>\n <button\n type=\"button\"\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n title={problem?.message}\n data-issue={problem?.code}\n onClick={() => setOpen(isOpen ? null : chip.index)}\n onKeyDown={(e) => {\n if (e.key === 'Escape') setOpen(null);\n }}\n className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs ${\n error ? 'border-red-500/60' : warning ? 'border-amber-500/60' : 'border-border'\n } bg-muted/40 hover:bg-muted`}\n >\n <span>{renderAsset ? renderAsset(chip) : `@${chip.asset.label ?? chip.handle}`}</span>\n <span\n className={`rounded px-1 text-[10px] uppercase tracking-wide ${chip.role ? 'bg-primary/15' : 'opacity-60'}`}\n data-role-badge={chip.role ?? ''}\n >\n {chip.roleLabel ?? 'No role'}\n </span>\n </button>\n {isOpen && (\n <div\n role=\"listbox\"\n aria-label={`Role for ${chip.asset.label ?? chip.handle}`}\n className=\"absolute left-0 top-full z-50 mt-1 flex min-w-[12rem] flex-col rounded-md border border-border bg-background p-1 text-xs shadow-lg\"\n data-role-picker=\"\"\n onKeyDown={(e) => {\n if (e.key === 'Escape') setOpen(null);\n }}\n >\n {options.map((option) => (\n <button\n key={option.role}\n type=\"button\"\n role=\"option\"\n aria-selected={chip.role === option.role}\n data-role-option={option.role}\n title={option.description}\n onClick={() => pick(chip, option.role)}\n className=\"flex items-center justify-between gap-2 rounded px-2 py-1 text-left hover:bg-muted\"\n >\n <span>{option.label}</span>\n {option.accepts?.length ? (\n <span className=\"text-[10px] opacity-60\">{option.accepts.join(', ')}</span>\n ) : null}\n </button>\n ))}\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={!chip.role}\n data-role-option=\"\"\n onClick={() => pick(chip, null)}\n className=\"rounded px-2 py-1 text-left opacity-70 hover:bg-muted\"\n >\n No role\n </button>\n {chip.issues.length > 0 && (\n <ul className=\"mt-1 border-t border-border px-2 pt-1 text-[10px]\" data-chip-issues=\"\">\n {chip.issues.map((issue, i) => (\n <li key={i} className={issue.severity === 'error' ? 'text-red-500' : 'text-amber-500'}>\n {issue.message}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </span>\n );\n })}\n </div>\n );\n};\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n DRIFT_TYPE_LABELS,\n recreateRequest,\n referenceRoleLabel,\n stableStringify,\n variationRequest,\n type AssetLookup,\n type GenerationRecord,\n type GenerationRecordFilter,\n type GenerationRecordStore,\n type ModelCapabilities,\n type RecreateMode,\n type RecreateOptions,\n type RecreateResult,\n} from '@pixerate/editor/generation';\n\ntype Template = NonNullable<RecreateOptions['templates']>[number];\n\nexport interface UseGenerationRecordsResult {\n records: GenerationRecord[];\n loading: boolean;\n error: unknown;\n refresh: () => Promise<void>;\n}\n\n/**\n * Loads records from a `GenerationRecordStore` (newest first) and reloads\n * whenever the store changes. `filter` is compared by value.\n */\nexport function useGenerationRecords(\n store: GenerationRecordStore | null | undefined,\n filter?: GenerationRecordFilter,\n): UseGenerationRecordsResult {\n const [records, setRecords] = useState<GenerationRecord[]>([]);\n const [loading, setLoading] = useState(!!store);\n const [error, setError] = useState<unknown>(null);\n const filterKey = stableStringify(filter ?? {});\n\n const refresh = useCallback(async () => {\n if (!store) {\n setRecords([]);\n setLoading(false);\n return;\n }\n setLoading(true);\n try {\n const next = await store.list(filter);\n setRecords(next);\n setError(null);\n } catch (err) {\n setError(err);\n } finally {\n setLoading(false);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store, filterKey]);\n\n useEffect(() => {\n void refresh();\n if (!store) return;\n return store.subscribe(() => void refresh());\n }, [store, refresh]);\n\n return { records, loading, error, refresh };\n}\n\nexport interface GenerationHistoryProps {\n records: readonly GenerationRecord[];\n /** Current templates (drift detection, and resolution in `latest` mode). */\n templates?: readonly Template[];\n /** Current models (capability drift and re-planning). */\n capabilities?: ModelCapabilities | readonly ModelCapabilities[];\n /** Current assets (missing / changed asset drift). */\n assets?: AssetLookup;\n /** Recreate mode (controlled); otherwise a toggle starting at `exact`. */\n mode?: RecreateMode;\n onModeChange?: (mode: RecreateMode) => void;\n /** \"Recreate\": receives the rebuilt request and drift report. */\n onRecreate?: (result: RecreateResult, record: GenerationRecord) => void;\n /** \"Variation\": same request with a new seed. */\n onVariation?: (result: RecreateResult, record: GenerationRecord) => void;\n onRemove?: (record: GenerationRecord) => void;\n /** Extra content per record (e.g. output thumbnails). */\n renderPreview?: (record: GenerationRecord) => React.ReactNode;\n emptyText?: string;\n className?: string;\n}\n\nconst severityClass = {\n info: 'text-sky-600 dark:text-sky-300',\n warning: 'text-amber-600 dark:text-amber-300',\n error: 'text-red-600 dark:text-red-400',\n} as const;\n\n/**\n * Generation history: one entry per record with its model, prompt, asset\n * role badges and the drift since it was made (templates edited, model\n * capabilities changed, settings no longer supported, assets missing), plus\n * Recreate and Variation buttons. Recreate is disabled when drift blocks it.\n */\nexport const GenerationHistory: React.FC<GenerationHistoryProps> = ({\n records,\n templates,\n capabilities,\n assets,\n mode: modeProp,\n onModeChange,\n onRecreate,\n onVariation,\n onRemove,\n renderPreview,\n emptyText = 'No generations yet.',\n className = '',\n}) => {\n const [innerMode, setInnerMode] = useState<RecreateMode>('exact');\n const mode = modeProp ?? innerMode;\n const setMode = (next: RecreateMode) => {\n if (modeProp === undefined) setInnerMode(next);\n onModeChange?.(next);\n };\n const options = useMemo(() => ({ templates, capabilities, assets, mode }), [templates, capabilities, assets, mode]);\n const results = useMemo(() => records.map((record) => recreateRequest(record, options)), [records, options]);\n const models = useMemo(\n () => (capabilities ? (Array.isArray(capabilities) ? capabilities : [capabilities as ModelCapabilities]) : []),\n [capabilities],\n );\n\n return (\n <div className={`flex flex-col gap-2 text-sm ${className}`} data-generation-history=\"\">\n <div className=\"flex items-center gap-2 text-xs\" role=\"radiogroup\" aria-label=\"Recreate mode\">\n {(['exact', 'latest'] as const).map((value) => (\n <label key={value} className=\"inline-flex items-center gap-1\">\n <input\n type=\"radio\"\n name=\"generation-history-mode\"\n value={value}\n checked={mode === value}\n onChange={() => setMode(value)}\n data-mode={value}\n />\n {value === 'exact' ? 'Exact (recorded versions)' : 'Latest templates & settings'}\n </label>\n ))}\n </div>\n {records.length === 0 && <p className=\"text-xs text-muted-foreground\">{emptyText}</p>}\n <ul className=\"flex flex-col gap-2\">\n {records.map((record, i) => {\n const result = results[i];\n const model = models.find((m) => m.id === record.provenance.modelId);\n const blocked = !result.ok;\n return (\n <li\n key={record.id}\n className=\"rounded-md border border-border p-2\"\n data-record={record.id}\n data-drift={result.drift.length}\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-xs\">\n <span className=\"font-medium\">{model?.name ?? record.provenance.modelId}</span>\n <span className=\"text-muted-foreground\">\n {record.kind !== 'generate' && <span data-kind=\"\">{record.kind} · </span>}\n <time dateTime={record.createdAt}>{record.createdAt.replace('T', ' ').slice(0, 16)}</time>\n {record.seed !== undefined && <> · seed {record.seed}</>}\n </span>\n </div>\n <p className=\"mt-1 line-clamp-3 break-words text-xs\" data-record-prompt=\"\">\n {record.provenance.resolvedPrompt}\n </p>\n {record.assets.length > 0 && (\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {record.assets.map((asset) => (\n <span\n key={`${asset.role}:${asset.id}`}\n className=\"rounded-full bg-muted px-2 py-0.5 text-[10px]\"\n data-asset-role={asset.role}\n >\n {asset.id} · {referenceRoleLabel(asset.role, model)}\n </span>\n ))}\n </div>\n )}\n {renderPreview?.(record)}\n {result.drift.length > 0 && (\n <ul className=\"mt-1 flex flex-col gap-0.5 text-[11px]\" data-drift-report=\"\">\n {result.drift.map((item, j) => (\n <li key={j} className={severityClass[item.severity]} data-drift-type={item.type}>\n <strong>{DRIFT_TYPE_LABELS[item.type]}:</strong> {item.message}\n </li>\n ))}\n </ul>\n )}\n <div className=\"mt-2 flex gap-2\">\n {onRecreate && (\n <button\n type=\"button\"\n disabled={blocked}\n title={blocked ? 'This generation cannot be recreated as recorded.' : undefined}\n onClick={() => onRecreate(result, record)}\n className=\"rounded border border-border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-50\"\n data-action=\"recreate\"\n >\n Recreate\n </button>\n )}\n {onVariation && (\n <button\n type=\"button\"\n onClick={() => onVariation(variationRequest(record, {}, options), record)}\n className=\"rounded border border-border px-2 py-0.5 text-xs hover:bg-muted\"\n data-action=\"variation\"\n >\n Variation\n </button>\n )}\n {onRemove && (\n <button\n type=\"button\"\n onClick={() => onRemove(record)}\n className=\"ml-auto rounded px-2 py-0.5 text-xs text-muted-foreground hover:bg-muted\"\n data-action=\"remove\"\n >\n Remove\n </button>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n );\n};\n"],"mappings":"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","names":["import_react","import_generation","import_jsx_runtime","import_react","import_generation","import_jsx_runtime","import_react","import_generation","import_jsx_runtime"]}