@uploadcare/ai-enhancer 0.1.1

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 (78) hide show
  1. package/README.md +314 -0
  2. package/dist/UcAiEnhancer-D0mic9eT.cjs +444 -0
  3. package/dist/UcAiEnhancer-D1z2-v9q.js +3299 -0
  4. package/dist/ai-enhancer.cjs +1 -0
  5. package/dist/ai-enhancer.d.ts +532 -0
  6. package/dist/ai-enhancer.js +5 -0
  7. package/dist/ar-0rfB4z3f.js +29 -0
  8. package/dist/ar-DYF6cE7-.cjs +1 -0
  9. package/dist/az-CyK2FKx4.js +29 -0
  10. package/dist/az-UnBZVrss.cjs +1 -0
  11. package/dist/ca-CAoPN2lq.js +29 -0
  12. package/dist/ca-CuwmB1Gw.cjs +1 -0
  13. package/dist/cs-AwdVESvI.cjs +1 -0
  14. package/dist/cs-gutH5sZI.js +29 -0
  15. package/dist/da-BC58D6q4.cjs +1 -0
  16. package/dist/da-CjNgqmRE.js +29 -0
  17. package/dist/de-BC0mixOW.js +29 -0
  18. package/dist/de-DEF79Sit.cjs +1 -0
  19. package/dist/el-DFmdf7I1.cjs +1 -0
  20. package/dist/el-lfrMPw8j.js +29 -0
  21. package/dist/es-BkhHze52.cjs +1 -0
  22. package/dist/es-D0qq2qhV.js +29 -0
  23. package/dist/et-BhG8YNek.cjs +1 -0
  24. package/dist/et-Drgz7t_M.js +29 -0
  25. package/dist/fi-Cyypxkac.cjs +1 -0
  26. package/dist/fi-DA-ikQJH.js +29 -0
  27. package/dist/fr-CFVF2OgM.js +29 -0
  28. package/dist/fr-nhxYdowR.cjs +1 -0
  29. package/dist/he-0YWGAesl.cjs +1 -0
  30. package/dist/he-BZFhB0Wn.js +29 -0
  31. package/dist/hy-CY51XCFd.cjs +1 -0
  32. package/dist/hy-DvnjH66b.js +29 -0
  33. package/dist/is-DLmDXgjm.js +29 -0
  34. package/dist/is-Nssowr9F.cjs +1 -0
  35. package/dist/it-Ch7oZNp5.js +29 -0
  36. package/dist/it-DK-Xszlz.cjs +1 -0
  37. package/dist/ja-BZtfRu9w.cjs +1 -0
  38. package/dist/ja-B_rMbHKq.js +29 -0
  39. package/dist/ka-DSCPqvM4.cjs +1 -0
  40. package/dist/ka-cFaf_BUT.js +29 -0
  41. package/dist/kk-DGN5Pk5W.cjs +1 -0
  42. package/dist/kk-K2vhij8e.js +29 -0
  43. package/dist/ko-BnVYElzl.cjs +1 -0
  44. package/dist/ko-DeRxambx.js +29 -0
  45. package/dist/lv-CizQndPI.js +29 -0
  46. package/dist/lv-DxBkV0GW.cjs +1 -0
  47. package/dist/nb-BxtTiZSk.js +29 -0
  48. package/dist/nb-ByZ1aeGs.cjs +1 -0
  49. package/dist/nl-C12-qyO6.js +29 -0
  50. package/dist/nl-DaahHFo1.cjs +1 -0
  51. package/dist/pl-BRDowgAP.cjs +1 -0
  52. package/dist/pl-DnVfWHgL.js +29 -0
  53. package/dist/plugin.cjs +2 -0
  54. package/dist/plugin.d.ts +62 -0
  55. package/dist/plugin.js +200 -0
  56. package/dist/pt-DTs3scou.cjs +1 -0
  57. package/dist/pt-JpSURXrS.js +29 -0
  58. package/dist/ro-CtdLT2xS.cjs +1 -0
  59. package/dist/ro-qmi5XBhp.js +29 -0
  60. package/dist/ru-COjncrMy.cjs +1 -0
  61. package/dist/ru-C_rsFTyL.js +29 -0
  62. package/dist/sk-10Fuyb_E.js +29 -0
  63. package/dist/sk-DZF9evla.cjs +1 -0
  64. package/dist/sr-CTcREzcN.js +29 -0
  65. package/dist/sr-TVYoxU-s.cjs +1 -0
  66. package/dist/sv-BfxAcWfi.js +29 -0
  67. package/dist/sv-UPU_fRLB.cjs +1 -0
  68. package/dist/tr-B4vyEPOt.cjs +1 -0
  69. package/dist/tr-CLDSkp-W.js +29 -0
  70. package/dist/uk-BT0jZlPK.js +29 -0
  71. package/dist/uk-EP2kCiy9.cjs +1 -0
  72. package/dist/vi-BpWn9XQo.js +29 -0
  73. package/dist/vi-DI3QVinB.cjs +1 -0
  74. package/dist/zh-BxANO4fS.cjs +1 -0
  75. package/dist/zh-C0AOtYB8.js +29 -0
  76. package/dist/zh-TW-BNfdfwdz.js +29 -0
  77. package/dist/zh-TW-BxiS-SSf.cjs +1 -0
  78. package/package.json +81 -0
