Ir al contenido

Adaptador React

El paquete @presage-kit/react proporciona componentes y hooks de React para construir interfaces adaptativas.

Ventana de terminal
pnpm add @presage-kit/core @presage-kit/react

Proporciona el AdaptiveClient a todo el arbol de componentes mediante el contexto de 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:

PropTipoDescripcion
clientAdaptiveClientLa instancia del cliente creada con createAdaptiveClient()
childrenReactNodeSu arbol de aplicacion

Declara un adaptation point y renderiza la variante correspondiente.

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>:

PropTipoDescripcion
idstringIdentificador unico del adaptation point
defaultVariantstringVariante a mostrar cuando ninguna regla coincide
childrenReactNodeDebe contener componentes <Variant>

Props de <Variant>:

PropTipoDescripcion
idstringIdentificador de la variante (referenciado en las acciones de reglas)
childrenReactNodeContenido a renderizar cuando esta variante es seleccionada

El componente <Adaptive> utiliza internamente useAdaptive() y rastrea automaticamente las impresiones cuando la variante seleccionada cambia.

Renderiza una lista de elementos de navegacion que pueden ser reordenados por reglas de adaptacion.

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>
)}
/>
)
}

Con una regla reorder, el orden de navegacion cambia segun el contexto del usuario:

{
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'] },
}

Con una regla hide, toda la navegacion se oculta:

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

Props:

PropTipoDescripcion
idstringIdentificador del adaptation point
itemsT[] (extiende NavItem)Array de elementos, cada uno con al menos un campo id
renderItem(item: T, index: number) => ReactNodeFuncion de renderizado para cada elemento

Interfaz NavItem:

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

El hook principal para resolver adaptation points. Devuelve la variante seleccionada, detalles completos de resolucion, contexto y una funcion de rastreo con scope.

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} />
}
}

Parametros:

ParametroTipoDescripcion
adaptationIdstringIdentificador unico del adaptation point
config.variantsreadonly string[]IDs de variantes disponibles
config.defaultVariantstringVariante de respaldo
config.strategyStrategyOpcional. Por defecto { type: 'rules' }

Tipo de retorno:

CampoTipoDescripcion
selectedVariantVLa variante seleccionada (tipo restringido a su union de variantes)
resolutionResolvedAdaptationDetalles completos de resolucion (estrategia, razon, marca de tiempo)
contextUserContextContexto actual del usuario
track(event: string, properties?: Record<string, unknown>) => voidFuncion de rastreo con scope para este adaptation point

Genericos de TypeScript: El hook infiere el tipo de variante a partir de variants:

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

Rastreo automatico de impresiones: Cuando la variante seleccionada cambia, useAdaptive() rastrea automaticamente un evento presage:impression con el ID de adaptacion, la variante y la estrategia.

Un hook mas ligero que devuelve unicamente la cadena de la variante seleccionada. Uselo cuando no necesite los detalles completos de resolucion.

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>
}

Parametros: Los mismos que useAdaptive().

Tipo de retorno: V — La cadena de la variante seleccionada.

Devuelve la instancia de AdaptiveClient desde el contexto. Util para operaciones imperativas como rastreo e identificacion.

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>
}

Tipo de retorno: AdaptiveClient

Lanza un error si se llama fuera de <AdaptiveProvider>.

Este ejemplo muestra una barra lateral adaptativa y un flujo de incorporacion para un tablero 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>
)
}