Adaptador Vue
El paquete @presage-kit/vue proporciona composables de Vue 3 y un plugin para construir interfaces adaptativas.
Instalacion
Sección titulada «Instalacion»pnpm add @presage-kit/core @presage-kit/vueAdaptivePlugin
Sección titulada «AdaptivePlugin»Instale el plugin para proporcionar el AdaptiveClient a todos los componentes mediante la inyeccion de dependencias de Vue.
import { createApp } from 'vue'import { AdaptivePlugin } from '@presage-kit/vue'import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'import App from './App.vue'
const client = createAdaptiveClient({ rules: [/* ... */], persistence: { driver: createLocalStorageDriver('my-app') },})
const app = createApp(App)app.use(AdaptivePlugin, { client })app.mount('#app')Opciones:
| Opcion | Tipo | Descripcion |
|---|---|---|
client | AdaptiveClient | La instancia del cliente creada con createAdaptiveClient() |
Composable useAdaptive()
Sección titulada «Composable useAdaptive()»El composable principal para resolver adaptation points. Devuelve getters reactivos para la variante seleccionada, la resolucion y el contexto.
<script setup lang="ts">import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant, resolution, context, track } = useAdaptive('onboarding', { variants: ['guided-tour', 'standard', 'minimal'] as const, defaultVariant: 'standard',})
function handleComplete() { track('onboarding_completed')}</script>
<template> <div v-if="selectedVariant === 'guided-tour'"> <h2>Welcome! Let us show you around.</h2> <button @click="handleComplete">Complete tour</button> </div> <div v-else-if="selectedVariant === 'standard'"> <h2>Welcome</h2> </div> <div v-else> <p>Good to see you again.</p> </div></template>Parametros:
| Parametro | Tipo | Descripcion |
|---|---|---|
adaptationId | string | Identificador unico del adaptation point |
config.variants | readonly string[] | IDs de variantes disponibles |
config.defaultVariant | string | Variante de respaldo |
config.strategy | Strategy | Opcional. Por defecto { type: 'rules' } |
Tipo de retorno:
El objeto de retorno utiliza getters reactivos, por lo que los valores se actualizan automaticamente cuando el contexto del usuario cambia.
| Campo | Tipo | Descripcion |
|---|---|---|
selectedVariant | V (getter) | La cadena de la variante seleccionada |
resolution | ResolvedAdaptation (getter) | Detalles completos de resolucion |
context | UserContext (getter) | Contexto actual del usuario |
track | (event: string, properties?: Record<string, unknown>) => void | Funcion de rastreo con scope |
Rastreo automatico de impresiones: Al igual que el hook de React, useAdaptive() observa los cambios de variante y rastrea automaticamente eventos presage:impression.
Composable useVariant()
Sección titulada «Composable useVariant()»Un composable mas ligero que devuelve unicamente la cadena de la variante seleccionada.
<script setup lang="ts">import { useVariant } from '@presage-kit/vue'
const variant = useVariant('cta-style', { variants: ['primary', 'secondary', 'subtle'] as const, defaultVariant: 'primary',})</script>
<template> <button :class="`cta cta--${variant}`">Get Started</button></template>Parametros: Los mismos que useAdaptive().
Tipo de retorno: V — La cadena de la variante seleccionada (getter reactivo).
Composable useAdaptiveClient()
Sección titulada «Composable useAdaptiveClient()»Devuelve la instancia de AdaptiveClient desde la inyeccion del plugin. Uselo para operaciones imperativas.
<script setup lang="ts">import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
function handleExport() { client.track('feature_used', { featureId: 'export' })}</script>
<template> <button @click="handleExport">Export Data</button></template>Lanza un error si el AdaptivePlugin no ha sido instalado.
AdaptiveNav manual con evaluateAction()
Sección titulada «AdaptiveNav manual con evaluateAction()»A diferencia del adaptador React, el paquete Vue no incluye un componente AdaptiveNav dedicado. En su lugar, use evaluateAction() directamente para reordenar u ocultar elementos de navegacion.
<script setup lang="ts">import { computed } from 'vue'import { useAdaptiveClient } from '@presage-kit/vue'
interface NavItem { id: string label: string href: string}
const client = useAdaptiveClient()
const baseItems: NavItem[] = [ { id: 'home', label: 'Home', href: '/' }, { id: 'analytics', label: 'Analytics', href: '/analytics' }, { id: 'settings', label: 'Settings', href: '/settings' },]
const navItems = computed(() => { const action = client.evaluateAction('sidebar-nav')
if (action?.type === 'hide') return []
if (action?.type === 'reorder') { return reorder(baseItems, action.order) }
return baseItems})
function reorder(items: NavItem[], order: string[]): NavItem[] { const map = new Map(items.map((item) => [item.id, item])) const ordered: NavItem[] = []
for (const id of order) { const item = map.get(id) if (item) { ordered.push(item) map.delete(id) } }
// Append items not in the order list for (const item of map.values()) { ordered.push(item) }
return ordered}</script>
<template> <nav> <a v-for="item in navItems" :key="item.id" :href="item.href"> {{ item.label }} </a> </nav></template>Ejemplo completo: Tablero SaaS
Sección titulada «Ejemplo completo: Tablero SaaS»import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
export const client = createAdaptiveClient({ rules: [ { id: 'power-user-sidebar', adaptationId: 'sidebar-nav', priority: 10, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'power' }], }, action: { type: 'reorder', order: ['analytics', 'dashboards', 'settings', 'home'] }, }, { id: 'new-user-tour', adaptationId: 'onboarding', priority: 10, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'new' }], }, action: { type: 'show', variantId: 'guided-tour' }, }, { id: 'experienced-skip', adaptationId: 'onboarding', priority: 5, conditions: { any: [ { field: 'maturity', operator: 'eq', value: 'active' }, { field: 'maturity', operator: 'eq', value: 'power' }, ], }, action: { type: 'show', variantId: 'minimal' }, }, ], persistence: { driver: createLocalStorageDriver('vue-demo'), },})import { createApp } from 'vue'import { AdaptivePlugin } from '@presage-kit/vue'import { client } from './lib/adaptive-client'import App from './App.vue'
const app = createApp(App)app.use(AdaptivePlugin, { client })app.mount('#app')<script setup lang="ts">import SidebarNav from './components/SidebarNav.vue'import Onboarding from './components/Onboarding.vue'</script>
<template> <div class="layout"> <SidebarNav /> <main> <Onboarding /> <router-view /> </main> </div></template><script setup lang="ts">import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant, track } = useAdaptive('onboarding', { variants: ['guided-tour', 'standard', 'minimal'] as const, defaultVariant: 'standard',})
function handleComplete() { track('onboarding_completed')}</script>
<template> <div v-if="selectedVariant === 'guided-tour'" class="onboarding"> <h2>Welcome! Let us show you around.</h2> <button @click="handleComplete">Complete Tour</button> </div> <div v-else-if="selectedVariant === 'standard'" class="onboarding"> <h2>What is new</h2> <p>Check out the latest features.</p> </div> <div v-else class="onboarding"> <p>Welcome back!</p> </div></template><script setup lang="ts">import { computed } from 'vue'import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
const items = [ { id: 'home', label: 'Home', href: '/' }, { id: 'dashboards', label: 'Dashboards', href: '/dashboards' }, { id: 'analytics', label: 'Analytics', href: '/analytics' }, { id: 'settings', label: 'Settings', href: '/settings' },]
const orderedItems = computed(() => { const action = client.evaluateAction('sidebar-nav') if (action?.type === 'hide') return [] if (action?.type === 'reorder') { const map = new Map(items.map((i) => [i.id, i])) const result = action.order .filter((id) => map.has(id)) .map((id) => map.get(id)!) const remaining = items.filter((i) => !action.order.includes(i.id)) return [...result, ...remaining] } return items})</script>
<template> <nav class="sidebar"> <a v-for="item in orderedItems" :key="item.id" :href="item.href"> {{ item.label }} </a> </nav></template>