Aller au contenu

@presage-kit/vue

Vue 3 bindings for Presage. Provides a plugin for dependency injection and composables for reactive adaptation.

Fenêtre de terminal
pnpm add @presage-kit/core @presage-kit/vue

A Vue 3 plugin that provides the AdaptiveClient to all components via provide/inject.

import { createApp } from 'vue'
import { AdaptivePlugin } from '@presage-kit/vue'
import { createAdaptiveClient } from '@presage-kit/core'
const client = createAdaptiveClient({ /* ... */ })
const app = createApp(App)
app.use(AdaptivePlugin, { client })
app.mount('#app')

Install options: AdaptivePluginOptions

interface AdaptivePluginOptions {
client: AdaptiveClient
}
OptionTypeRequiredDescription
clientAdaptiveClientYesClient from createAdaptiveClient()

Implementation: Calls app.provide() with an injection key symbol, making the client available to all descendant components.

Resolves an adaptation point reactively. Re-evaluates when user context changes.

import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant, resolution, context, track } = useAdaptive('onboarding', {
variants: ['guided-tour', 'standard', 'minimal'] as const,
defaultVariant: 'standard',
})

Parameters:

ParamTypeDescription
adaptationIdstringUnique adaptation point ID
config.variantsreadonly V[]Array of variant IDs
config.defaultVariantNoInfer<V>Default variant (must be in variants)
config.strategyStrategyOptional. Defaults to { type: 'rules' }

Return type:

The returned object uses JavaScript getters backed by Vue computed() refs, making all values reactive.

FieldTypeDescription
selectedVariantV (getter)Currently selected variant
resolutionResolvedAdaptation (getter)Full resolution metadata
contextUserContext (getter)Current user context
track(event: string, props?: Record<string, unknown>) => voidScoped track function

Reactivity: The composable uses useAtom() internally to bridge the core’s atom-based state to Vue’s reactivity system. When the client state changes, all computed values update automatically.

Impressions: Uses Vue’s watch() with { immediate: true } to track presage:impression events when the selected variant changes.

Usage in templates:

<script setup lang="ts">
import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant } = useAdaptive('panel', {
variants: ['compact', 'expanded'] as const,
defaultVariant: 'compact',
})
</script>
<template>
<CompactPanel v-if="selectedVariant === 'compact'" />
<ExpandedPanel v-else />
</template>

Lightweight composable returning only the selected variant string.

import { useVariant } from '@presage-kit/vue'
const variant = useVariant('layout', {
variants: ['sidebar', 'topnav'] as const,
defaultVariant: 'sidebar',
})

Parameters: Same as useAdaptive().

Return type: V — The selected variant string (reactive getter).

Internally delegates to useAdaptive() and returns selectedVariant.

Usage in templates:

<script setup lang="ts">
import { useVariant } from '@presage-kit/vue'
const variant = useVariant('cta-style', {
variants: ['primary', 'secondary'] as const,
defaultVariant: 'primary',
})
</script>
<template>
<button :class="`btn btn--${variant}`">Get Started</button>
</template>

Returns the AdaptiveClient instance from the plugin injection.

import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
client.track('feature_used', { featureId: 'export' })
client.identify('user-789', { role: 'admin' })
const context = client.getContext()

Return type: AdaptiveClient

Throws: Error if AdaptivePlugin has not been installed.

Common patterns:

<script setup lang="ts">
import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
// Identify after authentication
onMounted(() => {
const user = getCurrentUser()
client.identify(user.id, {
role: user.role,
plan: user.plan,
signupDate: user.createdAt,
})
})
// Track actions
function handleExport() {
client.track('feature_used', { featureId: 'export' })
doExport()
}
// Evaluate rules imperatively
function getNavAction() {
return client.evaluateAction('sidebar-nav')
}
</script>

Declares an adaptation point and renders the matching <Variant> child. Built with defineComponent.

<script setup lang="ts">
import { Adaptive, Variant } from '@presage-kit/vue'
</script>
<template>
<Adaptive id="onboarding" default-variant="standard">
<Variant id="guided-tour">
<GuidedTour />
</Variant>
<Variant id="standard">
<StandardOnboarding />
</Variant>
</Adaptive>
</template>

Props:

PropTypeRequiredDescription
idstringYesUnique adaptation point identifier
default-variantstringYesVariant to show when no rule matches

Behavior: Internally calls useAdaptive() with the variant IDs collected from child <Variant> components. Automatically tracks presage:impression events when the selected variant changes.

Defines a single variant inside an <Adaptive> parent.

Props:

PropTypeRequiredDescription
idstringYesVariant identifier (referenced in rule actions)

Only the matching variant’s slot content is rendered.

Generic adaptive ordering component for any list of items. Evaluates rules to reorder, hide, or preserve the original order. Uses Vue scoped slots for rendering.

<script setup lang="ts">
import { AdaptiveOrder } from '@presage-kit/vue'
const features = [
{ id: 'analytics', title: 'Analytics', description: 'Track user behavior' },
{ id: 'automation', title: 'Automation', description: 'Automate repetitive tasks' },
]
</script>
<template>
<AdaptiveOrder id="feature-highlights" :items="features" v-slot="{ item, index }">
<div class="card">{{ item.title }}: {{ item.description }}</div>
</AdaptiveOrder>
</template>

Props:

PropTypeRequiredDescription
idstringYesAdaptation point identifier
itemsT[] (extends Orderable)YesArray of items, each with at least an id field

Scoped slot:

FieldTypeDescription
itemTThe current item
indexnumberThe current item index in the ordered list

Orderable interface:

interface Orderable {
id: string
[key: string]: unknown
}

Behavior: Evaluates reorder and hide actions from the rule engine. When hidden, renders nothing. When reordered, items are rendered in the new order. Items not mentioned in the order array are appended at the end.

A thin wrapper around <AdaptiveOrder>, specialized for navigation items. Internally delegates all logic to <AdaptiveOrder>.

Renders navigation items that can be reordered or hidden by adaptation rules. Uses Vue scoped slots for rendering.

<script setup lang="ts">
import { AdaptiveNav } from '@presage-kit/vue'
const items = [
{ id: 'home', label: 'Home', href: '/' },
{ id: 'analytics', label: 'Analytics', href: '/analytics' },
]
</script>
<template>
<AdaptiveNav id="sidebar-nav" :items="items" v-slot="{ item }">
<a :href="item.href">{{ item.label }}</a>
</AdaptiveNav>
</template>

Props:

PropTypeRequiredDescription
idstringYesAdaptation point identifier
itemsT[] (extends NavItem)YesArray of items, each with at least an id field

Scoped slot:

FieldTypeDescription
itemTThe current navigation item

NavItem interface:

interface NavItem {
id: string
[key: string]: unknown
}

Behavior: Evaluates reorder and hide actions from the rule engine. When hidden, renders nothing. When reordered, items are rendered in the new order.

FeatureReactVue
Provider<AdaptiveProvider> componentAdaptivePlugin (Vue plugin)
Declarative component<Adaptive> + <Variant><Adaptive> + <Variant> (defineComponent-based)
Generic ordering<AdaptiveOrder> with renderItem prop<AdaptiveOrder> with scoped slots
Adaptive navigation<AdaptiveNav> (wraps <AdaptiveOrder>)<AdaptiveNav> (wraps <AdaptiveOrder>)
Hook/composable returnPlain objectObject with reactive getters
State bridgeuseSyncExternalStore-styleref + atom subscribe()