Aller au contenu

Adaptateur React

Le package @presage-kit/react fournit des composants React et des hooks pour construire des interfaces adaptatives.

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

Fournit le AdaptiveClient à l’ensemble de l’arbre de composants via le contexte React.

import { AdaptiveProvider } from '@presage-kit/react'
import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
const client = createAdaptiveClient({
rules: [/* ... */],
persistence: { driver: createLocalStorageDriver('my-app') },
})
function App() {
return (
<AdaptiveProvider client={client}>
<YourApp />
</AdaptiveProvider>
)
}

Props :

PropTypeDescription
clientAdaptiveClientL’instance du client issue de createAdaptiveClient()
childrenReactNodeVotre arbre applicatif

Déclare un point d’adaptation et rend la variante correspondante.

import { Adaptive, Variant } from '@presage-kit/react'
function Dashboard() {
return (
<Adaptive id="dashboard-layout" defaultVariant="standard">
<Variant id="compact">
<CompactDashboard />
</Variant>
<Variant id="standard">
<StandardDashboard />
</Variant>
<Variant id="advanced">
<AdvancedDashboard />
</Variant>
</Adaptive>
)
}

Props de <Adaptive> :

PropTypeDescription
idstringIdentifiant unique du point d’adaptation
defaultVariantstringVariante à afficher quand aucune règle ne correspond
childrenReactNodeDoit contenir des composants <Variant>

Props de <Variant> :

PropTypeDescription
idstringIdentifiant de la variante (référencé dans les actions de règles)
childrenReactNodeContenu à rendre quand cette variante est sélectionnée

Le composant <Adaptive> utilise en interne useAdaptive() et suit automatiquement les impressions quand la variante sélectionnée change.

Rend une liste d’éléments de navigation pouvant être réordonnés par les règles d’adaptation.

import { AdaptiveNav, type NavItem } from '@presage-kit/react'
interface MenuItem extends NavItem {
label: string
href: string
icon: string
}
const menuItems: MenuItem[] = [
{ id: 'home', label: 'Home', href: '/', icon: 'home' },
{ id: 'analytics', label: 'Analytics', href: '/analytics', icon: 'chart' },
{ id: 'settings', label: 'Settings', href: '/settings', icon: 'gear' },
]
function Sidebar() {
return (
<AdaptiveNav
id="sidebar-nav"
items={menuItems}
renderItem={(item, index) => (
<a key={item.id} href={item.href}>
{item.icon} {item.label}
</a>
)}
/>
)
}

Avec une règle reorder, l’ordre de navigation change en fonction du contexte utilisateur :

{
id: 'power-user-nav-order',
adaptationId: 'sidebar-nav',
priority: 10,
conditions: {
all: [{ field: 'maturity', operator: 'eq', value: 'power' }],
},
action: { type: 'reorder', order: ['analytics', 'home', 'settings'] },
}

Avec une règle hide, la navigation entière est masquée :

{
id: 'hide-nav-for-new-users',
adaptationId: 'sidebar-nav',
priority: 20,
conditions: {
all: [{ field: 'maturity', operator: 'eq', value: 'new' }],
},
action: { type: 'hide' },
}

Props :

PropTypeDescription
idstringIdentifiant du point d’adaptation
itemsT[] (extends NavItem)Tableau d’éléments, chacun avec au minimum un champ id
renderItem(item: T, index: number) => ReactNodeFonction de rendu pour chaque élément

Interface NavItem :

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

Le hook principal pour résoudre les points d’adaptation. Retourne la variante sélectionnée, les détails complets de résolution, le contexte et une fonction de suivi scopée.

import { useAdaptive } from '@presage-kit/react'
function FeatureDiscovery() {
const { selectedVariant, resolution, context, track } = useAdaptive('feature-discovery', {
variants: ['tooltip', 'banner', 'modal'] as const,
defaultVariant: 'tooltip',
})
// Track a conversion event scoped to this adaptation point
function handleDismiss() {
track('feature_discovery_dismissed')
}
switch (selectedVariant) {
case 'tooltip':
return <Tooltip onDismiss={handleDismiss} />
case 'banner':
return <Banner onDismiss={handleDismiss} />
case 'modal':
return <Modal onDismiss={handleDismiss} />
}
}

Paramètres :

ParamTypeDescription
adaptationIdstringIdentifiant unique du point d’adaptation
config.variantsreadonly string[]IDs de variantes disponibles
config.defaultVariantstringVariante de repli
config.strategyStrategyOptionnel. Par défaut { type: 'rules' }

Type de retour :

