veo-sdk 0.6.0 → 0.6.2

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 (34) hide show
  1. package/dist/builder-ENKEIVF2.mjs +5 -0
  2. package/dist/{builder-3QPHB2VJ.mjs.map → builder-ENKEIVF2.mjs.map} +1 -1
  3. package/dist/builder.cjs +366 -20
  4. package/dist/builder.cjs.map +1 -1
  5. package/dist/builder.d.cts +2 -2
  6. package/dist/builder.d.ts +2 -2
  7. package/dist/builder.mjs +4 -4
  8. package/dist/{chunk-N4VFMZFA.mjs → chunk-4QZDNJJE.mjs} +3 -3
  9. package/dist/{chunk-N4VFMZFA.mjs.map → chunk-4QZDNJJE.mjs.map} +1 -1
  10. package/dist/{chunk-GMXQMZ4X.mjs → chunk-L3QQJLDJ.mjs} +3 -3
  11. package/dist/{chunk-GMXQMZ4X.mjs.map → chunk-L3QQJLDJ.mjs.map} +1 -1
  12. package/dist/{chunk-O6USA4TU.mjs → chunk-ZILDR4YE.mjs} +368 -22
  13. package/dist/chunk-ZILDR4YE.mjs.map +1 -0
  14. package/dist/detect-theme-X4K3TLUL.mjs +446 -0
  15. package/dist/detect-theme-X4K3TLUL.mjs.map +1 -0
  16. package/dist/{guide-preview-DylsEhrg.d.cts → guide-preview-DEFhfA4o.d.cts} +115 -0
  17. package/dist/{guide-preview-DylsEhrg.d.ts → guide-preview-DEFhfA4o.d.ts} +115 -0
  18. package/dist/index.cjs +994 -51
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +13 -1
  21. package/dist/index.d.ts +13 -1
  22. package/dist/index.mjs +141 -16
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/veo-builder.js +92 -20
  25. package/dist/veo-builder.js.map +1 -1
  26. package/dist/veo-guides.js +84 -12
  27. package/dist/veo-guides.js.map +1 -1
  28. package/dist/veo-theme.js +2 -0
  29. package/dist/veo-theme.js.map +1 -0
  30. package/dist/veo.js +2 -2
  31. package/dist/veo.js.map +1 -1
  32. package/package.json +2 -2
  33. package/dist/builder-3QPHB2VJ.mjs +0 -5
  34. package/dist/chunk-O6USA4TU.mjs.map +0 -1
