Svelte Adapter
The @presage-kit/svelte package provides Svelte stores and context helpers for building adaptive interfaces.
Installation
Section intitulée « Installation »pnpm add @presage-kit/core @presage-kit/svelteContext Setup
Section intitulée « Context Setup »Use setAdaptiveClient() in your root layout to make the client available to all child components via Svelte’s context API.
<script> import { setAdaptiveClient } from '@presage-kit/svelte' import { client } from '$lib/adaptive-client'
setAdaptiveClient(client)</script>
<slot />useAdaptive() Store
Section intitulée « useAdaptive() Store »The primary function for resolving adaptation points. Returns Svelte readable stores that update reactively when user context changes.
<script lang="ts"> import { useAdaptive } from '@presage-kit/svelte'
const { selectedVariant, resolution, context, track } = useAdaptive('onboarding', { variants: ['guided-tour', 'standard', 'minimal'] as const, defaultVariant: 'standard', })
function handleComplete() { track('onboarding_completed') }</script>
{#if $selectedVariant === 'guided-tour'} <h2>Welcome! Let us show you around.</h2> <button on:click={handleComplete}>Complete tour</button>{:else if $selectedVariant === 'standard'} <h2>Welcome</h2>{:else} <p>Good to see you again.</p>{/if}Parameters:
| Param | Type | Description |
|---|---|---|
adaptationId | string | Unique identifier for the adaptation point |
config.variants | readonly string[] | Available variant IDs |
config.defaultVariant | string | Fallback variant |
config.strategy | Strategy | Optional. Defaults to { type: 'rules' } |
Return type:
All reactive values are Svelte Readable stores — use the $ prefix to subscribe.
| Field | Type | Description |
|---|---|---|
selectedVariant | Readable<V> | The selected variant string |
resolution | Readable<ResolvedAdaptation> | Full resolution details |
context | Readable<UserContext> | Current user context |
track | (event: string, properties?) => void | Scoped track function |
Automatic impression tracking: useAdaptive() watches for variant changes and automatically tracks presage:impression events.
useVariant() Store
Section intitulée « useVariant() Store »A lighter function that returns only the selected variant as a readable store.
<script lang="ts"> import { useVariant } from '@presage-kit/svelte'
const variant = useVariant('cta-style', { variants: ['primary', 'secondary', 'subtle'] as const, defaultVariant: 'primary', })</script>
<button class="cta cta--{$variant}">Get Started</button>Parameters: Same as useAdaptive().
Return type: Readable<V> — A store containing the selected variant string.
getAdaptiveClient()
Section intitulée « getAdaptiveClient() »Returns the AdaptiveClient instance from context. Use for imperative operations.
<script lang="ts"> import { getAdaptiveClient } from '@presage-kit/svelte'
const client = getAdaptiveClient()
function handleExport() { client.track('feature_used', { featureId: 'export' }) }</script>
<button on:click={handleExport}>Export Data</button>Throws an error if setAdaptiveClient() has not been called in a parent component.
Adaptive Navigation with evaluateAction()
Section intitulée « Adaptive Navigation with evaluateAction() »Like the Vue adapter, the Svelte package does not ship a dedicated navigation component. Use evaluateAction() with a reactive declaration to reorder or hide navigation items.
<script lang="ts"> import { getAdaptiveClient } from '@presage-kit/svelte' import { useAtom } from '@presage-kit/svelte' import { derived } from 'svelte/store'
const client = getAdaptiveClient()
const baseItems = [ { id: 'home', label: 'Home', href: '/' }, { id: 'analytics', label: 'Analytics', href: '/analytics' }, { id: 'settings', label: 'Settings', href: '/settings' }, ]
const navItems = derived(useAtom(client.state), () => { const action = client.evaluateAction('sidebar-nav')
if (action?.type === 'hide') return []
if (action?.type === 'reorder') { const map = new Map(baseItems.map((item) => [item.id, item])) const ordered = action.order.filter((id) => map.has(id)).map((id) => map.get(id)!) const rest = baseItems.filter((i) => !action.order.includes(i.id)) return [...ordered, ...rest] }
return baseItems })</script>
<nav> {#each $navItems as item (item.id)} <a href={item.href}>{item.label}</a> {/each}</nav>Full Example: SaaS Dashboard
Section intitulée « Full Example: SaaS Dashboard »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('svelte-demo'), },})<script> import { setAdaptiveClient } from '@presage-kit/svelte' import { client } from '$lib/adaptive-client'
setAdaptiveClient(client)</script>
<div class="layout"> <SidebarNav /> <main> <slot /> </main></div><script lang="ts"> import { useAdaptive } from '@presage-kit/svelte'
const { selectedVariant, track } = useAdaptive('onboarding', { variants: ['guided-tour', 'standard', 'minimal'] as const, defaultVariant: 'standard', })
function handleComplete() { track('onboarding_completed') }</script>
{#if $selectedVariant === 'guided-tour'} <div class="onboarding"> <h2>Welcome! Let us show you around.</h2> <button on:click={handleComplete}>Complete Tour</button> </div>{:else if $selectedVariant === 'standard'} <div class="onboarding"> <h2>What is new</h2> <p>Check out the latest features.</p> </div>{:else} <div class="onboarding"> <p>Welcome back!</p> </div>{/if}