@@ -0,0 +1,3299 @@
1
+ var gt = Object.defineProperty;
2
+ var Fe = (t) => {
3
+ throw TypeError(t);
4
+ };
5
+ var vt = (t, e, i) => e in t ? gt(t, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[e] = i;
6
+ var b = (t, e, i) => vt(t, typeof e != "symbol" ? e + "" : e, i), ae = (t, e, i) => e.has(t) || Fe("Cannot " + i);
7
+ var E = (t, e, i) => (ae(t, e, "read from private field"), i ? i.call(t) : e.get(t)), ne = (t, e, i) => e.has(t) ? Fe("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, i), Me = (t, e, i, r) => (ae(t, e, "write to private field"), r ? r.call(t, i) : e.set(t, i), i), X = (t, e, i) => (ae(t, e, "access private method"), i);
8
+ import { unsafeCSS as B, LitElement as j, html as f, nothing as v } from "lit";
9
+ import { property as c, state as C, query as F, customElement as G } from "lit/decorators.js";
10
+ import { classMap as S } from "lit/directives/class-map.js";
11
+ import { unsafeSVG as te } from "lit/directives/unsafe-svg.js";
12
+ import { nothing as tt } from "lit/html.js";
13
+ import { directive as it, PartType as rt } from "lit/directive.js";
14
+ import { AsyncDirective as st } from "lit/async-directive.js";
15
+ import { repeat as bt } from "lit/directives/repeat.js";
16
+ const W = "original";
17
+ function O(t) {
18
+ return t != null && t !== W;
19
+ }
20
+ function pe(t, e) {
21
+ return t === W || e === W ? t === e : $t(t, e);
22
+ }
23
+ const yt = [
24
+ [2, 3],
25
+ [3, 2],
26
+ [1, 1],
27
+ [9, 16],
28
+ [16, 9]
29
+ ], wt = [3, 2], xt = {
30
+ "1:1": "ai-enhancer-aspect-square",
31
+ "2:3": "ai-enhancer-aspect-tall",
32
+ "3:2": "ai-enhancer-aspect-wide",
33
+ "4:5": "ai-enhancer-aspect-portrait",
34
+ "5:4": "ai-enhancer-aspect-landscape",
35
+ "9:16": "ai-enhancer-aspect-vertical",
36
+ "16:9": "ai-enhancer-aspect-widescreen"
37
+ }, kt = 0.1, Et = 10;
38
+ function ye(t) {
39
+ const [e, i] = t;
40
+ if (!Number.isFinite(e) || !Number.isFinite(i) || e <= 0 || i <= 0) return !1;
41
+ const r = e / i;
42
+ return r >= kt && r <= Et;
43
+ }
44
+ function Z(t) {
45
+ return `${t[0]}:${t[1]}`;
46
+ }
47
+ function Rt(t) {
48
+ return xt[Z(t)] ?? null;
49
+ }
50
+ function St(t) {
51
+ return { value: t, labelKey: Rt(t) };
52
+ }
53
+ function Ct(t) {
54
+ const e = [];
55
+ for (const i of t.split(/[\s,]+/)) {
56
+ const r = i.trim();
57
+ if (!r) continue;
58
+ const s = r.indexOf(":");
59
+ if (s === -1) continue;
60
+ const o = Number(r.slice(0, s)), a = Number(r.slice(s + 1)), n = [o, a];
61
+ ye(n) && e.push(n);
62
+ }
63
+ return e;
64
+ }
65
+ function $t(t, e) {
66
+ return t[0] === e[0] && t[1] === e[1];
67
+ }
68
+ function At(t) {
69
+ const [e, i] = t, r = 12, s = e >= i ? r : r * (e / i), o = i >= e ? r : r * (i / e), a = (16 - s) / 2, n = (16 - o) / 2;
70
+ return `<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect x="${a.toFixed(2)}" y="${n.toFixed(2)}" width="${s.toFixed(2)}" height="${o.toFixed(2)}" rx="1.5" stroke="currentColor" stroke-width="1.4"/></svg>`;
71
+ }
72
+ const fe = {
73
+ generate: {
74
+ id: "generate",
75
+ placeholderKey: "ai-enhancer-generate-placeholder",
76
+ // Complete, descriptive starting prompts. Flux responds best to rich
77
+ // natural-language descriptions, and clicking a chip fills the prompt so the
78
+ // user can run it as-is or tweak it.
79
+ presets: [
80
+ {
81
+ label: "Portrait",
82
+ prompt: "A photorealistic close-up portrait of a woman with freckles and windswept hair, soft natural window light, shallow depth of field, shot on an 85mm lens, ultra-detailed skin texture"
83
+ },
84
+ {
85
+ label: "Cinematic",
86
+ prompt: "Cinematic film still of a lone traveler on a neon-lit Tokyo street at night, rain-slicked pavement, glowing reflections, moody atmosphere, anamorphic, shot on 35mm"
87
+ },
88
+ {
89
+ label: "Product",
90
+ prompt: "Product photography of a frosted glass perfume bottle on a polished marble surface, soft studio lighting, gentle reflections, minimalist composition, high detail"
91
+ },
92
+ {
93
+ label: "Landscape",
94
+ prompt: "A serene mountain landscape at golden hour, low mist drifting through the valley, dramatic clouds, mirror-still lake reflections, photorealistic, ultra-detailed"
95
+ },
96
+ {
97
+ label: "Illustration",
98
+ prompt: "A flat vector illustration of a cozy bookshop café, warm color palette, clean bold shapes, soft shadows, modern editorial style"
99
+ },
100
+ {
101
+ label: "3D character",
102
+ prompt: "A cute 3D-rendered robot character, Pixar style, big expressive eyes, soft studio lighting, pastel color palette, smooth glossy materials, octane render"
103
+ }
104
+ ]
105
+ },
106
+ edit: {
107
+ id: "edit",
108
+ placeholderKey: "ai-enhancer-edit-placeholder",
109
+ // Instruction-style edits Flux Kontext handles well — restyling, relighting,
110
+ // and background/subject changes that preserve the source image.
111
+ presets: [
112
+ {
113
+ label: "Enhance",
114
+ prompt: "Enhance the photo: improve the lighting, sharpen details, and make the colors richer while keeping it natural"
115
+ },
116
+ { label: "Golden hour", prompt: "Relight the scene with warm golden-hour sunlight and long, soft shadows" },
117
+ {
118
+ label: "White studio",
119
+ prompt: "Place the subject on a clean seamless white studio backdrop with soft, even lighting"
120
+ },
121
+ { label: "Remove people", prompt: "Remove all other people from the scene, keeping the main subject intact" },
122
+ {
123
+ label: "Watercolor",
124
+ prompt: "Restyle the image as a soft watercolor painting with delicate, visible brush strokes"
125
+ },
126
+ {
127
+ label: "Black & white",
128
+ prompt: "Convert to dramatic high-contrast black and white film photography with subtle grain"
129
+ }
130
+ ]
131
+ }
132
+ };
133
+ class we extends Error {
134
+ constructor(e, i, r) {
135
+ super(i), this.name = "AiProviderError", this.errorCode = e, this.errorSource = r;
136
+ }
137
+ }
138
+ function Ut(t) {
139
+ const e = t == null ? void 0 : t.error;
140
+ return !!e && typeof e == "object" && typeof e.error_code == "string";
141
+ }
142
+ async function J(t, e) {
143
+ }
144
+ async function Ie(t, e) {
145
+ const i = await t.text().catch(() => "");
146
+ let r = null;
147
+ if (i)
148
+ try {
149
+ r = JSON.parse(i);
150
+ } catch {
151
+ }
152
+ if (Ut(r)) {
153
+ const { error_code: s, content: o } = r.error;
154
+ throw new we(s, o ?? s);
155
+ }
156
+ if (!t.ok)
157
+ throw new Error(
158
+ `Uploadcare ${e} failed (${t.status} ${t.statusText})${i ? `: ${i}` : ""}`
159
+ );
160
+ return r;
161
+ }
162
+ class Tt {
163
+ constructor(e) {
164
+ if (!e.publicKey)
165
+ throw new Error("UploadcareApiClient: publicKey is required");
166
+ this.publicKey = e.publicKey, this.baseUrl = e.baseUrl ?? "https://upload.uploadcare.com", this.doFetch = e.fetch ?? globalThis.fetch.bind(globalThis);
167
+ }
168
+ /** Start a text→image generation job. Resolves to the job handle. */
169
+ async generate(e) {
170
+ const i = {
171
+ pub_key: this.publicKey,
172
+ prompt: e.prompt,
173
+ aspect_ratio: [e.aspectRatio[0], e.aspectRatio[1]],
174
+ filename: e.filename
175
+ };
176
+ return e.store !== void 0 && (i.store = e.store), e.metadata && (i.metadata = e.metadata), await J(), this.startJob(new URL("/derivative/image/generate/", this.baseUrl), i, "generate", e.signal);
177
+ }
178
+ /** Start an image→image edit job. Resolves to the job handle. */
179
+ async edit(e) {
180
+ const i = {
181
+ pub_key: this.publicKey,
182
+ prompt: e.prompt,
183
+ source: e.source,
184
+ filename: e.filename
185
+ };
186
+ return e.aspectRatio && (i.aspect_ratio = [e.aspectRatio[0], e.aspectRatio[1]]), e.store !== void 0 && (i.store = e.store), e.metadata && (i.metadata = e.metadata), await J(), this.startJob(new URL("/derivative/image/edit/", this.baseUrl), i, "edit", e.signal);
187
+ }
188
+ /** Fetch the current state of a generation/edit job. */
189
+ async getJobStatus(e, i) {
190
+ const r = new URL("/derivative/status/", this.baseUrl);
191
+ r.searchParams.set("pub_key", this.publicKey), r.searchParams.set("job_id", e);
192
+ const s = await this.doFetch(r.href, { method: "GET", headers: { Accept: "application/json" }, signal: i }), o = await Ie(s, "generate status");
193
+ return await J(), o;
194
+ }
195
+ async startJob(e, i, r, s) {
196
+ const o = await this.doFetch(e.href, {
197
+ method: "POST",
198
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
199
+ body: JSON.stringify(i),
200
+ signal: s
201
+ }), a = await Ie(o, r);
202
+ return await J(), a;
203
+ }
204
+ }
205
+ const ot = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", Ft = new RegExp(`^${ot}$`, "i"), Mt = new RegExp(`^(${ot})~([0-9]+)$`, "i");
206
+ function xe(t) {
207
+ return t.replace(/\/+$/, "");
208
+ }
209
+ function me(t, e = "size") {
210
+ return typeof t == "number" ? String(t) : t.replace("%", "p");
211
+ }
212
+ function at(t, e, i = "dimensions") {
213
+ const r = t == null ? "" : me(t, `${i} width`), s = e == null ? "" : me(e, `${i} height`);
214
+ return `${r}x${s}`;
215
+ }
216
+ function Oe(t, e) {
217
+ return typeof t == "number" ? String(t) : me(t, e);
218
+ }
219
+ function It(t, e = "alignment") {
220
+ return typeof t == "string" ? t : `${Oe(t.x, `${e} x`)},${Oe(t.y, `${e} y`)}`;
221
+ }
222
+ const Ot = [
223
+ "video",
224
+ "document",
225
+ "gif2video"
226
+ ], Pt = /\/(https?:\/\/.+)$/i;
227
+ function zt(t) {
228
+ return t != null && Ot.includes(t);
229
+ }
230
+ function nt(t) {
231
+ var _;
232
+ let e;
233
+ try {
234
+ e = new URL(t);
235
+ } catch {
236
+ throw new TypeError(`Invalid URL: "${t}"`);
237
+ }
238
+ const i = `${e.protocol}//${e.host}`, r = e.pathname, s = (_ = r.match(Pt)) == null ? void 0 : _[1];
239
+ if (s !== void 0) {
240
+ const x = r.slice(0, r.length - s.length);
241
+ return {
242
+ kind: "proxy",
243
+ origin: i,
244
+ operations: le(Pe(x), "proxy prefix"),
245
+ sourceUrl: s + e.search + e.hash
246
+ };
247
+ }
248
+ const o = r.endsWith("/"), a = Pe(r), n = a.shift();
249
+ if (n === void 0)
250
+ throw new TypeError(`Not a CDN URL (empty path): "${t}"`);
251
+ const l = { origin: i, search: e.search, hash: e.hash }, h = n.match(Mt);
252
+ if ((h == null ? void 0 : h[1]) !== void 0) {
253
+ const x = {
254
+ uuid: h[1],
255
+ count: Number(h[2])
256
+ };
257
+ if (a[0] === "nth") {
258
+ const w = Number(a[1]);
259
+ if (!Number.isInteger(w))
260
+ throw new TypeError(`Invalid group element index in "${t}"`);
261
+ a.splice(0, 2);
262
+ const $ = ze(a, o);
263
+ return {
264
+ kind: "group-element",
265
+ ...l,
266
+ group: x,
267
+ nth: w,
268
+ operations: le(a, t),
269
+ filename: $
270
+ };
271
+ }
272
+ if (a.length > 0)
273
+ throw new TypeError(`Unexpected path after group id in "${t}"`);
274
+ return { kind: "group", ...l, group: x };
275
+ }
276
+ if (!Ft.test(n))
277
+ throw new TypeError(
278
+ `Not a CDN URL (no uuid, group or proxy source): "${t}"`
279
+ );
280
+ let p = null;
281
+ zt(a[0]) && (p = a[0], a.shift());
282
+ const u = ze(a, o);
283
+ return {
284
+ kind: "file",
285
+ ...l,
286
+ uuid: n,
287
+ conversion: p,
288
+ operations: le(a, t),
289
+ filename: u
290
+ };
291
+ }
292
+ function Pe(t) {
293
+ return t.split("/").filter((e) => e !== "");
294
+ }
295
+ function ze(t, e) {
296
+ return e || t.length === 0 ? null : t.pop() ?? null;
297
+ }
298
+ function le(t, e) {
299
+ const i = [];
300
+ let r = 0;
301
+ for (; r < t.length; ) {
302
+ if (t[r] !== "-")
303
+ throw new TypeError(
304
+ `Unexpected path segment "${t[r]}" in "${e}"`
305
+ );
306
+ r += 1;
307
+ const s = t[r];
308
+ if (s == null || s === "-")
309
+ throw new TypeError(`Missing operation name in "${e}"`);
310
+ r += 1;
311
+ const o = [];
312
+ for (; r < t.length; ) {
313
+ const a = t[r];
314
+ if (a === void 0 || a === "-") break;
315
+ o.push(a), r += 1;
316
+ }
317
+ i.push({ name: s, params: o });
318
+ }
319
+ return i;
320
+ }
321
+ function lt(t) {
322
+ return t.map((e) => `-/${[e.name, ...e.params].join("/")}/`).join("");
323
+ }
324
+ function ct(t) {
325
+ const e = xe(t.origin), i = lt(t.operations ?? []);
326
+ if ("sourceUrl" in t && t.sourceUrl != null)
327
+ return `${e}/${i}${t.sourceUrl}`;
328
+ const r = ("search" in t ? t.search : "") ?? "", s = ("hash" in t ? t.hash : "") ?? "";
329
+ if ("group" in t && t.group != null) {
330
+ let o = `${e}/${t.group.uuid}~${t.group.count}/`;
331
+ return t.nth != null && (o += `nth/${t.nth}/${i}${t.filename ?? ""}`), o + r + s;
332
+ }
333
+ if ("uuid" in t && t.uuid != null) {
334
+ const o = t.conversion != null ? `${t.conversion}/` : "";
335
+ return `${e}/${t.uuid}/${o}${i}${t.filename ?? ""}${r}${s}`;
336
+ }
337
+ throw new TypeError("serializeCdnUrl requires one of: uuid, group, sourceUrl");
338
+ }
339
+ function Lt(t) {
340
+ return typeof t == "string" ? t : "opName" in t ? t.opName : t.name;
341
+ }
342
+ function ce(t, e) {
343
+ const i = Lt(e);
344
+ return t.name === i || t.name.startsWith(`${i}~`);
345
+ }
346
+ function ht(t, e) {
347
+ return Object.assign(e, { opName: t });
348
+ }
349
+ const Dt = (t, e) => {
350
+ const i = new URL(e);
351
+ return i.hostname = `${t}.${i.hostname}`, i.toString().replace(/\/$/, "");
352
+ }, Nt = "0123456789abcdefghijklmnopqrstuvwxyz", Bt = (t) => {
353
+ if (t <= 0n)
354
+ return "0";
355
+ let e = "";
356
+ for (; t > 0n; ) {
357
+ const i = t % 36n;
358
+ e = Nt[Number(i)] + e, t = t / 36n;
359
+ }
360
+ return e;
361
+ }, jt = (t, e) => {
362
+ try {
363
+ const i = new URL(t), r = new URL(e);
364
+ return i.hostname.endsWith(r.hostname);
365
+ } catch {
366
+ return !1;
367
+ }
368
+ }, Gt = async (t) => {
369
+ const e = new TextEncoder().encode(t), i = await window.crypto.subtle.digest("SHA-256", e), r = Array.from(new Uint8Array(i)).map((s) => s.toString(16).padStart(2, "0")).join("");
370
+ return BigInt(`0x${r}`);
371
+ }, Ht = 10, Wt = async (t) => {
372
+ const e = await Gt(t);
373
+ return Bt(e).slice(0, Ht);
374
+ }, Vt = async (t, e) => {
375
+ const i = await Wt(t);
376
+ return Dt(i, e);
377
+ };
378
+ function Le(t) {
379
+ return Object.prototype.toString.call(t) === "[object Object]";
380
+ }
381
+ const qt = /\W|_/g;
382
+ function Kt(t) {
383
+ return t.split(qt).map((e, i) => e.charAt(0)[i > 0 ? "toUpperCase" : "toLowerCase"]() + e.slice(1)).join("");
384
+ }
385
+ function De(t, { ignoreKeys: e } = { ignoreKeys: [] }) {
386
+ return Array.isArray(t) ? t.map((i) => ke(i, { ignoreKeys: e })) : t;
387
+ }
388
+ function ke(t, { ignoreKeys: e } = { ignoreKeys: [] }) {
389
+ if (Array.isArray(t))
390
+ return De(t, { ignoreKeys: e });
391
+ if (!Le(t))
392
+ return t;
393
+ const i = {};
394
+ for (const r of Object.keys(t)) {
395
+ let s = t[r];
396
+ if (e.includes(r)) {
397
+ i[r] = s;
398
+ continue;
399
+ }
400
+ Le(s) ? s = ke(s, { ignoreKeys: e }) : Array.isArray(s) && (s = De(s, { ignoreKeys: e })), i[Kt(r)] = s;
401
+ }
402
+ return i;
403
+ }
404
+ const Yt = (t) => new Promise((e) => setTimeout(e, t));
405
+ function Xt({ libraryName: t, libraryVersion: e, userAgent: i, publicKey: r = "", integration: s = "" }) {
406
+ const o = "JavaScript";
407
+ if (typeof i == "string")
408
+ return i;
409
+ if (typeof i == "function")
410
+ return i({
411
+ publicKey: r,
412
+ libraryName: t,
413
+ libraryVersion: e,
414
+ languageName: o,
415
+ integration: s
416
+ });
417
+ const a = [t, e, r].filter(Boolean).join("/"), n = [o, s].filter(Boolean).join("; ");
418
+ return `${a} (${n})`;
419
+ }
420
+ const Jt = {
421
+ factor: 2,
422
+ time: 100
423
+ };
424
+ function Zt(t, e = Jt) {
425
+ let i = 0;
426
+ function r(s) {
427
+ const o = Math.round(e.time * e.factor ** i);
428
+ return s({
429
+ attempt: i,
430
+ retry: (n) => Yt(n ?? o).then(() => (i += 1, r(s)))
431
+ });
432
+ }
433
+ return r(t);
434
+ }
435
+ class Ee extends Error {
436
+ }
437
+ class ie extends Ee {
438
+ constructor(i) {
439
+ super();
440
+ b(this, "originalProgressEvent");
441
+ this.name = "NetworkError", this.message = "Network error", Object.setPrototypeOf(this, ie.prototype), this.originalProgressEvent = i;
442
+ }
443
+ }
444
+ const Qt = (t, e) => {
445
+ t && (t.aborted ? Promise.resolve().then(e) : t.addEventListener("abort", () => e(), { once: !0 }));
446
+ };
447
+ class Re extends Ee {
448
+ constructor(i = "Request canceled") {
449
+ super(i);
450
+ b(this, "isCancel", !0);
451
+ this.name = "CancelError", Object.setPrototypeOf(this, Re.prototype);
452
+ }
453
+ }
454
+ const Q = {
455
+ baseCDN: "https://ucarecdn.com",
456
+ baseURL: "https://upload.uploadcare.com",
457
+ retryThrottledRequestMaxTimes: 1,
458
+ retryNetworkErrorMaxTimes: 3
459
+ }, ei = ({ method: t, url: e, data: i, headers: r = {}, signal: s, onProgress: o }) => new Promise((a, n) => {
460
+ const l = new XMLHttpRequest(), h = (t == null ? void 0 : t.toUpperCase()) || "GET";
461
+ let p = !1;
462
+ l.open(h, e, !0), r && Object.entries(r).forEach((u) => {
463
+ const [_, x] = u;
464
+ typeof x < "u" && !Array.isArray(x) && l.setRequestHeader(_, x);
465
+ }), l.responseType = "text", Qt(s, () => {
466
+ p = !0, l.abort(), n(new Re());
467
+ }), l.onload = () => {
468
+ if (l.status != 200)
469
+ n(new Error(`Error ${l.status}: ${l.statusText}`));
470
+ else {
471
+ const u = {
472
+ method: h,
473
+ url: e,
474
+ data: i,
475
+ headers: r || void 0,
476
+ signal: s,
477
+ onProgress: o
478
+ }, _ = l.getAllResponseHeaders().trim().split(/[\r\n]+/), x = {};
479
+ _.forEach(function(R) {
480
+ const I = R.split(": "), H = I.shift(), Y = I.join(": ");
481
+ H && typeof H < "u" && (x[H] = Y);
482
+ });
483
+ const w = l.response, $ = l.status;
484
+ a({
485
+ request: u,
486
+ data: w,
487
+ headers: x,
488
+ status: $
489
+ });
490
+ }
491
+ }, l.onerror = (u) => {
492
+ p || n(new ie(u));
493
+ }, o && typeof o == "function" && (l.upload.onprogress = (u) => {
494
+ u.lengthComputable ? o({
495
+ isComputable: !0,
496
+ value: u.loaded / u.total
497
+ }) : o({ isComputable: !1 });
498
+ }), i ? l.send(i) : l.send();
499
+ });
500
+ class Se extends Ee {
501
+ constructor(i, r, s, o, a) {
502
+ super();
503
+ b(this, "code");
504
+ b(this, "request");
505
+ b(this, "response");
506
+ b(this, "headers");
507
+ this.name = "UploadError", this.message = i, this.code = r, this.request = s, this.response = o, this.headers = a, Object.setPrototypeOf(this, Se.prototype);
508
+ }
509
+ }
510
+ const ti = (t) => {
511
+ const e = new URLSearchParams();
512
+ for (const [i, r] of Object.entries(t))
513
+ r && typeof r == "object" && !Array.isArray(r) ? Object.entries(r).filter((s) => s[1] ?? !1).forEach((s) => e.set(`${i}[${s[0]}]`, String(s[1]))) : Array.isArray(r) ? r.forEach((s) => {
514
+ e.append(`${i}[]`, s);
515
+ }) : typeof r == "string" && r ? e.set(i, r) : typeof r == "number" && e.set(i, r.toString());
516
+ return e.toString();
517
+ }, _e = (t, e, i) => {
518
+ const r = new URL(t);
519
+ return r.pathname = (r.pathname + e).replace("//", "/"), i && (r.search = ti(i)), r.toString();
520
+ };
521
+ var ii = "6.18.4";
522
+ const ri = "UploadcareUploadClient", si = ii;
523
+ function oi(t) {
524
+ return Xt({
525
+ libraryName: ri,
526
+ libraryVersion: si,
527
+ ...t
528
+ });
529
+ }
530
+ const ai = "RequestThrottledError", Ne = 15e3, ni = 1e3;
531
+ function li(t) {
532
+ const { headers: e } = t || {};
533
+ if (!e || typeof e["retry-after"] != "string")
534
+ return Ne;
535
+ const i = parseInt(e["retry-after"], 10);
536
+ return Number.isFinite(i) ? i * 1e3 : Ne;
537
+ }
538
+ function ci(t, e) {
539
+ const { retryThrottledRequestMaxTimes: i, retryNetworkErrorMaxTimes: r } = e;
540
+ return Zt(({ attempt: s, retry: o }) => t().catch((a) => {
541
+ if ("response" in a && (a == null ? void 0 : a.code) === ai && s < i)
542
+ return o(li(a));
543
+ if (a instanceof ie && s < r)
544
+ return o((s + 1) * ni);
545
+ throw a;
546
+ }));
547
+ }
548
+ var Be;
549
+ (function(t) {
550
+ t.Token = "token", t.FileInfo = "file_info";
551
+ })(Be || (Be = {}));
552
+ var je;
553
+ (function(t) {
554
+ t.Unknown = "unknown", t.Waiting = "waiting", t.Progress = "progress", t.Error = "error", t.Success = "success";
555
+ })(je || (je = {}));
556
+ function hi(t, { publicKey: e, baseURL: i = Q.baseURL, signal: r, source: s, integration: o, userAgent: a, retryThrottledRequestMaxTimes: n = Q.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes: l = Q.retryNetworkErrorMaxTimes }) {
557
+ return ci(() => ei({
558
+ method: "GET",
559
+ headers: {
560
+ "X-UC-User-Agent": oi({ publicKey: e, integration: o, userAgent: a })
561
+ },
562
+ url: _e(i, "/info/", {
563
+ jsonerrors: 1,
564
+ pub_key: e,
565
+ file_id: t,
566
+ source: s
567
+ }),
568
+ signal: r
569
+ }).then(({ data: h, headers: p, request: u }) => {
570
+ const _ = ke(JSON.parse(h));
571
+ if ("error" in _)
572
+ throw new Se(_.error.content, _.error.errorCode, u, _, p);
573
+ return _;
574
+ }), { retryThrottledRequestMaxTimes: n, retryNetworkErrorMaxTimes: l });
575
+ }
576
+ function ui(t) {
577
+ return "defaultEffects" in t;
578
+ }
579
+ class Ge {
580
+ constructor(e, { baseCDN: i = Q.baseCDN, fileName: r } = {}) {
581
+ b(this, "uuid");
582
+ b(this, "name");
583
+ b(this, "size");
584
+ b(this, "isStored");
585
+ b(this, "isImage");
586
+ b(this, "mimeType");
587
+ b(this, "cdnUrl");
588
+ b(this, "s3Url");
589
+ b(this, "originalFilename");
590
+ b(this, "imageInfo");
591
+ b(this, "videoInfo");
592
+ b(this, "contentInfo");
593
+ b(this, "metadata");
594
+ b(this, "s3Bucket");
595
+ b(this, "defaultEffects", null);
596
+ const { uuid: s, s3Bucket: o } = e, a = _e(i, `${s}/`), n = o ? _e(`https://${o}.s3.amazonaws.com/`, `${s}/${e.filename}`) : null;
597
+ this.uuid = s, this.name = r || e.filename, this.size = e.size, this.isStored = e.isStored, this.isImage = e.isImage, this.mimeType = e.mimeType, this.cdnUrl = a, this.originalFilename = e.originalFilename, this.imageInfo = e.imageInfo, this.videoInfo = e.videoInfo, this.contentInfo = e.contentInfo, this.metadata = e.metadata || null, this.s3Bucket = o || null, this.s3Url = n, ui(e) && (this.defaultEffects = e.defaultEffects);
598
+ }
599
+ }
600
+ const di = /\W|_/g;
601
+ function pi(t) {
602
+ return typeof t == "object" && t !== null && !Array.isArray(t);
603
+ }
604
+ function fi(t) {
605
+ return t.split(di).map((e, i) => e && e.charAt(0)[i > 0 ? "toUpperCase" : "toLowerCase"]() + e.slice(1)).join("");
606
+ }
607
+ function ge(t) {
608
+ if (Array.isArray(t))
609
+ return t.map((i) => ge(i));
610
+ if (!pi(t))
611
+ return t;
612
+ const e = {};
613
+ for (const i of Object.keys(t))
614
+ e[fi(i)] = ge(t[i]);
615
+ return e;
616
+ }
617
+ const mi = [1, 1], He = "https://ucarecdn.com", _i = 1500, gi = 1e6;
618
+ function vi(t, e) {
619
+ return new Promise((i, r) => {
620
+ if (e != null && e.aborted) {
621
+ r(new DOMException("Aborted", "AbortError"));
622
+ return;
623
+ }
624
+ const s = setTimeout(() => {
625
+ e == null || e.removeEventListener("abort", o), i();
626
+ }, t), o = () => {
627
+ clearTimeout(s), r(new DOMException("Aborted", "AbortError"));
628
+ };
629
+ e == null || e.addEventListener("abort", o, { once: !0 });
630
+ });
631
+ }
632
+ function We() {
633
+ return typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now();
634
+ }
635
+ class bi {
636
+ constructor(e) {
637
+ if (this.id = "uploadcare-derivative", !e.publicKey)
638
+ throw new Error("UploadcareDerivativeApi: publicKey is required");
639
+ this.api = new Tt({
640
+ publicKey: e.publicKey,
641
+ baseUrl: e.baseUrl,
642
+ fetch: e.fetch
643
+ }), this.publicKey = e.publicKey, this.baseUrl = e.baseUrl, this.filename = e.filename ?? "generated.png", this.store = e.store, this.cname = e.cdnBaseUrl ?? He, this.cnamePrefixed = e.cdnCnamePrefixed ?? "https://ucarecd.net", this.pollIntervalMs = e.pollIntervalMs ?? _i, this.pollTimeoutMs = e.pollTimeoutMs ?? gi;
644
+ }
645
+ async generate(e) {
646
+ const i = await this.startJob(e);
647
+ return this.pollUntilDone(i, e);
648
+ }
649
+ /**
650
+ * Resolve a stored file's UUID to its CDN URL, using the same key-derived CDN
651
+ * base as generation results — so an input image displays identically to one
652
+ * the editor produced.
653
+ */
654
+ async resolveCdnUrl(e) {
655
+ return ct({ origin: await this.getCdnBase(), uuid: e });
656
+ }
657
+ /**
658
+ * Resolve a stored file's full info (image dimensions, original filename,
659
+ * mime, …) from its uuid, as an {@link UploadcareFile} — the same shape
660
+ * generation results carry. Lets the editor frame the canvas to the source's
661
+ * true aspect ratio before the image decodes, and name outputs after it.
662
+ */
663
+ async getFileInfo(e, i) {
664
+ const r = await hi(e, { publicKey: this.publicKey, baseURL: this.baseUrl, signal: i });
665
+ return new Ge(r, { baseCDN: await this.getCdnBase() });
666
+ }
667
+ async startJob(e) {
668
+ const i = e.aspectRatio && ye(e.aspectRatio) ? [e.aspectRatio[0], e.aspectRatio[1]] : void 0, r = e.filename ?? this.filename, s = e.mode === "edit" ? await this.startEditJob(e, i, r, e.metadata) : await this.api.generate({
669
+ prompt: e.prompt,
670
+ aspectRatio: i ?? mi,
671
+ filename: r,
672
+ store: this.store,
673
+ signal: e.signal,
674
+ metadata: e.metadata
675
+ });
676
+ if (!s.job_id)
677
+ throw new Error("Uploadcare derivative: response did not include a job_id");
678
+ return s.job_id;
679
+ }
680
+ startEditJob(e, i, r, s) {
681
+ if (!e.source)
682
+ throw new Error("Uploadcare edit: a source image uuid is required");
683
+ return this.api.edit({
684
+ prompt: e.prompt,
685
+ source: e.source,
686
+ aspectRatio: i,
687
+ filename: r,
688
+ store: this.store,
689
+ signal: e.signal,
690
+ metadata: s
691
+ });
692
+ }
693
+ async pollUntilDone(e, i) {
694
+ const r = this.pollTimeoutMs + We();
695
+ for (; ; ) {
696
+ const s = await this.api.getJobStatus(e, i.signal);
697
+ if (s.status === "success") {
698
+ if (!s.uuid)
699
+ throw new Error("Uploadcare derivative: response did not include a uuid");
700
+ const o = ge(s), a = new Ge(o, { baseCDN: await this.getCdnBase() });
701
+ return { url: a.cdnUrl, uuid: a.uuid, prompt: i.prompt, mode: i.mode, file: a };
702
+ }
703
+ if (s.status === "error") {
704
+ const o = s.error_code ?? "unknown", a = s.error ?? o;
705
+ throw new we(o, a, s.error_source);
706
+ }
707
+ if (We() >= r)
708
+ throw new Error(`Uploadcare derivative: timed out waiting for job ${e}`);
709
+ await vi(this.pollIntervalMs, i.signal);
710
+ }
711
+ }
712
+ /**
713
+ * Resolve the CDN base, deriving it from the public key when the cname is the
714
+ * default (or already a prefixed base) — the same logic the file uploader
715
+ * applies in its `cdnCname` computed config. Computed once and cached.
716
+ */
717
+ getCdnBase() {
718
+ return this.cdnBasePromise || (this.cdnBasePromise = this.cname === He || jt(this.cname, this.cnamePrefixed) ? Vt(this.publicKey, this.cnamePrefixed) : Promise.resolve(this.cname)), this.cdnBasePromise;
719
+ }
720
+ }
721
+ const Ve = 20;
722
+ class yi {
723
+ constructor(e) {
724
+ this.busy = !1, this.resultUrl = null, this.result = null, this.error = null, this.errorCode = null, this.history = [], this._abortController = null, this._host = e, e.addController(this);
725
+ }
726
+ hostDisconnected() {
727
+ this.abort();
728
+ }
729
+ abort() {
730
+ var e;
731
+ (e = this._abortController) == null || e.abort();
732
+ }
733
+ reset() {
734
+ this.abort(), this.resultUrl = null, this.result = null, this.error = null, this.errorCode = null, this._host.requestUpdate();
735
+ }
736
+ /** Drop the prompt-history strip (e.g. on "Start over"). */
737
+ clearHistory() {
738
+ this.history = [], this._host.requestUpdate();
739
+ }
740
+ /** Replace the strip with entries hydrated from storage (e.g. when the editor
741
+ * opens on a source whose lineage was generated in a past session). */
742
+ setHistory(e) {
743
+ this.history = e.slice(0, Ve), this._host.requestUpdate();
744
+ }
745
+ setResult(e) {
746
+ this.resultUrl = e.url, this.result = e, this.error = null, this.errorCode = null, this._host.requestUpdate();
747
+ }
748
+ async run(e) {
749
+ var r;
750
+ if (this.busy) return null;
751
+ (r = this._abortController) == null || r.abort();
752
+ const i = new AbortController();
753
+ this._abortController = i, this.busy = !0, this.error = null, this.errorCode = null, this._host.requestUpdate();
754
+ try {
755
+ const s = await e.provider.generate({
756
+ prompt: e.prompt,
757
+ mode: e.mode,
758
+ aspectRatio: e.aspectRatio,
759
+ source: e.source,
760
+ filename: e.filename,
761
+ metadata: e.metadata,
762
+ signal: i.signal
763
+ });
764
+ return i.signal.aborted ? null : (this.resultUrl = s.url, this.result = s, this.history = [
765
+ {
766
+ id: crypto.randomUUID(),
767
+ prompt: s.prompt,
768
+ mode: s.mode,
769
+ url: s.url,
770
+ file: s.file,
771
+ ratio: e.ratioValue ?? null
772
+ },
773
+ ...this.history
774
+ ].slice(0, Ve), s);
775
+ } catch (s) {
776
+ if ((s == null ? void 0 : s.name) === "AbortError") return null;
777
+ throw this.error = s.message || "Generation failed", this.errorCode = s instanceof we ? s.errorCode : null, s;
778
+ } finally {
779
+ this._abortController === i && (this.busy = !1, this._abortController = null), this._host.requestUpdate();
780
+ }
781
+ }
782
+ }
783
+ const wi = {
784
+ "ai-enhancer-source-label": "Generate image",
785
+ "ai-enhancer-file-action-label": "AI Edit",
786
+ "ai-enhancer-generate-title": "Generate image",
787
+ "ai-enhancer-edit-title": "Edit image",
788
+ "ai-enhancer-generate-placeholder": "Create image...",
789
+ "ai-enhancer-edit-placeholder": "Edit image...",
790
+ "ai-enhancer-cancel": "Cancel",
791
+ "ai-enhancer-generate-btn": "Generate",
792
+ "ai-enhancer-done-btn": "Done",
793
+ "ai-enhancer-start-over": "Start over",
794
+ "ai-enhancer-history-title": "Recent prompts",
795
+ "ai-enhancer-busy": "Generating…",
796
+ "ai-enhancer-error": "Something went wrong. Try again.",
797
+ "ai-enhancer-fullscreen": "View fullscreen",
798
+ "ai-enhancer-exit-fullscreen": "Exit fullscreen",
799
+ "ai-enhancer-aspect-ratio-aria": "Pick aspect ratio",
800
+ "ai-enhancer-aspect-original": "Original",
801
+ "ai-enhancer-aspect-square": "Square",
802
+ "ai-enhancer-aspect-tall": "Tall",
803
+ "ai-enhancer-aspect-wide": "Wide",
804
+ "ai-enhancer-aspect-portrait": "Portrait",
805
+ "ai-enhancer-aspect-landscape": "Landscape",
806
+ "ai-enhancer-aspect-vertical": "Vertical",
807
+ "ai-enhancer-aspect-widescreen": "Widescreen"
808
+ }, xi = {
809
+ // Platform validation (POST generate/edit/outpaint, GET status)
810
+ "ai-enhancer-error-invalid_request": "Something went wrong with the request. Please try again.",
811
+ "ai-enhancer-error-invalid_source": "The source image couldn't be read. Please try a different image.",
812
+ "ai-enhancer-error-source_not_found": "The source image couldn't be found.",
813
+ "ai-enhancer-error-source_not_image": "The source file must be an image.",
814
+ "ai-enhancer-error-source_url_unavailable": "The source image couldn't be downloaded. Please try again.",
815
+ "ai-enhancer-error-invalid_aspect_ratio": "That aspect ratio isn't supported.",
816
+ "ai-enhancer-error-canvas_too_large": "The image is too large (max 4 megapixels). Try a smaller size.",
817
+ "ai-enhancer-error-canvas_dimension_too_small": "The image is too small — each side must be at least 256px.",
818
+ "ai-enhancer-error-source_extends_beyond_canvas": "The source image doesn't fit the canvas. Try a larger canvas.",
819
+ "ai-enhancer-error-derivative_disabled": "AI image generation isn't enabled for this account.",
820
+ "ai-enhancer-error-job_id_required": "Something went wrong. Please try again.",
821
+ "ai-enhancer-error-job_not_found": "This generation has expired. Please try again.",
822
+ // AI gateway (job status)
823
+ "ai-enhancer-error-content_moderated": "This request was blocked by content moderation. Try a different prompt.",
824
+ "ai-enhancer-error-provider_unavailable": "The image service is busy right now. Please try again in a moment.",
825
+ "ai-enhancer-error-generation_timeout": "Generation took too long and timed out. Please try again.",
826
+ "ai-enhancer-error-invalid_input": "Some settings are invalid. Please adjust them and try again.",
827
+ "ai-enhancer-error-RequestThrottledError": "Too many requests right now. Please wait a moment and try again.",
828
+ // Upload pipeline (job status)
829
+ "ai-enhancer-error-DownloadFileHTTPClientError": "Couldn't retrieve the generated image. Please try again.",
830
+ "ai-enhancer-error-DownloadFileNotFoundError": "The generated image couldn't be found. Please try again.",
831
+ "ai-enhancer-error-DownloadFileTaskFailedError": "Couldn't save the generated image. Please try again."
832
+ }, N = { ...wi, ...xi }, he = {
833
+ en: async () => N,
834
+ ar: () => import("./ar-0rfB4z3f.js").then((t) => t.default),
835
+ az: () => import("./az-CyK2FKx4.js").then((t) => t.default),
836
+ ca: () => import("./ca-CAoPN2lq.js").then((t) => t.default),
837
+ cs: () => import("./cs-gutH5sZI.js").then((t) => t.default),
838
+ da: () => import("./da-CjNgqmRE.js").then((t) => t.default),
839
+ de: () => import("./de-BC0mixOW.js").then((t) => t.default),
840
+ el: () => import("./el-lfrMPw8j.js").then((t) => t.default),
841
+ es: () => import("./es-D0qq2qhV.js").then((t) => t.default),
842
+ et: () => import("./et-Drgz7t_M.js").then((t) => t.default),
843
+ fi: () => import("./fi-DA-ikQJH.js").then((t) => t.default),
844
+ fr: () => import("./fr-CFVF2OgM.js").then((t) => t.default),
845
+ he: () => import("./he-BZFhB0Wn.js").then((t) => t.default),
846
+ hy: () => import("./hy-DvnjH66b.js").then((t) => t.default),
847
+ is: () => import("./is-DLmDXgjm.js").then((t) => t.default),
848
+ it: () => import("./it-Ch7oZNp5.js").then((t) => t.default),
849
+ ja: () => import("./ja-B_rMbHKq.js").then((t) => t.default),
850
+ ka: () => import("./ka-cFaf_BUT.js").then((t) => t.default),
851
+ kk: () => import("./kk-K2vhij8e.js").then((t) => t.default),
852
+ ko: () => import("./ko-DeRxambx.js").then((t) => t.default),
853
+ lv: () => import("./lv-CizQndPI.js").then((t) => t.default),
854
+ nb: () => import("./nb-BxtTiZSk.js").then((t) => t.default),
855
+ nl: () => import("./nl-C12-qyO6.js").then((t) => t.default),
856
+ pl: () => import("./pl-DnVfWHgL.js").then((t) => t.default),
857
+ pt: () => import("./pt-JpSURXrS.js").then((t) => t.default),
858
+ ro: () => import("./ro-qmi5XBhp.js").then((t) => t.default),
859
+ ru: () => import("./ru-C_rsFTyL.js").then((t) => t.default),
860
+ sk: () => import("./sk-10Fuyb_E.js").then((t) => t.default),
861
+ sr: () => import("./sr-CTcREzcN.js").then((t) => t.default),
862
+ sv: () => import("./sv-BfxAcWfi.js").then((t) => t.default),
863
+ tr: () => import("./tr-CLDSkp-W.js").then((t) => t.default),
864
+ uk: () => import("./uk-BT0jZlPK.js").then((t) => t.default),
865
+ vi: () => import("./vi-BpWn9XQo.js").then((t) => t.default),
866
+ zh: () => import("./zh-C0AOtYB8.js").then((t) => t.default),
867
+ "zh-TW": () => import("./zh-TW-BNfdfwdz.js").then((t) => t.default)
868
+ };
869
+ function ki(t, e) {
870
+ return (e == null ? void 0 : e[t]) ?? N[t];
871
+ }
872
+ function Ei(t) {
873
+ if ("kind" in t) return t;
874
+ const e = xe(t.origin);
875
+ if ("sourceUrl" in t)
876
+ return {
877
+ kind: "proxy",
878
+ origin: e,
879
+ operations: t.operations ?? [],
880
+ sourceUrl: t.sourceUrl
881
+ };
882
+ const i = t.search ?? "", r = t.hash ?? "";
883
+ return "group" in t ? t.nth != null ? {
884
+ kind: "group-element",
885
+ origin: e,
886
+ group: t.group,
887
+ nth: t.nth,
888
+ operations: t.operations ?? [],
889
+ filename: t.filename ?? null,
890
+ search: i,
891
+ hash: r
892
+ } : { kind: "group", origin: e, group: t.group, search: i, hash: r } : {
893
+ kind: "file",
894
+ origin: e,
895
+ uuid: t.uuid,
896
+ conversion: t.conversion ?? null,
897
+ operations: t.operations ?? [],
898
+ filename: t.filename ?? null,
899
+ search: i,
900
+ hash: r
901
+ };
902
+ }
903
+ var k, V, ee, M;
904
+ let Ri = (M = class {
905
+ constructor(e) {
906
+ ne(this, V);
907
+ ne(this, k);
908
+ Me(this, k, Ei(e));
909
+ }
910
+ /**
911
+ * Parses an existing CDN URL.
912
+ *
913
+ * @throws TypeError when the URL cannot be interpreted as a CDN URL.
914
+ */
915
+ static parse(e) {
916
+ return new M(nt(e));
917
+ }
918
+ /** A defensive copy of the operation chain (empty for group root urls). */
919
+ get operations() {
920
+ return "operations" in E(this, k) ? [...E(this, k).operations] : [];
921
+ }
922
+ /** The serialized URL string. */
923
+ get href() {
924
+ return ct(E(this, k));
925
+ }
926
+ /** Alias of {@link CdnUrl.href} for string coercion. */
927
+ toString() {
928
+ return this.href;
929
+ }
930
+ /** The underlying {@link ParsedCdnUrl}, discriminated by `kind`. */
931
+ toJSON() {
932
+ return "operations" in E(this, k) ? { ...E(this, k), operations: [...E(this, k).operations] } : { ...E(this, k) };
933
+ }
934
+ /**
935
+ * Appends operations to the chain.
936
+ *
937
+ * @throws TypeError on group root urls, which cannot carry operations.
938
+ */
939
+ with(...e) {
940
+ return X(this, V, ee).call(this, (i) => [...i, ...e]);
941
+ }
942
+ /**
943
+ * Removes every occurrence of an operation. Accepts the operation name,
944
+ * an operation object, or the creator itself: `url.without(resize)`.
945
+ */
946
+ without(e) {
947
+ return X(this, V, ee).call(this, (i) => i.filter((r) => !ce(r, e)));
948
+ }
949
+ /** Replaces the first same-named operation in place, or appends it. */
950
+ replace(e) {
951
+ return X(this, V, ee).call(this, (i) => {
952
+ const r = i.findIndex((o) => o.name === e.name);
953
+ if (r === -1) return [...i, e];
954
+ const s = [...i];
955
+ return s[r] = e, s;
956
+ });
957
+ }
958
+ /** Whether a matching operation is present (name, object or creator ref). */
959
+ has(e) {
960
+ return this.operations.some((i) => ce(i, e));
961
+ }
962
+ /** First matching operation (name, object or creator ref), or null. */
963
+ get(e) {
964
+ return this.operations.find((i) => ce(i, e)) ?? null;
965
+ }
966
+ /**
967
+ * Sets or clears (`null`) the trailing filename.
968
+ *
969
+ * @throws TypeError on group root and proxy urls.
970
+ */
971
+ setFilename(e) {
972
+ return E(this, k).kind === "group" || E(this, k).kind === "proxy" ? this : new M({ ...E(this, k), filename: e });
973
+ }
974
+ /** Rebases the url onto another domain. */
975
+ setOrigin(e) {
976
+ return new M({ ...E(this, k), origin: xe(e) });
977
+ }
978
+ }, k = new WeakMap(), V = new WeakSet(), ee = function(e) {
979
+ return "operations" in E(this, k) ? new M({
980
+ ...E(this, k),
981
+ operations: e(E(this, k).operations)
982
+ }) : this;
983
+ }, M);
984
+ const ve = (t, ...e) => ({
985
+ name: t,
986
+ params: e
987
+ }), Si = /* @__PURE__ */ ht(
988
+ "preview",
989
+ function(t, e) {
990
+ return t == null && e == null ? ve("preview") : ve("preview", at(t, e, "preview"));
991
+ }
992
+ ), Ci = /* @__PURE__ */ ht(
993
+ "scale_crop",
994
+ function(t, e, i = {}) {
995
+ const r = [at(t, e, "scale_crop")];
996
+ return i.type != null && r.push(i.type), i.align != null && r.push(It(i.align, "scale_crop alignment")), ve("scale_crop", ...r);
997
+ }
998
+ ), $i = 3e3;
999
+ function ut(t) {
1000
+ const e = typeof window < "u" ? window.devicePixelRatio : 1;
1001
+ return Math.min(Math.ceil(t * Math.max(e, 1)), $i);
1002
+ }
1003
+ function dt(t, e) {
1004
+ if (e.length === 0) return t;
1005
+ try {
1006
+ return Ri.parse(t).with(...e).href;
1007
+ } catch {
1008
+ return t;
1009
+ }
1010
+ }
1011
+ function Ai(t, e) {
1012
+ const i = ut(e);
1013
+ return dt(t, [Si(i, i)]);
1014
+ }
1015
+ function Ui(t, e) {
1016
+ const i = ut(e);
1017
+ return dt(t, [Ci(i, i, { align: "center" })]);
1018
+ }
1019
+ const Ti = "uc-ai-enhancer/history", qe = 200, Fi = 10080 * 60 * 1e3;
1020
+ class Mi {
1021
+ constructor(e) {
1022
+ this._key = null, e.addController(this);
1023
+ }
1024
+ hostDisconnected() {
1025
+ }
1026
+ /** Namespace the store by pubkey. Passing an empty key disables persistence. */
1027
+ setNamespace(e) {
1028
+ this._key = e ? `${Ti}/${e}` : null;
1029
+ }
1030
+ /** Upsert the result as a node and persist (evicting expired/overflowing nodes). */
1031
+ record(e) {
1032
+ const i = this._key;
1033
+ if (!i) return;
1034
+ const r = this._read(i);
1035
+ r[e.uuid] = { ...e, createdAt: Date.now() }, this._write(i, this._evict(r));
1036
+ }
1037
+ /**
1038
+ * Persist the original source image as a root node (`source: null`), so it
1039
+ * survives reloads as the base of its lineage. Idempotent: keeps an existing
1040
+ * node untouched (preserving its ordering). New nodes are dated just before the
1041
+ * lineage's oldest entry so the source always sorts last (the base of the strip).
1042
+ */
1043
+ recordSource(e) {
1044
+ const i = this._key;
1045
+ if (!i) return;
1046
+ const r = this._read(i);
1047
+ if (r[e.uuid]) return;
1048
+ const s = Object.values(r).reduce((o, a) => Math.min(o, a.createdAt), Date.now());
1049
+ r[e.uuid] = { ...e, source: null, createdAt: s - 1 }, this._write(i, this._evict(r));
1050
+ }
1051
+ /**
1052
+ * The history strip for `uuid`'s lineage, newest-first: every stored result
1053
+ * connected to it by parent/child links (so branches off an older result are
1054
+ * included). Returns `[]` when persistence is off or nothing is connected — incl.
1055
+ * the common case of opening on a freshly uploaded image with no prior edits.
1056
+ */
1057
+ lineage(e) {
1058
+ const i = this._key;
1059
+ return !i || !e ? [] : this._component(this._read(i), e).sort((r, s) => s.createdAt - r.createdAt).map(Ii);
1060
+ }
1061
+ /** Nodes in `start`'s connected component, walking both parent and child edges.
1062
+ * `start` may be a node itself or only a parent uuid (a source not yet edited). */
1063
+ _component(e, i) {
1064
+ const r = /* @__PURE__ */ new Map();
1065
+ for (const n of Object.values(e)) {
1066
+ if (!n.source) continue;
1067
+ const l = r.get(n.source);
1068
+ l ? l.push(n) : r.set(n.source, [n]);
1069
+ }
1070
+ const s = [], o = /* @__PURE__ */ new Set(), a = [i];
1071
+ for (; a.length > 0; ) {
1072
+ const n = a.shift();
1073
+ if (n === void 0 || o.has(n)) continue;
1074
+ o.add(n);
1075
+ const l = e[n];
1076
+ l && (s.push(l), l.source && a.push(l.source));
1077
+ for (const h of r.get(n) ?? []) a.push(h.uuid);
1078
+ }
1079
+ return s;
1080
+ }
1081
+ /** Drop expired nodes, then the oldest beyond {@link MAX_NODES}. Dropping a
1082
+ * middle node just orphans its descendants (their lineage walk stops early). */
1083
+ _evict(e) {
1084
+ const i = Date.now();
1085
+ let r = Object.values(e).filter((o) => i - o.createdAt < Fi);
1086
+ r.length > qe && (r = r.sort((o, a) => a.createdAt - o.createdAt).slice(0, qe));
1087
+ const s = {};
1088
+ for (const o of r) s[o.uuid] = o;
1089
+ return s;
1090
+ }
1091
+ _read(e) {
1092
+ var i;
1093
+ try {
1094
+ const r = (i = globalThis.localStorage) == null ? void 0 : i.getItem(e);
1095
+ if (!r) return {};
1096
+ const s = JSON.parse(r);
1097
+ return s && typeof s == "object" ? s : {};
1098
+ } catch {
1099
+ return {};
1100
+ }
1101
+ }
1102
+ _write(e, i) {
1103
+ var r;
1104
+ try {
1105
+ (r = globalThis.localStorage) == null || r.setItem(e, JSON.stringify(i));
1106
+ } catch {
1107
+ }
1108
+ }
1109
+ }
1110
+ function Ii(t) {
1111
+ return {
1112
+ id: t.uuid,
1113
+ prompt: t.prompt,
1114
+ mode: t.mode,
1115
+ url: t.url,
1116
+ file: t.file,
1117
+ ratio: t.ratio
1118
+ };
1119
+ }
1120
+ function Oi(t) {
1121
+ try {
1122
+ const e = nt(t);
1123
+ if (e.kind === "file")
1124
+ return {
1125
+ uuid: e.uuid,
1126
+ cdnUrlModifiers: lt(e.operations),
1127
+ fileName: e.filename ?? ""
1128
+ };
1129
+ } catch {
1130
+ }
1131
+ return { uuid: "", cdnUrlModifiers: "", fileName: "" };
1132
+ }
1133
+ function Pi(t, e) {
1134
+ return e ? e(t, Oi(t)) : t;
1135
+ }
1136
+ class pt {
1137
+ constructor(e) {
1138
+ this._cache = /* @__PURE__ */ new Map(), this._pending = /* @__PURE__ */ new Set(), this._host = e, e.addController(this);
1139
+ }
1140
+ hostDisconnected() {
1141
+ this._cache.clear(), this._pending.clear();
1142
+ }
1143
+ /** Point at a new resolver; clears the cache since the signing changed. */
1144
+ setResolver(e) {
1145
+ this._resolver = e, this._cache.clear(), this._pending.clear(), this._host.requestUpdate();
1146
+ }
1147
+ /** The delivery url for `url`, or `null` while an async resolver is pending. */
1148
+ resolve(e) {
1149
+ if (!e || !this._resolver) return e;
1150
+ const i = this._cache.get(e);
1151
+ if (i !== void 0) return i;
1152
+ if (this._pending.has(e)) return null;
1153
+ const r = Pi(e, this._resolver);
1154
+ return typeof r == "string" ? (this._cache.set(e, r), r) : (this._pending.add(e), r.then((s) => this._cache.set(e, s)).catch(() => this._cache.set(e, e)).finally(() => {
1155
+ this._pending.delete(e), this._host.requestUpdate();
1156
+ }), null);
1157
+ }
1158
+ }
1159
+ const Dr = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1160
+ <path d="M9.5 3 11 6.5 14.5 8 11 9.5 9.5 13 8 9.5 4.5 8 8 6.5 9.5 3Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
1161
+ <path d="M17.5 12 18.4 14.1 20.5 15 18.4 15.9 17.5 18 16.6 15.9 14.5 15 16.6 14.1 17.5 12Z" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round"/>
1162
+ <path d="M5.5 16 6.1 17.4 7.5 18 6.1 18.6 5.5 20 4.9 18.6 3.5 18 4.9 17.4 5.5 16Z" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round"/>
1163
+ </svg>`, Nr = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1164
+ <path d="m14.5 4.5 5 5L9 20H4v-5L14.5 4.5Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
1165
+ <path d="m13 6 5 5" stroke="currentColor" stroke-width="1.5"/>
1166
+ <path d="M18.5 14.5 19 16l1.5.5L19 17l-.5 1.5L18 17l-1.5-.5L18 16l.5-1.5Z" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/>
1167
+ </svg>`, zi = `<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1168
+ <path d="M3 6.74251L8 2L13 6.74251M7.99961 14V2.10636" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
1169
+ </svg>`, Li = `<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1170
+ <rect x="2" y="3" width="12" height="10" rx="1.6" stroke="currentColor" stroke-width="1.4"/>
1171
+ <circle cx="5.75" cy="6.25" r="1.05" stroke="currentColor" stroke-width="1.2"/>
1172
+ <path d="M3 11.5l3-2.6 2.3 1.8L11 8l2 2.4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
1173
+ </svg>`, Di = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1174
+ <path d="M9 4H4v5M15 4h5v5M9 20H4v-5M15 20h5v-5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
1175
+ </svg>`, Ni = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1176
+ <path d="M4 9h5V4M20 9h-5V4M4 15h5v5M20 15h-5v5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
1177
+ </svg>`, Bi = ":host{display:inline-flex;position:relative}.trigger{anchor-name:--ai-aspect-anchor;display:inline-flex;align-items:center;gap:8px;height:var(--uc-ai-button-size);padding:0 10px;background:var(--uc-ai-secondary);border:0;border-radius:var(--uc-ai-radius-button);color:var(--uc-ai-foreground);cursor:pointer;font:inherit;transition:background var(--uc-ai-transition),transform .14s var(--uc-ai-ease-out, ease)}.trigger:hover,.trigger[aria-expanded=true]{background:var(--uc-ai-secondary-hover)}.trigger:active{transform:scale(.97)}.trigger:disabled{opacity:.4;cursor:not-allowed}.trigger svg{width:14px;height:14px;color:var(--uc-ai-foreground)}.trigger-label{font-variant-numeric:tabular-nums;font-size:12px;font-weight:500;letter-spacing:.02em;line-height:20px}.popover{margin:0 0 6px;padding:0;border:0;background:transparent;color:inherit;overflow:visible;width:max-content;min-width:180px;max-width:320px;position-anchor:--ai-aspect-anchor;inset:auto;bottom:anchor(top);right:anchor(right);transform-origin:bottom right;transition:opacity .15s var(--uc-ai-ease-out, ease),transform .15s var(--uc-ai-ease-out, ease),display .15s allow-discrete,overlay .15s allow-discrete}.popover:not(:popover-open){display:none;opacity:0;transform:scale(.96) translateY(4px)}@starting-style{.popover:popover-open{opacity:0;transform:scale(.96) translateY(4px)}}.popover-inner{background:var(--uc-ai-background);border:1px solid var(--uc-ai-border);border-radius:var(--uc-ai-radius-input, 12px);box-shadow:var(--uc-ai-dialog-shadow);padding:5px;display:flex;flex-direction:column;gap:2px}.option{display:flex;align-items:center;gap:10px;width:100%;padding:6px 10px;background:transparent;border:0;border-radius:max(0px,calc(var(--uc-ai-radius-input) - 5px));cursor:pointer;color:var(--uc-ai-foreground);font:inherit;font-size:13px;text-align:left;transition:background .12s ease}.option:hover{background:var(--uc-ai-secondary)}.option[aria-selected=true]{background:var(--uc-ai-secondary-hover)}.option svg{width:16px;height:16px;flex:0 0 16px;color:var(--uc-ai-foreground)}.option-ratio{flex:0 0 36px;font-variant-numeric:tabular-nums;font-weight:500;white-space:nowrap;color:var(--uc-ai-foreground)}.option-label{flex:1;min-width:0;color:var(--uc-ai-muted-foreground);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@media(prefers-reduced-motion:reduce){.trigger,.popover{transition-property:opacity,background,display,overlay}.trigger:active{transform:none}.popover:not(:popover-open){transform:none}}";
1178
+ var ji = Object.defineProperty, Gi = Object.getOwnPropertyDescriptor, z = (t, e, i, r) => {
1179
+ for (var s = r > 1 ? void 0 : r ? Gi(e, i) : e, o = t.length - 1, a; o >= 0; o--)
1180
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
1181
+ return r && s && ji(e, i, s), s;
1182
+ };
1183
+ let A = class extends j {
1184
+ constructor() {
1185
+ super(...arguments), this.options = [], this.selected = null, this.busy = !1, this.labelText = null, this.labelFor = (t) => O(t.value) ? Z(t.value) : "", this.open = !1, this._onToggle = (t) => {
1186
+ t.newState === "closed" && this.open && (this.open = !1);
1187
+ };
1188
+ }
1189
+ _setOpen(t) {
1190
+ this.open = t;
1191
+ const e = this._popover;
1192
+ if (!e) return;
1193
+ const i = e.matches(":popover-open");
1194
+ t && !i ? e.showPopover() : !t && i && e.hidePopover();
1195
+ }
1196
+ _toggle() {
1197
+ this._setOpen(!this.open);
1198
+ }
1199
+ _select(t) {
1200
+ this.dispatchEvent(
1201
+ new CustomEvent("uc:select", {
1202
+ detail: { value: t },
1203
+ bubbles: !0,
1204
+ composed: !0
1205
+ })
1206
+ ), this._setOpen(!1);
1207
+ }
1208
+ /** Icon for a selection: the ratio's shape, or the generic "Original" glyph. */
1209
+ _iconFor(t) {
1210
+ return O(t) ? At(t) : Li;
1211
+ }
1212
+ _triggerLabel() {
1213
+ const t = this.selected;
1214
+ if (!t) return "";
1215
+ if (O(t)) return Z(t);
1216
+ const e = this.options.find((i) => i.value === t);
1217
+ return e ? this.labelFor(e) : "";
1218
+ }
1219
+ render() {
1220
+ const t = this._triggerLabel();
1221
+ return f`
1222
+ <button
1223
+ type="button"
1224
+ class="trigger"
1225
+ aria-haspopup="listbox"
1226
+ aria-expanded="${this.open ? "true" : "false"}"
1227
+ aria-label="${this.labelText ?? "Aspect ratio"}"
1228
+ ?disabled=${this.busy}
1229
+ @click=${this._toggle}
1230
+ >
1231
+ ${this.selected ? te(this._iconFor(this.selected)) : null}
1232
+ ${t ? f`<span class="trigger-label">${t}</span>` : null}
1233
+ </button>
1234
+ <div class="popover" popover="auto" role="listbox" @toggle=${this._onToggle}>
1235
+ <div class="popover-inner">
1236
+ ${this.options.map((e) => {
1237
+ const i = this.selected ? pe(e.value, this.selected) : !1;
1238
+ return f`
1239
+ <button
1240
+ type="button"
1241
+ class="option"
1242
+ role="option"
1243
+ aria-selected="${i ? "true" : "false"}"
1244
+ @click=${() => this._select(e.value)}
1245
+ >
1246
+ ${te(this._iconFor(e.value))}
1247
+ <span class="option-ratio">${O(e.value) ? Z(e.value) : ""}</span>
1248
+ <span class="option-label">${this.labelFor(e)}</span>
1249
+ </button>
1250
+ `;
1251
+ })}
1252
+ </div>
1253
+ </div>
1254
+ `;
1255
+ }
1256
+ };
1257
+ A.styles = B(Bi);
1258
+ z([
1259
+ c({ attribute: !1 })
1260
+ ], A.prototype, "options", 2);
1261
+ z([
1262
+ c({ attribute: !1 })
1263
+ ], A.prototype, "selected", 2);
1264
+ z([
1265
+ c({ type: Boolean })
1266
+ ], A.prototype, "busy", 2);
1267
+ z([
1268
+ c({ attribute: "aria-label-text" })
1269
+ ], A.prototype, "labelText", 2);
1270
+ z([
1271
+ c({ attribute: !1 })
1272
+ ], A.prototype, "labelFor", 2);
1273
+ z([
1274
+ C()
1275
+ ], A.prototype, "open", 2);
1276
+ z([
1277
+ F(".popover")
1278
+ ], A.prototype, "_popover", 2);
1279
+ A = z([
1280
+ G("uc-ai-aspect-ratio")
1281
+ ], A);
1282
+ const Hi = /* @__PURE__ */ new WeakMap();
1283
+ let Ke = 0;
1284
+ const ue = /* @__PURE__ */ new Map(), Ye = /* @__PURE__ */ new WeakSet(), Xe = () => new Promise((t) => requestAnimationFrame(t)), Je = (t, e) => {
1285
+ const i = t - e;
1286
+ return i === 0 ? void 0 : i;
1287
+ }, Ze = (t, e) => {
1288
+ const i = t / e;
1289
+ return i === 1 ? void 0 : i;
1290
+ }, de = { left: (t, e) => {
1291
+ const i = Je(t, e);
1292
+ return { value: i, transform: i == null || isNaN(i) ? void 0 : `translateX(${i}px)` };
1293
+ }, top: (t, e) => {
1294
+ const i = Je(t, e);
1295
+ return { value: i, transform: i == null || isNaN(i) ? void 0 : `translateY(${i}px)` };
1296
+ }, width: (t, e) => {
1297
+ let i;
1298
+ e === 0 && (e = 1, i = { width: "1px" });
1299
+ const r = Ze(t, e);
1300
+ return { value: r, overrideFrom: i, transform: r == null || isNaN(r) ? void 0 : `scaleX(${r})` };
1301
+ }, height: (t, e) => {
1302
+ let i;
1303
+ e === 0 && (e = 1, i = { height: "1px" });
1304
+ const r = Ze(t, e);
1305
+ return { value: r, overrideFrom: i, transform: r == null || isNaN(r) ? void 0 : `scaleY(${r})` };
1306
+ } }, Wi = { duration: 333, easing: "ease-in-out" }, Vi = ["left", "top", "width", "height", "opacity", "color", "background"], Qe = /* @__PURE__ */ new WeakMap();
1307
+ class qi extends st {
1308
+ constructor(e) {
1309
+ if (super(e), this.t = !1, this.i = null, this.o = null, this.h = !0, this.shouldLog = !1, e.type === rt.CHILD) throw Error("The `animate` directive must be used in attribute position.");
1310
+ this.createFinished();
1311
+ }
1312
+ createFinished() {
1313
+ var e;
1314
+ (e = this.resolveFinished) == null || e.call(this), this.finished = new Promise((i) => {
1315
+ this.l = i;
1316
+ });
1317
+ }
1318
+ async resolveFinished() {
1319
+ var e;
1320
+ (e = this.l) == null || e.call(this), this.l = void 0;
1321
+ }
1322
+ render(e) {
1323
+ return tt;
1324
+ }
1325
+ getController() {
1326
+ return Hi.get(this.u);
1327
+ }
1328
+ isDisabled() {
1329
+ var e;
1330
+ return this.options.disabled || ((e = this.getController()) == null ? void 0 : e.disabled);
1331
+ }
1332
+ update(e, [i]) {
1333
+ var s;
1334
+ const r = this.u === void 0;
1335
+ return r && (this.u = (s = e.options) == null ? void 0 : s.host, this.u.addController(this), this.u.updateComplete.then((o) => this.t = !0), this.element = e.element, Qe.set(this.element, this)), this.optionsOrCallback = i, (r || typeof i != "function") && this.m(i), this.render(i);
1336
+ }
1337
+ m(e) {
1338
+ e = e ?? {};
1339
+ const i = this.getController();
1340
+ i !== void 0 && ((e = { ...i.defaultOptions, ...e }).keyframeOptions = { ...i.defaultOptions.keyframeOptions, ...e.keyframeOptions }), e.properties ?? (e.properties = Vi), this.options = e;
1341
+ }
1342
+ p() {
1343
+ const e = {}, i = this.element.getBoundingClientRect(), r = getComputedStyle(this.element);
1344
+ return this.options.properties.forEach((s) => {
1345
+ const o = i[s] ?? (de[s] ? void 0 : r[s]), a = Number(o);
1346
+ e[s] = isNaN(a) ? o + "" : a;
1347
+ }), e;
1348
+ }
1349
+ v() {
1350
+ let e, i = !0;
1351
+ return this.options.guard && (e = this.options.guard(), i = ((r, s) => {
1352
+ if (Array.isArray(r)) {
1353
+ if (Array.isArray(s) && s.length === r.length && r.every((o, a) => o === s[a])) return !1;
1354
+ } else if (s === r) return !1;
1355
+ return !0;
1356
+ })(e, this._)), this.h = this.t && !this.isDisabled() && !this.isAnimating() && i && this.element.isConnected, this.h && (this._ = Array.isArray(e) ? Array.from(e) : e), this.h;
1357
+ }
1358
+ hostUpdate() {
1359
+ typeof this.optionsOrCallback == "function" && this.m(this.optionsOrCallback()), this.v() && (this.A = this.p(), this.i = this.i ?? this.element.parentNode, this.o = this.element.nextSibling);
1360
+ }
1361
+ async hostUpdated() {
1362
+ if (!this.h || !this.element.isConnected || this.options.skipInitial && !this.isHostRendered) return;
1363
+ let e;
1364
+ this.prepare(), await Xe;
1365
+ const i = this.P(), r = this.V(this.options.keyframeOptions, i), s = this.p();
1366
+ if (this.A !== void 0) {
1367
+ const { from: o, to: a } = this.O(this.A, s, i);
1368
+ this.log("measured", [this.A, s, o, a]), e = this.calculateKeyframes(o, a);
1369
+ } else {
1370
+ const o = ue.get(this.options.inId);
1371
+ if (o) {
1372
+ ue.delete(this.options.inId);
1373
+ const { from: a, to: n } = this.O(o, s, i);
1374
+ e = this.calculateKeyframes(a, n), e = this.options.in ? [{ ...this.options.in[0], ...e[0] }, ...this.options.in.slice(1), e[1]] : e, Ke++, e.forEach((l) => l.zIndex = Ke);
1375
+ } else this.options.in && (e = [...this.options.in, {}]);
1376
+ }
1377
+ this.animate(e, r);
1378
+ }
1379
+ resetStyles() {
1380
+ this.j !== void 0 && (this.element.setAttribute("style", this.j ?? ""), this.j = void 0);
1381
+ }
1382
+ commitStyles() {
1383
+ var e, i;
1384
+ this.j = this.element.getAttribute("style"), (e = this.webAnimation) == null || e.commitStyles(), (i = this.webAnimation) == null || i.cancel();
1385
+ }
1386
+ reconnected() {
1387
+ }
1388
+ async disconnected() {
1389
+ var i;
1390
+ if (!this.h || (this.options.id !== void 0 && ue.set(this.options.id, this.A), this.options.out === void 0)) return;
1391
+ if (this.prepare(), await Xe(), (i = this.i) == null ? void 0 : i.isConnected) {
1392
+ const r = this.o && this.o.parentNode === this.i ? this.o : null;
1393
+ if (this.i.insertBefore(this.element, r), this.options.stabilizeOut) {
1394
+ const s = this.p();
1395
+ this.log("stabilizing out");
1396
+ const o = this.A.left - s.left, a = this.A.top - s.top;
1397
+ getComputedStyle(this.element).position !== "static" || o === 0 && a === 0 || (this.element.style.position = "relative"), o !== 0 && (this.element.style.left = o + "px"), a !== 0 && (this.element.style.top = a + "px");
1398
+ }
1399
+ }
1400
+ const e = this.V(this.options.keyframeOptions);
1401
+ await this.animate(this.options.out, e), this.element.remove();
1402
+ }
1403
+ prepare() {
1404
+ this.createFinished();
1405
+ }
1406
+ start() {
1407
+ var e, i;
1408
+ (i = (e = this.options).onStart) == null || i.call(e, this);
1409
+ }
1410
+ didFinish(e) {
1411
+ var i, r;
1412
+ e && ((r = (i = this.options).onComplete) == null || r.call(i, this)), this.A = void 0, this.animatingProperties = void 0, this.frames = void 0, this.resolveFinished();
1413
+ }
1414
+ P() {
1415
+ const e = [];
1416
+ for (let i = this.element.parentNode; i; i = i == null ? void 0 : i.parentNode) {
1417
+ const r = Qe.get(i);
1418
+ r && !r.isDisabled() && r && e.push(r);
1419
+ }
1420
+ return e;
1421
+ }
1422
+ get isHostRendered() {
1423
+ const e = Ye.has(this.u);
1424
+ return e || this.u.updateComplete.then(() => {
1425
+ Ye.add(this.u);
1426
+ }), e;
1427
+ }
1428
+ V(e, i = this.P()) {
1429
+ const r = { ...Wi };
1430
+ return i.forEach((s) => Object.assign(r, s.options.keyframeOptions)), Object.assign(r, e), r;
1431
+ }
1432
+ O(e, i, r) {
1433
+ e = { ...e }, i = { ...i };
1434
+ const s = r.map((n) => n.animatingProperties).filter((n) => n !== void 0);
1435
+ let o = 1, a = 1;
1436
+ return s.length > 0 && (s.forEach((n) => {
1437
+ n.width && (o /= n.width), n.height && (a /= n.height);
1438
+ }), e.left !== void 0 && i.left !== void 0 && (e.left = o * e.left, i.left = o * i.left), e.top !== void 0 && i.top !== void 0 && (e.top = a * e.top, i.top = a * i.top)), { from: e, to: i };
1439
+ }
1440
+ calculateKeyframes(e, i, r = !1) {
1441
+ const s = {}, o = {};
1442
+ let a = !1;
1443
+ const n = {};
1444
+ for (const l in i) {
1445
+ const h = e[l], p = i[l];
1446
+ if (l in de) {
1447
+ const u = de[l];
1448
+ if (h === void 0 || p === void 0) continue;
1449
+ const _ = u(h, p);
1450
+ _.transform !== void 0 && (n[l] = _.value, a = !0, s.transform = `${s.transform ?? ""} ${_.transform}`, _.overrideFrom !== void 0 && Object.assign(s, _.overrideFrom));
1451
+ } else h !== p && h !== void 0 && p !== void 0 && (a = !0, s[l] = h, o[l] = p);
1452
+ }
1453
+ return s.transformOrigin = o.transformOrigin = r ? "center center" : "top left", this.animatingProperties = n, a ? [s, o] : void 0;
1454
+ }
1455
+ async animate(e, i = this.options.keyframeOptions) {
1456
+ this.start(), this.frames = e;
1457
+ let r = !1;
1458
+ if (!this.isAnimating() && !this.isDisabled() && (this.options.onFrames && (this.frames = e = this.options.onFrames(this), this.log("modified frames", e)), e !== void 0)) {
1459
+ this.log("animate", [e, i]), r = !0, this.webAnimation = this.element.animate(e, i);
1460
+ const s = this.getController();
1461
+ s == null || s.add(this);
1462
+ try {
1463
+ await this.webAnimation.finished;
1464
+ } catch {
1465
+ }
1466
+ s == null || s.remove(this);
1467
+ }
1468
+ return this.didFinish(r), r;
1469
+ }
1470
+ isAnimating() {
1471
+ var e, i;
1472
+ return ((e = this.webAnimation) == null ? void 0 : e.playState) === "running" || ((i = this.webAnimation) == null ? void 0 : i.pending);
1473
+ }
1474
+ log(e, i) {
1475
+ this.shouldLog && !this.isDisabled() && console.log(e, this.options.id, i);
1476
+ }
1477
+ }
1478
+ const Ki = it(qi), Yi = ["top", "right", "bottom", "left"];
1479
+ class Xi extends st {
1480
+ constructor(e) {
1481
+ if (super(e), e.type !== rt.ELEMENT) throw Error("The `position` directive must be used in attribute position.");
1482
+ }
1483
+ render(e, i) {
1484
+ return tt;
1485
+ }
1486
+ update(e, [i, r]) {
1487
+ var s;
1488
+ return this.u === void 0 && (this.u = (s = e.options) == null ? void 0 : s.host, this.u.addController(this)), this.C = e.element, this.N = i, this.S = r ?? ["left", "top", "width", "height"], this.render(i, r);
1489
+ }
1490
+ hostUpdated() {
1491
+ this.F();
1492
+ }
1493
+ F() {
1494
+ var o, a;
1495
+ const e = typeof this.N == "function" ? this.N() : (o = this.N) == null ? void 0 : o.value, i = e.offsetParent;
1496
+ if (e === void 0 || !i) return;
1497
+ const r = e.getBoundingClientRect(), s = i.getBoundingClientRect();
1498
+ (a = this.S) == null || a.forEach((n) => {
1499
+ const l = Yi.includes(n) ? r[n] - s[n] : r[n];
1500
+ this.C.style[n] = l + "px";
1501
+ });
1502
+ }
1503
+ }
1504
+ it(Xi);
1505
+ const Ji = ':host{display:flex;justify-content:center}.strip{position:relative;display:inline-flex;align-items:center;min-height:44px}.chip{display:flex;align-items:center;padding:2px;margin-right:-11px;background:var(--uc-ai-floating, var(--uc-ai-background));border:1px solid transparent;border-radius:calc(var(--uc-ai-radius-button, 8px) + 2px);box-shadow:0 1px 8px #0000004d;cursor:pointer;transform:scale(1);transition:margin .3s var(--uc-ai-ease-out, ease),border-color 225ms ease,transform .27s var(--uc-ai-ease-out, ease),opacity .33s var(--uc-ai-ease-out, ease)}.chip:disabled{cursor:not-allowed}.chip:last-child{margin-right:0}@media(hover:hover)and (pointer:fine){.chip:hover:not(:disabled){transform:scale(1.1)}.strip:hover .chip:not(:disabled){margin-right:7px}.strip:hover .chip:not(:disabled):last-child{margin-right:0}}.chip--selected{border-color:var(--uc-ai-primary);transform:scale(1.2)}.thumb{position:relative;display:block;width:40px;height:40px;border-radius:var(--uc-ai-radius-button, 8px);background-color:var(--uc-ai-muted);overflow:hidden}.thumb:not(.thumb--loaded):after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:linear-gradient(100deg,transparent 30%,color-mix(in srgb,var(--uc-ai-foreground) 9%,transparent) 50%,transparent 70%);transform:translate(-100%);animation:thumb-shimmer 1.2s ease-in-out infinite}@keyframes thumb-shimmer{to{transform:translate(100%)}}.thumb__img{display:block;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .24s var(--uc-ai-ease-out, ease)}.thumb--loaded .thumb__img{opacity:1}@media(prefers-reduced-motion:reduce){.thumb:not(.thumb--loaded):after{animation:none}.thumb__img{transition:none}}.startover{position:absolute;right:calc(100% + 10px);top:50%;display:flex;align-items:center;background:var(--uc-ai-floating, var(--uc-ai-background));border:1px solid var(--uc-ai-floating-border, transparent);border-radius:calc(var(--uc-ai-radius-button, 8px) + 2px);box-shadow:var(--uc-ai-dialog-shadow);white-space:nowrap;opacity:0;transform:translateY(-50%) translate(-6px) scale(.95);transform-origin:right center;pointer-events:none;transition:opacity .26s var(--uc-ai-ease-out, ease),transform .26s var(--uc-ai-ease-out, ease)}.strip:hover .startover,.strip:focus-within .startover{opacity:1;transform:translateY(-50%) translate(0) scale(1);pointer-events:auto}.strip--empty .startover{position:static;opacity:1;transform:none;pointer-events:auto}.startover__btn{height:var(--uc-ai-button-size, 32px);padding:0 12px;background:transparent;border:0;border-radius:inherit;color:var(--uc-ai-foreground);font:inherit;font-size:13px;cursor:pointer}.startover__btn:disabled{cursor:not-allowed}.startover__btn:hover{background:var(--uc-ai-secondary)}.strip:before{content:"";position:absolute;right:100%;top:-12px;bottom:-12px;width:200px}.strip--empty:before{content:none}@media(prefers-reduced-motion:reduce){.chip,.startover{transition-property:opacity,border-color,margin}.chip:hover,.chip--selected{transform:scale(1)}.strip:not(.strip--empty) .startover,.strip:not(.strip--empty):hover .startover,.strip:not(.strip--empty):focus-within .startover{transform:translateY(-50%)}}';
1506
+ var Zi = Object.defineProperty, Qi = Object.getOwnPropertyDescriptor, L = (t, e, i, r) => {
1507
+ for (var s = r > 1 ? void 0 : r ? Qi(e, i) : e, o = t.length - 1, a; o >= 0; o--)
1508
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
1509
+ return r && s && Zi(e, i, s), s;
1510
+ };
1511
+ const er = 80;
1512
+ let U = class extends j {
1513
+ constructor() {
1514
+ super(...arguments), this.entries = [], this.selectedUuid = null, this.showStartOver = !1, this.startOverLabel = "", this.listLabel = "Generation history", this.busy = !1, this._secure = new pt(this), this._loaded = /* @__PURE__ */ new Set();
1515
+ }
1516
+ willUpdate(t) {
1517
+ if (t.has("secureResolver") && this._secure.setResolver(this.secureResolver), t.has("entries")) {
1518
+ const e = new Set(this.entries.map((i) => i.id));
1519
+ for (const i of this._loaded) e.has(i) || this._loaded.delete(i);
1520
+ }
1521
+ }
1522
+ /** Mark an entry's thumbnail decoded (or failed) so it fades in over the skeleton. */
1523
+ _onThumbSettled(t) {
1524
+ this._loaded.has(t) || (this._loaded.add(t), this.requestUpdate());
1525
+ }
1526
+ _select(t) {
1527
+ this.dispatchEvent(
1528
+ new CustomEvent("uc:select", { detail: { entry: t }, bubbles: !0, composed: !0 })
1529
+ );
1530
+ }
1531
+ _startOver() {
1532
+ this.dispatchEvent(new CustomEvent("uc:start-over", { bubbles: !0, composed: !0 }));
1533
+ }
1534
+ render() {
1535
+ const t = this.entries.length > 0;
1536
+ if (!t && !this.showStartOver) return f`${v}`;
1537
+ const e = { strip: !0, "strip--empty": !t }, i = [...this.entries].reverse();
1538
+ return f`
1539
+ <div class=${S(e)} role="toolbar" aria-label="${this.listLabel}">
1540
+ ${this.showStartOver ? f`
1541
+ <div class="startover">
1542
+ <button type="button" ?disabled="${this.busy}" class="startover__btn" @click=${this._startOver}>
1543
+ ${this.startOverLabel}
1544
+ </button>
1545
+ </div>
1546
+ ` : v}
1547
+ ${bt(
1548
+ i,
1549
+ (r) => r.id,
1550
+ (r) => {
1551
+ const s = this._secure.resolve(Ui(r.url, er)), o = this.selectedUuid != null && r.file.uuid === this.selectedUuid, a = this._loaded.has(r.id);
1552
+ return f`
1553
+ <button
1554
+ type="button"
1555
+ ?disabled=${this.busy}
1556
+ class=${S({ chip: !0, "chip--selected": o })}
1557
+ aria-pressed="${o ? "true" : "false"}"
1558
+ aria-label=${r.prompt || "Result"}
1559
+ title=${r.prompt}
1560
+ @click=${() => this._select(r)}
1561
+ ${Ki({ keyframeOptions: { duration: 300, easing: "cubic-bezier(0.23, 1, 0.32, 1)" } })}
1562
+ >
1563
+ <span class=${S({ thumb: !0, "thumb--loaded": a })}>
1564
+ ${// Rendering the <img> preloads it; the skeleton shows until it
1565
+ // decodes, then it fades in (see history.css).
1566
+ s ? f`<img
1567
+ class="thumb__img"
1568
+ src="${s}"
1569
+ alt=""
1570
+ aria-hidden="true"
1571
+ decoding="async"
1572
+ @load=${() => this._onThumbSettled(r.id)}
1573
+ @error=${() => this._onThumbSettled(r.id)}
1574
+ />` : v}
1575
+ </span>
1576
+ </button>
1577
+ `;
1578
+ }
1579
+ )}
1580
+ </div>
1581
+ `;
1582
+ }
1583
+ };
1584
+ U.styles = B(Ji);
1585
+ L([
1586
+ c({ attribute: !1 })
1587
+ ], U.prototype, "entries", 2);
1588
+ L([
1589
+ c({ attribute: "selected-uuid" })
1590
+ ], U.prototype, "selectedUuid", 2);
1591
+ L([
1592
+ c({ type: Boolean, attribute: "show-start-over" })
1593
+ ], U.prototype, "showStartOver", 2);
1594
+ L([
1595
+ c({ attribute: "start-over-label" })
1596
+ ], U.prototype, "startOverLabel", 2);
1597
+ L([
1598
+ c({ attribute: "list-label" })
1599
+ ], U.prototype, "listLabel", 2);
1600
+ L([
1601
+ c({ type: Boolean })
1602
+ ], U.prototype, "busy", 2);
1603
+ L([
1604
+ c({ attribute: !1 })
1605
+ ], U.prototype, "secureResolver", 2);
1606
+ U = L([
1607
+ G("uc-ai-history")
1608
+ ], U);
1609
+ const tr = ':host{display:block}.card{width:100%;box-sizing:border-box;background:color-mix(in srgb,var(--uc-ai-floating, var(--uc-ai-background)) 80%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--uc-ai-floating-border, transparent);border-radius:var(--uc-ai-composer-radius-top) var(--uc-ai-composer-radius-top) var(--uc-ai-composer-radius-bottom) var(--uc-ai-composer-radius-bottom);transition:border-radius .4s var(--uc-ai-ease-out),box-shadow .4s var(--uc-ai-ease-out);box-shadow:var(--uc-ai-composer-shadow);overflow:visible;--uc-ai-radius-button: max(0px, calc(var(--uc-ai-composer-radius) - var(--uc-ai-padding)))}.body{display:flex;flex-direction:column;gap:var(--uc-ai-padding);padding:var(--uc-ai-padding)}.input{box-sizing:border-box;width:100%;min-height:40px;max-height:var(--uc-ai-prompt-max-height, calc(var(--uc-ai-prompt-max-lines, 6) * 1.5em + 10px));resize:none;border:0;outline:none;padding:0 3px;background:transparent;font-family:inherit;font-size:var(--uc-ai-font-size);line-height:20px;color:var(--uc-ai-foreground);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--uc-ai-border) transparent;transition:height .16s var(--uc-ai-ease-out, ease)}@supports (field-sizing: content){.input{field-sizing:content;transition:none}}.input::placeholder{color:var(--uc-ai-muted-foreground)}.input:disabled{color:var(--uc-ai-muted-foreground);-webkit-text-fill-color:var(--uc-ai-muted-foreground);cursor:not-allowed}.row{display:flex;align-items:center;gap:10px}.actions{flex:1;min-width:0;display:flex;align-items:center}.actions::slotted(*){min-width:0}.controls{display:flex;align-items:center;gap:0;flex:none}.send{margin-left:5px;width:var(--uc-ai-button-size, 32px);height:var(--uc-ai-button-size, 32px);flex:none;min-width:0;display:inline-flex;align-items:center;justify-content:center;position:relative;background:var(--uc-ai-primary);color:var(--uc-ai-primary-foreground);border:none;border-radius:var(--uc-ai-radius-button);cursor:pointer;overflow:hidden;transition:width .22s var(--uc-ai-ease-out, ease),margin-left .22s var(--uc-ai-ease-out, ease),opacity .15s var(--uc-ai-ease-out, ease),transform .15s var(--uc-ai-ease-out, ease),background var(--uc-ai-transition)}.send:hover:not(:disabled){background:var(--uc-ai-primary-hover)}.send:active:not(:disabled){transform:scale(.95)}.send:disabled{cursor:default}.send[hidden]{display:inline-flex;width:0;min-width:0;padding:0;margin-left:0;opacity:0;transform:scale(.8);pointer-events:none}.send__icon,.send__spinner{position:absolute;top:50%;left:50%;width:16px;height:16px;transition:opacity .2s var(--uc-ai-ease-out, ease),transform .2s var(--uc-ai-ease-out, ease),filter .2s var(--uc-ai-ease-out, ease)}.send__icon{opacity:1;transform:translate(-50%,-50%) scale(1);filter:blur(0)}.send__icon svg{width:16px;height:16px;display:block}.send__spinner{opacity:0;transform:translate(-50%,-50%) scale(.95);filter:blur(3px)}.send__spinner:before,.send__spinner:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;border:1.5px solid currentColor}.send__spinner:before{opacity:.3}.send__spinner:after{border-top-color:transparent;animation:send-spin .7s linear infinite;will-change:transform}@keyframes send-spin{to{transform:rotate(360deg)}}.send--busy .send__icon{opacity:0;transform:translate(-50%,-50%) scale(.95);filter:blur(3px)}.send--busy .send__spinner{opacity:1;transform:translate(-50%,-50%) scale(1);filter:blur(0)}.send--busy:disabled{opacity:1}@media(prefers-reduced-motion:reduce){.input,.send{transition-property:opacity,background,width,margin-left}.send__icon,.send__spinner{transition-property:opacity}.send__spinner:after{animation:none}.send:active:not(:disabled){transform:none}}';
1610
+ var ir = Object.defineProperty, rr = Object.getOwnPropertyDescriptor, D = (t, e, i, r) => {
1611
+ for (var s = r > 1 ? void 0 : r ? rr(e, i) : e, o = t.length - 1, a; o >= 0; o--)
1612
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
1613
+ return r && s && ir(e, i, s), s;
1614
+ };
1615
+ let T = class extends j {
1616
+ constructor() {
1617
+ super(...arguments), this.mode = "generate", this.value = "", this.placeholder = "", this.busy = !1, this.allowCustom = !0, this.sendAriaLabel = "";
1618
+ }
1619
+ focusInput() {
1620
+ var t;
1621
+ (t = this._inputEl) == null || t.focus();
1622
+ }
1623
+ updated(t) {
1624
+ t.has("value") && this._resize();
1625
+ }
1626
+ /**
1627
+ * Auto-grow fallback for browsers without `field-sizing: content` support.
1628
+ * The CSS `max-height` caps the growth; overflow scrolls internally.
1629
+ */
1630
+ _resize() {
1631
+ const t = this._inputEl;
1632
+ !t || CSS.supports("field-sizing", "content") || (t.style.height = "auto", t.style.height = `${t.scrollHeight}px`);
1633
+ }
1634
+ _onInput(t) {
1635
+ const e = t.target.value;
1636
+ this.value = e, this.dispatchEvent(
1637
+ new CustomEvent("uc:input", { detail: { value: e }, bubbles: !0, composed: !0 })
1638
+ ), this._resize();
1639
+ }
1640
+ _onKeydown(t) {
1641
+ t.key === "Enter" && !t.shiftKey && !t.isComposing && this.value.trim() && !this.busy && (t.preventDefault(), this._emitSend());
1642
+ }
1643
+ _emitSend() {
1644
+ this.dispatchEvent(new CustomEvent("uc:send", { bubbles: !0, composed: !0 }));
1645
+ }
1646
+ render() {
1647
+ const t = this.value.trim().length === 0;
1648
+ return f`
1649
+ <div class="card">
1650
+ <div class="body">
1651
+ ${this.allowCustom ? f`<textarea
1652
+ class="input"
1653
+ rows="1"
1654
+ .value=${this.value}
1655
+ placeholder="${this.placeholder}"
1656
+ aria-label="${this.placeholder}"
1657
+ autocomplete="off"
1658
+ autocorrect="off"
1659
+ autocapitalize="off"
1660
+ spellcheck="false"
1661
+ name="uc-ai-prompt"
1662
+ data-1p-ignore
1663
+ data-lpignore="true"
1664
+ data-form-type="other"
1665
+ @input=${this._onInput}
1666
+ @keydown=${this._onKeydown}
1667
+ ?disabled=${this.busy}
1668
+ ></textarea>` : v}
1669
+
1670
+ <div class="row">
1671
+ <div class="actions">
1672
+ <slot name="chips"></slot>
1673
+ </div>
1674
+ <div class="controls">
1675
+ <slot name="aspect-ratio"></slot>
1676
+ <button
1677
+ type="button"
1678
+ class=${S({ send: !0, "send--busy": this.busy })}
1679
+ aria-label="${this.sendAriaLabel}"
1680
+ ?hidden=${t}
1681
+ ?disabled=${this.busy || t}
1682
+ @click=${this._emitSend}
1683
+ >
1684
+ <span class="send__icon">${te(zi)}</span>
1685
+ <span class="send__spinner" aria-hidden="true"></span>
1686
+ </button>
1687
+ </div>
1688
+ </div>
1689
+ </div>
1690
+ </div>
1691
+ `;
1692
+ }
1693
+ };
1694
+ T.styles = B(tr);
1695
+ D([
1696
+ c()
1697
+ ], T.prototype, "mode", 2);
1698
+ D([
1699
+ c()
1700
+ ], T.prototype, "value", 2);
1701
+ D([
1702
+ c()
1703
+ ], T.prototype, "placeholder", 2);
1704
+ D([
1705
+ c({ type: Boolean })
1706
+ ], T.prototype, "busy", 2);
1707
+ D([
1708
+ c({ type: Boolean })
1709
+ ], T.prototype, "allowCustom", 2);
1710
+ D([
1711
+ c({ attribute: "send-aria-label" })
1712
+ ], T.prototype, "sendAriaLabel", 2);
1713
+ D([
1714
+ F(".input")
1715
+ ], T.prototype, "_inputEl", 2);
1716
+ T = D([
1717
+ G("uc-ai-prompt-row")
1718
+ ], T);
1719
+ const sr = ":host{display:block;min-width:0}.row{display:flex;flex-wrap:nowrap;align-items:center;gap:5px;overflow-x:auto;scrollbar-width:none}.row::-webkit-scrollbar{display:none}.row.fade-left.fade-right{-webkit-mask-image:linear-gradient(to right,transparent 0,#000 10px,#000 calc(100% - 10px),transparent 100%);mask-image:linear-gradient(to right,transparent 0,#000 10px,#000 calc(100% - 10px),transparent 100%)}.row.fade-left:not(.fade-right){-webkit-mask-image:linear-gradient(to right,transparent 0,#000 10px);mask-image:linear-gradient(to right,transparent 0,#000 10px)}.row.fade-right:not(.fade-left){-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 10px),transparent 100%);mask-image:linear-gradient(to right,#000 calc(100% - 10px),transparent 100%)}.chip{flex:none;height:var(--uc-ai-button-size, 32px);display:inline-flex;align-items:center;justify-content:center;padding:0 10px;background:var(--uc-ai-secondary);border:0;border-radius:var(--uc-ai-radius-button);font-family:inherit;font-size:13px;line-height:20px;color:var(--uc-ai-secondary-foreground);cursor:pointer;white-space:nowrap;transition:background .15s ease,transform .14s var(--uc-ai-ease-out, ease)}@media(hover:hover)and (pointer:fine){.chip:hover{background:var(--uc-ai-secondary-hover)}}.chip:active{background:var(--uc-ai-secondary-hover);transform:scale(.97)}.chip:disabled{opacity:.5;cursor:not-allowed}@media(prefers-reduced-motion:reduce){.chip{transition-property:background}.chip:active{transform:none}}";
1720
+ var or = Object.defineProperty, ar = Object.getOwnPropertyDescriptor, K = (t, e, i, r) => {
1721
+ for (var s = r > 1 ? void 0 : r ? ar(e, i) : e, o = t.length - 1, a; o >= 0; o--)
1722
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
1723
+ return r && s && or(e, i, s), s;
1724
+ };
1725
+ let P = class extends j {
1726
+ constructor() {
1727
+ super(...arguments), this.mode = "generate", this.presets = null, this.busy = !1, this.labelText = "Quick prompts";
1728
+ }
1729
+ firstUpdated() {
1730
+ typeof ResizeObserver == "function" && this._rowEl && (this._resizeObserver = new ResizeObserver(() => this._updateFades()), this._resizeObserver.observe(this._rowEl)), this._updateFades();
1731
+ }
1732
+ updated() {
1733
+ this._updateFades();
1734
+ }
1735
+ disconnectedCallback() {
1736
+ var t;
1737
+ super.disconnectedCallback(), (t = this._resizeObserver) == null || t.disconnect();
1738
+ }
1739
+ /**
1740
+ * Show an edge fade only when there's more content to scroll toward. The fades
1741
+ * are toggled imperatively (not via reactive state): they're derived from
1742
+ * post-layout measurements and re-checked from `updated()`, so routing them
1743
+ * through `@state` would re-schedule an update from within the update cycle.
1744
+ */
1745
+ _updateFades() {
1746
+ const t = this._rowEl;
1747
+ if (!t) return;
1748
+ const e = t.scrollWidth - t.clientWidth, i = t.scrollLeft;
1749
+ t.classList.toggle("fade-left", i > 1), t.classList.toggle("fade-right", i < e - 1);
1750
+ }
1751
+ /** Let a vertical wheel scroll the chips horizontally when they overflow. */
1752
+ _onWheel(t) {
1753
+ const e = this._rowEl;
1754
+ !e || e.scrollWidth <= e.clientWidth || Math.abs(t.deltaY) <= Math.abs(t.deltaX) || (e.scrollLeft += t.deltaY, t.preventDefault());
1755
+ }
1756
+ _select(t) {
1757
+ this.dispatchEvent(
1758
+ new CustomEvent("uc:select", { detail: { preset: t }, bubbles: !0, composed: !0 })
1759
+ );
1760
+ }
1761
+ render() {
1762
+ const t = this.presets ?? fe[this.mode].presets;
1763
+ return f`
1764
+ <div
1765
+ class="row"
1766
+ role="toolbar"
1767
+ aria-label="${this.labelText}"
1768
+ @scroll=${this._updateFades}
1769
+ @wheel=${this._onWheel}
1770
+ >
1771
+ ${t.map(
1772
+ (e) => f`
1773
+ <button type="button" class="chip" @click=${() => this._select(e)} ?disabled=${this.busy}>
1774
+ ${e.label}
1775
+ </button>
1776
+ `
1777
+ )}
1778
+ </div>
1779
+ `;
1780
+ }
1781
+ };
1782
+ P.styles = B(sr);
1783
+ K([
1784
+ c()
1785
+ ], P.prototype, "mode", 2);
1786
+ K([
1787
+ c({ attribute: !1 })
1788
+ ], P.prototype, "presets", 2);
1789
+ K([
1790
+ c({ type: Boolean })
1791
+ ], P.prototype, "busy", 2);
1792
+ K([
1793
+ c({ attribute: "aria-label-text" })
1794
+ ], P.prototype, "labelText", 2);
1795
+ K([
1796
+ F(".row")
1797
+ ], P.prototype, "_rowEl", 2);
1798
+ P = K([
1799
+ G("uc-ai-chips")
1800
+ ], P);
1801
+ const be = 8, nr = `#version 300 es
1802
+ precision highp float;
1803
+ precision highp int;
1804
+ in vec2 aCorner; // unit quad corner, -0.5..0.5
1805
+ in float aClip; // per-instance frame clip, 0..1
1806
+ uniform vec2 uResolution;
1807
+ uniform float uCols;
1808
+ uniform vec2 uOffset;
1809
+ uniform float uCell;
1810
+ uniform float uBaseRadius;
1811
+ uniform float uFullHalf;
1812
+ uniform float uEnv;
1813
+ uniform float uShimMix;
1814
+ uniform int uMask;
1815
+ uniform int uGenerating;
1816
+ uniform float uMinScale;
1817
+ uniform float uPeakScale;
1818
+ uniform float uIdleScale;
1819
+ uniform int uEpiCount;
1820
+ uniform vec2 uEpis[${be}];
1821
+ uniform float uEpiRadius;
1822
+ uniform float uEpiFalloff;
1823
+ uniform float uColorA;
1824
+ uniform float uFalloffWarp; // bends the distance field (de-ring)
1825
+ uniform float uDither; // per-dot size dither
1826
+ out float vAlpha;
1827
+ out vec2 vLocalPx; // fragment offset from the dot centre, CSS px
1828
+ out float vHalf; // dot half-size, CSS px
1829
+
1830
+ float hash(float a, float b) { return fract(sin(a * 12.9898 + b * 78.233) * 43758.5453); }
1831
+
1832
+ float epiIntensity(vec2 p) {
1833
+ float best = 0.0;
1834
+ // Low-frequency warp of the distance field — dissolves ring banding.
1835
+ float k = uFalloffWarp > 0.0 ? (6.2831853 / (uEpiRadius * 0.7)) : 0.0;
1836
+ float warp = k > 0.0 ? uFalloffWarp * uEpiRadius * sin(p.x * k + 1.3) * cos(p.y * k * 0.9) : 0.0;
1837
+ for (int i = 0; i < ${be}; i++) {
1838
+ if (i >= uEpiCount) break;
1839
+ float d = max(0.0, distance(p, uEpis[i]) + warp);
1840
+ if (d >= uEpiRadius) continue;
1841
+ float t = 1.0 - d / uEpiRadius;
1842
+ float f = t * t * (3.0 - 2.0 * t); // smoothstep
1843
+ if (uEpiFalloff != 1.0) f = pow(f, uEpiFalloff);
1844
+ best = max(best, f);
1845
+ }
1846
+ return best;
1847
+ }
1848
+
1849
+ void main() {
1850
+ float col = mod(float(gl_InstanceID), uCols);
1851
+ float row = floor(float(gl_InstanceID) / uCols);
1852
+ vec2 center = uOffset + vec2(col, row) * uCell;
1853
+ float intensity = epiIntensity(center);
1854
+ // When masking, ignore the per-dot frame clip and let the scissor define the
1855
+ // frame edge instead: dots straddling the edge then poke in and cover it, so
1856
+ // the revealed image fills the frame exactly (no uncovered strip that pops in
1857
+ // when the grid hands off to the real <img>). The idle/shimmer grid keeps the
1858
+ // soft per-dot clip so stray dots never show outside the frame.
1859
+ float clipv = (uMask == 1) ? 1.0 : aClip;
1860
+
1861
+ // Per-dot size dither (scaled by intensity), breaking the size-wave's banding.
1862
+ float sizeDither = (hash(col, row) - 0.5) * uDither * intensity;
1863
+
1864
+ float halfSize;
1865
+ if (uMask == 1) {
1866
+ float wave = uMinScale + (uPeakScale - uMinScale) * intensity + sizeDither;
1867
+ float animated = (uGenerating == 1) ? wave : uMinScale;
1868
+ float smallHalf = uBaseRadius * animated;
1869
+ halfSize = (uFullHalf + uEnv * (smallHalf - uFullHalf)) * clipv;
1870
+ } else {
1871
+ float scale = uIdleScale;
1872
+ if (uShimMix > 0.0) {
1873
+ float wave = uMinScale + (uPeakScale - uMinScale) * intensity + sizeDither;
1874
+ scale += (wave - scale) * uShimMix;
1875
+ }
1876
+ halfSize = uBaseRadius * scale * clipv;
1877
+ }
1878
+
1879
+ if (halfSize <= 0.0) {
1880
+ gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // offscreen → culled
1881
+ vAlpha = 0.0;
1882
+ vLocalPx = vec2(0.0);
1883
+ vHalf = 0.0;
1884
+ return;
1885
+ }
1886
+
1887
+ // Expand the quad ~1px beyond the dot so the fragment can anti-alias the edge
1888
+ // sub-pixel — without this, hard quad edges snap to whole pixels and the
1889
+ // grow/shrink reveal looks stepped.
1890
+ float ext = halfSize + 1.0;
1891
+ vLocalPx = aCorner * (2.0 * ext);
1892
+ vHalf = halfSize;
1893
+ vec2 pos = center + aCorner * (2.0 * ext);
1894
+ vec2 ndc = (pos / uResolution) * 2.0 - 1.0;
1895
+ gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
1896
+
1897
+ vAlpha = (uMask == 1) ? 1.0 : uColorA;
1898
+ }`, lr = `#version 300 es
1899
+ precision highp float;
1900
+ precision highp int;
1901
+ in float vAlpha;
1902
+ in vec2 vLocalPx; // CSS px from the dot centre
1903
+ in float vHalf; // dot half-size, CSS px
1904
+ uniform vec3 uColorRGB;
1905
+ uniform int uMask;
1906
+ out vec4 frag;
1907
+ void main() {
1908
+ // Box signed distance, evaluated in CSS px, anti-aliased over ~1px of screen
1909
+ // space via fwidth — so size changes are sub-pixel-smooth (no stepping) while
1910
+ // a square at idle still reads crisp.
1911
+ vec2 d = abs(vLocalPx) - vec2(vHalf);
1912
+ float sd = min(max(d.x, d.y), 0.0) + length(max(d, vec2(0.0)));
1913
+ float aaw = max(fwidth(sd), 1e-4);
1914
+ float cov = clamp(0.5 - sd / aaw, 0.0, 1.0);
1915
+ vec3 rgb = (uMask == 1) ? vec3(1.0) : uColorRGB;
1916
+ frag = vec4(rgb * vAlpha * cov, vAlpha * cov); // premultiplied
1917
+ }`, cr = `#version 300 es
1918
+ precision highp float;
1919
+ in vec2 aQuad; // 0..1
1920
+ uniform vec2 uResolution;
1921
+ uniform vec4 uFrame; // left, top, right, bottom (CSS px)
1922
+ out vec2 vFramePx;
1923
+ void main() {
1924
+ vec2 px = mix(uFrame.xy, uFrame.zw, aQuad);
1925
+ vFramePx = px - uFrame.xy;
1926
+ vec2 ndc = (px / uResolution) * 2.0 - 1.0;
1927
+ gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
1928
+ }`, hr = `#version 300 es
1929
+ precision highp float;
1930
+ in vec2 vFramePx;
1931
+ uniform sampler2D uImage;
1932
+ uniform vec2 uFrameSize;
1933
+ uniform vec2 uImageSize;
1934
+ out vec4 frag;
1935
+ void main() {
1936
+ // object-fit: cover.
1937
+ float s = max(uFrameSize.x / uImageSize.x, uFrameSize.y / uImageSize.y);
1938
+ vec2 dsz = uImageSize * s;
1939
+ vec2 off = (uFrameSize - dsz) * 0.5;
1940
+ vec2 uv = (vFramePx - off) / dsz;
1941
+ frag = vec4(texture(uImage, uv).rgb, 1.0);
1942
+ }`;
1943
+ class Ce {
1944
+ constructor(e) {
1945
+ this._dotUniforms = {}, this._imgUniforms = {}, this._appliedW = 0, this._appliedH = 0, this._appliedScale = 0, this._texImage = null, this._texOk = !1, this._gl = e, this._dotProgram = this._link(nr, lr), this._imgProgram = this._link(cr, hr), this._cornerBuf = this._staticBuffer([-0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5]), this._quadBuf = this._staticBuffer([0, 0, 1, 0, 0, 1, 1, 1]), this._clipBuf = e.createBuffer(), this._dotVao = e.createVertexArray(), e.bindVertexArray(this._dotVao);
1946
+ const i = e.getAttribLocation(this._dotProgram, "aCorner");
1947
+ e.bindBuffer(e.ARRAY_BUFFER, this._cornerBuf), e.enableVertexAttribArray(i), e.vertexAttribPointer(i, 2, e.FLOAT, !1, 0, 0);
1948
+ const r = e.getAttribLocation(this._dotProgram, "aClip");
1949
+ e.bindBuffer(e.ARRAY_BUFFER, this._clipBuf), e.enableVertexAttribArray(r), e.vertexAttribPointer(r, 1, e.FLOAT, !1, 0, 0), e.vertexAttribDivisor(r, 1), e.bindVertexArray(null), this._imgVao = e.createVertexArray(), e.bindVertexArray(this._imgVao);
1950
+ const s = e.getAttribLocation(this._imgProgram, "aQuad");
1951
+ e.bindBuffer(e.ARRAY_BUFFER, this._quadBuf), e.enableVertexAttribArray(s), e.vertexAttribPointer(s, 2, e.FLOAT, !1, 0, 0), e.bindVertexArray(null);
1952
+ for (const o of [
1953
+ "uResolution",
1954
+ "uCols",
1955
+ "uOffset",
1956
+ "uCell",
1957
+ "uBaseRadius",
1958
+ "uFullHalf",
1959
+ "uEnv",
1960
+ "uShimMix",
1961
+ "uMask",
1962
+ "uGenerating",
1963
+ "uMinScale",
1964
+ "uPeakScale",
1965
+ "uIdleScale",
1966
+ "uEpiCount",
1967
+ "uEpis",
1968
+ "uEpiRadius",
1969
+ "uEpiFalloff",
1970
+ "uColorA",
1971
+ "uColorRGB",
1972
+ "uFalloffWarp",
1973
+ "uDither"
1974
+ ])
1975
+ this._dotUniforms[o] = e.getUniformLocation(this._dotProgram, o);
1976
+ for (const o of ["uResolution", "uFrame", "uImage", "uFrameSize", "uImageSize"])
1977
+ this._imgUniforms[o] = e.getUniformLocation(this._imgProgram, o);
1978
+ this._texture = e.createTexture(), e.bindTexture(e.TEXTURE_2D, this._texture), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR), e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL, !1), e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1);
1979
+ }
1980
+ /** Create a renderer on `canvas`, or null if WebGL2 / compilation is unavailable. */
1981
+ static create(e) {
1982
+ let i = null;
1983
+ try {
1984
+ i = e.getContext("webgl2", {
1985
+ premultipliedAlpha: !0,
1986
+ antialias: !1,
1987
+ alpha: !0,
1988
+ preserveDrawingBuffer: !0
1989
+ });
1990
+ } catch {
1991
+ return null;
1992
+ }
1993
+ if (!i) return null;
1994
+ try {
1995
+ return new Ce(i);
1996
+ } catch (r) {
1997
+ return typeof console < "u" && console.warn("[dot-grid] WebGL init failed, using 2D:", r), null;
1998
+ }
1999
+ }
2000
+ /** Upload (or clear) the image used for masking. Cross-origin images need CORS;
2001
+ * if the upload taints/fails the renderer just skips the image pass. */
2002
+ setImage(e) {
2003
+ const i = this._gl;
2004
+ if (this._texImage = e, this._texOk = !1, !(!e || !e.complete || e.naturalWidth === 0)) {
2005
+ i.bindTexture(i.TEXTURE_2D, this._texture);
2006
+ try {
2007
+ i.texImage2D(i.TEXTURE_2D, 0, i.RGBA, i.RGBA, i.UNSIGNED_BYTE, e), this._texOk = !0;
2008
+ } catch {
2009
+ this._texOk = !1;
2010
+ }
2011
+ }
2012
+ }
2013
+ /** Whether the current image was uploaded successfully (CORS-clean). */
2014
+ get hasImage() {
2015
+ return this._texOk;
2016
+ }
2017
+ render(e) {
2018
+ const i = this._gl;
2019
+ this._resize(e.cssW, e.cssH, e.scale), i.disable(i.SCISSOR_TEST), i.clearColor(0, 0, 0, 0), i.clear(i.COLOR_BUFFER_BIT);
2020
+ const r = e.cols * e.rows;
2021
+ if (r <= 0) return;
2022
+ if (e.mask) {
2023
+ const o = e.scale, a = Math.round(e.frameLeft * o), n = Math.round((e.cssH - e.frameBottom) * o), l = Math.round((e.frameRight - e.frameLeft) * o), h = Math.round((e.frameBottom - e.frameTop) * o);
2024
+ i.enable(i.SCISSOR_TEST), i.scissor(a, n, Math.max(0, l), Math.max(0, h));
2025
+ }
2026
+ i.bindBuffer(i.ARRAY_BUFFER, this._clipBuf), i.bufferData(i.ARRAY_BUFFER, e.clip, i.DYNAMIC_DRAW), i.enable(i.BLEND), i.blendFunc(i.ONE, i.ONE_MINUS_SRC_ALPHA), i.useProgram(this._dotProgram), i.bindVertexArray(this._dotVao);
2027
+ const s = this._dotUniforms;
2028
+ if (i.uniform2f(s.uResolution, e.cssW, e.cssH), i.uniform1f(s.uCols, e.cols), i.uniform2f(s.uOffset, e.offsetX, e.offsetY), i.uniform1f(s.uCell, e.cell), i.uniform1f(s.uBaseRadius, e.baseRadius), i.uniform1f(s.uFullHalf, e.fullHalf), i.uniform1f(s.uEnv, e.env), i.uniform1f(s.uShimMix, e.shimMix), i.uniform1i(s.uMask, e.mask ? 1 : 0), i.uniform1i(s.uGenerating, e.generating ? 1 : 0), i.uniform1f(s.uMinScale, e.minScale), i.uniform1f(s.uPeakScale, e.peakScale), i.uniform1f(s.uIdleScale, e.idleScale), i.uniform1i(s.uEpiCount, Math.min(e.epiCount, be)), i.uniform2fv(s.uEpis, e.epis), i.uniform1f(s.uEpiRadius, e.epiRadius), i.uniform1f(s.uEpiFalloff, e.epiFalloff), i.uniform1f(s.uColorA, e.color[3]), i.uniform3f(s.uColorRGB, e.color[0], e.color[1], e.color[2]), i.uniform1f(s.uFalloffWarp, e.falloffWarp), i.uniform1f(s.uDither, e.dither), i.drawArraysInstanced(i.TRIANGLE_STRIP, 0, 4, r), e.mask && this._texOk && this._texImage) {
2029
+ i.blendFunc(i.DST_ALPHA, i.ZERO), i.useProgram(this._imgProgram), i.bindVertexArray(this._imgVao);
2030
+ const o = this._imgUniforms;
2031
+ i.uniform2f(o.uResolution, e.cssW, e.cssH), i.uniform4f(o.uFrame, e.frameLeft, e.frameTop, e.frameRight, e.frameBottom), i.uniform2f(o.uFrameSize, e.frameRight - e.frameLeft, e.frameBottom - e.frameTop), i.uniform2f(o.uImageSize, this._texImage.naturalWidth, this._texImage.naturalHeight), i.activeTexture(i.TEXTURE0), i.bindTexture(i.TEXTURE_2D, this._texture), i.uniform1i(o.uImage, 0), i.drawArrays(i.TRIANGLE_STRIP, 0, 4);
2032
+ }
2033
+ i.disable(i.SCISSOR_TEST), i.bindVertexArray(null);
2034
+ }
2035
+ dispose() {
2036
+ var i;
2037
+ const e = this._gl;
2038
+ e.deleteProgram(this._dotProgram), e.deleteProgram(this._imgProgram), e.deleteBuffer(this._cornerBuf), e.deleteBuffer(this._quadBuf), e.deleteBuffer(this._clipBuf), e.deleteVertexArray(this._dotVao), e.deleteVertexArray(this._imgVao), e.deleteTexture(this._texture), (i = e.getExtension("WEBGL_lose_context")) == null || i.loseContext();
2039
+ }
2040
+ _resize(e, i, r) {
2041
+ if (e === this._appliedW && i === this._appliedH && r === this._appliedScale) return;
2042
+ const s = this._gl;
2043
+ s.canvas.width = Math.round(e * r), s.canvas.height = Math.round(i * r), s.canvas.style.width = `${e}px`, s.canvas.style.height = `${i}px`, s.viewport(0, 0, s.canvas.width, s.canvas.height), this._appliedW = e, this._appliedH = i, this._appliedScale = r;
2044
+ }
2045
+ _staticBuffer(e) {
2046
+ const i = this._gl, r = i.createBuffer();
2047
+ return i.bindBuffer(i.ARRAY_BUFFER, r), i.bufferData(i.ARRAY_BUFFER, new Float32Array(e), i.STATIC_DRAW), r;
2048
+ }
2049
+ _link(e, i) {
2050
+ const r = this._gl, s = this._compile(r.VERTEX_SHADER, e), o = this._compile(r.FRAGMENT_SHADER, i), a = r.createProgram();
2051
+ if (r.attachShader(a, s), r.attachShader(a, o), r.linkProgram(a), r.deleteShader(s), r.deleteShader(o), !r.getProgramParameter(a, r.LINK_STATUS)) {
2052
+ const n = r.getProgramInfoLog(a);
2053
+ throw r.deleteProgram(a), new Error(`DotGrid GL link failed: ${n}`);
2054
+ }
2055
+ return a;
2056
+ }
2057
+ _compile(e, i) {
2058
+ const r = this._gl, s = r.createShader(e);
2059
+ if (r.shaderSource(s, i), r.compileShader(s), !r.getShaderParameter(s, r.COMPILE_STATUS)) {
2060
+ const o = r.getShaderInfoLog(s);
2061
+ throw r.deleteShader(s), new Error(`DotGrid GL compile failed: ${o}`);
2062
+ }
2063
+ return s;
2064
+ }
2065
+ }
2066
+ const ur = 1200, dr = 800, pr = 1.5, et = (t) => 1 - (1 - t) ** 3, fr = {
2067
+ cellSize: 6,
2068
+ dotRatio: 0.46,
2069
+ sizeScale: 1,
2070
+ minScale: 0.68,
2071
+ peakScale: 1.6,
2072
+ dither: 0.1,
2073
+ epiCount: 2,
2074
+ epiRadiusRatio: 0.4,
2075
+ epiSpeed: 0.54,
2076
+ epiWander: 0.115,
2077
+ epiFalloff: 1.5,
2078
+ falloffWarp: 0.12,
2079
+ idleScale: 0.9,
2080
+ maxDpr: 3,
2081
+ edgeTau: 80,
2082
+ enterMs: 380,
2083
+ exitMs: 420,
2084
+ shimEnterMs: 450,
2085
+ shimExitMs: 450
2086
+ };
2087
+ class mr {
2088
+ constructor(e, i) {
2089
+ this._refs = null, this._ctx = null, this._gl = null, this._glImageEl = null, this._glImageReady = !1, this._cfg = { ...fr }, this._sizeMul = 1, this._dotColor = "rgba(0, 0, 0, 0.16)", this._dotColorRGBA = [0, 0, 0, 0.16], this._w = 0, this._h = 0, this._cols = 0, this._rows = 0, this._offsetX = 0, this._offsetY = 0, this._epiRadius = 1, this._appliedScale = 0, this._clip = new Float32Array(0), this._env = 0, this._envFrom = 0, this._envTo = 0, this._envStart = 0, this._envDur = 0, this._envAnimating = !1, this._shimMix = 0, this._shimFrom = 0, this._shimTo = 0, this._shimStart = 0, this._shimDur = 0, this._shimAnimating = !1, this._exitPending = !1, this._prevShim = !1, this._opacityManual = !1, this._hiddenImage = null, this._rafId = null, this._lastTime = 0, this._state = { shimmering: !1, empty: !0, generating: !1 }, this._epis = [], this._onThemeChange = () => {
2090
+ this.refreshColor();
2091
+ }, this._rectCache = null, this._glEpis = new Float32Array(16), this._tick = (r) => {
2092
+ const s = this._lastTime ? Math.min(64, r - this._lastTime) : 16;
2093
+ if (this._lastTime = r, this._rectCache = this._frameRect(), this._envAnimating) {
2094
+ const a = Math.min(1, (r - this._envStart) / this._envDur);
2095
+ this._env = this._envFrom + (this._envTo - this._envFrom) * et(a), a >= 1 && (this._env = this._envTo, this._envAnimating = !1);
2096
+ }
2097
+ if (this._shimAnimating) {
2098
+ const a = Math.min(1, (r - this._shimStart) / this._shimDur);
2099
+ this._shimMix = this._shimFrom + (this._shimTo - this._shimFrom) * et(a), a >= 1 && (this._shimMix = this._shimTo, this._shimAnimating = !1);
2100
+ }
2101
+ this._state.generating && !this._reduceMotion && this._moveEpicenters(s);
2102
+ const o = this._followFrame(s);
2103
+ this._draw(), this._rectCache = null, this._state.shimmering || this._envAnimating || this._shimAnimating || o ? this._rafId = requestAnimationFrame(this._tick) : (this._rafId = null, this._lastTime = 0);
2104
+ }, e.addController(this), i && (this._cfg = { ...this._cfg, ...i }), this._reduceMotion = typeof window < "u" && typeof window.matchMedia == "function" ? window.matchMedia("(prefers-reduced-motion: reduce)").matches : !1;
2105
+ }
2106
+ /** True when either backend can paint. */
2107
+ get _canDraw() {
2108
+ return !!this._ctx || !!this._gl;
2109
+ }
2110
+ /** Dot half-size in px. A getter so live config tweaks apply. */
2111
+ get _baseRadius() {
2112
+ return this._cfg.cellSize * this._cfg.dotRatio / 2;
2113
+ }
2114
+ /** Canvas-size multiplier: ratio^sizeScale, where ratio = √(area / reference).
2115
+ * Exactly 1 at the reference size; sizeScale is the strength (0 = off, 1 =
2116
+ * proportional, >1 exaggerates, <0 inverts). Always positive, so it never
2117
+ * produces a negative radius/speed however far it's pushed. */
2118
+ _computeSizeMul() {
2119
+ return this._w <= 0 || this._h <= 0 ? 1 : Math.sqrt(this._w * this._h / (ur * dr)) ** this._cfg.sizeScale;
2120
+ }
2121
+ /** Wire the painter to the canvas's rendered elements. */
2122
+ attach(e) {
2123
+ if (this._refs = e, this._cfg.useWebgl !== !1 && (this._gl = Ce.create(e.surface)), this._gl || (this._ctx = e.surface.getContext("2d")), !!this._canDraw) {
2124
+ if (this._readDotColor(), typeof ResizeObserver == "function" && (this._resizeObserver = new ResizeObserver(() => {
2125
+ this._resize(), this.sync(this._state);
2126
+ }), this._resizeObserver.observe(e.viewport), this._frameObserver = new ResizeObserver(() => this._ensureLoop()), this._frameObserver.observe(e.frame)), typeof window < "u" && typeof window.matchMedia == "function" && (this._schemeMql = window.matchMedia("(prefers-color-scheme: dark)"), this._schemeMql.addEventListener("change", this._onThemeChange)), typeof MutationObserver == "function" && typeof document < "u") {
2127
+ this._themeObserver = new MutationObserver(this._onThemeChange);
2128
+ for (const i of [document.documentElement, document.body])
2129
+ i && this._themeObserver.observe(i, { attributes: !0, attributeFilter: ["class", "style", "data-theme"] });
2130
+ }
2131
+ this._resize(), this.sync(this._state);
2132
+ }
2133
+ }
2134
+ hostDisconnected() {
2135
+ var e, i, r, s, o;
2136
+ (e = this._resizeObserver) == null || e.disconnect(), (i = this._frameObserver) == null || i.disconnect(), (r = this._themeObserver) == null || r.disconnect(), (s = this._schemeMql) == null || s.removeEventListener("change", this._onThemeChange), this._rafId !== null && cancelAnimationFrame(this._rafId), this._rafId = null, (o = this._gl) == null || o.dispose(), this._gl = null;
2137
+ }
2138
+ /** Notify the painter that the result image finished loading. */
2139
+ onImageLoad() {
2140
+ this._glImageReady = !1, this._tryStartExit(), this._ensureLoop();
2141
+ }
2142
+ /** Re-read the theme-driven overlay colour (e.g. after a theme switch). */
2143
+ refreshColor() {
2144
+ this._readDotColor(), this._rafId === null && this._draw();
2145
+ }
2146
+ /**
2147
+ * Cancel any in-flight or pending cover/reveal and snap to the settled state —
2148
+ * the revealed image (or the idle grid when empty). Used when the tab regains
2149
+ * visibility: background-tab RAF/timer throttling can otherwise leave a reveal
2150
+ * envelope frozen mid-play (or a cover armed), which would surface as a
2151
+ * spurious shimmer on return even though nothing is generating.
2152
+ */
2153
+ settle() {
2154
+ this._canDraw && (this._rafId !== null && (cancelAnimationFrame(this._rafId), this._rafId = null, this._lastTime = 0), this._exitPending = !1, this._envAnimating = !1, this._shimAnimating = !1, this._env = 0, this._shimMix = 0, this._prevShim = !1, this._showHiddenImage(), this._draw());
2155
+ }
2156
+ /**
2157
+ * Reconcile to a new visual state. Drives the enter/exit envelopes off the
2158
+ * shimmer transition, mirroring the prototype's `syncProgress`.
2159
+ */
2160
+ sync(e) {
2161
+ if (this._state = e, !this._canDraw) return;
2162
+ const i = e.shimmering;
2163
+ i && !this._prevShim ? (this._exitPending = !1, this._initEpicenters(), this._hasImage() ? this._startEnv(1, this._cfg.enterMs) : (this._env = 1, this._envAnimating = !1, this._startShimMix(1, this._cfg.shimEnterMs))) : !i && this._prevShim && (this._hasImage() ? (this._env = 1, this._startEnv(0, this._cfg.exitMs), this._shimMix = 0) : e.empty ? (this._env = 0, this._envAnimating = !1, this._startShimMix(0, this._cfg.shimExitMs)) : this._exitPending = !0), this._prevShim = i, i || this._envAnimating || this._shimAnimating ? this._ensureLoop() : this._rafId === null && this._draw();
2164
+ }
2165
+ /** Merge live {@link ShimmerConfig} (host-supplied; the shimmer lab uses it for
2166
+ * slider tweaks). Re-applies layout-affecting params when already attached.
2167
+ * @internal */
2168
+ setConfig(e) {
2169
+ e && (this._cfg = { ...this._cfg, ...e }, this._canDraw && this.recalibrate());
2170
+ }
2171
+ /** Re-apply layout-affecting params (grid spacing, backing scale, epicenter
2172
+ * count) after a config change. Purely dynamic params are picked up by the
2173
+ * running animation frame. */
2174
+ recalibrate() {
2175
+ this._canDraw && (this._resize(), this._epis.length !== this._cfg.epiCount && this._initEpicenters(), this._rafId === null && this._draw());
2176
+ }
2177
+ /** Hard reset to the static initial (no-image) grid (used by "Start over"). */
2178
+ reset() {
2179
+ this._env = 0, this._envAnimating = !1, this._shimMix = 0, this._shimAnimating = !1, this._exitPending = !1, this._prevShim = !1, this._epis.length = 0, this._state = { shimmering: !1, empty: !0, generating: !1 }, this._restoreOpacity(), this._canDraw && (this._snapClip(), this._draw());
2180
+ }
2181
+ _now() {
2182
+ return typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now();
2183
+ }
2184
+ _readDotColor() {
2185
+ if (!this._refs) return;
2186
+ const e = getComputedStyle(this._refs.surface).color;
2187
+ e && (this._dotColor = e, this._dotColorRGBA = this._parseColor(e));
2188
+ }
2189
+ /** Resolve any CSS colour string to 0..1 RGBA via a 1×1 scratch context. */
2190
+ _parseColor(e) {
2191
+ if (this._scratch2d === void 0) {
2192
+ const s = document.createElement("canvas");
2193
+ s.width = s.height = 1, this._scratch2d = s.getContext("2d", { willReadFrequently: !0 });
2194
+ }
2195
+ const i = this._scratch2d;
2196
+ if (!i) return this._dotColorRGBA;
2197
+ i.clearRect(0, 0, 1, 1), i.fillStyle = "#000", i.fillStyle = e, i.fillRect(0, 0, 1, 1);
2198
+ const r = i.getImageData(0, 0, 1, 1).data;
2199
+ return [r[0] / 255, r[1] / 255, r[2] / 255, r[3] / 255];
2200
+ }
2201
+ _hasImage() {
2202
+ var i;
2203
+ const e = ((i = this._refs) == null ? void 0 : i.getImage()) ?? null;
2204
+ return !!e && !!e.getAttribute("src") && e.complete && e.naturalWidth > 0;
2205
+ }
2206
+ /** The grid masks the image while shimmering and during the reveal envelope. */
2207
+ _maskingImage() {
2208
+ return this._hasImage() && !this._state.empty && (this._state.shimmering || this._env > 1e-3);
2209
+ }
2210
+ _startEnv(e, i) {
2211
+ if (i <= 0 || this._reduceMotion) {
2212
+ this._env = e, this._envTo = e, this._envAnimating = !1;
2213
+ return;
2214
+ }
2215
+ this._envFrom = this._env, this._envTo = e, this._envStart = this._now(), this._envDur = i, this._envAnimating = !0, this._ensureLoop();
2216
+ }
2217
+ _startShimMix(e, i) {
2218
+ if (i <= 0 || this._reduceMotion) {
2219
+ this._shimMix = e, this._shimAnimating = !1;
2220
+ return;
2221
+ }
2222
+ this._shimFrom = this._shimMix, this._shimTo = e, this._shimStart = this._now(), this._shimDur = i, this._shimAnimating = !0, this._ensureLoop();
2223
+ }
2224
+ /** Frame rectangle in viewport coordinates, read from the *live* layout. */
2225
+ _frameRect() {
2226
+ const e = this._refs, i = e.frame.getBoundingClientRect(), r = e.viewport.getBoundingClientRect(), s = i.left - r.left, o = i.top - r.top;
2227
+ return { left: s, top: o, right: s + i.width, bottom: o + i.height };
2228
+ }
2229
+ /** The frame rect, reusing the per-tick cache when one is active. */
2230
+ _liveRect() {
2231
+ return this._rectCache ?? this._frameRect();
2232
+ }
2233
+ /** Epicentre falloff radius for the live frame. Based on the frame's geometric
2234
+ * mean √(w·h) — a square-equivalent size — rather than its width, so the
2235
+ * spotlight stays balanced on portrait frames (a narrow width would otherwise
2236
+ * shrink it). Stays a constant *relative* fraction of the frame on any AR. */
2237
+ _epiRadiusFor(e) {
2238
+ const i = Math.max(0, e.right - e.left), r = Math.max(0, e.bottom - e.top);
2239
+ return Math.sqrt(i * r) * this._cfg.epiRadiusRatio || 1;
2240
+ }
2241
+ _inFrame(e, i, r) {
2242
+ return e - this._baseRadius >= r.left && e + this._baseRadius <= r.right && i - this._baseRadius >= r.top && i + this._baseRadius <= r.bottom;
2243
+ }
2244
+ _snapClip() {
2245
+ const e = this._frameRect(), i = this._cfg.cellSize;
2246
+ let r = 0;
2247
+ for (let s = 0; s < this._rows; s++) {
2248
+ const o = this._offsetY + s * i;
2249
+ for (let a = 0; a < this._cols; a++, r++)
2250
+ this._clip[r] = this._inFrame(this._offsetX + a * i, o, e) ? 1 : 0;
2251
+ }
2252
+ }
2253
+ /** Ease the mask toward the live frame. Returns true while still settling. */
2254
+ _followFrame(e) {
2255
+ const i = this._liveRect(), r = this._cfg.cellSize, s = this._reduceMotion ? 1 : 1 - Math.exp(-e / this._cfg.edgeTau);
2256
+ let o = !1, a = 0;
2257
+ for (let n = 0; n < this._rows; n++) {
2258
+ const l = this._offsetY + n * r;
2259
+ for (let h = 0; h < this._cols; h++, a++) {
2260
+ const p = this._inFrame(this._offsetX + h * r, l, i) ? 1 : 0;
2261
+ let u = this._clip[a] + (p - this._clip[a]) * s;
2262
+ Math.abs(p - u) < 2e-3 ? u = p : o = !0, this._clip[a] = u;
2263
+ }
2264
+ }
2265
+ return o;
2266
+ }
2267
+ _allocate() {
2268
+ const e = this._cfg.cellSize;
2269
+ this._cols = Math.max(1, Math.round(this._w / e)), this._rows = Math.max(1, Math.round(this._h / e)), this._offsetX = (this._w - (this._cols - 1) * e) / 2, this._offsetY = (this._h - (this._rows - 1) * e) / 2, this._clip = new Float32Array(this._cols * this._rows), this._snapClip();
2270
+ }
2271
+ /** Backing-store density: the device pixel ratio, capped at
2272
+ * {@link ShimmerConfig.maxDpr}. Rendering 1:1 with the device keeps the crisp
2273
+ * flat-alpha squares sharp. The animated 2D path is additionally capped at
2274
+ * {@link MAX_ANIMATED_DPR} so per-frame raster stays cheap on hi-dpi. */
2275
+ _scale(e = !1) {
2276
+ const i = Math.min(window.devicePixelRatio || 1, this._cfg.maxDpr);
2277
+ return e ? Math.min(i, pr) : i;
2278
+ }
2279
+ /** Size the backing store to `scale`× the viewport. Note: setting width/height
2280
+ * clears the canvas and resets the context, so the transform is re-applied. */
2281
+ _applyBacking(e) {
2282
+ const i = this._refs, r = this._ctx;
2283
+ !i || !r || (i.surface.width = Math.round(this._w * e), i.surface.height = Math.round(this._h * e), i.surface.style.width = `${this._w}px`, i.surface.style.height = `${this._h}px`, r.setTransform(e, 0, 0, e, 0, 0), this._appliedScale = e);
2284
+ }
2285
+ /** Switch backing density when the mode flips (crisp squares ↔ smooth bells).
2286
+ * The grid layout is unchanged, so the eased clip state is preserved. */
2287
+ _ensureScale(e) {
2288
+ const i = this._scale(e);
2289
+ i !== this._appliedScale && this._applyBacking(i);
2290
+ }
2291
+ _resize() {
2292
+ const e = this._refs;
2293
+ !e || !this._canDraw || (this._w = e.viewport.clientWidth, this._h = e.viewport.clientHeight, !(this._w <= 0 || this._h <= 0) && (this._sizeMul = this._computeSizeMul(), this._allocate(), this._ctx ? this._applyBacking(this._scale()) : this._appliedScale = this._scale()));
2294
+ }
2295
+ // ----- Epicentre shimmer -----
2296
+ _initEpicenters() {
2297
+ const e = this._frameRect();
2298
+ this._epis.length = 0;
2299
+ const i = this._cfg.epiSpeed * this._sizeMul;
2300
+ for (let r = 0; r < this._cfg.epiCount; r++) {
2301
+ const s = Math.random() * Math.PI * 2;
2302
+ this._epis.push({
2303
+ x: e.left + Math.random() * (e.right - e.left),
2304
+ y: e.top + Math.random() * (e.bottom - e.top),
2305
+ vx: Math.cos(s) * i,
2306
+ vy: Math.sin(s) * i
2307
+ });
2308
+ }
2309
+ }
2310
+ _moveEpicenters(e) {
2311
+ this._epis.length === 0 && this._initEpicenters();
2312
+ const i = this._liveRect(), r = this._cfg.epiSpeed * this._sizeMul;
2313
+ for (const s of this._epis) {
2314
+ const o = Math.atan2(s.vy, s.vx) + (Math.random() - 0.5) * this._cfg.epiWander;
2315
+ s.vx = Math.cos(o) * r, s.vy = Math.sin(o) * r, s.x += s.vx * e, s.y += s.vy * e, s.x < i.left ? (s.x = i.left, s.vx = Math.abs(s.vx)) : s.x > i.right && (s.x = i.right, s.vx = -Math.abs(s.vx)), s.y < i.top ? (s.y = i.top, s.vy = Math.abs(s.vy)) : s.y > i.bottom && (s.y = i.bottom, s.vy = -Math.abs(s.vy));
2316
+ }
2317
+ }
2318
+ _epiIntensity(e, i) {
2319
+ let r = 0;
2320
+ const s = this._cfg.falloffWarp, o = s > 0 ? Math.PI * 2 / (this._epiRadius * 0.7 || 1) : 0, a = o > 0 ? s * this._epiRadius * Math.sin(e * o + 1.3) * Math.cos(i * o * 0.9) : 0, n = this._cfg.epiFalloff;
2321
+ for (const l of this._epis) {
2322
+ const h = Math.max(0, Math.hypot(e - l.x, i - l.y) + a);
2323
+ if (h >= this._epiRadius) continue;
2324
+ const p = 1 - h / this._epiRadius;
2325
+ let u = p * p * (3 - 2 * p);
2326
+ n !== 1 && (u = u ** n), u > r && (r = u);
2327
+ }
2328
+ return r;
2329
+ }
2330
+ _staticScale() {
2331
+ return this._cfg.idleScale;
2332
+ }
2333
+ /** Deterministic per-dot value in [0, 1) — a stable hash of the grid cell. */
2334
+ _hash(e, i) {
2335
+ const r = Math.sin(e * 12.9898 + i * 78.233) * 43758.5453;
2336
+ return r - Math.floor(r);
2337
+ }
2338
+ _shimmerScale(e, i, r, s) {
2339
+ const o = this._epiIntensity(r, s), { minScale: a, peakScale: n } = this._cfg, l = (this._hash(e, i) - 0.5) * this._cfg.dither * o;
2340
+ return a + (n - a) * o + l;
2341
+ }
2342
+ _drawCover(e) {
2343
+ var u;
2344
+ const i = this._ctx, r = (u = this._refs) == null ? void 0 : u.getImage();
2345
+ if (!r) return;
2346
+ const s = r.naturalWidth, o = r.naturalHeight;
2347
+ if (!s || !o) return;
2348
+ const a = e.right - e.left, n = e.bottom - e.top, l = Math.max(a / s, n / o), h = s * l, p = o * l;
2349
+ i.drawImage(r, e.left + (a - h) / 2, e.top + (n - p) / 2, h, p);
2350
+ }
2351
+ _setOpacity(e) {
2352
+ const i = this._refs;
2353
+ if (!i) return;
2354
+ const r = i.getImage();
2355
+ e ? (this._opacityManual || (i.surface.style.transition = "none", i.surface.style.opacity = "1", this._opacityManual = !0), r && r !== this._hiddenImage && (this._showHiddenImage(), r.style.transition = "none", r.style.opacity = "0", this._hiddenImage = r)) : (this._opacityManual && (i.surface.style.transition = "", i.surface.style.opacity = "", this._opacityManual = !1), this._showHiddenImage());
2356
+ }
2357
+ /** Restore the element we forced transparent (if it's still in the DOM). */
2358
+ _showHiddenImage() {
2359
+ const e = this._hiddenImage;
2360
+ e && (e.isConnected && (e.style.transition = "", e.style.opacity = "1"), this._hiddenImage = null);
2361
+ }
2362
+ _restoreOpacity() {
2363
+ const e = this._refs;
2364
+ this._opacityManual && e && (e.surface.style.transition = "", e.surface.style.opacity = "", this._opacityManual = !1), this._showHiddenImage();
2365
+ }
2366
+ _draw() {
2367
+ if (this._gl) {
2368
+ this._drawGL();
2369
+ return;
2370
+ }
2371
+ const e = this._ctx;
2372
+ if (!e || this._w <= 0 || this._h <= 0) return;
2373
+ const i = this._maskingImage();
2374
+ if (this._setOpacity(i), !(this._state.shimmering || this._state.empty || i)) return;
2375
+ const r = i || this._state.shimmering || this._envAnimating || this._shimAnimating;
2376
+ this._ensureScale(r), e.clearRect(0, 0, this._w, this._h);
2377
+ const s = this._liveRect();
2378
+ this._epiRadius = this._epiRadiusFor(s);
2379
+ const o = this._cfg.cellSize, a = o / 2;
2380
+ e.fillStyle = i ? "#000" : this._dotColor;
2381
+ const n = typeof Path2D == "function" ? new Path2D() : null;
2382
+ let l = 0;
2383
+ for (let h = 0; h < this._rows; h++) {
2384
+ const p = this._offsetY + h * o;
2385
+ for (let u = 0; u < this._cols; u++, l++) {
2386
+ const _ = this._clip[l];
2387
+ if (_ <= 0) continue;
2388
+ const x = this._offsetX + u * o;
2389
+ let w;
2390
+ if (i) {
2391
+ const R = this._reduceMotion ? 1 : this._state.generating ? this._shimmerScale(u, h, x, p) : this._cfg.minScale, I = this._baseRadius * R;
2392
+ w = (a + this._env * (I - a)) * _;
2393
+ } else {
2394
+ let R = this._staticScale();
2395
+ if (!this._reduceMotion && this._shimMix > 0) {
2396
+ const I = this._shimmerScale(u, h, x, p);
2397
+ R += (I - R) * this._shimMix;
2398
+ }
2399
+ w = this._baseRadius * R * _;
2400
+ }
2401
+ if (w <= 0) continue;
2402
+ const $ = w * 2;
2403
+ n ? n.rect(x - w, p - w, $, $) : e.fillRect(x - w, p - w, $, $);
2404
+ }
2405
+ }
2406
+ n && e.fill(n), i && (e.globalCompositeOperation = "source-in", this._drawCover(s), e.globalCompositeOperation = "source-over");
2407
+ }
2408
+ /** WebGL render path — mirrors {@link _draw}'s orchestration, but the per-dot
2409
+ * size/brightness and the image mask are computed on the GPU. */
2410
+ _drawGL() {
2411
+ const e = this._gl, i = this._refs;
2412
+ if (!e || !i || this._w <= 0 || this._h <= 0) return;
2413
+ const r = this._maskingImage();
2414
+ if (this._setOpacity(r), !(this._state.shimmering || this._state.empty || r)) return;
2415
+ const s = this._liveRect();
2416
+ if (this._epiRadius = this._epiRadiusFor(s), r) {
2417
+ const l = i.getImage();
2418
+ (l !== this._glImageEl || l !== null && l.complete && !this._glImageReady) && (e.setImage(l && l.complete && l.naturalWidth > 0 ? l : null), this._glImageEl = l, this._glImageReady = e.hasImage);
2419
+ }
2420
+ const o = Math.min(this._epis.length, 8);
2421
+ for (let l = 0; l < o; l++)
2422
+ this._glEpis[l * 2] = this._epis[l].x, this._glEpis[l * 2 + 1] = this._epis[l].y;
2423
+ const a = this._cfg.cellSize, n = {
2424
+ cssW: this._w,
2425
+ cssH: this._h,
2426
+ scale: this._appliedScale || this._scale(),
2427
+ cols: this._cols,
2428
+ rows: this._rows,
2429
+ offsetX: this._offsetX,
2430
+ offsetY: this._offsetY,
2431
+ cell: a,
2432
+ baseRadius: this._baseRadius,
2433
+ fullHalf: a / 2,
2434
+ env: this._env,
2435
+ shimMix: this._shimMix,
2436
+ mask: r,
2437
+ // Reduced motion → uniform brightness (no roaming spotlight); the
2438
+ // epicentres are already frozen by _tick in that case.
2439
+ generating: this._state.generating && !this._reduceMotion,
2440
+ minScale: this._cfg.minScale,
2441
+ peakScale: this._cfg.peakScale,
2442
+ idleScale: this._cfg.idleScale,
2443
+ epis: this._glEpis,
2444
+ epiCount: o,
2445
+ epiRadius: this._epiRadius,
2446
+ epiFalloff: this._cfg.epiFalloff,
2447
+ falloffWarp: this._cfg.falloffWarp,
2448
+ dither: this._cfg.dither,
2449
+ color: this._dotColorRGBA,
2450
+ clip: this._clip,
2451
+ frameLeft: s.left,
2452
+ frameTop: s.top,
2453
+ frameRight: s.right,
2454
+ frameBottom: s.bottom
2455
+ };
2456
+ e.render(n);
2457
+ }
2458
+ _ensureLoop() {
2459
+ this._canDraw && this._rafId === null && (this._lastTime = 0, this._rafId = requestAnimationFrame(this._tick));
2460
+ }
2461
+ _tryStartExit() {
2462
+ this._exitPending && this._hasImage() && (this._exitPending = !1, this._env = 1, this._startEnv(0, this._cfg.exitMs));
2463
+ }
2464
+ }
2465
+ const _r = ":host{display:block;width:100%;height:100%;container-type:inline-size}.canvas{position:relative;width:100%;height:100%;min-height:240px;overflow:hidden}.canvas__bg{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--uc-ai-background)}.canvas__viewport{position:absolute;top:20px;right:20px;bottom:20px;left:20px;display:grid;place-items:center;pointer-events:none}.canvas__frame{position:relative;overflow:hidden}.canvas.is-ready .canvas__frame{transition:width .46s var(--uc-ai-ease-in-out, ease),height .46s var(--uc-ai-ease-in-out, ease)}.canvas__image{position:relative;z-index:1;width:100%;height:100%;display:block;object-fit:cover;transition:opacity .3s var(--uc-ai-ease-out, ease)}.canvas__under{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;width:100%;height:100%;display:block;object-fit:cover}.dot-grid{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;opacity:0;color:var(--uc-ai-dot-grid-color, color-mix(in srgb, currentColor 15%, transparent));transition:opacity .2s ease}.canvas.is-empty .dot-grid,.canvas.is-loading .dot-grid{opacity:1}.preload{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}.layer.full{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;object-fit:contain;z-index:4}.fullscreen-btn{position:absolute;top:12px;right:12px;z-index:5;display:grid;place-items:center;width:var(--uc-ai-button-size, 32px);height:var(--uc-ai-button-size, 32px);padding:0;border:0;border-radius:var(--uc-ai-radius-button, 8px);background:color-mix(in oklch,var(--uc-ai-background) 75%,transparent);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);color:var(--uc-ai-foreground);cursor:pointer;opacity:0;transition:opacity var(--uc-ai-transition, .2s ease),background var(--uc-ai-transition, .2s ease)}.fullscreen-btn svg{width:18px;height:18px}.canvas:hover .fullscreen-btn,.fullscreen-btn:focus-visible{opacity:1}.fullscreen-btn:hover{background:var(--uc-ai-background)}@media(hover:none){.fullscreen-btn{opacity:1}}.canvas:fullscreen{background:#000}.canvas:fullscreen .canvas__bg{background:#000}.error-state{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center;padding:16px;text-align:center;color:var(--uc-ai-muted-foreground);font-size:.875em;z-index:3}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(prefers-reduced-motion:reduce){.canvas__viewport,.canvas__frame,.canvas__image,.fullscreen-btn{transition:none}}";
2466
+ var gr = Object.defineProperty, vr = Object.getOwnPropertyDescriptor, y = (t, e, i, r) => {
2467
+ for (var s = r > 1 ? void 0 : r ? vr(e, i) : e, o = t.length - 1, a; o >= 0; o--)
2468
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
2469
+ return r && s && gr(e, i, s), s;
2470
+ };
2471
+ const br = 3 / 2, yr = 70;
2472
+ let g = class extends j {
2473
+ constructor() {
2474
+ super(...arguments), this.url = null, this.ratio = null, this.naturalRatio = null, this.busy = !1, this.alt = "", this.busyLabel = "", this.errorLabel = "", this.fullscreenLabel = "", this.exitFullscreenLabel = "", this.fullsizeUrl = null, this._displayedUrl = null, this._fadingUrl = null, this._failed = !1, this._frameReady = !1, this._fullscreen = !1, this._dotGrid = new mr(this), this._switchCovering = !1, this._seenUrls = /* @__PURE__ */ new Set(), this._instantSwap = !1, this._onVisibilityChange = () => {
2475
+ document.visibilityState !== "visible" || this.busy || !this._displayedUrl || (this._clearCoverTimer(), this._switchCovering = !1, this._dotGrid.settle());
2476
+ }, this._preloadedFullsizeUrl = null, this._onFullscreenKeydown = (t) => {
2477
+ t.key === "Escape" && document.fullscreenElement && (t.preventDefault(), t.stopPropagation(), document.exitFullscreen());
2478
+ };
2479
+ }
2480
+ connectedCallback() {
2481
+ super.connectedCallback(), document.addEventListener("visibilitychange", this._onVisibilityChange);
2482
+ }
2483
+ disconnectedCallback() {
2484
+ var t;
2485
+ super.disconnectedCallback(), (t = this._resizeObserver) == null || t.disconnect(), this._clearCoverTimer(), document.removeEventListener("keydown", this._onFullscreenKeydown, !0), document.removeEventListener("visibilitychange", this._onVisibilityChange);
2486
+ }
2487
+ firstUpdated() {
2488
+ const t = this._dotGridEl, e = this._viewportEl, i = this._frameEl;
2489
+ t && e && i && this._dotGrid.attach({ surface: t, viewport: e, frame: i, getImage: () => this._imageEl ?? null }), typeof ResizeObserver == "function" && e && (this._resizeObserver = new ResizeObserver(() => this._updateFrame()), this._resizeObserver.observe(e)), this._updateFrame(), requestAnimationFrame(() => {
2490
+ requestAnimationFrame(() => {
2491
+ this._frameReady = !0;
2492
+ });
2493
+ });
2494
+ }
2495
+ willUpdate(t) {
2496
+ t.has("shimmerConfig") && this._dotGrid.setConfig(this.shimmerConfig), t.has("url") && (this.url ? this.url !== this._displayedUrl && (this._failed = !1) : (this._displayedUrl = null, this._failed = !1));
2497
+ }
2498
+ updated(t) {
2499
+ const e = t.has("_displayedUrl");
2500
+ (t.has("ratio") || t.has("naturalRatio") || e) && this._updateFrame(), (t.has("busy") || t.has("url") || e) && (this._updateSwitchCover(t.has("busy")), this._syncGrid());
2501
+ }
2502
+ _syncGrid() {
2503
+ this._dotGrid.sync({
2504
+ // The grid covers during a generation (`busy`) and during a slow image
2505
+ // switch (`_switchCovering`), then materialises the result out of the dots.
2506
+ shimmering: this.busy || this._switchCovering,
2507
+ empty: this._displayedUrl == null,
2508
+ // Only a real generation wanders the epicenters; switches/reveals are a
2509
+ // uniform, ring-free growth.
2510
+ generating: this.busy
2511
+ });
2512
+ }
2513
+ /**
2514
+ * Gate the dot transition for a plain history/source switch: only cover with
2515
+ * dots if the new image is still loading after a short delay. A cached/instant
2516
+ * switch skips the transition and swaps directly (no glitchy dot flash).
2517
+ * Generations drive their own cover via `busy`, so they're left untouched.
2518
+ */
2519
+ _updateSwitchCover(t) {
2520
+ if (!(this.url != null && this.url !== this._displayedUrl && !this._failed)) {
2521
+ this._clearCoverTimer(), this._switchCovering = !1;
2522
+ return;
2523
+ }
2524
+ if (this.busy) {
2525
+ this._clearCoverTimer(), this._instantSwap = !1;
2526
+ return;
2527
+ }
2528
+ if (t) {
2529
+ this._clearCoverTimer(), this._instantSwap = !1, this._switchCovering = !0;
2530
+ return;
2531
+ }
2532
+ if (this.url != null && this._seenUrls.has(this.url)) {
2533
+ this._clearCoverTimer(), this._switchCovering = !1, this._instantSwap = !0;
2534
+ return;
2535
+ }
2536
+ this._instantSwap = !1, !(this._switchCovering || this._coverTimer != null) && (this._coverTimer = window.setTimeout(() => {
2537
+ this._coverTimer = void 0, this.url != null && this.url !== this._displayedUrl && !this._failed && !this.busy && !this._switchCovering && (this._switchCovering = !0, this._syncGrid());
2538
+ }, yr));
2539
+ }
2540
+ _clearCoverTimer() {
2541
+ this._coverTimer != null && (clearTimeout(this._coverTimer), this._coverTimer = void 0);
2542
+ }
2543
+ /** Reset the dot grid to its empty state — used when the editor starts over. */
2544
+ resetGrid() {
2545
+ this._dotGrid.reset();
2546
+ }
2547
+ _frameRatioValue() {
2548
+ if (this.ratio && this.ratio > 0) return this.ratio;
2549
+ if (this.naturalRatio && this.naturalRatio > 0) return this.naturalRatio;
2550
+ const t = this._imageEl;
2551
+ return t && t.naturalWidth > 0 && t.naturalHeight > 0 ? t.naturalWidth / t.naturalHeight : br;
2552
+ }
2553
+ /** Size the frame to the largest box of the chosen ratio that fits the viewport. */
2554
+ _updateFrame() {
2555
+ const t = this._viewportEl, e = this._frameEl;
2556
+ if (!t || !e) return;
2557
+ const i = t.clientWidth, r = t.clientHeight;
2558
+ if (!i || !r) return;
2559
+ const s = this._frameRatioValue();
2560
+ let o, a;
2561
+ i / r > s ? (a = r, o = a * s) : (o = i, a = o / s), e.style.width = `${Math.round(o)}px`, e.style.height = `${Math.round(a)}px`;
2562
+ }
2563
+ _onLoaded(t) {
2564
+ const e = t.currentTarget.getAttribute("src");
2565
+ if (!e || e !== this.url) return;
2566
+ const i = this._displayedUrl;
2567
+ this._instantSwap && i && i !== e && (this._fadingUrl = i), this._displayedUrl = e, this._failed = !1, this._seenUrls.add(e);
2568
+ }
2569
+ /**
2570
+ * The on-screen image finished decoding. Driving the reveal off the displayed
2571
+ * <img>'s own `load` (rather than the preload's `complete` at a microtask)
2572
+ * makes the dot-grid reveal fire reliably, even on a cold cache.
2573
+ */
2574
+ _onDisplayedLoad() {
2575
+ this._fadingUrl = null, this._updateFrame(), this._dotGrid.onImageLoad();
2576
+ }
2577
+ _onError() {
2578
+ this._failed = !0, this.dispatchEvent(new CustomEvent("uc:image-error", { detail: { url: this.url }, bubbles: !0, composed: !0 }));
2579
+ }
2580
+ /** Fullscreen is unavailable on some platforms (e.g. iPhone Safari). */
2581
+ get _fullscreenSupported() {
2582
+ var t;
2583
+ return document.fullscreenEnabled && typeof ((t = this._canvasEl) == null ? void 0 : t.requestFullscreen) == "function";
2584
+ }
2585
+ /** Warm the browser cache for the fullscreen rendition ahead of the click. */
2586
+ _preloadFullsize() {
2587
+ !this.fullsizeUrl || this.fullsizeUrl === this._preloadedFullsizeUrl || (this._preloadedFullsizeUrl = this.fullsizeUrl, new Image().src = this.fullsizeUrl);
2588
+ }
2589
+ _toggleFullscreen() {
2590
+ var t;
2591
+ document.fullscreenElement ? document.exitFullscreen() : (t = this._canvasEl) == null || t.requestFullscreen();
2592
+ }
2593
+ _onFullscreenChange() {
2594
+ this._fullscreen = document.fullscreenElement != null, this._fullscreen ? document.addEventListener("keydown", this._onFullscreenKeydown, !0) : document.removeEventListener("keydown", this._onFullscreenKeydown, !0);
2595
+ }
2596
+ render() {
2597
+ const t = this.url != null && this.url !== this._displayedUrl && !this._failed, e = this._displayedUrl == null, i = !e && !this._failed && !this.busy && this._fullscreenSupported, r = {
2598
+ canvas: !0,
2599
+ "is-empty": e,
2600
+ "is-loading": this.busy,
2601
+ "is-ready": this._frameReady
2602
+ };
2603
+ return f`
2604
+ <div class=${S(r)} @fullscreenchange=${this._onFullscreenChange}>
2605
+ <div class="canvas__bg"></div>
2606
+
2607
+ <div class="canvas__viewport">
2608
+ <div class="canvas__frame">
2609
+ ${// Previous image held underneath during an instant (cached) swap so
2610
+ // the frame never blanks for the frame it takes the new <img> to
2611
+ // paint; dropped on the new image's load.
2612
+ this._fadingUrl ? f`<img class="canvas__under" src="${this._fadingUrl}" alt="" aria-hidden="true" crossorigin="anonymous" />` : v}
2613
+ ${this._displayedUrl ? f`<img
2614
+ class="canvas__image"
2615
+ src="${this._displayedUrl}"
2616
+ alt="${this.alt || "AI image"}"
2617
+ decoding="async"
2618
+ crossorigin="anonymous"
2619
+ @load=${this._onDisplayedLoad}
2620
+ />` : v}
2621
+ </div>
2622
+ <canvas class="dot-grid" aria-hidden="true"></canvas>
2623
+ </div>
2624
+
2625
+ ${// Full-quality rendition overlays the preview while fullscreen.
2626
+ this._fullscreen && this.fullsizeUrl ? f`<img class="layer full" src="${this.fullsizeUrl}" alt="${this.alt || "AI image"}" decoding="async" />` : v}
2627
+ ${t ? f`<img
2628
+ class="preload"
2629
+ src="${this.url}"
2630
+ alt=""
2631
+ aria-hidden="true"
2632
+ decoding="async"
2633
+ crossorigin="anonymous"
2634
+ @load=${this._onLoaded}
2635
+ @error=${this._onError}
2636
+ />` : v}
2637
+ ${this._failed ? f`<div class="error-state" role="alert">${this.errorLabel || "Failed to load image"}</div>` : v}
2638
+ ${i ? f`
2639
+ <button
2640
+ type="button"
2641
+ class="fullscreen-btn"
2642
+ data-testid="fullscreen-btn"
2643
+ aria-label="${this._fullscreen ? this.exitFullscreenLabel : this.fullscreenLabel}"
2644
+ @mouseenter=${this._preloadFullsize}
2645
+ @focus=${this._preloadFullsize}
2646
+ @click=${this._toggleFullscreen}
2647
+ >
2648
+ ${te(this._fullscreen ? Ni : Di)}
2649
+ </button>
2650
+ ` : v}
2651
+ <span class="sr-only" role="status" aria-live="polite">${this.busy ? this.busyLabel : ""}</span>
2652
+ </div>
2653
+ `;
2654
+ }
2655
+ };
2656
+ g.styles = B(_r);
2657
+ y([
2658
+ c()
2659
+ ], g.prototype, "url", 2);
2660
+ y([
2661
+ c({ type: Number })
2662
+ ], g.prototype, "ratio", 2);
2663
+ y([
2664
+ c({ type: Number, attribute: "natural-ratio" })
2665
+ ], g.prototype, "naturalRatio", 2);
2666
+ y([
2667
+ c({ type: Boolean })
2668
+ ], g.prototype, "busy", 2);
2669
+ y([
2670
+ c()
2671
+ ], g.prototype, "alt", 2);
2672
+ y([
2673
+ c({ attribute: "busy-label" })
2674
+ ], g.prototype, "busyLabel", 2);
2675
+ y([
2676
+ c({ attribute: "error-label" })
2677
+ ], g.prototype, "errorLabel", 2);
2678
+ y([
2679
+ c({ attribute: "fullscreen-label" })
2680
+ ], g.prototype, "fullscreenLabel", 2);
2681
+ y([
2682
+ c({ attribute: "exit-fullscreen-label" })
2683
+ ], g.prototype, "exitFullscreenLabel", 2);
2684
+ y([
2685
+ c({ attribute: "fullsize-url" })
2686
+ ], g.prototype, "fullsizeUrl", 2);
2687
+ y([
2688
+ c({ attribute: !1 })
2689
+ ], g.prototype, "shimmerConfig", 2);
2690
+ y([
2691
+ C()
2692
+ ], g.prototype, "_displayedUrl", 2);
2693
+ y([
2694
+ C()
2695
+ ], g.prototype, "_fadingUrl", 2);
2696
+ y([
2697
+ C()
2698
+ ], g.prototype, "_failed", 2);
2699
+ y([
2700
+ C()
2701
+ ], g.prototype, "_frameReady", 2);
2702
+ y([
2703
+ C()
2704
+ ], g.prototype, "_fullscreen", 2);
2705
+ y([
2706
+ F(".canvas")
2707
+ ], g.prototype, "_canvasEl", 2);
2708
+ y([
2709
+ F(".canvas__viewport")
2710
+ ], g.prototype, "_viewportEl", 2);
2711
+ y([
2712
+ F(".canvas__frame")
2713
+ ], g.prototype, "_frameEl", 2);
2714
+ y([
2715
+ F(".canvas__image")
2716
+ ], g.prototype, "_imageEl", 2);
2717
+ y([
2718
+ F(".dot-grid")
2719
+ ], g.prototype, "_dotGridEl", 2);
2720
+ g = y([
2721
+ G("uc-ai-canvas")
2722
+ ], g);
2723
+ const wr = ":host{display:block;container-type:inline-size}.footer{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:var(--uc-ai-padding);background:transparent}.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:var(--uc-ai-button-size);padding:0 14px;border:0;border-radius:var(--uc-ai-radius-button);font-family:inherit;font-size:14px;font-weight:500;cursor:pointer;transition:background .15s ease,filter .15s ease,transform .14s var(--uc-ai-ease-out, ease)}.btn:active{transform:scale(.97)}.btn--ghost{background:var(--uc-ai-secondary);color:var(--uc-ai-secondary-foreground)}.btn--primary{background:var(--uc-ai-primary);color:var(--uc-ai-primary-foreground)}@media(hover:hover)and (pointer:fine){.btn--ghost:hover{background:var(--uc-ai-secondary-hover)}.btn--primary:hover{background:var(--uc-ai-primary-hover)}}.btn--primary:disabled{opacity:.5;cursor:not-allowed;background:var(--uc-ai-primary)}.btn svg{width:14px;height:14px}@media(prefers-reduced-motion:reduce){.btn{transition-property:background,filter}.btn:active{transform:none}}";
2724
+ var xr = Object.defineProperty, kr = Object.getOwnPropertyDescriptor, re = (t, e, i, r) => {
2725
+ for (var s = r > 1 ? void 0 : r ? kr(e, i) : e, o = t.length - 1, a; o >= 0; o--)
2726
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
2727
+ return r && s && xr(e, i, s), s;
2728
+ };
2729
+ let q = class extends j {
2730
+ constructor() {
2731
+ super(...arguments), this.cancelLabel = "", this.primaryLabel = "", this.primaryDisabled = !1;
2732
+ }
2733
+ _emitCancel() {
2734
+ this.dispatchEvent(new CustomEvent("uc:cancel", { bubbles: !0, composed: !0 }));
2735
+ }
2736
+ _emitPrimary() {
2737
+ this.dispatchEvent(new CustomEvent("uc:primary", { bubbles: !0, composed: !0 }));
2738
+ }
2739
+ render() {
2740
+ return f`
2741
+ <div class="footer">
2742
+ <button type="button" class="btn btn--ghost" @click=${this._emitCancel}>
2743
+ <span>${this.cancelLabel}</span>
2744
+ </button>
2745
+ <button
2746
+ type="button"
2747
+ class="btn btn--primary"
2748
+ @click=${this._emitPrimary}
2749
+ ?disabled=${this.primaryDisabled}
2750
+ >
2751
+ <span>${this.primaryLabel}</span>
2752
+ </button>
2753
+ </div>
2754
+ `;
2755
+ }
2756
+ };
2757
+ q.styles = B(wr);
2758
+ re([
2759
+ c({ attribute: "cancel-label" })
2760
+ ], q.prototype, "cancelLabel", 2);
2761
+ re([
2762
+ c({ attribute: "primary-label" })
2763
+ ], q.prototype, "primaryLabel", 2);
2764
+ re([
2765
+ c({ type: Boolean, attribute: "primary-disabled" })
2766
+ ], q.prototype, "primaryDisabled", 2);
2767
+ q = re([
2768
+ G("uc-ai-footer")
2769
+ ], q);
2770
+ const Er = ":host{--uc-ai-foreground: light-dark(#181818, #e1e1e1);--uc-ai-background: light-dark(#ffffff, #1b1b1b);--uc-ai-floating: var(--uc-floating, light-dark(#ffffff, #242424));--uc-ai-floating-border: var(--uc-floating-border, light-dark(transparent, rgba(255, 255, 255, .05)));--uc-ai-muted: light-dark(#f5f5f5, #242424);--uc-ai-muted-foreground: light-dark(#717171, #989898);--uc-ai-primary: light-dark(#174bd7, #579aff);--uc-ai-primary-hover: light-dark(#1141c0, #4a8aef);--uc-ai-primary-foreground: light-dark(#ffffff, #000000);--uc-ai-primary-transparent: light-dark(rgba(23, 75, 215, .07), rgba(87, 154, 255, .07));--uc-ai-secondary: light-dark(rgba(24, 24, 24, .05), rgba(225, 225, 225, .07));--uc-ai-secondary-hover: light-dark(rgba(24, 24, 24, .08), rgba(225, 225, 225, .1));--uc-ai-secondary-foreground: light-dark(#181818, #e1e1e1);--uc-ai-border: light-dark(#e4e4e8, #3d3d3d);--uc-ai-shadow-color: light-dark(rgba(24, 24, 24, .18), rgba(0, 0, 0, .5));--uc-ai-dialog-shadow: 0 6px 20px light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .25));--uc-ai-composer-shadow: 0 4px 14px light-dark(rgba(0, 0, 0, .18), rgba(0, 0, 0, .34)), 0 0 26px light-dark(rgba(0, 0, 0, .2), rgba(0, 0, 0, .42));--uc-ai-composer-shadow-peek: 0 2px 10px light-dark(rgba(0, 0, 0, .16), rgba(0, 0, 0, .34));--uc-ai-composer-radius: var(--uc-ai-radius-frame);--uc-ai-composer-radius-top: var(--uc-ai-composer-radius);--uc-ai-composer-radius-bottom: var(--uc-ai-composer-radius);--uc-ai-destructive: #d8473e;--uc-ai-destructive-foreground: light-dark(#b3261e, #ff9d96);--uc-ai-radius: 8px;--uc-ai-radius-button: var(--uc-ai-radius);--uc-ai-radius-input: calc(var(--uc-ai-radius) * 1.5);--uc-ai-radius-card: calc(var(--uc-ai-radius) * 2);--uc-ai-radius-frame: calc(var(--uc-ai-radius) * 2.25);--uc-ai-padding: 10px;--uc-ai-button-size: 32px;--uc-ai-font-family: system-ui, -apple-system, sans-serif;--uc-ai-font-size: 14px;--uc-ai-transition: .2s ease;--uc-ai-ease-out: cubic-bezier(.23, 1, .32, 1);--uc-ai-ease-in-out: cubic-bezier(.77, 0, .175, 1);--uc-ai-dot-grid-color: light-dark(rgba(0, 0, 0, .21), rgba(255, 255, 255, .1));--uc-ai-prompt-max-lines: 6;--uc-ai-prompt-max-height: calc(var(--uc-ai-prompt-max-lines) * 1.5em + 10px);display:block;width:100%;height:100%;font-family:var(--uc-ai-font-family);font-size:var(--uc-ai-font-size);color:var(--uc-ai-foreground);color-scheme:light dark;container-type:inline-size}:host([hidden]){display:none}:host(.uc-light),:host-context(.uc-light){color-scheme:light}:host(.uc-dark),:host-context(.uc-dark){color-scheme:dark}.shell{display:flex;flex-direction:column;background:var(--uc-ai-background);border-radius:var(--uc-ai-radius-card);overflow:hidden;box-shadow:var(--uc-ai-dialog-shadow);height:100%}.stage{position:relative;flex:1;min-height:360px;overflow:hidden;background:var(--uc-ai-background)}uc-ai-canvas{position:absolute;top:0;right:0;bottom:0;left:0}.composer{width:700px;max-width:calc(100% - 40px)}.composer__content{display:flex;flex-direction:column;gap:14px;align-items:center}.composer--overlay{position:absolute;left:50%;transform:translate(-50%);z-index:5;transition:transform .48s var(--uc-ai-ease-out)}.composer--overlay-bottom{bottom:32px}.composer--overlay-top{top:32px}.composer--docked{margin-inline:auto;padding:14px 20px;position:relative;z-index:1}.composer--docked-bottom{padding-top:8px}.composer--docked-top{padding-bottom:8px}.history-pinned{position:absolute;left:50%;transform:translate(-50%);width:700px;max-width:calc(100% - 40px);z-index:5}.history-pinned--canvas-top{top:20px}.history-pinned--canvas-bottom{bottom:20px}.history-pinned--docked.history-pinned--canvas-top{top:6px}.history-pinned--docked.history-pinned--canvas-bottom{bottom:6px}.dock-hotzone{position:absolute;left:0;right:0;height:100px;z-index:4;pointer-events:none}.dock-hotzone--bottom{bottom:0}.dock-hotzone--top{top:0}:host([composer-auto-hide]) .stage:not(.is-empty) .dock-hotzone{pointer-events:auto}.composer-fade{position:absolute;left:0;right:0;height:26px;z-index:6;pointer-events:none;opacity:0;transition:opacity .3s var(--uc-ai-ease-out)}.composer-fade--bottom{bottom:0;background:linear-gradient(to top,var(--uc-ai-background) 0,var(--uc-ai-background) 8px,transparent)}.composer-fade--top{top:0;background:linear-gradient(to bottom,var(--uc-ai-background) 0,var(--uc-ai-background) 8px,transparent)}:host([composer-auto-hide]) .stage:not(.is-empty) .composer-fade{opacity:1}:host([composer-auto-hide]) .stage:not(.is-empty):has(.dock-hotzone:hover) .composer-fade,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay:hover) .composer-fade,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay:focus-within) .composer-fade{opacity:0}:host([composer-auto-hide]) .stage:not(.is-empty) .composer--overlay-bottom{transform:translate(-50%,calc(100% + 4px))}:host([composer-auto-hide]) .stage:not(.is-empty) .composer--overlay-top{transform:translate(-50%,calc(-100% - 4px))}:host([composer-auto-hide]) .stage:not(.is-empty):not(:has(.composer--overlay:hover)):not(:has(.composer--overlay:focus-within)):not(:has(.dock-hotzone:hover)) .composer--overlay{--uc-ai-composer-shadow: var(--uc-ai-composer-shadow-peek)}:host([composer-auto-hide]) .stage:not(.is-empty):not(:has(.composer--overlay:hover)):not(:has(.composer--overlay:focus-within)):not(:has(.dock-hotzone:hover)) .composer--overlay-bottom{--uc-ai-composer-radius-bottom: 0px}:host([composer-auto-hide]) .stage:not(.is-empty):not(:has(.composer--overlay:hover)):not(:has(.composer--overlay:focus-within)):not(:has(.dock-hotzone:hover)) .composer--overlay-top{--uc-ai-composer-radius-top: 0px}:host([composer-auto-hide]) .stage:not(.is-empty):has(.dock-hotzone--bottom:hover) .composer--overlay-bottom,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay-bottom:hover) .composer--overlay-bottom,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay-bottom:focus-within) .composer--overlay-bottom,:host([composer-auto-hide]) .stage:not(.is-empty):has(.dock-hotzone--top:hover) .composer--overlay-top,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay-top:hover) .composer--overlay-top,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay-top:focus-within) .composer--overlay-top{transform:translate(-50%)}:host([composer-auto-hide]) .stage:not(.is-empty):has(.dock-hotzone:hover) .dock-hotzone,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay:hover) .dock-hotzone,:host([composer-auto-hide]) .stage:not(.is-empty):has(.composer--overlay:focus-within) .dock-hotzone{height:320px}:host([composer-auto-hide]) .shell--has-image .composer--docked{margin-block:8px 14px;position:relative}:host([composer-auto-hide]) .shell--has-image .composer--docked .composer__content{position:relative;transition:transform .5s var(--uc-ai-ease-out)}:host([composer-auto-hide]) .shell--has-image .composer--docked .composer__content uc-ai-history{position:absolute;left:0;right:0}:host([composer-auto-hide]) .shell--has-image .composer--docked-bottom .composer__content uc-ai-history{bottom:calc(100% + 14px)}:host([composer-auto-hide]) .shell--has-image .composer--docked-top .composer__content uc-ai-history{top:calc(100% + 14px)}:host([composer-auto-hide]) .shell--has-image .composer--docked-bottom{clip-path:inset(-200px -200px 0 -200px)}:host([composer-auto-hide]) .shell--has-image .composer--docked-top{clip-path:inset(0 -200px -200px -200px)}:host([composer-auto-hide]) .shell--has-image:not(:has(.composer--docked:hover)):not(:has(.composer--docked:focus-within)) .composer--docked{--uc-ai-composer-shadow: var(--uc-ai-composer-shadow-peek)}:host([composer-auto-hide]) .shell--has-image:not(:has(.composer--docked:hover)):not(:has(.composer--docked:focus-within)) .composer--docked-bottom .composer__content{transform:translateY(calc(100% - 22px))}:host([composer-auto-hide]) .shell--has-image:not(:has(.composer--docked:hover)):not(:has(.composer--docked:focus-within)) .composer--docked-top .composer__content{transform:translateY(calc(-100% + 22px))}uc-ai-history,uc-ai-prompt-row{width:100%}.error-box{position:absolute;top:0;right:0;bottom:0;left:0;z-index:6;display:grid;place-items:center;padding:20px;pointer-events:none}.error-box__card{pointer-events:auto;max-width:75%;padding:10px 15px;background:var(--uc-ai-floating, var(--uc-ai-background));border:1px solid var(--uc-ai-floating-border, transparent);border-radius:var(--uc-ai-radius-card);box-shadow:var(--uc-ai-dialog-shadow);color:var(--uc-ai-destructive-foreground);font-size:14px;line-height:1.4;text-align:center}";
2771
+ var Rr = Object.defineProperty, Sr = Object.getOwnPropertyDescriptor, m = (t, e, i, r) => {
2772
+ for (var s = r > 1 ? void 0 : r ? Sr(e, i) : e, o = t.length - 1, a; o >= 0; o--)
2773
+ (a = t[o]) && (s = (r ? a(e, i, s) : a(s)) || s);
2774
+ return r && s && Rr(e, i, s), s;
2775
+ };
2776
+ const Cr = ["top", "bottom"], $r = ["full", "available"], Ar = [
2777
+ "composer-above",
2778
+ "composer-below",
2779
+ "canvas-top",
2780
+ "canvas-bottom"
2781
+ ];
2782
+ let d = class extends j {
2783
+ constructor() {
2784
+ super(...arguments), this.sourceUuid = null, this.pubkey = "", this.aspectRatios = null, this.localeName = "en", this.localeDefinitionOverride = {}, this.presetsOnly = !1, this.presets = {}, this.composerPlacement = "bottom", this.canvasFit = "available", this.historyPlacement = "composer-above", this.composerAutoHide = !1, this.toolbarPlacement = "bottom", this._prompt = "", this._selectedRatio = null, this._inputUrl = null, this._gen = new yi(this), this._history = new Mi(this), this._secure = new pt(this), this._localeStrings = N, this._localeToken = 0, this._lastPreviewUrl = null, this._ratioOptionsCache = /* @__PURE__ */ new Map(), this._labelForOption = (t) => t.labelKey ? this._l(t.labelKey) : "";
2785
+ }
2786
+ /** @internal */
2787
+ willUpdate(t) {
2788
+ const e = t.has("provider") || t.has("pubkey") || t.has("baseUrl") || t.has("cdnCname") || t.has("cdnCnamePrefixed");
2789
+ e && (this._provider = this.provider ?? (this.pubkey ? new bi({
2790
+ publicKey: this.pubkey,
2791
+ baseUrl: this.baseUrl,
2792
+ cdnBaseUrl: this.cdnCname,
2793
+ cdnCnamePrefixed: this.cdnCnamePrefixed
2794
+ }) : void 0)), t.has("secureDeliveryProxyUrlResolver") && this._secure.setResolver(this.secureDeliveryProxyUrlResolver);
2795
+ const i = t.has("sourceUuid") || t.has("sourceFileInfo");
2796
+ if (t.has("pubkey") && this._history.setNamespace(this.pubkey), i && this._gen.reset(), i || t.has("pubkey")) {
2797
+ const s = this._history.lineage(this._sourceUuid);
2798
+ this._gen.setHistory(s);
2799
+ const o = s[0];
2800
+ o && o.file.uuid !== this._sourceUuid && this._gen.setResult({
2801
+ url: o.url,
2802
+ uuid: o.file.uuid,
2803
+ prompt: o.prompt,
2804
+ mode: o.mode,
2805
+ file: o.file
2806
+ });
2807
+ }
2808
+ (e || i) && this._resolveInputUrl(), (e || i) && this._resolveSourceFileInfo();
2809
+ const r = this._mode;
2810
+ if (r !== this._lastMode)
2811
+ this._lastMode = r, this._selectedRatio = r === "edit" ? W : this._defaultGenerateRatio();
2812
+ else if (t.has("aspectRatios")) {
2813
+ const s = this._selectedRatio;
2814
+ O(s) && !this._standardRatios().some((o) => pe(o, s)) && (this._selectedRatio = this._defaultGenerateRatio());
2815
+ }
2816
+ t.has("aspectRatios") && this._ratioOptionsCache.clear(), (t.has("localeName") || t.has("localeDefinitionOverride")) && this._resolveLocale();
2817
+ }
2818
+ /** Load the active locale's built-in strings and layer its overrides on top. */
2819
+ async _resolveLocale() {
2820
+ var s, o;
2821
+ const t = this.localeName || "en", e = ++this._localeToken;
2822
+ let i = N;
2823
+ if (t !== "en")
2824
+ try {
2825
+ i = await ((s = he[t]) == null ? void 0 : s.call(he)) ?? N;
2826
+ } catch {
2827
+ i = N;
2828
+ }
2829
+ if (e !== this._localeToken) return;
2830
+ const r = (o = this.localeDefinitionOverride) == null ? void 0 : o[t];
2831
+ this._localeStrings = r ? { ...i, ...r } : i;
2832
+ }
2833
+ _l(t) {
2834
+ return ki(t, this._localeStrings);
2835
+ }
2836
+ /** Friendly message for the current failure: the per-`error_code` string
2837
+ * (`ai-enhancer-error-<code>`, overridable via the locale) when one is
2838
+ * defined, otherwise the generic error message. */
2839
+ _errorMessage() {
2840
+ const t = this._gen.errorCode;
2841
+ if (t) {
2842
+ const e = `ai-enhancer-error-${t}`, i = this._localeStrings[e] ?? N[e];
2843
+ if (i) return i;
2844
+ }
2845
+ return this._l("ai-enhancer-error");
2846
+ }
2847
+ /** The source image's uuid, from whichever input was given. */
2848
+ get _sourceUuid() {
2849
+ var t;
2850
+ return this.sourceUuid ?? ((t = this.sourceFileInfo) == null ? void 0 : t.uuid) ?? null;
2851
+ }
2852
+ /** UUID of the image the editor is currently operating on, if any. */
2853
+ get _currentSourceUuid() {
2854
+ var t;
2855
+ return ((t = this._gen.result) == null ? void 0 : t.uuid) ?? this._sourceUuid;
2856
+ }
2857
+ /**
2858
+ * Derived editor mode: `edit` whenever there is a current image (an input
2859
+ * source or a generation result), otherwise `generate`. This makes the first
2860
+ * successful generation flip the editor into edit mode for free.
2861
+ */
2862
+ get _mode() {
2863
+ return this._currentSourceUuid ? "edit" : "generate";
2864
+ }
2865
+ /** Resolve the source uuid to a display URL via the provider's CDN base.
2866
+ * No-op for a provider that can't resolve uuids (generate-only). */
2867
+ _resolveInputUrl() {
2868
+ const t = this._sourceUuid, e = this._provider;
2869
+ if (!t || !(e != null && e.resolveCdnUrl)) {
2870
+ this._inputUrl = null;
2871
+ return;
2872
+ }
2873
+ e.resolveCdnUrl(t).then((i) => {
2874
+ this._sourceUuid === t && this._provider === e && (this._inputUrl = i, this._persistSourceEntry());
2875
+ });
2876
+ }
2877
+ /** Persist the original source as the root node of its lineage, so it survives
2878
+ * reloads as the base of the strip. Runs once both its url and file info are
2879
+ * known; idempotent in storage. */
2880
+ _persistSourceEntry() {
2881
+ const t = this._sourceEntry;
2882
+ t && this._history.recordSource({
2883
+ uuid: t.file.uuid,
2884
+ url: t.url,
2885
+ prompt: t.prompt,
2886
+ mode: t.mode,
2887
+ ratio: t.ratio,
2888
+ file: t.file
2889
+ });
2890
+ }
2891
+ /** Effective source info: the injected value, else the fetched fallback. */
2892
+ get _effectiveSourceFileInfo() {
2893
+ return this.sourceFileInfo ?? this._fetchedFileInfo;
2894
+ }
2895
+ /** Resolve the source's file info — an injected {@link sourceFileInfo} wins;
2896
+ * otherwise fetch it from {@link sourceUuid}. Failures fall back silently. */
2897
+ _resolveSourceFileInfo() {
2898
+ if (this._fetchedFileInfo = void 0, this.sourceFileInfo) return;
2899
+ const t = this.sourceUuid, e = this._provider;
2900
+ !t || !(e != null && e.getFileInfo) || e.getFileInfo(t).then(
2901
+ (i) => {
2902
+ this.sourceUuid === t && this._provider === e && !this.sourceFileInfo && (this._fetchedFileInfo = i, this._persistSourceEntry());
2903
+ },
2904
+ () => {
2905
+ }
2906
+ );
2907
+ }
2908
+ get _displayUrl() {
2909
+ return this._gen.resultUrl ?? this._inputUrl;
2910
+ }
2911
+ /**
2912
+ * The original source image as a strip entry, so editing always shows what you
2913
+ * started from and lets you revert to it. Display-only — it's not a generation,
2914
+ * so it's never persisted. `null` until the source's url and file info are
2915
+ * known, or in generate mode (no source).
2916
+ */
2917
+ get _sourceEntry() {
2918
+ const t = this._sourceUuid, e = this._effectiveSourceFileInfo, i = this._inputUrl;
2919
+ return !t || !i || !e ? null : { id: t, prompt: "", mode: "edit", url: i, file: e, ratio: W };
2920
+ }
2921
+ /** Strip entries: the generated results (newest-first) plus the original source
2922
+ * appended as the base (oldest) when editing. */
2923
+ get _historyEntries() {
2924
+ const t = this._sourceEntry;
2925
+ return !t || this._gen.history.some((e) => e.file.uuid === t.file.uuid) ? this._gen.history : [...this._gen.history, t];
2926
+ }
2927
+ /**
2928
+ * Intrinsic ratio of the image currently on the canvas, from metadata when
2929
+ * known — the displayed result's file info, else the source's. Lets the canvas
2930
+ * frame correctly before the image decodes. `null` when unknown.
2931
+ */
2932
+ _displayedNaturalRatio() {
2933
+ var e, i;
2934
+ const t = ((e = this._gen.result) == null ? void 0 : e.file.imageInfo) ?? ((i = this._effectiveSourceFileInfo) == null ? void 0 : i.imageInfo);
2935
+ return t && t.width > 0 && t.height > 0 ? t.width / t.height : null;
2936
+ }
2937
+ /** CDN-optimized, secure-delivery-resolved rendition for the on-canvas preview. */
2938
+ get _previewUrl() {
2939
+ const t = this._displayUrl;
2940
+ if (!t)
2941
+ return this._lastPreviewUrl = null, null;
2942
+ const e = this._secure.resolve(Ai(t, this.clientWidth || 1024));
2943
+ return e != null && (this._lastPreviewUrl = e), this._lastPreviewUrl;
2944
+ }
2945
+ /** Full-resolution rendition for fullscreen, secure-delivery-resolved. */
2946
+ get _fullsizeUrl() {
2947
+ return this._secure.resolve(this._displayUrl);
2948
+ }
2949
+ /** The configured (or popular) standard ratios, validated. */
2950
+ _standardRatios() {
2951
+ const t = (this.aspectRatios ?? []).filter(ye);
2952
+ return t.length > 0 ? t : [...yt];
2953
+ }
2954
+ /**
2955
+ * The ratio the generate flow starts on: the prototype's landscape default
2956
+ * ({@link DEFAULT_GENERATE_RATIO}) when it's in the available set, else the
2957
+ * first available ratio.
2958
+ */
2959
+ _defaultGenerateRatio() {
2960
+ const t = this._standardRatios();
2961
+ return t.find((e) => pe(e, wt)) ?? t[0] ?? null;
2962
+ }
2963
+ _ratioOptions(t) {
2964
+ const e = this._ratioOptionsCache.get(t);
2965
+ if (e) return e;
2966
+ const i = this._standardRatios().map(St), r = t === "edit" ? [{ value: W, labelKey: "ai-enhancer-aspect-original" }, ...i] : i;
2967
+ return this._ratioOptionsCache.set(t, r), r;
2968
+ }
2969
+ /**
2970
+ * Resolve the result's filename from {@link outputFilename}: a function gets
2971
+ * the source's original name + this generation's 1-based counter; a string is
2972
+ * used verbatim. Unset preserves the source's original name (`undefined` when
2973
+ * generating from scratch → the provider's default).
2974
+ */
2975
+ _resolveOutputFilename() {
2976
+ var i;
2977
+ const t = ((i = this._effectiveSourceFileInfo) == null ? void 0 : i.originalFilename) || void 0, e = this.outputFilename;
2978
+ return typeof e == "function" ? e(t, this._gen.history.length + 1) || void 0 : typeof e == "string" ? e || void 0 : t;
2979
+ }
2980
+ /**
2981
+ * Resolve {@link metadata}: a static bag is used as-is; a callback is invoked
2982
+ * with the source file (only when one exists — a generate-from-scratch gets
2983
+ * none) and may be async. A throwing callback yields no metadata.
2984
+ */
2985
+ async _resolveMetadata() {
2986
+ const t = this.metadata;
2987
+ if (typeof t != "function") return t ?? void 0;
2988
+ const e = this._effectiveSourceFileInfo;
2989
+ if (e)
2990
+ try {
2991
+ return await t(e);
2992
+ } catch {
2993
+ return;
2994
+ }
2995
+ }
2996
+ async _generate() {
2997
+ const t = this._prompt.trim(), e = this._provider;
2998
+ if (!t || !e) return;
2999
+ const i = this._mode, r = i === "edit" ? this._currentSourceUuid : null, s = await this._resolveMetadata();
3000
+ try {
3001
+ const o = await this._gen.run({
3002
+ provider: e,
3003
+ prompt: t,
3004
+ mode: i,
3005
+ // "Original" (and generate's null) omit the ratio; only a concrete pick
3006
+ // is sent — in edit that reshapes, otherwise the source AR is preserved.
3007
+ aspectRatio: O(this._selectedRatio) ? this._selectedRatio : void 0,
3008
+ // Record the full selection (incl. "Original") so the history entry can
3009
+ // restore the picker when re-selected.
3010
+ ratioValue: this._selectedRatio,
3011
+ source: i === "edit" ? this._currentSourceUuid ?? void 0 : void 0,
3012
+ // Name the result (resolver / static string / preserved source name).
3013
+ filename: this._resolveOutputFilename(),
3014
+ // Attach the configured metadata to the result, for both modes.
3015
+ metadata: s
3016
+ });
3017
+ o && (this._prompt = "", this._history.record({
3018
+ uuid: o.uuid,
3019
+ source: r,
3020
+ url: o.url,
3021
+ prompt: o.prompt,
3022
+ mode: o.mode,
3023
+ ratio: this._selectedRatio,
3024
+ file: o.file
3025
+ }));
3026
+ } catch (o) {
3027
+ this.dispatchEvent(new CustomEvent("uc:error", { detail: { error: o }, bubbles: !0, composed: !0 }));
3028
+ }
3029
+ }
3030
+ /** Discard the current image (input or result) and prompt history, returning
3031
+ * to a blank generate session. */
3032
+ _onStartOver() {
3033
+ var t;
3034
+ this.sourceUuid = null, this.sourceFileInfo = void 0, this._inputUrl = null, this._fetchedFileInfo = void 0, this._prompt = "", this._gen.reset(), this._gen.clearHistory(), (t = this._canvasEl) == null || t.resetGrid();
3035
+ }
3036
+ _onPromptInput(t) {
3037
+ this._prompt = t.detail.value;
3038
+ }
3039
+ _onSend() {
3040
+ this._generate();
3041
+ }
3042
+ _onSelectHistoryEntry(t) {
3043
+ const { entry: e } = t.detail;
3044
+ this._prompt = e.prompt, this._selectedRatio = e.ratio, this._gen.setResult({
3045
+ url: e.url,
3046
+ uuid: e.file.uuid,
3047
+ prompt: e.prompt,
3048
+ mode: e.mode,
3049
+ file: e.file
3050
+ });
3051
+ }
3052
+ _onSelectAspectRatio(t) {
3053
+ this._selectedRatio = t.detail.value;
3054
+ }
3055
+ _onSelectPreset(t) {
3056
+ if (this._prompt = t.detail.preset.prompt, this.presetsOnly) {
3057
+ this._generate();
3058
+ return;
3059
+ }
3060
+ queueMicrotask(() => {
3061
+ var e;
3062
+ return (e = this._promptRow) == null ? void 0 : e.focusInput();
3063
+ });
3064
+ }
3065
+ _onPrimary() {
3066
+ const t = this._gen.result;
3067
+ if (!t) return;
3068
+ const e = {
3069
+ url: t.url,
3070
+ uuid: t.uuid,
3071
+ prompt: t.prompt,
3072
+ mode: t.mode,
3073
+ aspectRatio: O(this._selectedRatio) ? this._selectedRatio : void 0,
3074
+ file: t.file
3075
+ };
3076
+ this.dispatchEvent(new CustomEvent("uc:done", { detail: e, bubbles: !0, composed: !0 }));
3077
+ }
3078
+ _onCancel(t) {
3079
+ t.stopPropagation(), this.dispatchEvent(new CustomEvent("uc:cancel", { bubbles: !0, composed: !0 }));
3080
+ }
3081
+ /** @internal */
3082
+ render() {
3083
+ var Ue, Te;
3084
+ const t = this._mode, e = t === "edit" && !this.sourceUuid && !this.sourceFileInfo, i = fe[t].placeholderKey, r = ((Ue = this.presets) == null ? void 0 : Ue[t]) ?? fe[t].presets, s = this._gen.busy || !this._gen.result, o = this._ratioOptions(t), a = this._displayUrl != null, n = O(this._selectedRatio) ? this._selectedRatio[0] / this._selectedRatio[1] : null, l = {
3085
+ stage: !0,
3086
+ "is-empty": !a
3087
+ }, h = Cr.includes(this.composerPlacement) ? this.composerPlacement : "bottom", u = ($r.includes(this.canvasFit) ? this.canvasFit : "available") === "full", _ = !u, x = `${u ? "overlay" : "docked"}-${h}`, w = Ar.includes(this.historyPlacement) ? this.historyPlacement : "composer-above", $ = w === "composer-above" || w === "composer-below", R = (u || _ && this.composerAutoHide) && $, I = w === "canvas-top" ? "top" : w === "canvas-bottom" ? "bottom" : h, H = this._historyEntries, Y = H.length > 0 || e, se = Y ? f`
3088
+ <uc-ai-history
3089
+ .busy=${this._gen.busy}
3090
+ .entries=${H}
3091
+ .selectedUuid=${((Te = this._gen.result) == null ? void 0 : Te.uuid) ?? this._sourceUuid}
3092
+ ?show-start-over=${e}
3093
+ start-over-label="${this._l("ai-enhancer-start-over")}"
3094
+ list-label="${this._l("ai-enhancer-history-title")}"
3095
+ .secureResolver=${this.secureDeliveryProxyUrlResolver}
3096
+ @uc:select=${this._onSelectHistoryEntry}
3097
+ @uc:start-over=${this._onStartOver}
3098
+ ></uc-ai-history>
3099
+ ` : v, ft = f`
3100
+ <uc-ai-prompt-row
3101
+ .mode=${t}
3102
+ .value=${this._prompt}
3103
+ .placeholder=${this._l(i)}
3104
+ .busy=${this._gen.busy}
3105
+ .allowCustom=${!this.presetsOnly}
3106
+ send-aria-label="${this._l("ai-enhancer-generate-btn")}"
3107
+ @uc:input=${this._onPromptInput}
3108
+ @uc:send=${this._onSend}
3109
+ >
3110
+ ${r.length > 0 ? f`
3111
+ <uc-ai-chips
3112
+ slot="chips"
3113
+ .mode=${t}
3114
+ .presets=${r}
3115
+ .busy=${this._gen.busy}
3116
+ @uc:select=${this._onSelectPreset}
3117
+ ></uc-ai-chips>
3118
+ ` : v}
3119
+ ${o.length > 0 ? f`
3120
+ <uc-ai-aspect-ratio
3121
+ slot="aspect-ratio"
3122
+ .options=${o}
3123
+ .selected=${this._selectedRatio}
3124
+ .busy=${this._gen.busy}
3125
+ .labelFor=${this._labelForOption}
3126
+ aria-label-text="${this._l("ai-enhancer-aspect-ratio-aria")}"
3127
+ @uc:select=${this._onSelectAspectRatio}
3128
+ ></uc-ai-aspect-ratio>
3129
+ ` : v}
3130
+ </uc-ai-prompt-row>
3131
+ `, oe = f`
3132
+ <div
3133
+ class=${S({
3134
+ composer: !0,
3135
+ "composer--overlay": u,
3136
+ "composer--docked": _,
3137
+ [`composer--${x}`]: !0
3138
+ })}
3139
+ >
3140
+ <div class="composer__content">
3141
+ ${R && w === "composer-above" ? se : v}
3142
+ ${ft}
3143
+ ${R && w === "composer-below" ? se : v}
3144
+ </div>
3145
+ </div>
3146
+ `, mt = Y && !R ? f`<div
3147
+ class=${S({
3148
+ "history-pinned": !0,
3149
+ "history-pinned--docked": _,
3150
+ [`history-pinned--canvas-${I}`]: !0
3151
+ })}
3152
+ >
3153
+ ${se}
3154
+ </div>` : v, _t = this.composerAutoHide && u ? f`
3155
+ <div class=${S({ "dock-hotzone": !0, [`dock-hotzone--${h}`]: !0 })}></div>
3156
+ <div class=${S({ "composer-fade": !0, [`composer-fade--${h}`]: !0 })}></div>
3157
+ ` : v, $e = this.toolbarPlacement === "top", Ae = f`
3158
+ <uc-ai-footer
3159
+ cancel-label="${this._l("ai-enhancer-cancel")}"
3160
+ primary-label="${this._l("ai-enhancer-done-btn")}"
3161
+ ?primary-disabled=${s}
3162
+ @uc:cancel=${this._onCancel}
3163
+ @uc:primary=${this._onPrimary}
3164
+ ></uc-ai-footer>
3165
+ `;
3166
+ return f`
3167
+ <div
3168
+ class=${S({ shell: !0, "shell--has-image": a })}
3169
+ role="region"
3170
+ aria-label="${this._l(t === "edit" ? "ai-enhancer-edit-title" : "ai-enhancer-generate-title")}"
3171
+ >
3172
+ ${$e ? Ae : v}
3173
+ ${_ && h === "top" ? oe : v}
3174
+ <div class=${S(l)}>
3175
+ <uc-ai-canvas
3176
+ .url=${this._previewUrl}
3177
+ .ratio=${n}
3178
+ .naturalRatio=${this._displayedNaturalRatio()}
3179
+ .fullsizeUrl=${this._fullsizeUrl}
3180
+ .shimmerConfig=${this.shimmerConfig}
3181
+ .busy=${this._gen.busy}
3182
+ .alt=${this._prompt}
3183
+ busy-label="${this._l("ai-enhancer-busy")}"
3184
+ error-label="${this._l("ai-enhancer-error")}"
3185
+ fullscreen-label="${this._l("ai-enhancer-fullscreen")}"
3186
+ exit-fullscreen-label="${this._l("ai-enhancer-exit-fullscreen")}"
3187
+ ></uc-ai-canvas>
3188
+
3189
+ ${_t}
3190
+ ${mt}
3191
+ ${u ? oe : v}
3192
+
3193
+ ${this._gen.error ? f`<div class="error-box" role="alert">
3194
+ <div class="error-box__card">${this._errorMessage()}</div>
3195
+ </div>` : v}
3196
+ </div>
3197
+ ${_ && h === "bottom" ? oe : v}
3198
+ ${$e ? v : Ae}
3199
+ </div>
3200
+ `;
3201
+ }
3202
+ };
3203
+ d.styles = B(Er);
3204
+ m([
3205
+ c({ attribute: "source-uuid" })
3206
+ ], d.prototype, "sourceUuid", 2);
3207
+ m([
3208
+ c({ attribute: !1 })
3209
+ ], d.prototype, "sourceFileInfo", 2);
3210
+ m([
3211
+ c({ attribute: !1 })
3212
+ ], d.prototype, "outputFilename", 2);
3213
+ m([
3214
+ c({ attribute: !1 })
3215
+ ], d.prototype, "metadata", 2);
3216
+ m([
3217
+ c()
3218
+ ], d.prototype, "pubkey", 2);
3219
+ m([
3220
+ c({ attribute: !1 })
3221
+ ], d.prototype, "provider", 2);
3222
+ m([
3223
+ c({ attribute: "base-url" })
3224
+ ], d.prototype, "baseUrl", 2);
3225
+ m([
3226
+ c({ attribute: "cdn-cname" })
3227
+ ], d.prototype, "cdnCname", 2);
3228
+ m([
3229
+ c({ attribute: "cdn-cname-prefixed" })
3230
+ ], d.prototype, "cdnCnamePrefixed", 2);
3231
+ m([
3232
+ c({ attribute: !1 })
3233
+ ], d.prototype, "secureDeliveryProxyUrlResolver", 2);
3234
+ m([
3235
+ c({ type: Array, attribute: "aspect-ratios", converter: (t) => t ? Ct(t) : null })
3236
+ ], d.prototype, "aspectRatios", 2);
3237
+ m([
3238
+ c({ attribute: "locale-name" })
3239
+ ], d.prototype, "localeName", 2);
3240
+ m([
3241
+ c({ attribute: !1 })
3242
+ ], d.prototype, "localeDefinitionOverride", 2);
3243
+ m([
3244
+ c({ type: Boolean, attribute: "presets-only" })
3245
+ ], d.prototype, "presetsOnly", 2);
3246
+ m([
3247
+ c({ attribute: !1 })
3248
+ ], d.prototype, "presets", 2);
3249
+ m([
3250
+ c({ attribute: "composer-placement" })
3251
+ ], d.prototype, "composerPlacement", 2);
3252
+ m([
3253
+ c({ attribute: "canvas-fit" })
3254
+ ], d.prototype, "canvasFit", 2);
3255
+ m([
3256
+ c({ attribute: "history-placement" })
3257
+ ], d.prototype, "historyPlacement", 2);
3258
+ m([
3259
+ c({ type: Boolean, attribute: "composer-auto-hide", reflect: !0 })
3260
+ ], d.prototype, "composerAutoHide", 2);
3261
+ m([
3262
+ c({ attribute: "toolbar-placement" })
3263
+ ], d.prototype, "toolbarPlacement", 2);
3264
+ m([
3265
+ c({ attribute: !1 })
3266
+ ], d.prototype, "shimmerConfig", 2);
3267
+ m([
3268
+ C()
3269
+ ], d.prototype, "_prompt", 2);
3270
+ m([
3271
+ C()
3272
+ ], d.prototype, "_selectedRatio", 2);
3273
+ m([
3274
+ C()
3275
+ ], d.prototype, "_inputUrl", 2);
3276
+ m([
3277
+ C()
3278
+ ], d.prototype, "_fetchedFileInfo", 2);
3279
+ m([
3280
+ F("uc-ai-prompt-row")
3281
+ ], d.prototype, "_promptRow", 2);
3282
+ m([
3283
+ F("uc-ai-canvas")
3284
+ ], d.prototype, "_canvasEl", 2);
3285
+ m([
3286
+ C()
3287
+ ], d.prototype, "_localeStrings", 2);
3288
+ d = m([
3289
+ G("uc-ai-enhancer")
3290
+ ], d);
3291
+ export {
3292
+ Nr as I,
3293
+ he as L,
3294
+ yt as P,
3295
+ d as U,
3296
+ Dr as a,
3297
+ N as e,
3298
+ ye as i
3299
+ };