/** * Tipos consumidos por el plugin de guides. Reflejan el shape que devuelve * `GET /v1/guides/resolve` en el backend — debe mantenerse en sync con * `veo-backend/src/modules/guides/types/guide-content.types.ts` y * `guide.response.ts`. */ type GuideType = 'modal' | 'banner' | 'tooltip' | 'walkthrough' | 'custom' | 'inline' | 'inline-custom' | 'form' | 'inline-form' | 'badge' | 'composite'; type FormFieldType = 'text' | 'textarea' | 'number' | 'select' | 'multiselect' | 'radio' | 'checkbox' | 'yesno' | 'nps' | 'rating'; /** * Un campo de una guía `form`. `key` es el nombre de la PROPIEDAD que se * escribe en los traits del usuario que responde (encuesta/NPS estilo Pendo). */ interface FormField { key: string; label: string; type: FormFieldType; /** Para select/radio: opciones visibles (el valor guardado es el texto). */ options?: string[] | null; required?: boolean | null; placeholder?: string | null; } type CustomPlacementMode = 'floating' | 'anchored'; type CustomFloatingPosition = 'top-left' | 'top-center' | 'top-right' | 'center' | 'bottom-left' | 'bottom-center' | 'bottom-right'; type CustomAnchorSide = 'top' | 'bottom' | 'left' | 'right'; /** Dónde se monta una guía `custom`. Ver backend `guide-content.types.ts`. */ interface CustomPlacement { mode: CustomPlacementMode; position?: CustomFloatingPosition; offsetX?: number; offsetY?: number; selector?: string; side?: CustomAnchorSide; width?: number | string; height?: number | string; } type UrlMatchType = 'exact' | 'prefix' | 'regex'; type ActivationTrigger = 'immediate' | 'on_element' | 'on_event' | 'delayed' | 'on_click' | 'on_hover'; type CtaAction = 'dismiss' | 'next' | 'url' | 'guide'; /** * Acciones de un bloque `button` en el modelo unificado (estilo Pendo). Superset * de `CtaAction`: agrega navegación (prev) y envío de formularios del paso. */ type ButtonAction = 'dismiss' | 'next' | 'prev' | 'url' | 'guide' | 'submit-forms' | 'submit-forms-advance' | 'submit-forms-goto'; interface UrlMatcher { type: UrlMatchType; pattern: string; } interface ActivationRules { url: UrlMatcher; trigger: ActivationTrigger; selector?: string; eventName?: string; delayMs?: number; } /** Tipo de un bloque de contenido (para pasos con varios títulos/textos/botones). */ type StepBlockType = 'title' | 'text' | 'button' | 'image' | 'code' | 'form'; /** * Un bloque de contenido dentro de un paso. Permite componer un paso con VARIOS * títulos/textos/botones/imágenes en orden (no solo un título + un texto + un * CTA). Si `step.blocks` está presente, el renderer lo usa; si no, cae a los * campos escalares (`title`/`content`/`ctaText`/`imageUrl`) — retrocompatible. */ interface StepBlock { type: StepBlockType; /** * button: identificador ESTABLE del botón para analytics (el editor lo * genera al crear el bloque). Viaja como `metadata.buttonId` del * `cta_clicked` — permite medir clicks POR botón cuando hay varios. */ id?: string | null; /** title/text/button: el texto. En bloques `text` es el FALLBACK de `html`. */ text?: string | null; /** * Solo bloques `text`: rich text con subset whitelisted (negrita/cursiva/ * links/listas). El backend lo guarda sanitizado; el SDK lo re-valida al * renderizar con `renderRichText` (DOMParser inerte + rebuild manual — nunca * innerHTML sobre DOM vivo). Si está presente, manda sobre `text`. */ html?: string | null; /** Bloques `code`: CSS/JS crudos. `js` corre en la página host (modo no-sandbox). */ css?: string | null; js?: string | null; /** * Bloques `code`: `true` → iframe aislado (comportamiento viejo `custom`); * `false`/ausente → JS con acceso al DOM host (tipo GTM). Excepción * sancionada a la regla no-eval (ver CLAUDE.md). */ sandboxed?: boolean | null; /** Bloques `form`: los campos del formulario (desacoplado del botón). */ fields?: FormField[] | null; /** image: la URL; button con acción `url`: el destino. */ url?: string | null; /** button: qué hace al hacer click (composite: `ButtonAction`). */ action?: ButtonAction | null; /** button con acción `guide`: id de la guía que abre (encadenado). */ targetGuideId?: string | null; /** button con acción `submit-forms-goto`: índice del paso destino. */ targetStep?: number | null; /** Estilo por-bloque (align/color/fontSize/margin…). Se aplica inline. */ style?: Record | null; } interface GuideStep { title: string; content: string; ctaText?: string | null; ctaAction?: CtaAction | null; imageUrl?: string | null; selector?: string | null; /** * Free-form JSONB. Convención: si `ctaAction === 'url'`, la URL destino * se lee de `style.ctaUrl`. Otras keys que puede traer: `position` * (`top` | `bottom` para banners), `theme`, y `render` (tipo de presentación * del paso dentro de un walkthrough heterogéneo: modal/banner/tooltip). */ style?: Record | null; /** * Bloques de contenido ordenados (varios títulos/textos/botones/imágenes). * Si está presente y no vacío, tiene prioridad sobre los campos escalares. */ blocks?: StepBlock[] | null; /** Solo guías `custom`: código a renderizar en un iframe sandbox + ubicación. */ html?: string | null; css?: string | null; js?: string | null; placement?: CustomPlacement | null; /** Solo guías `form`: los campos del formulario. */ fields?: FormField[] | null; } /** Entrada mínima para previsualizar una guía. */ interface PreviewGuideInput { guideType: GuideType; guideSteps: GuideStep[]; /** * Opcional. Solo se usa `activationRules.selector` como fallback del * ancla para tooltip/walkthrough cuando el step no trae su propio * `selector`. El resto de reglas (url/trigger/delay) se ignoran. */ activationRules?: Partial; /** Nombre mostrado (p.ej. en el `title` del iframe de guías `custom`). */ guideName?: string; /** * Solo walkthrough: paso inicial a mostrar (default 0). Lo usa el editor del * dashboard para que la preview salte al paso que se está editando. */ startStepIndex?: number; /** * Solo guías form: envío REAL de respuestas. Sin esto, el submit en preview * es un no-op (no escribe props). Lo usa el modo preview-por-link, que sí * guarda en el usuario que responde. */ formSubmit?: (answers: Record) => Promise; /** Nota bajo el "¡Gracias!" cuando hay `formSubmit` propio. */ formSubmitNote?: string; } /** Resultado del primer render de una preview. */ interface PreviewResult { /** * `false` cuando la guía no pudo pintarse — típicamente un * tooltip/walkthrough cuyo `selector` no existe en la página de preview. */ rendered: boolean; } /** Handle de una preview activa. */ interface PreviewHandle { /** Cierra y limpia la preview. Idempotente. */ close(): void; /** Resuelve cuando el primer render terminó. */ ready: Promise; /** * Host de la guía activa (o `null` si no hay nada montado). Lo usa el modo * builder para adjuntar la manipulación directa (drag/resize) del editor. */ host(): HTMLElement | null; } /** * Previsualiza una guía en la página actual usando los renderers reales * del SDK. Devuelve un handle con `close()` y una promesa `ready`. * * Pensado para el builder no-code: no necesita `init()` ni apiKey. Abrir * una nueva preview cierra automáticamente la anterior. * * @example * ```ts * import { previewGuide } from '@veo/sdk'; * * const preview = previewGuide({ * guideType: 'modal', * guideSteps: [{ title: 'Hola', content: 'Esto es una preview' }], * }); * const { rendered } = await preview.ready; * // ...más tarde: * preview.close(); * ``` */ declare function previewGuide(input: PreviewGuideInput): PreviewHandle; /** Cierra la preview activa, si la hay. Idempotente. */ declare function closeGuidePreview(): void; export { type PreviewGuideInput as P, type PreviewHandle as a, type PreviewResult as b, closeGuidePreview as c, previewGuide as p };