veo-sdk 0.6.1 → 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.
- package/dist/builder-ENKEIVF2.mjs +5 -0
- package/dist/{builder-BKPMANUB.mjs.map → builder-ENKEIVF2.mjs.map} +1 -1
- package/dist/builder.cjs +287 -13
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +2 -2
- package/dist/builder.d.ts +2 -2
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-VWF4UHUU.mjs → chunk-4QZDNJJE.mjs} +3 -3
- package/dist/{chunk-VWF4UHUU.mjs.map → chunk-4QZDNJJE.mjs.map} +1 -1
- package/dist/{chunk-GVPAJFNW.mjs → chunk-L3QQJLDJ.mjs} +3 -3
- package/dist/{chunk-GVPAJFNW.mjs.map → chunk-L3QQJLDJ.mjs.map} +1 -1
- package/dist/{chunk-NGP7IJVE.mjs → chunk-ZILDR4YE.mjs} +289 -15
- package/dist/chunk-ZILDR4YE.mjs.map +1 -0
- package/dist/detect-theme-X4K3TLUL.mjs +446 -0
- package/dist/detect-theme-X4K3TLUL.mjs.map +1 -0
- package/dist/{guide-preview-DylsEhrg.d.cts → guide-preview-DEFhfA4o.d.cts} +115 -0
- package/dist/{guide-preview-DylsEhrg.d.ts → guide-preview-DEFhfA4o.d.ts} +115 -0
- package/dist/index.cjs +914 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.mjs +141 -16
- package/dist/index.mjs.map +1 -1
- package/dist/veo-builder.js +92 -20
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo-guides.js +84 -12
- package/dist/veo-guides.js.map +1 -1
- package/dist/veo-theme.js +2 -0
- package/dist/veo-theme.js.map +1 -0
- package/dist/veo.js +2 -2
- package/dist/veo.js.map +1 -1
- package/package.json +2 -2
- package/dist/builder-BKPMANUB.mjs +0 -5
- package/dist/chunk-NGP7IJVE.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -902,6 +902,10 @@ function clampNum(n, min, max) {
|
|
|
902
902
|
return Math.min(max, Math.max(min, n));
|
|
903
903
|
}
|
|
904
904
|
function applyBlockStyle(el2, style, kind) {
|
|
905
|
+
if (kind === "text") {
|
|
906
|
+
const explicit = style && typeof style === "object" ? style.preset : void 0;
|
|
907
|
+
el2.dataset.veoPreset = typeof explicit === "string" ? explicit : el2.classList.contains("veo-guide-title") ? "title" : "paragraph";
|
|
908
|
+
}
|
|
905
909
|
if (!style || typeof style !== "object") return;
|
|
906
910
|
const s = style;
|
|
907
911
|
if (kind === "image" && s.bleed === true) {
|
|
@@ -918,8 +922,9 @@ function applyBlockStyle(el2, style, kind) {
|
|
|
918
922
|
if (kind === "text" && typeof s.preset === "string" && s.preset in TEXT_PRESETS) {
|
|
919
923
|
const preset = TEXT_PRESETS[s.preset];
|
|
920
924
|
if (preset) {
|
|
921
|
-
|
|
922
|
-
el2.style.
|
|
925
|
+
const token = s.preset === "small" ? null : `--veo-t-${s.preset}`;
|
|
926
|
+
el2.style.fontSize = token ? `var(${token}-size, ${preset.size}px)` : `${preset.size}px`;
|
|
927
|
+
el2.style.fontWeight = token ? `var(${token}-weight, ${preset.weight})` : String(preset.weight);
|
|
923
928
|
el2.style.lineHeight = String(preset.lineHeight);
|
|
924
929
|
}
|
|
925
930
|
}
|
|
@@ -1635,20 +1640,92 @@ var init_styles = __esm({
|
|
|
1635
1640
|
.veo-guide-actions {
|
|
1636
1641
|
display: flex; gap: 8px; justify-content: var(--veo-actions-justify);
|
|
1637
1642
|
}
|
|
1643
|
+
/* Tema del workspace (design system): cada preset de texto toma sus tokens de
|
|
1644
|
+
las variables que publica \`applyThemeVars\` en la tarjeta. Las reglas solo
|
|
1645
|
+
existen bajo .veo-card--themed; los estilos inline del bloque las pisan. El
|
|
1646
|
+
\`*\` cubre el rich text (la regla global de fuente aplica a cada hijo). */
|
|
1647
|
+
.veo-card--themed [data-veo-preset="title"] {
|
|
1648
|
+
color: var(--veo-t-title-color); font-size: var(--veo-t-title-size);
|
|
1649
|
+
font-weight: var(--veo-t-title-weight); text-align: var(--veo-t-title-align);
|
|
1650
|
+
}
|
|
1651
|
+
.veo-card--themed [data-veo-preset="subtitle"] {
|
|
1652
|
+
color: var(--veo-t-subtitle-color); font-size: var(--veo-t-subtitle-size);
|
|
1653
|
+
font-weight: var(--veo-t-subtitle-weight); text-align: var(--veo-t-subtitle-align);
|
|
1654
|
+
}
|
|
1655
|
+
.veo-card--themed [data-veo-preset="paragraph"] {
|
|
1656
|
+
color: var(--veo-t-paragraph-color); font-size: var(--veo-t-paragraph-size);
|
|
1657
|
+
font-weight: var(--veo-t-paragraph-weight); text-align: var(--veo-t-paragraph-align);
|
|
1658
|
+
}
|
|
1659
|
+
.veo-card--themed [data-veo-preset="small"] { color: var(--veo-t-paragraph-color); }
|
|
1660
|
+
.veo-card--themed [data-veo-preset="title"], .veo-card--themed [data-veo-preset="title"] * {
|
|
1661
|
+
font-family: var(--veo-t-title-font, var(--veo-font));
|
|
1662
|
+
}
|
|
1663
|
+
.veo-card--themed [data-veo-preset="subtitle"], .veo-card--themed [data-veo-preset="subtitle"] * {
|
|
1664
|
+
font-family: var(--veo-t-subtitle-font, var(--veo-font));
|
|
1665
|
+
}
|
|
1666
|
+
.veo-card--themed [data-veo-preset="paragraph"], .veo-card--themed [data-veo-preset="paragraph"] *,
|
|
1667
|
+
.veo-card--themed [data-veo-preset="small"], .veo-card--themed [data-veo-preset="small"] * {
|
|
1668
|
+
font-family: var(--veo-t-paragraph-font, var(--veo-font));
|
|
1669
|
+
}
|
|
1670
|
+
/* Formulario del tema (pesta\xF1a Formulario). Dentro de un .veo-form los tokens
|
|
1671
|
+
de texto \`--veo-t-*\` se REDEFINEN con \xABTexto principal\xBB: la pregunta es un
|
|
1672
|
+
bloque con preset (su tama\xF1o va inline con esas variables), as\xED toma los del
|
|
1673
|
+
formulario y no los del modal. Etiquetas y opciones = \xABTexto secundario\xBB. */
|
|
1674
|
+
.veo-card--themed-form .veo-form {
|
|
1675
|
+
background: var(--veo-f-bg); padding: var(--veo-f-pad);
|
|
1676
|
+
border: var(--veo-f-border, none); border-radius: var(--veo-f-radius, 8px);
|
|
1677
|
+
box-shadow: var(--veo-f-shadow, none);
|
|
1678
|
+
--veo-t-title-color: var(--veo-f-primary-color); --veo-t-title-size: var(--veo-f-primary-size);
|
|
1679
|
+
--veo-t-title-weight: var(--veo-f-primary-weight); --veo-t-title-align: var(--veo-f-primary-align);
|
|
1680
|
+
--veo-t-title-font: var(--veo-f-primary-font);
|
|
1681
|
+
--veo-t-subtitle-color: var(--veo-f-primary-color); --veo-t-subtitle-size: var(--veo-f-primary-size);
|
|
1682
|
+
--veo-t-subtitle-weight: var(--veo-f-primary-weight); --veo-t-subtitle-align: var(--veo-f-primary-align);
|
|
1683
|
+
--veo-t-subtitle-font: var(--veo-f-primary-font);
|
|
1684
|
+
--veo-t-paragraph-color: var(--veo-f-primary-color); --veo-t-paragraph-size: var(--veo-f-primary-size);
|
|
1685
|
+
--veo-t-paragraph-weight: var(--veo-f-primary-weight); --veo-t-paragraph-align: var(--veo-f-primary-align);
|
|
1686
|
+
--veo-t-paragraph-font: var(--veo-f-primary-font);
|
|
1687
|
+
}
|
|
1688
|
+
.veo-card--themed-form .veo-form-label,
|
|
1689
|
+
.veo-card--themed-form .veo-form-option,
|
|
1690
|
+
.veo-card--themed-form .veo-scale-label {
|
|
1691
|
+
color: var(--veo-f-secondary-color); font-weight: var(--veo-f-secondary-weight);
|
|
1692
|
+
font-family: var(--veo-f-secondary-font, var(--veo-font));
|
|
1693
|
+
}
|
|
1694
|
+
.veo-card--themed-form .veo-form-label,
|
|
1695
|
+
.veo-card--themed-form .veo-form-option {
|
|
1696
|
+
font-size: var(--veo-f-secondary-size); text-align: var(--veo-f-secondary-align);
|
|
1697
|
+
}
|
|
1698
|
+
.veo-card--themed-form .veo-form-input:focus { outline-color: var(--veo-f-accent); }
|
|
1699
|
+
.veo-card--themed-form .veo-form-option input { accent-color: var(--veo-f-accent); }
|
|
1700
|
+
.veo-card--themed-form .veo-nps-btn:hover { border-color: var(--veo-scale-color, var(--veo-f-accent)); }
|
|
1701
|
+
.veo-card--themed-form .veo-scale-active.veo-nps-btn {
|
|
1702
|
+
background: var(--veo-scale-color, var(--veo-f-accent)); color: var(--veo-f-on-accent);
|
|
1703
|
+
border-color: var(--veo-scale-color, var(--veo-f-accent));
|
|
1704
|
+
}
|
|
1638
1705
|
.veo-guide-cta {
|
|
1639
1706
|
background: var(--veo-cta-bg, var(--veo-primary));
|
|
1640
|
-
color: var(--veo-cta-color, #fff); border: none;
|
|
1641
|
-
padding: 9px 18px; border-radius: var(--veo-cta-radius, 8px);
|
|
1642
|
-
font-size: var(--veo-cta-size, 14px); font-weight: 500; cursor: pointer;
|
|
1707
|
+
color: var(--veo-cta-color, #fff); border: var(--veo-cta-border, none);
|
|
1708
|
+
padding: var(--veo-cta-pad, 9px 18px); border-radius: var(--veo-cta-radius, 8px);
|
|
1709
|
+
font-size: var(--veo-cta-size, 14px); font-weight: var(--veo-cta-weight, 500); cursor: pointer;
|
|
1643
1710
|
transition: opacity 120ms ease;
|
|
1644
1711
|
}
|
|
1645
1712
|
.veo-guide-cta:hover { opacity: 0.9; }
|
|
1646
1713
|
/* Presets del boton (editor): secundario = contorno; enlace = solo texto. */
|
|
1647
1714
|
.veo-guide-cta--secondary {
|
|
1648
|
-
background: transparent; color: var(--veo-primary);
|
|
1649
|
-
border: 1px solid var(--veo-primary);
|
|
1715
|
+
background: var(--veo-cta2-bg, transparent); color: var(--veo-cta2-color, var(--veo-primary));
|
|
1716
|
+
border: var(--veo-cta2-border, 1px solid var(--veo-primary));
|
|
1717
|
+
padding: var(--veo-cta2-pad, var(--veo-cta-pad, 9px 18px));
|
|
1718
|
+
border-radius: var(--veo-cta2-radius, var(--veo-cta-radius, 8px));
|
|
1719
|
+
font-size: var(--veo-cta2-size, var(--veo-cta-size, 14px));
|
|
1720
|
+
font-weight: var(--veo-cta2-weight, var(--veo-cta-weight, 500));
|
|
1721
|
+
}
|
|
1722
|
+
.veo-guide-cta--link {
|
|
1723
|
+
background: transparent; color: var(--veo-cta3-color, var(--veo-primary));
|
|
1724
|
+
border: var(--veo-cta3-border, none); padding: var(--veo-cta3-pad, 0);
|
|
1725
|
+
border-radius: var(--veo-cta3-radius, 0);
|
|
1726
|
+
font-size: var(--veo-cta3-size, var(--veo-cta-size, 14px));
|
|
1727
|
+
font-weight: var(--veo-cta3-weight, var(--veo-cta-weight, 500));
|
|
1650
1728
|
}
|
|
1651
|
-
.veo-guide-cta--link { background: transparent; color: var(--veo-primary); padding: 0; }
|
|
1652
1729
|
.veo-guide-cta--link:hover { opacity: 1; text-decoration: underline; }
|
|
1653
1730
|
.veo-guide-cta:active { transform: translateY(1px); }
|
|
1654
1731
|
.veo-guide-close {
|
|
@@ -2030,8 +2107,18 @@ function positionArrow(arrowEl, placement, data) {
|
|
|
2030
2107
|
if (data?.x != null) arrowEl.style.setProperty("left", `${data.x}px`);
|
|
2031
2108
|
if (data?.y != null) arrowEl.style.setProperty("top", `${data.y}px`);
|
|
2032
2109
|
arrowEl.style.setProperty(side, "-6px");
|
|
2110
|
+
const width = arrowEl.dataset.veoBorder;
|
|
2111
|
+
if (width) {
|
|
2112
|
+
for (const edge of ["top", "right", "bottom", "left"]) {
|
|
2113
|
+
arrowEl.style.setProperty(
|
|
2114
|
+
`border-${edge}-width`,
|
|
2115
|
+
OUTER_EDGES[side].includes(edge) ? `${width}px` : "0"
|
|
2116
|
+
);
|
|
2117
|
+
}
|
|
2118
|
+
arrowEl.style.zIndex = "1";
|
|
2119
|
+
}
|
|
2033
2120
|
}
|
|
2034
|
-
var STATIC_SIDE;
|
|
2121
|
+
var STATIC_SIDE, OUTER_EDGES;
|
|
2035
2122
|
var init_floating_arrow = __esm({
|
|
2036
2123
|
"src/plugins/guides/renderers/floating-arrow.ts"() {
|
|
2037
2124
|
STATIC_SIDE = {
|
|
@@ -2040,6 +2127,12 @@ var init_floating_arrow = __esm({
|
|
|
2040
2127
|
left: "right",
|
|
2041
2128
|
right: "left"
|
|
2042
2129
|
};
|
|
2130
|
+
OUTER_EDGES = {
|
|
2131
|
+
top: ["top", "left"],
|
|
2132
|
+
right: ["top", "right"],
|
|
2133
|
+
bottom: ["bottom", "right"],
|
|
2134
|
+
left: ["bottom", "left"]
|
|
2135
|
+
};
|
|
2043
2136
|
}
|
|
2044
2137
|
});
|
|
2045
2138
|
function readBadgeConfig(step) {
|
|
@@ -3213,6 +3306,173 @@ var init_form_content = __esm({
|
|
|
3213
3306
|
}
|
|
3214
3307
|
});
|
|
3215
3308
|
|
|
3309
|
+
// src/plugins/guides/guide-theme.ts
|
|
3310
|
+
function channels(hex) {
|
|
3311
|
+
const h = hex.replace("#", "");
|
|
3312
|
+
const full = h.length === 3 ? [...h].map((x) => x + x).join("") : h.slice(0, 6);
|
|
3313
|
+
const ch = (i) => Number.parseInt(full.slice(i, i + 2), 16) || 0;
|
|
3314
|
+
return [ch(0), ch(2), ch(4)];
|
|
3315
|
+
}
|
|
3316
|
+
function boxShadow(shadow, hex) {
|
|
3317
|
+
if (shadow === "none") return "none";
|
|
3318
|
+
const spec = SHADOW_SPEC[shadow];
|
|
3319
|
+
const [r, g, b] = channels(hex);
|
|
3320
|
+
return `0 ${spec.y}px ${spec.blur}px rgba(${r}, ${g}, ${b}, ${spec.alpha})`;
|
|
3321
|
+
}
|
|
3322
|
+
function readableOn(hex) {
|
|
3323
|
+
const [r, g, b] = channels(hex);
|
|
3324
|
+
return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 > 0.6 ? "#111827" : "#ffffff";
|
|
3325
|
+
}
|
|
3326
|
+
function themeModeFor(theme, design) {
|
|
3327
|
+
if (!theme || design.theme !== WORKSPACE_THEME_ID) return null;
|
|
3328
|
+
return (design.colorMode === "dark" ? theme.dark : theme.light) ?? null;
|
|
3329
|
+
}
|
|
3330
|
+
function themeRowJustify(mode, inline, preset) {
|
|
3331
|
+
const box = inline ? mode.embedded : mode.overlay;
|
|
3332
|
+
if (box.align === "distribute") return null;
|
|
3333
|
+
const button = preset === "secondary" ? mode.buttons?.secondary : preset === "link" ? mode.buttons?.tertiary : preset === void 0 || preset === null || preset === "primary" ? mode.buttons?.primary : void 0;
|
|
3334
|
+
return button ? JUSTIFY[button.align] ?? null : null;
|
|
3335
|
+
}
|
|
3336
|
+
function appFont(ref, doc) {
|
|
3337
|
+
const view = doc.defaultView;
|
|
3338
|
+
if (!view) return null;
|
|
3339
|
+
if (ref === "inherit") return view.getComputedStyle(doc.body).fontFamily || null;
|
|
3340
|
+
if (ref === "app-heading") {
|
|
3341
|
+
const heading = Array.from(doc.querySelectorAll("h1,h2,h3")).find(
|
|
3342
|
+
(el2) => el2.getClientRects().length > 0
|
|
3343
|
+
);
|
|
3344
|
+
return view.getComputedStyle(heading ?? doc.body).fontFamily || null;
|
|
3345
|
+
}
|
|
3346
|
+
return ref;
|
|
3347
|
+
}
|
|
3348
|
+
function themeContainerDesign(mode, inline, tooltip = false) {
|
|
3349
|
+
const box = inline ? mode.embedded : mode.overlay;
|
|
3350
|
+
const tip = tooltip ? mode.tooltip : void 0;
|
|
3351
|
+
const padding = tip?.padding ?? box.padding;
|
|
3352
|
+
const out = {
|
|
3353
|
+
// El embebido va en el flujo de la página: sin fondo propio.
|
|
3354
|
+
background: tip ? tip.background : inline ? "transparent" : box.background ?? mode.colors.background,
|
|
3355
|
+
color: mode.colors.text,
|
|
3356
|
+
paddingTop: padding.top,
|
|
3357
|
+
paddingRight: padding.right,
|
|
3358
|
+
paddingBottom: padding.bottom,
|
|
3359
|
+
paddingLeft: padding.left,
|
|
3360
|
+
borderColor: tip?.borderColor ?? box.borderColor,
|
|
3361
|
+
borderWidth: tip?.borderWidth ?? box.borderWidth,
|
|
3362
|
+
radius: tip?.borderRadius ?? box.borderRadius
|
|
3363
|
+
};
|
|
3364
|
+
const shadow = tip?.shadow ?? box.shadow;
|
|
3365
|
+
const shadowColor = tip?.shadowColor ?? box.shadowColor;
|
|
3366
|
+
if (shadow === "none") {
|
|
3367
|
+
Object.assign(out, { shadowColor: "transparent", shadowBlur: 0 });
|
|
3368
|
+
} else {
|
|
3369
|
+
const spec = SHADOW_SPEC[shadow];
|
|
3370
|
+
const [r, g, b] = channels(shadowColor);
|
|
3371
|
+
Object.assign(out, {
|
|
3372
|
+
shadowX: 0,
|
|
3373
|
+
shadowY: spec.y,
|
|
3374
|
+
shadowBlur: spec.blur,
|
|
3375
|
+
shadowSpread: 0,
|
|
3376
|
+
shadowColor: `rgba(${r}, ${g}, ${b}, ${spec.alpha})`
|
|
3377
|
+
});
|
|
3378
|
+
}
|
|
3379
|
+
return out;
|
|
3380
|
+
}
|
|
3381
|
+
function applyThemeVars(card, mode, inline, tooltip = false) {
|
|
3382
|
+
const doc = card.ownerDocument ?? document;
|
|
3383
|
+
const box = inline ? mode.embedded : mode.overlay;
|
|
3384
|
+
const set = (name, value) => {
|
|
3385
|
+
if (value) card.style.setProperty(name, value);
|
|
3386
|
+
};
|
|
3387
|
+
card.classList.add("veo-card--themed");
|
|
3388
|
+
set("--veo-primary", mode.colors.accent);
|
|
3389
|
+
set("--veo-cta-color", readableOn(mode.colors.accent));
|
|
3390
|
+
const primary = mode.buttons?.primary;
|
|
3391
|
+
const publish = (prefix, b) => {
|
|
3392
|
+
if (!b) return;
|
|
3393
|
+
const p = b.padding;
|
|
3394
|
+
set(`${prefix}-bg`, b.background);
|
|
3395
|
+
set(`${prefix}-color`, b.color);
|
|
3396
|
+
set(`${prefix}-pad`, `${p.top}px ${p.right}px ${p.bottom}px ${p.left}px`);
|
|
3397
|
+
set(`${prefix}-size`, `${b.fontSize}px`);
|
|
3398
|
+
set(`${prefix}-weight`, String(b.fontWeight));
|
|
3399
|
+
set(`${prefix}-radius`, `${b.borderRadius}px`);
|
|
3400
|
+
set(
|
|
3401
|
+
`${prefix}-border`,
|
|
3402
|
+
b.borderWidth > 0 ? `${b.borderWidth}px solid ${b.borderColor}` : "none"
|
|
3403
|
+
);
|
|
3404
|
+
};
|
|
3405
|
+
publish("--veo-cta", primary);
|
|
3406
|
+
publish("--veo-cta2", mode.buttons?.secondary);
|
|
3407
|
+
publish("--veo-cta3", mode.buttons?.tertiary);
|
|
3408
|
+
set("--veo-text", mode.colors.text);
|
|
3409
|
+
set("--veo-text-secondary", mode.colors.textMuted);
|
|
3410
|
+
set("--veo-font", appFont("inherit", doc));
|
|
3411
|
+
set(
|
|
3412
|
+
"--veo-actions-justify",
|
|
3413
|
+
box.align === "distribute" || !primary ? JUSTIFY[box.align] : JUSTIFY[primary.align]
|
|
3414
|
+
);
|
|
3415
|
+
const form = mode.form;
|
|
3416
|
+
if (form) {
|
|
3417
|
+
card.classList.add("veo-card--themed-form");
|
|
3418
|
+
const fp = form.padding;
|
|
3419
|
+
set("--veo-f-bg", form.background);
|
|
3420
|
+
set("--veo-f-accent", form.accent);
|
|
3421
|
+
set("--veo-f-on-accent", form.onAccent);
|
|
3422
|
+
set("--veo-f-pad", `${fp.top}px ${fp.right}px ${fp.bottom}px ${fp.left}px`);
|
|
3423
|
+
if (typeof form.borderWidth === "number" && form.borderColor) {
|
|
3424
|
+
set(
|
|
3425
|
+
"--veo-f-border",
|
|
3426
|
+
form.borderWidth > 0 ? `${form.borderWidth}px solid ${form.borderColor}` : "none"
|
|
3427
|
+
);
|
|
3428
|
+
}
|
|
3429
|
+
if (typeof form.borderRadius === "number") set("--veo-f-radius", `${form.borderRadius}px`);
|
|
3430
|
+
if (form.shadow && form.shadowColor) {
|
|
3431
|
+
set("--veo-f-shadow", boxShadow(form.shadow, form.shadowColor));
|
|
3432
|
+
}
|
|
3433
|
+
for (const [name, t] of [
|
|
3434
|
+
["primary", form.text.primary],
|
|
3435
|
+
["secondary", form.text.secondary]
|
|
3436
|
+
]) {
|
|
3437
|
+
set(`--veo-f-${name}-color`, t.color);
|
|
3438
|
+
set(`--veo-f-${name}-size`, `${t.fontSize}px`);
|
|
3439
|
+
set(`--veo-f-${name}-weight`, String(t.fontWeight));
|
|
3440
|
+
set(`--veo-f-${name}-align`, t.align);
|
|
3441
|
+
set(`--veo-f-${name}-font`, appFont(t.fontFamily, doc));
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
const tip = tooltip ? mode.tooltip?.text : void 0;
|
|
3445
|
+
const tokens = [
|
|
3446
|
+
["title", tip?.primary ?? mode.text.title],
|
|
3447
|
+
["subtitle", tip?.secondary ?? mode.text.subtitle],
|
|
3448
|
+
["paragraph", tip?.secondary ?? mode.text.paragraph]
|
|
3449
|
+
];
|
|
3450
|
+
for (const [name, t] of tokens) {
|
|
3451
|
+
set(`--veo-t-${name}-color`, t.color);
|
|
3452
|
+
set(`--veo-t-${name}-size`, `${t.fontSize}px`);
|
|
3453
|
+
set(`--veo-t-${name}-weight`, String(t.fontWeight));
|
|
3454
|
+
set(`--veo-t-${name}-align`, t.align);
|
|
3455
|
+
set(`--veo-t-${name}-font`, appFont(t.fontFamily, doc));
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
var WORKSPACE_THEME_ID, SHADOW_SPEC, JUSTIFY;
|
|
3459
|
+
var init_guide_theme = __esm({
|
|
3460
|
+
"src/plugins/guides/guide-theme.ts"() {
|
|
3461
|
+
WORKSPACE_THEME_ID = "workspace";
|
|
3462
|
+
SHADOW_SPEC = {
|
|
3463
|
+
soft: { y: 4, blur: 14, alpha: 0.12 },
|
|
3464
|
+
medium: { y: 12, blur: 32, alpha: 0.22 },
|
|
3465
|
+
strong: { y: 24, blur: 64, alpha: 0.38 }
|
|
3466
|
+
};
|
|
3467
|
+
JUSTIFY = {
|
|
3468
|
+
left: "flex-start",
|
|
3469
|
+
center: "center",
|
|
3470
|
+
right: "flex-end",
|
|
3471
|
+
distribute: "space-between"
|
|
3472
|
+
};
|
|
3473
|
+
}
|
|
3474
|
+
});
|
|
3475
|
+
|
|
3216
3476
|
// src/plugins/guides/layout.ts
|
|
3217
3477
|
function groupLayout(blocks) {
|
|
3218
3478
|
const rows = /* @__PURE__ */ new Map();
|
|
@@ -3673,6 +3933,7 @@ function makeCaret(doc, design) {
|
|
|
3673
3933
|
if (typeof design.borderWidth === "number" && design.borderWidth > 0) {
|
|
3674
3934
|
const bc = typeof design.borderColor === "string" ? design.borderColor : "#bbbbbb";
|
|
3675
3935
|
s.border = `${design.borderWidth}px solid ${bc}`;
|
|
3936
|
+
caret.dataset.veoBorder = String(design.borderWidth);
|
|
3676
3937
|
}
|
|
3677
3938
|
return caret;
|
|
3678
3939
|
}
|
|
@@ -3765,6 +4026,7 @@ var init_composite_renderer = __esm({
|
|
|
3765
4026
|
init_checklist_block();
|
|
3766
4027
|
init_code_block();
|
|
3767
4028
|
init_form_content();
|
|
4029
|
+
init_guide_theme();
|
|
3768
4030
|
init_inline_host();
|
|
3769
4031
|
init_layout();
|
|
3770
4032
|
init_rich_text();
|
|
@@ -3786,6 +4048,11 @@ var init_composite_renderer = __esm({
|
|
|
3786
4048
|
bottom: "flex-end"
|
|
3787
4049
|
};
|
|
3788
4050
|
CompositeRenderer = class extends BaseRenderer {
|
|
4051
|
+
constructor() {
|
|
4052
|
+
super(...arguments);
|
|
4053
|
+
/** Alineación de filas de botones según el tema del workspace (null = sin tema). */
|
|
4054
|
+
this.themeRowJustify = null;
|
|
4055
|
+
}
|
|
3789
4056
|
async render(context) {
|
|
3790
4057
|
const idx = context.nav?.stepIndex ?? 0;
|
|
3791
4058
|
const step = context.guide.guideSteps[idx];
|
|
@@ -3816,7 +4083,13 @@ var init_composite_renderer = __esm({
|
|
|
3816
4083
|
if (typeof design.zIndex === "number") host.style.zIndex = String(design.zIndex);
|
|
3817
4084
|
const card = doc.createElement("div");
|
|
3818
4085
|
card.className = "veo-card";
|
|
3819
|
-
|
|
4086
|
+
const themeMode = themeModeFor(context.guide.theme, design);
|
|
4087
|
+
const inline = step.presentation === "inline";
|
|
4088
|
+
const tooltipLike = !inline && (badgeMode || step.position === "relative-to-element");
|
|
4089
|
+
if (themeMode) applyThemeVars(card, themeMode, inline, tooltipLike);
|
|
4090
|
+
this.themeRowJustify = themeMode ? (preset) => themeRowJustify(themeMode, inline, preset) : null;
|
|
4091
|
+
const cardDesign = themeMode ? { ...themeContainerDesign(themeMode, inline, tooltipLike), ...design } : design;
|
|
4092
|
+
applyCompositeDesign(card, cardDesign);
|
|
3820
4093
|
if (typeof design.ariaLabel === "string" && design.ariaLabel.trim()) {
|
|
3821
4094
|
card.setAttribute("role", "dialog");
|
|
3822
4095
|
card.setAttribute("aria-label", design.ariaLabel.trim());
|
|
@@ -3887,7 +4160,7 @@ var init_composite_renderer = __esm({
|
|
|
3887
4160
|
});
|
|
3888
4161
|
}
|
|
3889
4162
|
card.appendChild(closeBtn);
|
|
3890
|
-
reserveCloseSpace(card, blocks, closePos,
|
|
4163
|
+
reserveCloseSpace(card, blocks, closePos, cardDesign);
|
|
3891
4164
|
}
|
|
3892
4165
|
if (badgeMode && anchor) {
|
|
3893
4166
|
closeTooltip = this.renderBadgeMode(
|
|
@@ -3900,7 +4173,8 @@ var init_composite_renderer = __esm({
|
|
|
3900
4173
|
doc,
|
|
3901
4174
|
context,
|
|
3902
4175
|
idx,
|
|
3903
|
-
|
|
4176
|
+
// Con el tema ya fundido: la flecha del tooltip toma su fondo y borde.
|
|
4177
|
+
cardDesign
|
|
3904
4178
|
);
|
|
3905
4179
|
return;
|
|
3906
4180
|
}
|
|
@@ -3923,7 +4197,7 @@ var init_composite_renderer = __esm({
|
|
|
3923
4197
|
}
|
|
3924
4198
|
const wrapper = doc.createElement("div");
|
|
3925
4199
|
wrapper.className = "veo-composite-anchored";
|
|
3926
|
-
const caretEl = design.caret === false ? null : makeCaret(doc,
|
|
4200
|
+
const caretEl = design.caret === false ? null : makeCaret(doc, cardDesign);
|
|
3927
4201
|
if (caretEl) wrapper.appendChild(caretEl);
|
|
3928
4202
|
wrapper.appendChild(card);
|
|
3929
4203
|
root.appendChild(wrapper);
|
|
@@ -3983,6 +4257,7 @@ var init_composite_renderer = __esm({
|
|
|
3983
4257
|
const row = doc.createElement("div");
|
|
3984
4258
|
row.className = "veo-guide-actions";
|
|
3985
4259
|
let rowAlign;
|
|
4260
|
+
const firstPreset = b.style?.preset;
|
|
3986
4261
|
while (i < cell.length && cell[i]?.block.type === "button") {
|
|
3987
4262
|
const { block: bb, index: bi } = cell[i];
|
|
3988
4263
|
if (!rowAlign) {
|
|
@@ -3993,6 +4268,10 @@ var init_composite_renderer = __esm({
|
|
|
3993
4268
|
i++;
|
|
3994
4269
|
}
|
|
3995
4270
|
if (rowAlign) row.style.justifyContent = ROW_ALIGN[rowAlign] ?? "flex-end";
|
|
4271
|
+
else {
|
|
4272
|
+
const themed = this.themeRowJustify?.(firstPreset);
|
|
4273
|
+
if (themed) row.style.justifyContent = themed;
|
|
4274
|
+
}
|
|
3996
4275
|
container.appendChild(row);
|
|
3997
4276
|
continue;
|
|
3998
4277
|
}
|
|
@@ -4959,7 +5238,8 @@ function normalize(input) {
|
|
|
4959
5238
|
guideSteps: input.guideSteps,
|
|
4960
5239
|
activationRules,
|
|
4961
5240
|
displayFrequency: "always",
|
|
4962
|
-
displayPriority: 0
|
|
5241
|
+
displayPriority: 0,
|
|
5242
|
+
...input.theme ? { theme: input.theme } : {}
|
|
4963
5243
|
};
|
|
4964
5244
|
}
|
|
4965
5245
|
function createSingleStepRenderer(type) {
|
|
@@ -5741,9 +6021,9 @@ function injectBuilderPanel(opts) {
|
|
|
5741
6021
|
card.className = "veo-panel";
|
|
5742
6022
|
let topOffset = opts.topOffset ?? 0;
|
|
5743
6023
|
let left = 40;
|
|
5744
|
-
let
|
|
6024
|
+
let top2 = topOffset + MARGIN;
|
|
5745
6025
|
card.style.left = `${left}px`;
|
|
5746
|
-
card.style.top = `${
|
|
6026
|
+
card.style.top = `${top2}px`;
|
|
5747
6027
|
card.style.width = `${PANEL_W}px`;
|
|
5748
6028
|
card.style.height = `${PANEL_H}px`;
|
|
5749
6029
|
const header = document.createElement("div");
|
|
@@ -5787,7 +6067,7 @@ function injectBuilderPanel(opts) {
|
|
|
5787
6067
|
if (!compactRestore) compactRestore = { w: card.offsetWidth, h: card.offsetHeight };
|
|
5788
6068
|
card.style.minHeight = "0";
|
|
5789
6069
|
card.style.width = `${clamp3(Math.round(size.width), MIN_W, window.innerWidth - MARGIN * 2)}px`;
|
|
5790
|
-
card.style.height = `${clamp3(Math.round(size.height) + HEADER_H, HEADER_H + 80, window.innerHeight -
|
|
6070
|
+
card.style.height = `${clamp3(Math.round(size.height) + HEADER_H, HEADER_H + 80, window.innerHeight - top2 - MARGIN)}px`;
|
|
5791
6071
|
} else if (compactRestore) {
|
|
5792
6072
|
card.style.minHeight = "";
|
|
5793
6073
|
card.style.width = `${compactRestore.w}px`;
|
|
@@ -5798,19 +6078,19 @@ function injectBuilderPanel(opts) {
|
|
|
5798
6078
|
maximize.addEventListener("click", () => {
|
|
5799
6079
|
maximized = !maximized;
|
|
5800
6080
|
if (maximized) {
|
|
5801
|
-
restore = { left, top, w: card.offsetWidth, h: card.offsetHeight };
|
|
6081
|
+
restore = { left, top: top2, w: card.offsetWidth, h: card.offsetHeight };
|
|
5802
6082
|
left = MARGIN;
|
|
5803
|
-
|
|
6083
|
+
top2 = topOffset + MARGIN;
|
|
5804
6084
|
card.style.left = `${left}px`;
|
|
5805
|
-
card.style.top = `${
|
|
6085
|
+
card.style.top = `${top2}px`;
|
|
5806
6086
|
card.style.width = `${Math.max(MIN_W, window.innerWidth - MARGIN * 2)}px`;
|
|
5807
|
-
card.style.height = `${Math.max(MIN_H, window.innerHeight -
|
|
6087
|
+
card.style.height = `${Math.max(MIN_H, window.innerHeight - top2 - MARGIN)}px`;
|
|
5808
6088
|
maximize.title = "Restaurar";
|
|
5809
6089
|
} else if (restore) {
|
|
5810
6090
|
left = restore.left;
|
|
5811
|
-
|
|
6091
|
+
top2 = restore.top;
|
|
5812
6092
|
card.style.left = `${left}px`;
|
|
5813
|
-
card.style.top = `${
|
|
6093
|
+
card.style.top = `${top2}px`;
|
|
5814
6094
|
card.style.width = `${restore.w}px`;
|
|
5815
6095
|
card.style.height = `${restore.h}px`;
|
|
5816
6096
|
maximize.title = "Maximizar";
|
|
@@ -5846,13 +6126,13 @@ function injectBuilderPanel(opts) {
|
|
|
5846
6126
|
const sx = e.clientX;
|
|
5847
6127
|
const sy = e.clientY;
|
|
5848
6128
|
const ol = left;
|
|
5849
|
-
const ot =
|
|
6129
|
+
const ot = top2;
|
|
5850
6130
|
iframe.style.pointerEvents = "none";
|
|
5851
6131
|
const move = (ev) => {
|
|
5852
6132
|
left = clamp3(ol + (ev.clientX - sx), 0, Math.max(0, window.innerWidth - card.offsetWidth));
|
|
5853
|
-
|
|
6133
|
+
top2 = clamp3(ot + (ev.clientY - sy), topOffset, Math.max(topOffset, window.innerHeight - 40));
|
|
5854
6134
|
card.style.left = `${left}px`;
|
|
5855
|
-
card.style.top = `${
|
|
6135
|
+
card.style.top = `${top2}px`;
|
|
5856
6136
|
};
|
|
5857
6137
|
const up = () => {
|
|
5858
6138
|
window.removeEventListener("mousemove", move);
|
|
@@ -5898,9 +6178,9 @@ function injectBuilderPanel(opts) {
|
|
|
5898
6178
|
isVisible: () => visible,
|
|
5899
6179
|
setTopOffset: (px) => {
|
|
5900
6180
|
topOffset = px;
|
|
5901
|
-
if (
|
|
5902
|
-
|
|
5903
|
-
card.style.top = `${
|
|
6181
|
+
if (top2 < topOffset + MARGIN) {
|
|
6182
|
+
top2 = topOffset + MARGIN;
|
|
6183
|
+
card.style.top = `${top2}px`;
|
|
5904
6184
|
}
|
|
5905
6185
|
}
|
|
5906
6186
|
};
|
|
@@ -6081,9 +6361,9 @@ function attachModal(opts, shadow, card) {
|
|
|
6081
6361
|
const span = window.innerWidth - w;
|
|
6082
6362
|
return span <= 0 ? 0.5 : round3(clamp4(left / span, 0, 1));
|
|
6083
6363
|
};
|
|
6084
|
-
const posYFor = (
|
|
6364
|
+
const posYFor = (top2, h) => {
|
|
6085
6365
|
const span = window.innerHeight - h;
|
|
6086
|
-
return span <= 0 ? 0.5 : round3(clamp4(
|
|
6366
|
+
return span <= 0 ? 0.5 : round3(clamp4(top2 / span, 0, 1));
|
|
6087
6367
|
};
|
|
6088
6368
|
const onCardDown = (e) => {
|
|
6089
6369
|
if (isInteractive(e.target)) return;
|
|
@@ -7878,6 +8158,471 @@ var init_builder = __esm({
|
|
|
7878
8158
|
}
|
|
7879
8159
|
});
|
|
7880
8160
|
|
|
8161
|
+
// src/plugins/theme-detect/color.ts
|
|
8162
|
+
function parseRgb(value) {
|
|
8163
|
+
const m = RGB_RX.exec(value.trim());
|
|
8164
|
+
if (!m) return null;
|
|
8165
|
+
const a = m[4] === void 0 ? 1 : m[4].endsWith("%") ? Number.parseFloat(m[4]) / 100 : +m[4];
|
|
8166
|
+
return [+m[1], +m[2], +m[3], a];
|
|
8167
|
+
}
|
|
8168
|
+
function toCssColor(raw) {
|
|
8169
|
+
const v = raw.trim();
|
|
8170
|
+
const parts = v.split(/[\s,/]+/).filter(Boolean);
|
|
8171
|
+
const bare = parts.length >= 3 && parts.every((p) => /^-?[\d.]+(%|deg)?$/.test(p));
|
|
8172
|
+
if (!bare) return v;
|
|
8173
|
+
return v.includes("%") ? `hsl(${v})` : `rgb(${v})`;
|
|
8174
|
+
}
|
|
8175
|
+
function looksLikeColor(raw) {
|
|
8176
|
+
const v = raw.trim();
|
|
8177
|
+
if (!v || v.length > 64) return false;
|
|
8178
|
+
return /^(#|rgb|hsl|hwb|lab|lch|oklab|oklch|color\(|color-mix|light-dark)/i.test(v) || toCssColor(v) !== v;
|
|
8179
|
+
}
|
|
8180
|
+
function flatten(c, bg) {
|
|
8181
|
+
if (c[3] >= 1) return c;
|
|
8182
|
+
const mix = (i) => Math.round(c[i] * c[3] + bg[i] * (1 - c[3]));
|
|
8183
|
+
return [mix(0), mix(1), mix(2), 1];
|
|
8184
|
+
}
|
|
8185
|
+
function toHex(c) {
|
|
8186
|
+
const h = (n) => Math.round(n).toString(16).padStart(2, "0");
|
|
8187
|
+
return `#${h(c[0])}${h(c[1])}${h(c[2])}`.toUpperCase();
|
|
8188
|
+
}
|
|
8189
|
+
function luminance(c) {
|
|
8190
|
+
return (0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]) / 255;
|
|
8191
|
+
}
|
|
8192
|
+
function saturation(c) {
|
|
8193
|
+
const mx = Math.max(c[0], c[1], c[2]) / 255;
|
|
8194
|
+
const mn = Math.min(c[0], c[1], c[2]) / 255;
|
|
8195
|
+
const l = (mx + mn) / 2;
|
|
8196
|
+
return mx === mn ? 0 : (mx - mn) / (1 - Math.abs(2 * l - 1));
|
|
8197
|
+
}
|
|
8198
|
+
function createColorResolver(doc) {
|
|
8199
|
+
const probe = doc.createElement("span");
|
|
8200
|
+
probe.style.display = "none";
|
|
8201
|
+
doc.body.appendChild(probe);
|
|
8202
|
+
const view = doc.defaultView;
|
|
8203
|
+
let ctx;
|
|
8204
|
+
const cache = /* @__PURE__ */ new Map();
|
|
8205
|
+
const viaCanvas = (computed) => {
|
|
8206
|
+
if (ctx === void 0) {
|
|
8207
|
+
try {
|
|
8208
|
+
const canvas = doc.createElement("canvas");
|
|
8209
|
+
canvas.width = 1;
|
|
8210
|
+
canvas.height = 1;
|
|
8211
|
+
ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
8212
|
+
} catch {
|
|
8213
|
+
ctx = null;
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
8216
|
+
if (!ctx) return null;
|
|
8217
|
+
ctx.clearRect(0, 0, 1, 1);
|
|
8218
|
+
ctx.fillStyle = "#000";
|
|
8219
|
+
ctx.fillStyle = computed;
|
|
8220
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
8221
|
+
const d = ctx.getImageData(0, 0, 1, 1).data;
|
|
8222
|
+
return [d[0] ?? 0, d[1] ?? 0, d[2] ?? 0, (d[3] ?? 255) / 255];
|
|
8223
|
+
};
|
|
8224
|
+
return {
|
|
8225
|
+
resolve(raw) {
|
|
8226
|
+
const key = raw.trim();
|
|
8227
|
+
if (!key || !view) return null;
|
|
8228
|
+
const hit = cache.get(key);
|
|
8229
|
+
if (hit !== void 0) return hit;
|
|
8230
|
+
let out = null;
|
|
8231
|
+
probe.style.color = "";
|
|
8232
|
+
probe.style.color = toCssColor(key);
|
|
8233
|
+
if (probe.style.color) {
|
|
8234
|
+
const computed = view.getComputedStyle(probe).color;
|
|
8235
|
+
out = parseRgb(computed) ?? viaCanvas(computed);
|
|
8236
|
+
}
|
|
8237
|
+
cache.set(key, out);
|
|
8238
|
+
return out;
|
|
8239
|
+
},
|
|
8240
|
+
dispose() {
|
|
8241
|
+
probe.remove();
|
|
8242
|
+
}
|
|
8243
|
+
};
|
|
8244
|
+
}
|
|
8245
|
+
var RGB_RX;
|
|
8246
|
+
var init_color = __esm({
|
|
8247
|
+
"src/plugins/theme-detect/color.ts"() {
|
|
8248
|
+
RGB_RX = /^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/;
|
|
8249
|
+
}
|
|
8250
|
+
});
|
|
8251
|
+
|
|
8252
|
+
// src/plugins/theme-detect/fonts.ts
|
|
8253
|
+
function cleanFamily(name) {
|
|
8254
|
+
return name.trim().replace(/^["']|["']$/g, "");
|
|
8255
|
+
}
|
|
8256
|
+
function primaryFamily(stack) {
|
|
8257
|
+
const families = stack.split(",").map(cleanFamily).filter(Boolean);
|
|
8258
|
+
return families.find((f) => !GENERIC.test(f) && !/fallback/i.test(f)) ?? families[0] ?? "";
|
|
8259
|
+
}
|
|
8260
|
+
function prettyFamily(family) {
|
|
8261
|
+
return family.replace(/^__/, "").replace(/_Fallback_[0-9a-f]+$/i, " Fallback").replace(/_[0-9a-f]{6,}$/i, "").replace(/_/g, " ").trim();
|
|
8262
|
+
}
|
|
8263
|
+
function describeFont(doc, el2, faces) {
|
|
8264
|
+
const view = doc.defaultView;
|
|
8265
|
+
if (!el2 || !view) return void 0;
|
|
8266
|
+
const family = primaryFamily(view.getComputedStyle(el2).fontFamily);
|
|
8267
|
+
if (!family) return void 0;
|
|
8268
|
+
const font = {
|
|
8269
|
+
name: prettyFamily(family).slice(0, 80),
|
|
8270
|
+
family: family.slice(0, 120)
|
|
8271
|
+
};
|
|
8272
|
+
const weights = /* @__PURE__ */ new Set();
|
|
8273
|
+
try {
|
|
8274
|
+
for (const face of Array.from(doc.fonts ?? [])) {
|
|
8275
|
+
if (cleanFamily(face.family) === family && face.status === "loaded") weights.add(face.weight);
|
|
8276
|
+
}
|
|
8277
|
+
} catch {
|
|
8278
|
+
}
|
|
8279
|
+
if (weights.size > 0) font.weights = [...weights].sort().join(" ").slice(0, 80);
|
|
8280
|
+
const own = faces.filter((f) => f.family === family);
|
|
8281
|
+
const url = own.find((f) => f.url)?.url ?? null;
|
|
8282
|
+
let origin = null;
|
|
8283
|
+
try {
|
|
8284
|
+
origin = url ? new URL(url, doc.baseURI).origin : null;
|
|
8285
|
+
} catch {
|
|
8286
|
+
origin = null;
|
|
8287
|
+
}
|
|
8288
|
+
const links = Array.from(doc.querySelectorAll("link[href]")).map((l) => l.href);
|
|
8289
|
+
if (origin) {
|
|
8290
|
+
font.hosting = origin.includes("fonts.gstatic.com") ? "google" : origin === view.location.origin ? "self" : "external";
|
|
8291
|
+
} else if (own.length > 0) {
|
|
8292
|
+
font.hosting = "self";
|
|
8293
|
+
} else if (links.some((h) => h.includes("fonts.googleapis.com"))) {
|
|
8294
|
+
font.hosting = "google";
|
|
8295
|
+
} else if (links.some((h) => h.includes("use.typekit.net"))) {
|
|
8296
|
+
font.hosting = "adobe";
|
|
8297
|
+
} else {
|
|
8298
|
+
font.hosting = "system";
|
|
8299
|
+
}
|
|
8300
|
+
return font;
|
|
8301
|
+
}
|
|
8302
|
+
var GENERIC;
|
|
8303
|
+
var init_fonts = __esm({
|
|
8304
|
+
"src/plugins/theme-detect/fonts.ts"() {
|
|
8305
|
+
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;
|
|
8306
|
+
}
|
|
8307
|
+
});
|
|
8308
|
+
|
|
8309
|
+
// src/plugins/theme-detect/detect-theme.ts
|
|
8310
|
+
var detect_theme_exports = {};
|
|
8311
|
+
__export(detect_theme_exports, {
|
|
8312
|
+
detectTheme: () => detectTheme,
|
|
8313
|
+
snapshotHash: () => snapshotHash
|
|
8314
|
+
});
|
|
8315
|
+
function scanSheets(doc) {
|
|
8316
|
+
const scan = {
|
|
8317
|
+
names: /* @__PURE__ */ new Set(),
|
|
8318
|
+
byMode: { light: /* @__PURE__ */ new Map(), dark: /* @__PURE__ */ new Map() },
|
|
8319
|
+
faces: []
|
|
8320
|
+
};
|
|
8321
|
+
const walk = (rules, inDarkMedia) => {
|
|
8322
|
+
for (const rule of Array.from(rules)) {
|
|
8323
|
+
const style = rule.style;
|
|
8324
|
+
const selector = rule.selectorText;
|
|
8325
|
+
if (rule.constructor.name === "CSSFontFaceRule" && style) {
|
|
8326
|
+
const src = style.getPropertyValue("src");
|
|
8327
|
+
const url = /url\(["']?([^"')]+)["']?\)/.exec(src)?.[1] ?? null;
|
|
8328
|
+
scan.faces.push({ family: cleanFamily(style.getPropertyValue("font-family")), url });
|
|
8329
|
+
} else if (style && typeof selector === "string") {
|
|
8330
|
+
const selectors = selector.split(",").map((s) => s.trim());
|
|
8331
|
+
const mode = selectors.some((s) => DARK_SELECTOR.test(s)) ? "dark" : selectors.some((s) => LIGHT_SELECTOR.test(s)) ? inDarkMedia ? "dark" : "light" : null;
|
|
8332
|
+
for (const prop of Array.from(style)) {
|
|
8333
|
+
if (!prop.startsWith("--")) continue;
|
|
8334
|
+
scan.names.add(prop);
|
|
8335
|
+
if (mode) scan.byMode[mode].set(prop, style.getPropertyValue(prop).trim());
|
|
8336
|
+
}
|
|
8337
|
+
}
|
|
8338
|
+
const nested = rule.cssRules;
|
|
8339
|
+
if (nested) {
|
|
8340
|
+
const media = rule.conditionText ?? "";
|
|
8341
|
+
walk(nested, inDarkMedia || /prefers-color-scheme:\s*dark/.test(media));
|
|
8342
|
+
}
|
|
8343
|
+
}
|
|
8344
|
+
};
|
|
8345
|
+
for (const sheet of Array.from(doc.styleSheets)) {
|
|
8346
|
+
try {
|
|
8347
|
+
walk(sheet.cssRules, false);
|
|
8348
|
+
} catch {
|
|
8349
|
+
}
|
|
8350
|
+
}
|
|
8351
|
+
return scan;
|
|
8352
|
+
}
|
|
8353
|
+
function top(counts) {
|
|
8354
|
+
let best = null;
|
|
8355
|
+
let max = 0;
|
|
8356
|
+
for (const [hex, n] of counts) {
|
|
8357
|
+
if (n > max) {
|
|
8358
|
+
max = n;
|
|
8359
|
+
best = hex;
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
8362
|
+
return best;
|
|
8363
|
+
}
|
|
8364
|
+
function detectTheme(doc = document) {
|
|
8365
|
+
const view = doc.defaultView;
|
|
8366
|
+
const body = doc.body;
|
|
8367
|
+
if (!view || !body) return null;
|
|
8368
|
+
const html = doc.documentElement;
|
|
8369
|
+
const colors = createColorResolver(doc);
|
|
8370
|
+
const modeProbe = doc.createElement("div");
|
|
8371
|
+
try {
|
|
8372
|
+
const bodyCs = view.getComputedStyle(body);
|
|
8373
|
+
let bg = [255, 255, 255, 1];
|
|
8374
|
+
for (const el2 of [body, html]) {
|
|
8375
|
+
const c = colors.resolve(view.getComputedStyle(el2).backgroundColor);
|
|
8376
|
+
if (c && c[3] > 0) {
|
|
8377
|
+
bg = flatten(c, [255, 255, 255, 1]);
|
|
8378
|
+
break;
|
|
8379
|
+
}
|
|
8380
|
+
}
|
|
8381
|
+
const text = flatten(colors.resolve(bodyCs.color) ?? [0, 0, 0, 1], bg);
|
|
8382
|
+
const textHex = toHex(text);
|
|
8383
|
+
const muted = /* @__PURE__ */ new Map();
|
|
8384
|
+
const border = /* @__PURE__ */ new Map();
|
|
8385
|
+
const accent = /* @__PURE__ */ new Map();
|
|
8386
|
+
const link = /* @__PURE__ */ new Map();
|
|
8387
|
+
const bump = (m, k) => {
|
|
8388
|
+
m.set(k, (m.get(k) ?? 0) + 1);
|
|
8389
|
+
};
|
|
8390
|
+
const contrast = Math.abs(luminance(text) - luminance(bg));
|
|
8391
|
+
const elements = Array.from(body.querySelectorAll("*")).slice(0, MAX_ELEMENTS);
|
|
8392
|
+
for (const el2 of elements) {
|
|
8393
|
+
if (el2.getClientRects().length === 0) continue;
|
|
8394
|
+
const cs = view.getComputedStyle(el2);
|
|
8395
|
+
const hasText = Array.from(el2.childNodes).some(
|
|
8396
|
+
(n) => n.nodeType === 3 && (n.textContent ?? "").trim() !== ""
|
|
8397
|
+
);
|
|
8398
|
+
if (hasText) {
|
|
8399
|
+
const c = colors.resolve(cs.color);
|
|
8400
|
+
if (c && c[3] > 0) {
|
|
8401
|
+
const flat = flatten(c, bg);
|
|
8402
|
+
const hex = toHex(flat);
|
|
8403
|
+
const softer = Math.abs(luminance(flat) - luminance(bg)) < contrast;
|
|
8404
|
+
if (hex !== textHex && saturation(flat) < 0.3 && softer) bump(muted, hex);
|
|
8405
|
+
if (el2.closest("a") && saturation(flat) >= 0.3) bump(link, hex);
|
|
8406
|
+
}
|
|
8407
|
+
}
|
|
8408
|
+
if (Number.parseFloat(cs.borderTopWidth) > 0 && cs.borderTopStyle !== "none") {
|
|
8409
|
+
const c = colors.resolve(cs.borderTopColor);
|
|
8410
|
+
if (c && c[3] > 0) {
|
|
8411
|
+
const flat = flatten(c, bg);
|
|
8412
|
+
if (saturation(flat) < 0.3 && toHex(flat) !== textHex) bump(border, toHex(flat));
|
|
8413
|
+
}
|
|
8414
|
+
}
|
|
8415
|
+
if (el2.matches('button,[role="button"],input[type="submit"],a[class*="btn"],a[class*="button"]')) {
|
|
8416
|
+
const c = colors.resolve(cs.backgroundColor);
|
|
8417
|
+
if (c && c[3] > 0.5 && saturation(c) >= 0.3) bump(accent, toHex(c));
|
|
8418
|
+
}
|
|
8419
|
+
}
|
|
8420
|
+
const meta = doc.querySelector('meta[name="theme-color"]');
|
|
8421
|
+
const metaColor = meta ? colors.resolve(meta.content) : null;
|
|
8422
|
+
const sampled = {
|
|
8423
|
+
background: toHex(bg),
|
|
8424
|
+
text: textHex
|
|
8425
|
+
};
|
|
8426
|
+
const sampledAccent = top(accent) ?? top(link) ?? (metaColor ? toHex(metaColor) : null);
|
|
8427
|
+
if (sampledAccent) sampled.accent = sampledAccent;
|
|
8428
|
+
const sampledMuted = top(muted);
|
|
8429
|
+
if (sampledMuted) sampled.textMuted = sampledMuted;
|
|
8430
|
+
const sampledBorder = top(border);
|
|
8431
|
+
if (sampledBorder) sampled.border = sampledBorder;
|
|
8432
|
+
const hints = [
|
|
8433
|
+
html.className,
|
|
8434
|
+
html.dataset.theme,
|
|
8435
|
+
html.dataset.mode,
|
|
8436
|
+
body.className,
|
|
8437
|
+
body.dataset.theme
|
|
8438
|
+
].join(" ").toLowerCase();
|
|
8439
|
+
const mode = /\bdark\b/.test(hints) ? "dark" : /\blight\b/.test(hints) ? "light" : view.getComputedStyle(html).colorScheme === "dark" || luminance(bg) < 0.4 ? "dark" : "light";
|
|
8440
|
+
const other = mode === "dark" ? "light" : "dark";
|
|
8441
|
+
modeProbe.className = other;
|
|
8442
|
+
modeProbe.dataset.theme = other;
|
|
8443
|
+
modeProbe.dataset.mode = other;
|
|
8444
|
+
modeProbe.style.cssText = `display:none;color-scheme:${other}`;
|
|
8445
|
+
body.appendChild(modeProbe);
|
|
8446
|
+
const probeCs = view.getComputedStyle(modeProbe);
|
|
8447
|
+
const hexOf = (raw, over) => {
|
|
8448
|
+
if (!looksLikeColor(raw)) return null;
|
|
8449
|
+
const c = colors.resolve(raw);
|
|
8450
|
+
if (!c || c[3] === 0) return null;
|
|
8451
|
+
if (c[3] > 0.98) return toHex(c);
|
|
8452
|
+
return over ? toHex(flatten(c, over)) : null;
|
|
8453
|
+
};
|
|
8454
|
+
const scan = scanSheets(doc);
|
|
8455
|
+
const roleVar = {};
|
|
8456
|
+
const current = {};
|
|
8457
|
+
for (const role of ROLES) {
|
|
8458
|
+
for (const name of KNOWN_VARS[role]) {
|
|
8459
|
+
const hex = hexOf(bodyCs.getPropertyValue(name), bg);
|
|
8460
|
+
if (hex) {
|
|
8461
|
+
roleVar[role] = { name, confidence: 3 };
|
|
8462
|
+
current[role] = { hex, confidence: 3 };
|
|
8463
|
+
break;
|
|
8464
|
+
}
|
|
8465
|
+
}
|
|
8466
|
+
}
|
|
8467
|
+
const missing = ROLES.filter((r) => !roleVar[r] && sampled[r]);
|
|
8468
|
+
if (missing.length > 0) {
|
|
8469
|
+
const candidates = [];
|
|
8470
|
+
for (const name of Array.from(scan.names).slice(0, MAX_VARS)) {
|
|
8471
|
+
const cur = hexOf(bodyCs.getPropertyValue(name));
|
|
8472
|
+
if (cur) candidates.push({ name, cur, oth: hexOf(probeCs.getPropertyValue(name)) });
|
|
8473
|
+
}
|
|
8474
|
+
for (const role of missing) {
|
|
8475
|
+
let best = null;
|
|
8476
|
+
for (const c of candidates) {
|
|
8477
|
+
if (c.cur !== sampled[role]) continue;
|
|
8478
|
+
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);
|
|
8479
|
+
if (!best || score > best.score) best = { name: c.name, score };
|
|
8480
|
+
}
|
|
8481
|
+
if (best && best.score >= 2) roleVar[role] = { name: best.name, confidence: 2 };
|
|
8482
|
+
}
|
|
8483
|
+
}
|
|
8484
|
+
for (const role of ROLES) {
|
|
8485
|
+
const hex = sampled[role];
|
|
8486
|
+
if (!current[role] && hex) current[role] = { hex, confidence: roleVar[role] ? 2 : 1 };
|
|
8487
|
+
}
|
|
8488
|
+
const otherPalette = {};
|
|
8489
|
+
let differs = false;
|
|
8490
|
+
const otherOrder = ["background", "accent", "text", "textMuted", "border"];
|
|
8491
|
+
let otherBg = null;
|
|
8492
|
+
const noteBg = (role, hex) => {
|
|
8493
|
+
if (role === "background") otherBg = colors.resolve(hex);
|
|
8494
|
+
};
|
|
8495
|
+
for (const role of otherOrder) {
|
|
8496
|
+
const ref = roleVar[role];
|
|
8497
|
+
if (!ref) continue;
|
|
8498
|
+
const hex = hexOf(probeCs.getPropertyValue(ref.name), otherBg);
|
|
8499
|
+
if (!hex) continue;
|
|
8500
|
+
noteBg(role, hex);
|
|
8501
|
+
otherPalette[role] = { hex, confidence: ref.confidence };
|
|
8502
|
+
if (hex !== current[role]?.hex) differs = true;
|
|
8503
|
+
}
|
|
8504
|
+
if (!differs) {
|
|
8505
|
+
for (const role of ROLES) delete otherPalette[role];
|
|
8506
|
+
otherBg = null;
|
|
8507
|
+
const sheet = scan.byMode[other];
|
|
8508
|
+
const resolveVar = (value, depth = 0) => depth > 6 ? value : value.replace(
|
|
8509
|
+
/var\(\s*(--[\w-]+)\s*(?:,\s*([^()]*))?\)/g,
|
|
8510
|
+
(_m, name, fb) => resolveVar(
|
|
8511
|
+
sheet.get(name) ?? scan.byMode.light.get(name) ?? (bodyCs.getPropertyValue(name).trim() || fb || ""),
|
|
8512
|
+
depth + 1
|
|
8513
|
+
)
|
|
8514
|
+
);
|
|
8515
|
+
for (const role of otherOrder) {
|
|
8516
|
+
const ref = roleVar[role];
|
|
8517
|
+
const raw = ref ? sheet.get(ref.name) : void 0;
|
|
8518
|
+
const hex = raw ? hexOf(resolveVar(raw), otherBg) : null;
|
|
8519
|
+
if (!hex) continue;
|
|
8520
|
+
noteBg(role, hex);
|
|
8521
|
+
otherPalette[role] = { hex, confidence: 2 };
|
|
8522
|
+
if (hex !== current[role]?.hex) differs = true;
|
|
8523
|
+
}
|
|
8524
|
+
}
|
|
8525
|
+
const palettes = { [mode]: current };
|
|
8526
|
+
if (differs) palettes[other] = otherPalette;
|
|
8527
|
+
const firstVisible = (selector) => Array.from(doc.querySelectorAll(selector)).find(
|
|
8528
|
+
(el2) => el2.getClientRects().length > 0 && (el2.textContent ?? "").trim() !== ""
|
|
8529
|
+
) ?? null;
|
|
8530
|
+
const bodyFont = describeFont(doc, body, scan.faces);
|
|
8531
|
+
const headingFont = describeFont(doc, firstVisible("h1,h2,h3"), scan.faces);
|
|
8532
|
+
const fonts = {};
|
|
8533
|
+
if (bodyFont) fonts.body = bodyFont;
|
|
8534
|
+
if (headingFont) fonts.heading = headingFont;
|
|
8535
|
+
const snapshot = { host: view.location.host, mode, palettes };
|
|
8536
|
+
const appName = doc.title.trim().slice(0, 120);
|
|
8537
|
+
if (appName) snapshot.appName = appName;
|
|
8538
|
+
if (fonts.body || fonts.heading) snapshot.fonts = fonts;
|
|
8539
|
+
return snapshot;
|
|
8540
|
+
} finally {
|
|
8541
|
+
colors.dispose();
|
|
8542
|
+
modeProbe.remove();
|
|
8543
|
+
}
|
|
8544
|
+
}
|
|
8545
|
+
function snapshotHash(snapshot) {
|
|
8546
|
+
const colorsOf = (p) => ROLES.map((r) => {
|
|
8547
|
+
const c = p?.[r];
|
|
8548
|
+
return c ? `${c.hex}${c.confidence}` : "-";
|
|
8549
|
+
}).join("");
|
|
8550
|
+
return [
|
|
8551
|
+
snapshot.host,
|
|
8552
|
+
colorsOf(snapshot.palettes.light),
|
|
8553
|
+
colorsOf(snapshot.palettes.dark),
|
|
8554
|
+
snapshot.fonts?.body?.family ?? "",
|
|
8555
|
+
snapshot.fonts?.heading?.family ?? ""
|
|
8556
|
+
].join("|");
|
|
8557
|
+
}
|
|
8558
|
+
var ROLES, KNOWN_VARS, ROLE_NAME, PALETTE_NAME, DARK_SELECTOR, LIGHT_SELECTOR, MAX_ELEMENTS, MAX_VARS;
|
|
8559
|
+
var init_detect_theme = __esm({
|
|
8560
|
+
"src/plugins/theme-detect/detect-theme.ts"() {
|
|
8561
|
+
init_color();
|
|
8562
|
+
init_fonts();
|
|
8563
|
+
ROLES = ["accent", "text", "textMuted", "background", "border"];
|
|
8564
|
+
KNOWN_VARS = {
|
|
8565
|
+
accent: [
|
|
8566
|
+
"--primary",
|
|
8567
|
+
"--color-primary",
|
|
8568
|
+
"--brand",
|
|
8569
|
+
"--color-brand",
|
|
8570
|
+
"--brand-primary",
|
|
8571
|
+
"--mui-palette-primary-main",
|
|
8572
|
+
"--bs-primary",
|
|
8573
|
+
"--ant-color-primary",
|
|
8574
|
+
"--chakra-colors-brand-500",
|
|
8575
|
+
"--accent-color",
|
|
8576
|
+
"--accent"
|
|
8577
|
+
],
|
|
8578
|
+
text: [
|
|
8579
|
+
"--foreground",
|
|
8580
|
+
"--color-foreground",
|
|
8581
|
+
"--text",
|
|
8582
|
+
"--color-text",
|
|
8583
|
+
"--text-primary",
|
|
8584
|
+
"--bs-body-color",
|
|
8585
|
+
"--mui-palette-text-primary"
|
|
8586
|
+
],
|
|
8587
|
+
textMuted: [
|
|
8588
|
+
"--muted-foreground",
|
|
8589
|
+
"--color-muted-foreground",
|
|
8590
|
+
"--text-muted",
|
|
8591
|
+
"--text-secondary",
|
|
8592
|
+
"--bs-secondary-color",
|
|
8593
|
+
"--mui-palette-text-secondary"
|
|
8594
|
+
],
|
|
8595
|
+
background: [
|
|
8596
|
+
"--background",
|
|
8597
|
+
"--color-background",
|
|
8598
|
+
"--bg",
|
|
8599
|
+
"--color-bg",
|
|
8600
|
+
"--bs-body-bg",
|
|
8601
|
+
"--mui-palette-background-default"
|
|
8602
|
+
],
|
|
8603
|
+
border: [
|
|
8604
|
+
"--border",
|
|
8605
|
+
"--color-border",
|
|
8606
|
+
"--border-color",
|
|
8607
|
+
"--bs-border-color",
|
|
8608
|
+
"--mui-palette-divider"
|
|
8609
|
+
]
|
|
8610
|
+
};
|
|
8611
|
+
ROLE_NAME = {
|
|
8612
|
+
accent: /brand|primary|accent|main/i,
|
|
8613
|
+
text: /text|foreground|\bfg\b|-fg|ink|content|body/i,
|
|
8614
|
+
textMuted: /muted|secondary|subtle|soft|hint|placeholder|text|-fg/i,
|
|
8615
|
+
background: /background|\bbg\b|-bg|surface|canvas|page|base/i,
|
|
8616
|
+
border: /border|line|divider|stroke|outline|separator/i
|
|
8617
|
+
};
|
|
8618
|
+
PALETTE_NAME = /-(50|[1-9]00|950)$|white|black/i;
|
|
8619
|
+
DARK_SELECTOR = /\.dark\b|\[data-(theme|mode|color-scheme)=["']?dark|\.theme-dark|\.dark-theme/i;
|
|
8620
|
+
LIGHT_SELECTOR = /^(:root|html|:host|body)$|\.light\b|\[data-(theme|mode)=["']?light/i;
|
|
8621
|
+
MAX_ELEMENTS = 1500;
|
|
8622
|
+
MAX_VARS = 600;
|
|
8623
|
+
}
|
|
8624
|
+
});
|
|
8625
|
+
|
|
7881
8626
|
// src/contract/v1.ts
|
|
7882
8627
|
var SDK_VERSION = "0.0.1";
|
|
7883
8628
|
var DEFAULT_FLUSH_INTERVAL_MS = 5e3;
|
|
@@ -8186,6 +8931,119 @@ function spaRouterPlugin() {
|
|
|
8186
8931
|
});
|
|
8187
8932
|
}
|
|
8188
8933
|
|
|
8934
|
+
// src/plugins/theme-detect/index.ts
|
|
8935
|
+
init_safe_env();
|
|
8936
|
+
var STORAGE_PREFIX = "veo_theme_";
|
|
8937
|
+
var RESEND_AFTER_MS = 24 * 60 * 60 * 1e3;
|
|
8938
|
+
var SETTLE_MS = 4e3;
|
|
8939
|
+
var MAX_RUNS_PER_PAGE = 4;
|
|
8940
|
+
function readState(key) {
|
|
8941
|
+
try {
|
|
8942
|
+
const raw = localStorage.getItem(key);
|
|
8943
|
+
const parsed = raw ? JSON.parse(raw) : null;
|
|
8944
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
8945
|
+
} catch {
|
|
8946
|
+
return {};
|
|
8947
|
+
}
|
|
8948
|
+
}
|
|
8949
|
+
function writeState(key, state) {
|
|
8950
|
+
try {
|
|
8951
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
8952
|
+
} catch {
|
|
8953
|
+
}
|
|
8954
|
+
}
|
|
8955
|
+
function guessMode(doc, prefersDark) {
|
|
8956
|
+
const hints = [
|
|
8957
|
+
doc.documentElement.className,
|
|
8958
|
+
doc.documentElement.dataset.theme,
|
|
8959
|
+
doc.documentElement.dataset.mode,
|
|
8960
|
+
doc.body?.className
|
|
8961
|
+
].join(" ").toLowerCase();
|
|
8962
|
+
if (/\bdark\b/.test(hints)) return "dark";
|
|
8963
|
+
if (/\blight\b/.test(hints)) return "light";
|
|
8964
|
+
return prefersDark ? "dark" : "light";
|
|
8965
|
+
}
|
|
8966
|
+
function isFresh(state, mode, now) {
|
|
8967
|
+
const last = state[mode];
|
|
8968
|
+
return last !== void 0 && now - last.at < RESEND_AFTER_MS;
|
|
8969
|
+
}
|
|
8970
|
+
function shouldSendSnapshot(state, mode, hash, now) {
|
|
8971
|
+
const last = state[mode];
|
|
8972
|
+
return !last || last.hash !== hash || now - last.at >= RESEND_AFTER_MS;
|
|
8973
|
+
}
|
|
8974
|
+
function themeDetectPlugin(config) {
|
|
8975
|
+
const storageKey = `${STORAGE_PREFIX}${config.apiKey.slice(-16) || "default"}`;
|
|
8976
|
+
let observer = null;
|
|
8977
|
+
let timer = null;
|
|
8978
|
+
let destroyed = false;
|
|
8979
|
+
let runs = 0;
|
|
8980
|
+
const run = async () => {
|
|
8981
|
+
if (destroyed || runs >= MAX_RUNS_PER_PAGE) return;
|
|
8982
|
+
const prefersDark = typeof window.matchMedia === "function" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
8983
|
+
const guess = guessMode(document, prefersDark);
|
|
8984
|
+
if (isFresh(readState(storageKey), guess, Date.now())) return;
|
|
8985
|
+
runs++;
|
|
8986
|
+
try {
|
|
8987
|
+
const detector = await config.loadDetector();
|
|
8988
|
+
if (!detector || destroyed) return;
|
|
8989
|
+
const snapshot = detector.detectTheme();
|
|
8990
|
+
if (!snapshot) return;
|
|
8991
|
+
const hash = detector.snapshotHash(snapshot);
|
|
8992
|
+
const state = readState(storageKey);
|
|
8993
|
+
const now = Date.now();
|
|
8994
|
+
const mark = () => {
|
|
8995
|
+
const record = { hash, at: Date.now() };
|
|
8996
|
+
state[snapshot.mode] = record;
|
|
8997
|
+
state[guess] = state[guess] && guess !== snapshot.mode ? state[guess] : record;
|
|
8998
|
+
writeState(storageKey, state);
|
|
8999
|
+
};
|
|
9000
|
+
if (!shouldSendSnapshot(state, snapshot.mode, hash, now)) {
|
|
9001
|
+
mark();
|
|
9002
|
+
return;
|
|
9003
|
+
}
|
|
9004
|
+
if (config.debug) console.log("[veo] theme snapshot", snapshot);
|
|
9005
|
+
const res = await fetch(`${config.apiUrl}/v1/workspaces/theme-snapshot`, {
|
|
9006
|
+
method: "POST",
|
|
9007
|
+
headers: { "X-Api-Key": config.apiKey, "Content-Type": "application/json" },
|
|
9008
|
+
body: JSON.stringify(snapshot),
|
|
9009
|
+
credentials: "omit"
|
|
9010
|
+
});
|
|
9011
|
+
if (res.ok) mark();
|
|
9012
|
+
} catch (err) {
|
|
9013
|
+
if (config.debug) console.warn("[veo] theme detect failed", err);
|
|
9014
|
+
}
|
|
9015
|
+
};
|
|
9016
|
+
const schedule = (delayMs) => {
|
|
9017
|
+
if (timer) clearTimeout(timer);
|
|
9018
|
+
timer = setTimeout(() => {
|
|
9019
|
+
timer = null;
|
|
9020
|
+
const idle = window.requestIdleCallback;
|
|
9021
|
+
if (typeof idle === "function") idle(() => void run());
|
|
9022
|
+
else void run();
|
|
9023
|
+
}, delayMs);
|
|
9024
|
+
};
|
|
9025
|
+
return {
|
|
9026
|
+
name: "theme-detect",
|
|
9027
|
+
install() {
|
|
9028
|
+
if (!hasWindow() || !hasDocument()) return;
|
|
9029
|
+
if (document.readyState === "complete") schedule(SETTLE_MS);
|
|
9030
|
+
else window.addEventListener("load", () => schedule(SETTLE_MS), { once: true });
|
|
9031
|
+
if (typeof MutationObserver === "function") {
|
|
9032
|
+
observer = new MutationObserver(() => schedule(1500));
|
|
9033
|
+
observer.observe(document.documentElement, {
|
|
9034
|
+
attributes: true,
|
|
9035
|
+
attributeFilter: ["class", "data-theme", "data-mode"]
|
|
9036
|
+
});
|
|
9037
|
+
}
|
|
9038
|
+
},
|
|
9039
|
+
destroy() {
|
|
9040
|
+
destroyed = true;
|
|
9041
|
+
observer?.disconnect();
|
|
9042
|
+
if (timer) clearTimeout(timer);
|
|
9043
|
+
}
|
|
9044
|
+
};
|
|
9045
|
+
}
|
|
9046
|
+
|
|
8189
9047
|
// src/core/client.ts
|
|
8190
9048
|
init_safe_env();
|
|
8191
9049
|
init_uuid();
|
|
@@ -8338,26 +9196,26 @@ var Session = class {
|
|
|
8338
9196
|
|
|
8339
9197
|
// src/core/storage.ts
|
|
8340
9198
|
init_safe_env();
|
|
8341
|
-
var
|
|
9199
|
+
var STORAGE_PREFIX2 = "veo:";
|
|
8342
9200
|
var ONE_YEAR_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
8343
9201
|
var LocalStorageAdapter = class {
|
|
8344
9202
|
get(key) {
|
|
8345
|
-
return localStorage.getItem(
|
|
9203
|
+
return localStorage.getItem(STORAGE_PREFIX2 + key);
|
|
8346
9204
|
}
|
|
8347
9205
|
set(key, value) {
|
|
8348
9206
|
try {
|
|
8349
|
-
localStorage.setItem(
|
|
9207
|
+
localStorage.setItem(STORAGE_PREFIX2 + key, value);
|
|
8350
9208
|
} catch {
|
|
8351
9209
|
}
|
|
8352
9210
|
}
|
|
8353
9211
|
remove(key) {
|
|
8354
|
-
localStorage.removeItem(
|
|
9212
|
+
localStorage.removeItem(STORAGE_PREFIX2 + key);
|
|
8355
9213
|
}
|
|
8356
9214
|
clear() {
|
|
8357
9215
|
const toRemove = [];
|
|
8358
9216
|
for (let i = 0; i < localStorage.length; i++) {
|
|
8359
9217
|
const key = localStorage.key(i);
|
|
8360
|
-
if (key?.startsWith(
|
|
9218
|
+
if (key?.startsWith(STORAGE_PREFIX2)) toRemove.push(key);
|
|
8361
9219
|
}
|
|
8362
9220
|
for (const key of toRemove) localStorage.removeItem(key);
|
|
8363
9221
|
}
|
|
@@ -8368,7 +9226,7 @@ function readCookies() {
|
|
|
8368
9226
|
}
|
|
8369
9227
|
var CookieAdapter = class {
|
|
8370
9228
|
get(key) {
|
|
8371
|
-
const name = `${
|
|
9229
|
+
const name = `${STORAGE_PREFIX2}${key}=`;
|
|
8372
9230
|
for (const cookie of readCookies()) {
|
|
8373
9231
|
if (cookie.startsWith(name)) {
|
|
8374
9232
|
return decodeURIComponent(cookie.slice(name.length));
|
|
@@ -8379,19 +9237,19 @@ var CookieAdapter = class {
|
|
|
8379
9237
|
set(key, value, options) {
|
|
8380
9238
|
const maxAgeSec = Math.floor((options?.ttlMs ?? ONE_YEAR_MS) / 1e3);
|
|
8381
9239
|
const secure = typeof location !== "undefined" && location.protocol === "https:" ? "; Secure" : "";
|
|
8382
|
-
document.cookie = `${
|
|
9240
|
+
document.cookie = `${STORAGE_PREFIX2}${key}=${encodeURIComponent(
|
|
8383
9241
|
value
|
|
8384
9242
|
)}; Path=/; Max-Age=${maxAgeSec}; SameSite=Lax${secure}`;
|
|
8385
9243
|
}
|
|
8386
9244
|
remove(key) {
|
|
8387
|
-
document.cookie = `${
|
|
9245
|
+
document.cookie = `${STORAGE_PREFIX2}${key}=; Path=/; Max-Age=0; SameSite=Lax`;
|
|
8388
9246
|
}
|
|
8389
9247
|
clear() {
|
|
8390
9248
|
for (const cookie of readCookies()) {
|
|
8391
9249
|
const eq = cookie.indexOf("=");
|
|
8392
9250
|
const name = eq === -1 ? cookie : cookie.slice(0, eq);
|
|
8393
|
-
if (name.startsWith(
|
|
8394
|
-
this.remove(name.slice(
|
|
9251
|
+
if (name.startsWith(STORAGE_PREFIX2)) {
|
|
9252
|
+
this.remove(name.slice(STORAGE_PREFIX2.length));
|
|
8395
9253
|
}
|
|
8396
9254
|
}
|
|
8397
9255
|
}
|
|
@@ -8681,13 +9539,23 @@ var Client = class {
|
|
|
8681
9539
|
};
|
|
8682
9540
|
|
|
8683
9541
|
// src/core/setup.ts
|
|
8684
|
-
function setupClient(config, onGuides, loadBuilder) {
|
|
9542
|
+
function setupClient(config, onGuides, loadBuilder, loadThemeDetector) {
|
|
8685
9543
|
const client = new Client(config);
|
|
8686
9544
|
client.use(spaRouterPlugin());
|
|
8687
9545
|
if (config.autocapture !== false) {
|
|
8688
9546
|
const autocaptureConfig = typeof config.autocapture === "object" ? config.autocapture : {};
|
|
8689
9547
|
client.use(autocapturePlugin(autocaptureConfig));
|
|
8690
9548
|
}
|
|
9549
|
+
if (config.detectTheme !== false && loadThemeDetector && !isBuilderMode()) {
|
|
9550
|
+
client.use(
|
|
9551
|
+
themeDetectPlugin({
|
|
9552
|
+
apiUrl: resolveApiUrl(config),
|
|
9553
|
+
apiKey: config.apiKey,
|
|
9554
|
+
loadDetector: loadThemeDetector,
|
|
9555
|
+
...config.debug !== void 0 ? { debug: config.debug } : {}
|
|
9556
|
+
})
|
|
9557
|
+
);
|
|
9558
|
+
}
|
|
8691
9559
|
onGuides(client);
|
|
8692
9560
|
if (typeof window !== "undefined") {
|
|
8693
9561
|
const stub = window.veo;
|
|
@@ -10391,7 +11259,10 @@ function init(config) {
|
|
|
10391
11259
|
// Fallback de carga del builder para bundlers: `import()` dinámico → el bundler
|
|
10392
11260
|
// lo code-splitea (solo se descarga en modo builder). Así el consumidor por
|
|
10393
11261
|
// bundler NO necesita copiar `veo-builder.js` ni setear `builderUrl`.
|
|
10394
|
-
() => Promise.resolve().then(() => (init_builder(), builder_exports)).then((m) => m.initBuilderMode())
|
|
11262
|
+
() => Promise.resolve().then(() => (init_builder(), builder_exports)).then((m) => m.initBuilderMode()),
|
|
11263
|
+
// Detector de tema: también por `import()` dinámico → chunk aparte que el
|
|
11264
|
+
// bundler solo descarga cuando toca detectar (como mucho una vez al día).
|
|
11265
|
+
() => Promise.resolve().then(() => (init_detect_theme(), detect_theme_exports))
|
|
10395
11266
|
);
|
|
10396
11267
|
}
|
|
10397
11268
|
|