Adaptateur Vue
Le package @presage-kit/vue fournit des composables Vue 3 et un plugin pour construire des interfaces adaptatives.
Installation
Section intitulée « Installation »pnpm add @presage-kit/core @presage-kit/vueAdaptivePlugin
Section intitulée « AdaptivePlugin »Installez le plugin pour fournir le AdaptiveClient à tous les composants via l’injection de dépendances 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')Options :
| Option | Type | Description |
|---|---|---|
client | AdaptiveClient | L’instance du client issue de createAdaptiveClient() |
Composable useAdaptive()
Section intitulée « Composable useAdaptive() »Le composable principal pour résoudre les points d’adaptation. Retourne des getters réactifs pour la variante sélectionnée, la résolution et le contexte.
<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>Paramètres :
| Param | Type | Description |
|---|---|---|
adaptationId | string | Identifiant unique du point d’adaptation |
config.variants | readonly string[] | IDs de variantes disponibles |
config.defaultVariant | string | Variante de repli |
config.strategy | Strategy | Optionnel. Par défaut { type: 'rules' } |
Type de retour :
L’objet retourné utilise des getters réactifs, les valeurs se mettent donc à jour automatiquement quand le contexte utilisateur change.
| Champ | Type | Description |
|---|---|---|
selectedVariant | V (getter) | La chaîne de la variante sélectionnée |
resolution | ResolvedAdaptation (getter) | Détails complets de résolution |
context | UserContext (getter) | Contexte utilisateur courant |
track | (event: string, properties?: Record<string, unknown>) => void | Fonction de suivi scopée |
Suivi automatique des impressions : Comme le hook React, useAdaptive() surveille les changements de variante et suit automatiquement les événements presage:impression.
Composable useVariant()
Section intitulée « Composable useVariant() »Un composable plus léger qui retourne uniquement la chaîne de la variante sélectionnée.
<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>Paramètres : Identiques à useAdaptive().
Type de retour : V — La chaîne de la variante sélectionnée (getter réactif).
Composable useAdaptiveClient()
Section intitulée « Composable useAdaptiveClient() »Retourne l’instance AdaptiveClient depuis l’injection du plugin. Utilisez-le pour les opérations impératives.
<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>Lance une erreur si le AdaptivePlugin n’a pas été installé.
AdaptiveNav manuel avec evaluateAction()
Section intitulée « AdaptiveNav manuel avec evaluateAction() »Contrairement à l’adaptateur React, le package Vue ne fournit pas de composant AdaptiveNav dédié. Utilisez plutôt evaluateAction() directement pour réordonner ou masquer les éléments de navigation.
<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>Exemple complet : Tableau de bord SaaS
Section intitulée « Exemple complet : Tableau de bord 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>