@@ -0,0 +1,446 @@
1
+ // src/plugins/theme-detect/color.ts
2
+ var RGB_RX = /^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/;
3
+ function parseRgb(value) {
4
+ const m = RGB_RX.exec(value.trim());
5
+ if (!m) return null;
6
+ const a = m[4] === void 0 ? 1 : m[4].endsWith("%") ? Number.parseFloat(m[4]) / 100 : +m[4];
7
+ return [+m[1], +m[2], +m[3], a];
8
+ }
9
+ function toCssColor(raw) {
10
+ const v = raw.trim();
11
+ const parts = v.split(/[\s,/]+/).filter(Boolean);
12
+ const bare = parts.length >= 3 && parts.every((p) => /^-?[\d.]+(%|deg)?$/.test(p));
13
+ if (!bare) return v;
14
+ return v.includes("%") ? `hsl(${v})` : `rgb(${v})`;
15
+ }
16
+ function looksLikeColor(raw) {
17
+ const v = raw.trim();
18
+ if (!v || v.length > 64) return false;
19
+ return /^(#|rgb|hsl|hwb|lab|lch|oklab|oklch|color\(|color-mix|light-dark)/i.test(v) || toCssColor(v) !== v;
20
+ }
21
+ function flatten(c, bg) {
22
+ if (c[3] >= 1) return c;
23
+ const mix = (i) => Math.round(c[i] * c[3] + bg[i] * (1 - c[3]));
24
+ return [mix(0), mix(1), mix(2), 1];
25
+ }
26
+ function toHex(c) {
27
+ const h = (n) => Math.round(n).toString(16).padStart(2, "0");
28
+ return `#${h(c[0])}${h(c[1])}${h(c[2])}`.toUpperCase();
29
+ }
30
+ function luminance(c) {
31
+ return (0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]) / 255;
32
+ }
33
+ function saturation(c) {
34
+ const mx = Math.max(c[0], c[1], c[2]) / 255;
35
+ const mn = Math.min(c[0], c[1], c[2]) / 255;
36
+ const l = (mx + mn) / 2;
37
+ return mx === mn ? 0 : (mx - mn) / (1 - Math.abs(2 * l - 1));
38
+ }
39
+ function createColorResolver(doc) {
40
+ const probe = doc.createElement("span");
41
+ probe.style.display = "none";
42
+ doc.body.appendChild(probe);
43
+ const view = doc.defaultView;
44
+ let ctx;
45
+ const cache = /* @__PURE__ */ new Map();
46
+ const viaCanvas = (computed) => {
47
+ if (ctx === void 0) {
48
+ try {
49
+ const canvas = doc.createElement("canvas");
50
+ canvas.width = 1;
51
+ canvas.height = 1;
52
+ ctx = canvas.getContext("2d", { willReadFrequently: true });
53
+ } catch {
54
+ ctx = null;
55
+ }
56
+ }
57
+ if (!ctx) return null;
58
+ ctx.clearRect(0, 0, 1, 1);
59
+ ctx.fillStyle = "#000";
60
+ ctx.fillStyle = computed;
61
+ ctx.fillRect(0, 0, 1, 1);
62
+ const d = ctx.getImageData(0, 0, 1, 1).data;
63
+ return [d[0] ?? 0, d[1] ?? 0, d[2] ?? 0, (d[3] ?? 255) / 255];
64
+ };
65
+ return {
66
+ resolve(raw) {
67
+ const key = raw.trim();
68
+ if (!key || !view) return null;
69
+ const hit = cache.get(key);
70
+ if (hit !== void 0) return hit;
71
+ let out = null;
72
+ probe.style.color = "";
73
+ probe.style.color = toCssColor(key);
74
+ if (probe.style.color) {
75
+ const computed = view.getComputedStyle(probe).color;
76
+ out = parseRgb(computed) ?? viaCanvas(computed);
77
+ }
78
+ cache.set(key, out);
79
+ return out;
80
+ },
81
+ dispose() {
82
+ probe.remove();
83
+ }
84
+ };
85
+ }
86
+
87
+ // src/plugins/theme-detect/fonts.ts
88
+ var GENERIC = /^(serif|sans-serif|monospace|cursive|fantasy|system-ui|ui-sans-serif|ui-serif|ui-monospace|ui-rounded|emoji|math|fangsong|inherit|initial|-apple-system|BlinkMacSystemFont|Segoe UI|Roboto|Helvetica|Helvetica Neue|Arial|Noto Sans|Apple Color Emoji|Segoe UI Emoji|Segoe UI Symbol|Noto Color Emoji)$/i;
89
+ function cleanFamily(name) {
90
+ return name.trim().replace(/^["']|["']$/g, "");
91
+ }
92
+ function primaryFamily(stack) {
93
+ const families = stack.split(",").map(cleanFamily).filter(Boolean);
94
+ return families.find((f) => !GENERIC.test(f) && !/fallback/i.test(f)) ?? families[0] ?? "";
95
+ }
96
+ function prettyFamily(family) {
97
+ return family.replace(/^__/, "").replace(/_Fallback_[0-9a-f]+$/i, " Fallback").replace(/_[0-9a-f]{6,}$/i, "").replace(/_/g, " ").trim();
98
+ }
99
+ function describeFont(doc, el, faces) {
100
+ const view = doc.defaultView;
101
+ if (!el || !view) return void 0;
102
+ const family = primaryFamily(view.getComputedStyle(el).fontFamily);
103
+ if (!family) return void 0;
104
+ const font = {
105
+ name: prettyFamily(family).slice(0, 80),
106
+ family: family.slice(0, 120)
107
+ };
108
+ const weights = /* @__PURE__ */ new Set();
109
+ try {
110
+ for (const face of Array.from(doc.fonts ?? [])) {
111
+ if (cleanFamily(face.family) === family && face.status === "loaded") weights.add(face.weight);
112
+ }
113
+ } catch {
114
+ }
115
+ if (weights.size > 0) font.weights = [...weights].sort().join(" ").slice(0, 80);
116
+ const own = faces.filter((f) => f.family === family);
117
+ const url = own.find((f) => f.url)?.url ?? null;
118
+ let origin = null;
119
+ try {
120
+ origin = url ? new URL(url, doc.baseURI).origin : null;
121
+ } catch {
122
+ origin = null;
123
+ }
124
+ const links = Array.from(doc.querySelectorAll("link[href]")).map((l) => l.href);
125
+ if (origin) {
126
+ font.hosting = origin.includes("fonts.gstatic.com") ? "google" : origin === view.location.origin ? "self" : "external";
127
+ } else if (own.length > 0) {
128
+ font.hosting = "self";
129
+ } else if (links.some((h) => h.includes("fonts.googleapis.com"))) {
130
+ font.hosting = "google";
131
+ } else if (links.some((h) => h.includes("use.typekit.net"))) {
132
+ font.hosting = "adobe";
133
+ } else {
134
+ font.hosting = "system";
135
+ }
136
+ return font;
137
+ }
138
+
139
+ // src/plugins/theme-detect/detect-theme.ts
140
+ var ROLES = ["accent", "text", "textMuted", "background", "border"];
141
+ var KNOWN_VARS = {
142
+ accent: [
143
+ "--primary",
144
+ "--color-primary",
145
+ "--brand",
146
+ "--color-brand",
147
+ "--brand-primary",
148
+ "--mui-palette-primary-main",
149
+ "--bs-primary",
150
+ "--ant-color-primary",
151
+ "--chakra-colors-brand-500",
152
+ "--accent-color",
153
+ "--accent"
154
+ ],
155
+ text: [
156
+ "--foreground",
157
+ "--color-foreground",
158
+ "--text",
159
+ "--color-text",
160
+ "--text-primary",
161
+ "--bs-body-color",
162
+ "--mui-palette-text-primary"
163
+ ],
164
+ textMuted: [
165
+ "--muted-foreground",
166
+ "--color-muted-foreground",
167
+ "--text-muted",
168
+ "--text-secondary",
169
+ "--bs-secondary-color",
170
+ "--mui-palette-text-secondary"
171
+ ],
172
+ background: [
173
+ "--background",
174
+ "--color-background",
175
+ "--bg",
176
+ "--color-bg",
177
+ "--bs-body-bg",
178
+ "--mui-palette-background-default"
179
+ ],
180
+ border: [
181
+ "--border",
182
+ "--color-border",
183
+ "--border-color",
184
+ "--bs-border-color",
185
+ "--mui-palette-divider"
186
+ ]
187
+ };
188
+ var ROLE_NAME = {
189
+ accent: /brand|primary|accent|main/i,
190
+ text: /text|foreground|\bfg\b|-fg|ink|content|body/i,
191
+ textMuted: /muted|secondary|subtle|soft|hint|placeholder|text|-fg/i,
192
+ background: /background|\bbg\b|-bg|surface|canvas|page|base/i,
193
+ border: /border|line|divider|stroke|outline|separator/i
194
+ };
195
+ var PALETTE_NAME = /-(50|[1-9]00|950)$|white|black/i;
196
+ var DARK_SELECTOR = /\.dark\b|\[data-(theme|mode|color-scheme)=["']?dark|\.theme-dark|\.dark-theme/i;
197
+ var LIGHT_SELECTOR = /^(:root|html|:host|body)$|\.light\b|\[data-(theme|mode)=["']?light/i;
198
+ var MAX_ELEMENTS = 1500;
199
+ var MAX_VARS = 600;
200
+ function scanSheets(doc) {
201
+ const scan = {
202
+ names: /* @__PURE__ */ new Set(),
203
+ byMode: { light: /* @__PURE__ */ new Map(), dark: /* @__PURE__ */ new Map() },
204
+ faces: []
205
+ };
206
+ const walk = (rules, inDarkMedia) => {
207
+ for (const rule of Array.from(rules)) {
208
+ const style = rule.style;
209
+ const selector = rule.selectorText;
210
+ if (rule.constructor.name === "CSSFontFaceRule" && style) {
211
+ const src = style.getPropertyValue("src");
212
+ const url = /url\(["']?([^"')]+)["']?\)/.exec(src)?.[1] ?? null;
213
+ scan.faces.push({ family: cleanFamily(style.getPropertyValue("font-family")), url });
214
+ } else if (style && typeof selector === "string") {
215
+ const selectors = selector.split(",").map((s) => s.trim());
216
+ const mode = selectors.some((s) => DARK_SELECTOR.test(s)) ? "dark" : selectors.some((s) => LIGHT_SELECTOR.test(s)) ? inDarkMedia ? "dark" : "light" : null;
217
+ for (const prop of Array.from(style)) {
218
+ if (!prop.startsWith("--")) continue;
219
+ scan.names.add(prop);
220
+ if (mode) scan.byMode[mode].set(prop, style.getPropertyValue(prop).trim());
221
+ }
222
+ }
223
+ const nested = rule.cssRules;
224
+ if (nested) {
225
+ const media = rule.conditionText ?? "";
226
+ walk(nested, inDarkMedia || /prefers-color-scheme:\s*dark/.test(media));
227
+ }
228
+ }
229
+ };
230
+ for (const sheet of Array.from(doc.styleSheets)) {
231
+ try {
232
+ walk(sheet.cssRules, false);
233
+ } catch {
234
+ }
235
+ }
236
+ return scan;
237
+ }
238
+ function top(counts) {
239
+ let best = null;
240
+ let max = 0;
241
+ for (const [hex, n] of counts) {
242
+ if (n > max) {
243
+ max = n;
244
+ best = hex;
245
+ }
246
+ }
247
+ return best;
248
+ }
249
+ function detectTheme(doc = document) {
250
+ const view = doc.defaultView;
251
+ const body = doc.body;
252
+ if (!view || !body) return null;
253
+ const html = doc.documentElement;
254
+ const colors = createColorResolver(doc);
255
+ const modeProbe = doc.createElement("div");
256
+ try {
257
+ const bodyCs = view.getComputedStyle(body);
258
+ let bg = [255, 255, 255, 1];
259
+ for (const el of [body, html]) {
260
+ const c = colors.resolve(view.getComputedStyle(el).backgroundColor);
261
+ if (c && c[3] > 0) {
262
+ bg = flatten(c, [255, 255, 255, 1]);
263
+ break;
264
+ }
265
+ }
266
+ const text = flatten(colors.resolve(bodyCs.color) ?? [0, 0, 0, 1], bg);
267
+ const textHex = toHex(text);
268
+ const muted = /* @__PURE__ */ new Map();
269
+ const border = /* @__PURE__ */ new Map();
270
+ const accent = /* @__PURE__ */ new Map();
271
+ const link = /* @__PURE__ */ new Map();
272
+ const bump = (m, k) => {
273
+ m.set(k, (m.get(k) ?? 0) + 1);
274
+ };
275
+ const contrast = Math.abs(luminance(text) - luminance(bg));
276
+ const elements = Array.from(body.querySelectorAll("*")).slice(0, MAX_ELEMENTS);
277
+ for (const el of elements) {
278
+ if (el.getClientRects().length === 0) continue;
279
+ const cs = view.getComputedStyle(el);
280
+ const hasText = Array.from(el.childNodes).some(
281
+ (n) => n.nodeType === 3 && (n.textContent ?? "").trim() !== ""
282
+ );
283
+ if (hasText) {
284
+ const c = colors.resolve(cs.color);
285
+ if (c && c[3] > 0) {
286
+ const flat = flatten(c, bg);
287
+ const hex = toHex(flat);
288
+ const softer = Math.abs(luminance(flat) - luminance(bg)) < contrast;
289
+ if (hex !== textHex && saturation(flat) < 0.3 && softer) bump(muted, hex);
290
+ if (el.closest("a") && saturation(flat) >= 0.3) bump(link, hex);
291
+ }
292
+ }
293
+ if (Number.parseFloat(cs.borderTopWidth) > 0 && cs.borderTopStyle !== "none") {
294
+ const c = colors.resolve(cs.borderTopColor);
295
+ if (c && c[3] > 0) {
296
+ const flat = flatten(c, bg);
297
+ if (saturation(flat) < 0.3 && toHex(flat) !== textHex) bump(border, toHex(flat));
298
+ }
299
+ }
300
+ if (el.matches('button,[role="button"],input[type="submit"],a[class*="btn"],a[class*="button"]')) {
301
+ const c = colors.resolve(cs.backgroundColor);
302
+ if (c && c[3] > 0.5 && saturation(c) >= 0.3) bump(accent, toHex(c));
303
+ }
304
+ }
305
+ const meta = doc.querySelector('meta[name="theme-color"]');
306
+ const metaColor = meta ? colors.resolve(meta.content) : null;
307
+ const sampled = {
308
+ background: toHex(bg),
309
+ text: textHex
310
+ };
311
+ const sampledAccent = top(accent) ?? top(link) ?? (metaColor ? toHex(metaColor) : null);
312
+ if (sampledAccent) sampled.accent = sampledAccent;
313
+ const sampledMuted = top(muted);
314
+ if (sampledMuted) sampled.textMuted = sampledMuted;
315
+ const sampledBorder = top(border);
316
+ if (sampledBorder) sampled.border = sampledBorder;
317
+ const hints = [
318
+ html.className,
319
+ html.dataset.theme,
320
+ html.dataset.mode,
321
+ body.className,
322
+ body.dataset.theme
323
+ ].join(" ").toLowerCase();
324
+ const mode = /\bdark\b/.test(hints) ? "dark" : /\blight\b/.test(hints) ? "light" : view.getComputedStyle(html).colorScheme === "dark" || luminance(bg) < 0.4 ? "dark" : "light";
325
+ const other = mode === "dark" ? "light" : "dark";
326
+ modeProbe.className = other;
327
+ modeProbe.dataset.theme = other;
328
+ modeProbe.dataset.mode = other;
329
+ modeProbe.style.cssText = `display:none;color-scheme:${other}`;
330
+ body.appendChild(modeProbe);
331
+ const probeCs = view.getComputedStyle(modeProbe);
332
+ const hexOf = (raw, over) => {
333
+ if (!looksLikeColor(raw)) return null;
334
+ const c = colors.resolve(raw);
335
+ if (!c || c[3] === 0) return null;
336
+ if (c[3] > 0.98) return toHex(c);
337
+ return over ? toHex(flatten(c, over)) : null;
338
+ };
339
+ const scan = scanSheets(doc);
340
+ const roleVar = {};
341
+ const current = {};
342
+ for (const role of ROLES) {
343
+ for (const name of KNOWN_VARS[role]) {
344
+ const hex = hexOf(bodyCs.getPropertyValue(name), bg);
345
+ if (hex) {
346
+ roleVar[role] = { name, confidence: 3 };
347
+ current[role] = { hex, confidence: 3 };
348
+ break;
349
+ }
350
+ }
351
+ }
352
+ const missing = ROLES.filter((r) => !roleVar[r] && sampled[r]);
353
+ if (missing.length > 0) {
354
+ const candidates = [];
355
+ for (const name of Array.from(scan.names).slice(0, MAX_VARS)) {
356
+ const cur = hexOf(bodyCs.getPropertyValue(name));
357
+ if (cur) candidates.push({ name, cur, oth: hexOf(probeCs.getPropertyValue(name)) });
358
+ }
359
+ for (const role of missing) {
360
+ let best = null;
361
+ for (const c of candidates) {
362
+ if (c.cur !== sampled[role]) continue;
363
+ const score = (ROLE_NAME[role].test(c.name) ? 2 : 0) + (c.oth && c.oth !== c.cur ? 2 : 0) - (PALETTE_NAME.test(c.name) ? 1 : 0);
364
+ if (!best || score > best.score) best = { name: c.name, score };
365
+ }
366
+ if (best && best.score >= 2) roleVar[role] = { name: best.name, confidence: 2 };
367
+ }
368
+ }
369
+ for (const role of ROLES) {
370
+ const hex = sampled[role];
371
+ if (!current[role] && hex) current[role] = { hex, confidence: roleVar[role] ? 2 : 1 };
372
+ }
373
+ const otherPalette = {};
374
+ let differs = false;
375
+ const otherOrder = ["background", "accent", "text", "textMuted", "border"];
376
+ let otherBg = null;
377
+ const noteBg = (role, hex) => {
378
+ if (role === "background") otherBg = colors.resolve(hex);
379
+ };
380
+ for (const role of otherOrder) {
381
+ const ref = roleVar[role];
382
+ if (!ref) continue;
383
+ const hex = hexOf(probeCs.getPropertyValue(ref.name), otherBg);
384
+ if (!hex) continue;
385
+ noteBg(role, hex);
386
+ otherPalette[role] = { hex, confidence: ref.confidence };
387
+ if (hex !== current[role]?.hex) differs = true;
388
+ }
389
+ if (!differs) {
390
+ for (const role of ROLES) delete otherPalette[role];
391
+ otherBg = null;
392
+ const sheet = scan.byMode[other];
393
+ const resolveVar = (value, depth = 0) => depth > 6 ? value : value.replace(
394
+ /var\(\s*(--[\w-]+)\s*(?:,\s*([^()]*))?\)/g,
395
+ (_m, name, fb) => resolveVar(
396
+ sheet.get(name) ?? scan.byMode.light.get(name) ?? (bodyCs.getPropertyValue(name).trim() || fb || ""),
397
+ depth + 1
398
+ )
399
+ );
400
+ for (const role of otherOrder) {
401
+ const ref = roleVar[role];
402
+ const raw = ref ? sheet.get(ref.name) : void 0;
403
+ const hex = raw ? hexOf(resolveVar(raw), otherBg) : null;
404
+ if (!hex) continue;
405
+ noteBg(role, hex);
406
+ otherPalette[role] = { hex, confidence: 2 };
407
+ if (hex !== current[role]?.hex) differs = true;
408
+ }
409
+ }
410
+ const palettes = { [mode]: current };
411
+ if (differs) palettes[other] = otherPalette;
412
+ const firstVisible = (selector) => Array.from(doc.querySelectorAll(selector)).find(
413
+ (el) => el.getClientRects().length > 0 && (el.textContent ?? "").trim() !== ""
414
+ ) ?? null;
415
+ const bodyFont = describeFont(doc, body, scan.faces);
416
+ const headingFont = describeFont(doc, firstVisible("h1,h2,h3"), scan.faces);
417
+ const fonts = {};
418
+ if (bodyFont) fonts.body = bodyFont;
419
+ if (headingFont) fonts.heading = headingFont;
420
+ const snapshot = { host: view.location.host, mode, palettes };
421
+ const appName = doc.title.trim().slice(0, 120);
422
+ if (appName) snapshot.appName = appName;
423
+ if (fonts.body || fonts.heading) snapshot.fonts = fonts;
424
+ return snapshot;
425
+ } finally {
426
+ colors.dispose();
427
+ modeProbe.remove();
428
+ }
429
+ }
430
+ function snapshotHash(snapshot) {
431
+ const colorsOf = (p) => ROLES.map((r) => {
432
+ const c = p?.[r];
433
+ return c ? `${c.hex}${c.confidence}` : "-";
434
+ }).join("");
435
+ return [
436
+ snapshot.host,
437
+ colorsOf(snapshot.palettes.light),
438
+ colorsOf(snapshot.palettes.dark),
439
+ snapshot.fonts?.body?.family ?? "",
440
+ snapshot.fonts?.heading?.family ?? ""
441
+ ].join("|");
442
+ }
443
+
444
+ export { detectTheme, snapshotHash };
445
+ //# sourceMappingURL=detect-theme-X4K3TLUL.mjs.map
446
+ //# sourceMappingURL=detect-theme-X4K3TLUL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/theme-detect/color.ts","../src/plugins/theme-detect/fonts.ts","../src/plugins/theme-detect/detect-theme.ts"],"names":[],"mappings":"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","file":"detect-theme-X4K3TLUL.mjs","sourcesContent":["/** Color como `[r, g, b, a]` (a en 0..1). */\nexport type Rgba = [number, number, number, number];\n\nconst RGB_RX = /^rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/;\n\n/** Parsea el `rgb()/rgba()` que devuelve `getComputedStyle`. */\nexport function parseRgb(value: string): Rgba | null {\n const m = RGB_RX.exec(value.trim());\n if (!m) return null;\n const a = m[4] === undefined ? 1 : m[4].endsWith('%') ? Number.parseFloat(m[4]) / 100 : +m[4];\n return [+(m[1] as string), +(m[2] as string), +(m[3] as string), a];\n}\n\n/**\n * Valor crudo de una variable CSS → color CSS válido. Varias librerías guardan\n * los canales SUELTOS para componerlos después: shadcn «262 83% 58%» (hsl),\n * Tailwind viejo «124 58 237» (rgb).\n */\nexport function toCssColor(raw: string): string {\n const v = raw.trim();\n const parts = v.split(/[\\s,/]+/).filter(Boolean);\n const bare = parts.length >= 3 && parts.every((p) => /^-?[\\d.]+(%|deg)?$/.test(p));\n if (!bare) return v;\n return v.includes('%') ? `hsl(${v})` : `rgb(${v})`;\n}\n\n/** Descarta rápido valores de variables que no pueden ser un color (tamaños, sombras, fuentes…). */\nexport function looksLikeColor(raw: string): boolean {\n const v = raw.trim();\n if (!v || v.length > 64) return false;\n return (\n /^(#|rgb|hsl|hwb|lab|lch|oklab|oklch|color\\(|color-mix|light-dark)/i.test(v) ||\n toCssColor(v) !== v\n );\n}\n\n/** Aplana un color con alfa sobre un fondo opaco. */\nexport function flatten(c: Rgba, bg: Rgba): Rgba {\n if (c[3] >= 1) return c;\n const mix = (i: 0 | 1 | 2): number => Math.round(c[i] * c[3] + bg[i] * (1 - c[3]));\n return [mix(0), mix(1), mix(2), 1];\n}\n\nexport function toHex(c: Rgba): string {\n const h = (n: number): string => Math.round(n).toString(16).padStart(2, '0');\n return `#${h(c[0])}${h(c[1])}${h(c[2])}`.toUpperCase();\n}\n\n/** Luminancia relativa aproximada (0 = negro, 1 = blanco). */\nexport function luminance(c: Rgba): number {\n return (0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]) / 255;\n}\n\n/** Saturación HSL (0..1): separa colores de marca de grises. */\nexport function saturation(c: Rgba): number {\n const mx = Math.max(c[0], c[1], c[2]) / 255;\n const mn = Math.min(c[0], c[1], c[2]) / 255;\n const l = (mx + mn) / 2;\n return mx === mn ? 0 : (mx - mn) / (1 - Math.abs(2 * l - 1));\n}\n\n/**\n * Resuelve CUALQUIER color CSS (hex, hsl, oklch, color-mix, tripletas sueltas…)\n * a RGBA dejando que el navegador haga la conversión: se asigna a un elemento\n * oculto y se lee el computado; si no viene como `rgb()` (oklch, color(srgb…))\n * se pinta en un canvas de 1×1 y se lee el pixel.\n */\nexport function createColorResolver(doc: Document): {\n resolve: (raw: string) => Rgba | null;\n dispose: () => void;\n} {\n const probe = doc.createElement('span');\n probe.style.display = 'none';\n doc.body.appendChild(probe);\n const view = doc.defaultView;\n let ctx: CanvasRenderingContext2D | null | undefined;\n const cache = new Map<string, Rgba | null>();\n\n const viaCanvas = (computed: string): Rgba | null => {\n if (ctx === undefined) {\n try {\n const canvas = doc.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n ctx = canvas.getContext('2d', { willReadFrequently: true });\n } catch {\n ctx = null;\n }\n }\n if (!ctx) return null;\n ctx.clearRect(0, 0, 1, 1);\n ctx.fillStyle = '#000';\n ctx.fillStyle = computed;\n ctx.fillRect(0, 0, 1, 1);\n const d = ctx.getImageData(0, 0, 1, 1).data;\n return [d[0] ?? 0, d[1] ?? 0, d[2] ?? 0, (d[3] ?? 255) / 255];\n };\n\n return {\n resolve(raw) {\n const key = raw.trim();\n if (!key || !view) return null;\n const hit = cache.get(key);\n if (hit !== undefined) return hit;\n let out: Rgba | null = null;\n probe.style.color = '';\n probe.style.color = toCssColor(key);\n if (probe.style.color) {\n const computed = view.getComputedStyle(probe).color;\n out = parseRgb(computed) ?? viaCanvas(computed);\n }\n cache.set(key, out);\n return out;\n },\n dispose() {\n probe.remove();\n },\n };\n}\n","import type { DetectedFont } from './types';\n\nconst GENERIC =\n /^(serif|sans-serif|monospace|cursive|fantasy|system-ui|ui-sans-serif|ui-serif|ui-monospace|ui-rounded|emoji|math|fangsong|inherit|initial|-apple-system|BlinkMacSystemFont|Segoe UI|Roboto|Helvetica|Helvetica Neue|Arial|Noto Sans|Apple Color Emoji|Segoe UI Emoji|Segoe UI Symbol|Noto Color Emoji)$/i;\n\nexport function cleanFamily(name: string): string {\n return name.trim().replace(/^[\"']|[\"']$/g, '');\n}\n\n/** Primera familia REAL del stack (salta genéricas, del sistema y los «Fallback» de next/font). */\nexport function primaryFamily(stack: string): string {\n const families = stack.split(',').map(cleanFamily).filter(Boolean);\n return families.find((f) => !GENERIC.test(f) && !/fallback/i.test(f)) ?? families[0] ?? '';\n}\n\n/** Nombre legible: next/font mutila la familia («__Inter_5972bc» → «Inter»). */\nexport function prettyFamily(family: string): string {\n return family\n .replace(/^__/, '')\n .replace(/_Fallback_[0-9a-f]+$/i, ' Fallback')\n .replace(/_[0-9a-f]{6,}$/i, '')\n .replace(/_/g, ' ')\n .trim();\n}\n\nexport interface FontFaceInfo {\n family: string;\n url: string | null;\n}\n\n/** Describe la fuente de un elemento: nombre, pesos cargados y de dónde se sirve. */\nexport function describeFont(\n doc: Document,\n el: Element | null,\n faces: FontFaceInfo[],\n): DetectedFont | undefined {\n const view = doc.defaultView;\n if (!el || !view) return undefined;\n const family = primaryFamily(view.getComputedStyle(el).fontFamily);\n if (!family) return undefined;\n const font: DetectedFont = {\n name: prettyFamily(family).slice(0, 80),\n family: family.slice(0, 120),\n };\n\n const weights = new Set<string>();\n try {\n for (const face of Array.from(doc.fonts ?? [])) {\n if (cleanFamily(face.family) === family && face.status === 'loaded') weights.add(face.weight);\n }\n } catch {\n // FontFaceSet no disponible: se omiten los pesos.\n }\n if (weights.size > 0) font.weights = [...weights].sort().join(' ').slice(0, 80);\n\n const own = faces.filter((f) => f.family === family);\n const url = own.find((f) => f.url)?.url ?? null;\n let origin: string | null = null;\n try {\n origin = url ? new URL(url, doc.baseURI).origin : null;\n } catch {\n origin = null;\n }\n const links = Array.from(doc.querySelectorAll<HTMLLinkElement>('link[href]')).map((l) => l.href);\n if (origin) {\n font.hosting = origin.includes('fonts.gstatic.com')\n ? 'google'\n : origin === view.location.origin\n ? 'self'\n : 'external';\n } else if (own.length > 0) {\n font.hosting = 'self';\n } else if (links.some((h) => h.includes('fonts.googleapis.com'))) {\n // La hoja de Google Fonts es cross-origin: sus @font-face no se pueden leer.\n font.hosting = 'google';\n } else if (links.some((h) => h.includes('use.typekit.net'))) {\n font.hosting = 'adobe';\n } else {\n font.hosting = 'system';\n }\n return font;\n}\n","import {\n createColorResolver,\n flatten,\n looksLikeColor,\n luminance,\n type Rgba,\n saturation,\n toHex,\n} from './color';\nimport { cleanFamily, describeFont, type FontFaceInfo } from './fonts';\nimport type {\n DetectedColor,\n DetectedPalette,\n ThemeColorRole,\n ThemeMode,\n ThemeSnapshot,\n} from './types';\n\nconst ROLES: ThemeColorRole[] = ['accent', 'text', 'textMuted', 'background', 'border'];\n\n/**\n * Variables CSS conocidas por rol, de más a menos específica (shadcn, Tailwind\n * v4, Bootstrap, MUI, Ant, Chakra). Ojo: en shadcn `--accent` es el gris de\n * hover, por eso va al final.\n */\nconst KNOWN_VARS: Record<ThemeColorRole, string[]> = {\n accent: [\n '--primary',\n '--color-primary',\n '--brand',\n '--color-brand',\n '--brand-primary',\n '--mui-palette-primary-main',\n '--bs-primary',\n '--ant-color-primary',\n '--chakra-colors-brand-500',\n '--accent-color',\n '--accent',\n ],\n text: [\n '--foreground',\n '--color-foreground',\n '--text',\n '--color-text',\n '--text-primary',\n '--bs-body-color',\n '--mui-palette-text-primary',\n ],\n textMuted: [\n '--muted-foreground',\n '--color-muted-foreground',\n '--text-muted',\n '--text-secondary',\n '--bs-secondary-color',\n '--mui-palette-text-secondary',\n ],\n background: [\n '--background',\n '--color-background',\n '--bg',\n '--color-bg',\n '--bs-body-bg',\n '--mui-palette-background-default',\n ],\n border: [\n '--border',\n '--color-border',\n '--border-color',\n '--bs-border-color',\n '--mui-palette-divider',\n ],\n};\n\n/** Nombre «acorde al rol», para elegir entre variables con el mismo valor. */\nconst ROLE_NAME: Record<ThemeColorRole, RegExp> = {\n accent: /brand|primary|accent|main/i,\n text: /text|foreground|\\bfg\\b|-fg|ink|content|body/i,\n textMuted: /muted|secondary|subtle|soft|hint|placeholder|text|-fg/i,\n background: /background|\\bbg\\b|-bg|surface|canvas|page|base/i,\n border: /border|line|divider|stroke|outline|separator/i,\n};\n/** Variables de PALETA (`gray-500`, `white`): no cambian con el modo, no son semánticas. */\nconst PALETTE_NAME = /-(50|[1-9]00|950)$|white|black/i;\n\nconst DARK_SELECTOR =\n /\\.dark\\b|\\[data-(theme|mode|color-scheme)=[\"']?dark|\\.theme-dark|\\.dark-theme/i;\nconst LIGHT_SELECTOR = /^(:root|html|:host|body)$|\\.light\\b|\\[data-(theme|mode)=[\"']?light/i;\n\nconst MAX_ELEMENTS = 1500;\nconst MAX_VARS = 600;\n\ninterface SheetScan {\n names: Set<string>;\n byMode: Record<ThemeMode, Map<string, string>>;\n faces: FontFaceInfo[];\n}\n\n/** Una pasada por las hojas legibles: nombres de variables, valores por modo y @font-face. */\nfunction scanSheets(doc: Document): SheetScan {\n const scan: SheetScan = {\n names: new Set(),\n byMode: { light: new Map(), dark: new Map() },\n faces: [],\n };\n const walk = (rules: CSSRuleList, inDarkMedia: boolean): void => {\n for (const rule of Array.from(rules)) {\n const style = (rule as CSSStyleRule).style as CSSStyleDeclaration | undefined;\n const selector = (rule as CSSStyleRule).selectorText as string | undefined;\n if (rule.constructor.name === 'CSSFontFaceRule' && style) {\n const src = style.getPropertyValue('src');\n const url = /url\\([\"']?([^\"')]+)[\"']?\\)/.exec(src)?.[1] ?? null;\n scan.faces.push({ family: cleanFamily(style.getPropertyValue('font-family')), url });\n } else if (style && typeof selector === 'string') {\n const selectors = selector.split(',').map((s) => s.trim());\n const mode: ThemeMode | null = selectors.some((s) => DARK_SELECTOR.test(s))\n ? 'dark'\n : selectors.some((s) => LIGHT_SELECTOR.test(s))\n ? inDarkMedia\n ? 'dark'\n : 'light'\n : null;\n for (const prop of Array.from(style)) {\n if (!prop.startsWith('--')) continue;\n scan.names.add(prop);\n if (mode) scan.byMode[mode].set(prop, style.getPropertyValue(prop).trim());\n }\n }\n const nested = (rule as CSSGroupingRule).cssRules as CSSRuleList | undefined;\n if (nested) {\n const media = (rule as CSSMediaRule).conditionText ?? '';\n walk(nested, inDarkMedia || /prefers-color-scheme:\\s*dark/.test(media));\n }\n }\n };\n for (const sheet of Array.from(doc.styleSheets)) {\n try {\n walk(sheet.cssRules, false);\n } catch {\n // Hoja cross-origin sin CORS: ilegible.\n }\n }\n return scan;\n}\n\nfunction top(counts: Map<string, number>): string | null {\n let best: string | null = null;\n let max = 0;\n for (const [hex, n] of counts) {\n if (n > max) {\n max = n;\n best = hex;\n }\n }\n return best;\n}\n\n/**\n * Detecta el tema visual de la app donde corre el SDK: los 5 colores base\n * (acento, texto, texto tenue, fondo, borde) en el modo actual Y en el otro, y\n * las fuentes de cuerpo/encabezados. Solo lee estilos: nunca contenido.\n *\n * Colores, de más a menos fiable:\n * 1. variables CSS conocidas (`--primary`, `--foreground`…) → confianza 3;\n * 2. muestreo del DOM (fondo de botones, color del body, borde más frecuente)\n * y, con ese valor, la variable de la app que VALE eso → confianza 2 (así se\n * cubren apps con tokens propios, p. ej. `--color-brand`);\n * 3. el muestreo a secas → confianza 1.\n * El otro modo sale SIN activarlo: un elemento oculto con `class=\"dark\"`\n * hereda las variables de `.dark { … }`; si eso no cambia nada, se leen de la\n * hoja de estilos (`.dark`, `[data-theme=dark]`, `prefers-color-scheme`).\n */\nexport function detectTheme(doc: Document = document): ThemeSnapshot | null {\n const view = doc.defaultView;\n const body = doc.body;\n if (!view || !body) return null;\n const html = doc.documentElement;\n const colors = createColorResolver(doc);\n const modeProbe = doc.createElement('div');\n try {\n const bodyCs = view.getComputedStyle(body);\n\n // ── Fondo y texto base\n let bg: Rgba = [255, 255, 255, 1];\n for (const el of [body, html]) {\n const c = colors.resolve(view.getComputedStyle(el).backgroundColor);\n if (c && c[3] > 0) {\n bg = flatten(c, [255, 255, 255, 1]);\n break;\n }\n }\n const text = flatten(colors.resolve(bodyCs.color) ?? [0, 0, 0, 1], bg);\n const textHex = toHex(text);\n\n // ── Muestreo del DOM visible\n const muted = new Map<string, number>();\n const border = new Map<string, number>();\n const accent = new Map<string, number>();\n const link = new Map<string, number>();\n const bump = (m: Map<string, number>, k: string): void => {\n m.set(k, (m.get(k) ?? 0) + 1);\n };\n const contrast = Math.abs(luminance(text) - luminance(bg));\n const elements = Array.from(body.querySelectorAll('*')).slice(0, MAX_ELEMENTS);\n for (const el of elements) {\n if (el.getClientRects().length === 0) continue;\n const cs = view.getComputedStyle(el);\n const hasText = Array.from(el.childNodes).some(\n (n) => n.nodeType === 3 && (n.textContent ?? '').trim() !== '',\n );\n if (hasText) {\n const c = colors.resolve(cs.color);\n if (c && c[3] > 0) {\n const flat = flatten(c, bg);\n const hex = toHex(flat);\n const softer = Math.abs(luminance(flat) - luminance(bg)) < contrast;\n if (hex !== textHex && saturation(flat) < 0.3 && softer) bump(muted, hex);\n if (el.closest('a') && saturation(flat) >= 0.3) bump(link, hex);\n }\n }\n if (Number.parseFloat(cs.borderTopWidth) > 0 && cs.borderTopStyle !== 'none') {\n const c = colors.resolve(cs.borderTopColor);\n if (c && c[3] > 0) {\n const flat = flatten(c, bg);\n if (saturation(flat) < 0.3 && toHex(flat) !== textHex) bump(border, toHex(flat));\n }\n }\n if (\n el.matches('button,[role=\"button\"],input[type=\"submit\"],a[class*=\"btn\"],a[class*=\"button\"]')\n ) {\n const c = colors.resolve(cs.backgroundColor);\n if (c && c[3] > 0.5 && saturation(c) >= 0.3) bump(accent, toHex(c));\n }\n }\n const meta = doc.querySelector<HTMLMetaElement>('meta[name=\"theme-color\"]');\n const metaColor = meta ? colors.resolve(meta.content) : null;\n const sampled: Partial<Record<ThemeColorRole, string>> = {\n background: toHex(bg),\n text: textHex,\n };\n const sampledAccent = top(accent) ?? top(link) ?? (metaColor ? toHex(metaColor) : null);\n if (sampledAccent) sampled.accent = sampledAccent;\n const sampledMuted = top(muted);\n if (sampledMuted) sampled.textMuted = sampledMuted;\n const sampledBorder = top(border);\n if (sampledBorder) sampled.border = sampledBorder;\n\n // ── Modo actual: clase/atributo → color-scheme → luminancia del fondo\n const hints = [\n html.className,\n html.dataset.theme,\n html.dataset.mode,\n body.className,\n body.dataset.theme,\n ]\n .join(' ')\n .toLowerCase();\n const mode: ThemeMode = /\\bdark\\b/.test(hints)\n ? 'dark'\n : /\\blight\\b/.test(hints)\n ? 'light'\n : view.getComputedStyle(html).colorScheme === 'dark' || luminance(bg) < 0.4\n ? 'dark'\n : 'light';\n const other: ThemeMode = mode === 'dark' ? 'light' : 'dark';\n\n // ── Elemento oculto con la clase del OTRO modo: hereda sus variables\n modeProbe.className = other;\n modeProbe.dataset.theme = other;\n modeProbe.dataset.mode = other;\n modeProbe.style.cssText = `display:none;color-scheme:${other}`;\n body.appendChild(modeProbe);\n const probeCs = view.getComputedStyle(modeProbe);\n // Un color con alfa (p. ej. `--border: rgb(0 0 0 / .1)`) solo vale aplanado\n // sobre el fondo de SU modo; sin fondo conocido se descarta.\n const hexOf = (raw: string, over?: Rgba | null): string | null => {\n if (!looksLikeColor(raw)) return null;\n const c = colors.resolve(raw);\n if (!c || c[3] === 0) return null;\n if (c[3] > 0.98) return toHex(c);\n return over ? toHex(flatten(c, over)) : null;\n };\n\n // ── Rol → variable: por nombre conocido (3) o por valor muestreado (2)\n const scan = scanSheets(doc);\n const roleVar: Partial<Record<ThemeColorRole, { name: string; confidence: 2 | 3 }>> = {};\n const current: DetectedPalette = {};\n for (const role of ROLES) {\n for (const name of KNOWN_VARS[role]) {\n const hex = hexOf(bodyCs.getPropertyValue(name), bg);\n if (hex) {\n roleVar[role] = { name, confidence: 3 };\n current[role] = { hex, confidence: 3 };\n break;\n }\n }\n }\n const missing = ROLES.filter((r) => !roleVar[r] && sampled[r]);\n if (missing.length > 0) {\n const candidates: { name: string; cur: string; oth: string | null }[] = [];\n for (const name of Array.from(scan.names).slice(0, MAX_VARS)) {\n const cur = hexOf(bodyCs.getPropertyValue(name));\n if (cur) candidates.push({ name, cur, oth: hexOf(probeCs.getPropertyValue(name)) });\n }\n for (const role of missing) {\n let best: { name: string; score: number } | null = null;\n for (const c of candidates) {\n if (c.cur !== sampled[role]) continue;\n const score =\n (ROLE_NAME[role].test(c.name) ? 2 : 0) +\n (c.oth && c.oth !== c.cur ? 2 : 0) -\n (PALETTE_NAME.test(c.name) ? 1 : 0);\n if (!best || score > best.score) best = { name: c.name, score };\n }\n // Exige nombre acorde o que cambie con el modo: si no, es coincidencia.\n if (best && best.score >= 2) roleVar[role] = { name: best.name, confidence: 2 };\n }\n }\n for (const role of ROLES) {\n const hex = sampled[role];\n if (!current[role] && hex) current[role] = { hex, confidence: roleVar[role] ? 2 : 1 };\n }\n\n // ── El otro modo: probe; si no cambia nada, la hoja de estilos\n const otherPalette: DetectedPalette = {};\n let differs = false;\n // El fondo va primero: sobre él se aplanan los colores con alfa del otro modo.\n const otherOrder: ThemeColorRole[] = ['background', 'accent', 'text', 'textMuted', 'border'];\n let otherBg: Rgba | null = null;\n const noteBg = (role: ThemeColorRole, hex: string): void => {\n if (role === 'background') otherBg = colors.resolve(hex);\n };\n for (const role of otherOrder) {\n const ref = roleVar[role];\n if (!ref) continue;\n const hex = hexOf(probeCs.getPropertyValue(ref.name), otherBg);\n if (!hex) continue;\n noteBg(role, hex);\n otherPalette[role] = { hex, confidence: ref.confidence };\n if (hex !== current[role]?.hex) differs = true;\n }\n if (!differs) {\n for (const role of ROLES) delete otherPalette[role];\n otherBg = null;\n const sheet = scan.byMode[other];\n const resolveVar = (value: string, depth = 0): string =>\n depth > 6\n ? value\n : value.replace(\n /var\\(\\s*(--[\\w-]+)\\s*(?:,\\s*([^()]*))?\\)/g,\n (_m, name: string, fb?: string) =>\n resolveVar(\n sheet.get(name) ??\n scan.byMode.light.get(name) ??\n (bodyCs.getPropertyValue(name).trim() || fb || ''),\n depth + 1,\n ),\n );\n for (const role of otherOrder) {\n const ref = roleVar[role];\n const raw = ref ? sheet.get(ref.name) : undefined;\n const hex = raw ? hexOf(resolveVar(raw), otherBg) : null;\n if (!hex) continue;\n noteBg(role, hex);\n otherPalette[role] = { hex, confidence: 2 };\n if (hex !== current[role]?.hex) differs = true;\n }\n }\n\n const palettes: ThemeSnapshot['palettes'] = { [mode]: current };\n // Sin ninguna diferencia, la app no tiene (o no expone) otro modo: no se inventa.\n if (differs) palettes[other] = otherPalette;\n\n // ── Fuentes\n const firstVisible = (selector: string): Element | null =>\n Array.from(doc.querySelectorAll(selector)).find(\n (el) => el.getClientRects().length > 0 && (el.textContent ?? '').trim() !== '',\n ) ?? null;\n const bodyFont = describeFont(doc, body, scan.faces);\n const headingFont = describeFont(doc, firstVisible('h1,h2,h3'), scan.faces);\n const fonts: NonNullable<ThemeSnapshot['fonts']> = {};\n if (bodyFont) fonts.body = bodyFont;\n if (headingFont) fonts.heading = headingFont;\n\n const snapshot: ThemeSnapshot = { host: view.location.host, mode, palettes };\n const appName = doc.title.trim().slice(0, 120);\n if (appName) snapshot.appName = appName;\n if (fonts.body || fonts.heading) snapshot.fonts = fonts;\n return snapshot;\n } finally {\n colors.dispose();\n modeProbe.remove();\n }\n}\n\n/** Huella estable del snapshot: si no cambió desde el último envío, no se reenvía. */\nexport function snapshotHash(snapshot: ThemeSnapshot): string {\n const colorsOf = (p?: DetectedPalette): string =>\n ROLES.map((r) => {\n const c: DetectedColor | undefined = p?.[r];\n return c ? `${c.hex}${c.confidence}` : '-';\n }).join('');\n return [\n snapshot.host,\n colorsOf(snapshot.palettes.light),\n colorsOf(snapshot.palettes.dark),\n snapshot.fonts?.body?.family ?? '',\n snapshot.fonts?.heading?.family ?? '',\n ].join('|');\n}\n"]}
@@ -207,6 +207,119 @@ interface StepBlock {
207
207
  */
208
208
  editorId?: string | null;
209
209
  }
210
+ interface GuideThemeText {
211
+ color: string;
212
+ /** CSS font-family, o `inherit` (fuente de la app) / `app-heading` (la de sus encabezados). */
213
+ fontFamily: string;
214
+ fontWeight: number;
215
+ fontSize: number;
216
+ align: 'left' | 'center' | 'right';
217
+ }
218
+ interface GuideThemeBox {
219
+ /** Solo el modal flotante; el embebido no tiene fondo propio. */
220
+ background?: string;
221
+ padding: {
222
+ top: number;
223
+ right: number;
224
+ bottom: number;
225
+ left: number;
226
+ };
227
+ borderColor: string;
228
+ borderWidth: number;
229
+ borderRadius: number;
230
+ shadowColor: string;
231
+ shadow: 'none' | 'soft' | 'medium' | 'strong';
232
+ align: 'left' | 'center' | 'right' | 'distribute';
233
+ valign: 'top' | 'center' | 'bottom';
234
+ }
235
+ /** Botón del tema (pestaña Botones). Colores ya resueltos a hex por el backend. */
236
+ interface GuideThemeButton {
237
+ /** Dónde se ubica el botón en su fila. */
238
+ align: 'left' | 'center' | 'right';
239
+ padding: {
240
+ top: number;
241
+ right: number;
242
+ bottom: number;
243
+ left: number;
244
+ };
245
+ /** Hex o `transparent`. */
246
+ background: string;
247
+ color: string;
248
+ fontWeight: number;
249
+ fontSize: number;
250
+ borderColor: string;
251
+ borderWidth: number;
252
+ borderRadius: number;
253
+ }
254
+ /** Tooltip del tema: pasos anclados a un elemento y badges. */
255
+ interface GuideThemeTooltip {
256
+ text: {
257
+ primary: GuideThemeText;
258
+ secondary: GuideThemeText;
259
+ };
260
+ background: string;
261
+ padding: {
262
+ top: number;
263
+ right: number;
264
+ bottom: number;
265
+ left: number;
266
+ };
267
+ borderColor?: string;
268
+ borderWidth?: number;
269
+ borderRadius?: number;
270
+ shadowColor?: string;
271
+ shadow?: 'none' | 'soft' | 'medium' | 'strong';
272
+ }
273
+ /** Formulario del tema: bloques de encuesta. */
274
+ interface GuideThemeForm {
275
+ text: {
276
+ primary: GuideThemeText;
277
+ secondary: GuideThemeText;
278
+ };
279
+ background: string;
280
+ accent: string;
281
+ /** Texto legible sobre `accent`. */
282
+ onAccent: string;
283
+ padding: {
284
+ top: number;
285
+ right: number;
286
+ bottom: number;
287
+ left: number;
288
+ };
289
+ borderColor?: string;
290
+ borderWidth?: number;
291
+ borderRadius?: number;
292
+ shadowColor?: string;
293
+ shadow?: 'none' | 'soft' | 'medium' | 'strong';
294
+ }
295
+ interface GuideThemeMode {
296
+ colors: {
297
+ accent: string;
298
+ text: string;
299
+ textMuted: string;
300
+ background: string;
301
+ border: string;
302
+ };
303
+ /** Opcional: un backend anterior a la pestaña Formulario no lo manda. */
304
+ form?: GuideThemeForm;
305
+ /** Opcional: un backend anterior a la pestaña Tooltip no lo manda. */
306
+ tooltip?: GuideThemeTooltip;
307
+ /** Opcional: un backend anterior a la pestaña Botones no lo manda. */
308
+ buttons?: {
309
+ primary?: GuideThemeButton;
310
+ secondary?: GuideThemeButton;
311
+ /** El preset «link» del bloque botón. */
312
+ tertiary?: GuideThemeButton;
313
+ };
314
+ text: {
315
+ title: GuideThemeText;
316
+ subtitle: GuideThemeText;
317
+ paragraph: GuideThemeText;
318
+ };
319
+ overlay: GuideThemeBox;
320
+ embedded: GuideThemeBox;
321
+ }
322
+ type GuideTheme = Record<'light' | 'dark', GuideThemeMode>;
210
323
  interface GuideStep {
211
324
  title: string;
212
325
  content: string;
@@ -256,6 +369,8 @@ interface PreviewGuideInput {
256
369
  activationRules?: Partial<ActivationRules>;
257
370
  /** Nombre mostrado (p.ej. en el `title` del iframe de guías `custom`). */
258
371
  guideName?: string;
372
+ /** Tema del workspace (design system) ya resuelto; lo manda el editor del dashboard. */
373
+ theme?: GuideTheme | null;
259
374
  /**
260
375
  * Solo walkthrough: paso inicial a mostrar (default 0). Lo usa el editor del
261
376
  * dashboard para que la preview salte al paso que se está editando.