ChampTypeDescription
selectedVariantVLa variante sélectionnée (type restreint à votre union de variantes)
resolutionResolvedAdaptationDétails complets de résolution (stratégie, raison, horodatage)
contextUserContextContexte utilisateur courant
track(event: string, properties?: Record<string, unknown>) => voidFonction de suivi scopée à ce point d’adaptation

Génériques TypeScript : Le hook infère le type de variante depuis variants :

// selectedVariant is typed as 'tooltip' | 'banner' | 'modal'
const { selectedVariant } = useAdaptive('feature-discovery', {
variants: ['tooltip', 'banner', 'modal'] as const,
defaultVariant: 'tooltip',
})

Suivi automatique des impressions : Quand la variante sélectionnée change, useAdaptive() suit automatiquement un événement presage:impression avec l’ID d’adaptation, la variante et la stratégie.

Un hook plus léger qui retourne uniquement la chaîne de la variante sélectionnée. Utilisez-le quand vous n’avez pas besoin des détails complets de résolution.

import { useVariant } from '@presage-kit/react'
function CTAButton() {
const variant = useVariant('cta-style', {
variants: ['primary', 'secondary', 'subtle'] as const,
defaultVariant: 'primary',
})
return <button className={`cta cta--${variant}`}>Get Started</button>
}

Paramètres : Identiques à useAdaptive().

Type de retour : V — La chaîne de la variante sélectionnée.

Retourne l’instance AdaptiveClient depuis le contexte. Utile pour les opérations impératives comme le suivi et l’identification.

import { useAdaptiveClient } from '@presage-kit/react'
function TrackingButton() {
const client = useAdaptiveClient()
function handleClick() {
client.track('feature_used', { featureId: 'export' })
}
return <button onClick={handleClick}>Export</button>
}

Type de retour : AdaptiveClient

Lance une erreur s’il est appelé en dehors de <AdaptiveProvider>.

Cet exemple montre une barre latérale adaptative et un flux d’intégration pour un tableau de bord SaaS.

src/lib/adaptive-client.ts
import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
export const client = createAdaptiveClient({
rules: [
// Sidebar: prioritize analytics for power users
{
id: 'power-user-sidebar',
adaptationId: 'sidebar',
priority: 10,
conditions: {
all: [{ field: 'maturity', operator: 'eq', value: 'power' }],
},
action: { type: 'reorder', order: ['analytics', 'dashboards', 'settings', 'home'] },
},
// Onboarding: guided tour for new users
{
id: 'new-user-tour',
adaptationId: 'onboarding',
priority: 10,
conditions: {
all: [{ field: 'maturity', operator: 'eq', value: 'new' }],
},
action: { type: 'show', variantId: 'guided-tour' },
},
// Onboarding: hide for experienced users
{
id: 'experienced-no-onboarding',
adaptationId: 'onboarding',
priority: 5,
conditions: {
any: [
{ field: 'maturity', operator: 'eq', value: 'active' },
{ field: 'maturity', operator: 'eq', value: 'power' },
],
},
action: { type: 'hide' },
},
],
persistence: {
driver: createLocalStorageDriver('saas-demo'),
},
})
src/App.tsx
import { AdaptiveProvider } from '@presage-kit/react'
import { client } from './lib/adaptive-client'
import { Sidebar } from './components/Sidebar'
import { Onboarding } from './components/Onboarding'
import { Dashboard } from './components/Dashboard'
export function App() {
return (
<AdaptiveProvider client={client}>
<div style={{ display: 'flex' }}>
<Sidebar />
<main>
<Onboarding />
<Dashboard />
</main>
</div>
</AdaptiveProvider>
)
}
src/components/Sidebar.tsx
import { AdaptiveNav, type NavItem } from '@presage-kit/react'
interface SidebarItem extends NavItem {
label: string
href: string
}
const items: SidebarItem[] = [
{ id: 'home', label: 'Home', href: '/' },
{ id: 'dashboards', label: 'Dashboards', href: '/dashboards' },
{ id: 'analytics', label: 'Analytics', href: '/analytics' },
{ id: 'settings', label: 'Settings', href: '/settings' },
]
export function Sidebar() {
return (
<nav>
<AdaptiveNav
id="sidebar"
items={items}
renderItem={(item) => (
<a key={item.id} href={item.href}>
{item.label}
</a>
)}
/>
</nav>
)
}
src/components/Onboarding.tsx
import { Adaptive, Variant } from '@presage-kit/react'
export function Onboarding() {
return (
<Adaptive id="onboarding" defaultVariant="standard">
<Variant id="guided-tour">
<div>
<h2>Welcome! Let us show you around.</h2>
<p>Follow the steps to get set up.</p>
</div>
</Variant>
<Variant id="standard">
<div>
<h2>What is new</h2>
<p>Check out the latest features.</p>
</div>
</Variant>
</Adaptive>
)
}