Ir al contenido

Tour

Tour guiado con resaltado de foco y navegación por pasos.

import { Tour } from 'asterui'

Tour Básico

Un tour guiado simple con múltiples pasos.

import { Tour, Button, Input, Card } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const searchRef = useRef<HTMLInputElement>(null);
  const profileRef = useRef<HTMLButtonElement>(null);
  const settingsRef = useRef<HTMLButtonElement>(null);
  
  const steps = [
    {
      target: searchRef,
      title: 'Search',
      description: 'Use the search bar to find content quickly.',
      placement: 'bottom' as const,
    },
    {
      target: profileRef,
      title: 'Profile',
      description: 'Click here to view and edit your profile.',
      placement: 'bottom' as const,
    },
    {
      target: settingsRef,
      title: 'Settings',
      description: 'Customize your experience in settings.',
      placement: 'left' as const,
    },
  ];
  
  return (
      <Card className="p-4">
        <div className="flex gap-4 items-center mb-4">
          <Input ref={searchRef} placeholder="Search..." className="flex-1" />
          <Button ref={profileRef}>Profile</Button>
          <Button ref={settingsRef}>Settings</Button>
        </div>
        <Button color="primary" onClick={() => setOpen(true)}>
          Start Tour
        </Button>
        <Tour
          open={open}
          steps={steps}
          onClose={() => setOpen(false)}
          onFinish={() => setOpen(false)}
        />
      </Card>
    )
}

export default App

Tour Sin Objetivo

Los pasos sin objetivo aparecen centrados en la pantalla.

import { Tour, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const steps = [
    {
      title: 'Welcome!',
      description: 'This tour will guide you through the main features.',
    },
    {
      title: 'Getting Started',
      description: 'Follow along to learn how to use this application.',
    },
    {
      title: 'All Done!',
      description: 'You are ready to start using the app.',
    },
  ];
  
  return (
      <Button color="primary" onClick={() => setOpen(true)}>
        Start Intro
      </Button>
      <Tour
        open={open}
        steps={steps}
        onClose={() => setOpen(false)}
        type="primary"
      />
    )
}

export default App

Con Imagen de Portada

Añade imágenes o contenido personalizado sobre el título del paso.

import { Tour, Button } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  
  const steps = [
    {
      target: buttonRef,
      title: 'New Feature',
      description: 'Check out this amazing new feature we just added!',
      cover: (
        <img
          src="https://picsum.photos/320/160"
          alt="Feature preview"
          className="w-full h-40 object-cover"
        />
      ),
      placement: 'right' as const,
    },
  ];
  
  return (
      <Button ref={buttonRef} color="primary" onClick={() => setOpen(true)}>
        View Feature
      </Button>
      <Tour
        open={open}
        steps={steps}
        onClose={() => setOpen(false)}
        showSkip={false}
      />
    )
}

export default App

Posiciones

Controla dónde aparece el popover relativo al objetivo.

Target
import { Tour, Button, Space } from 'asterui'
import { useState, useRef } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  const targetRef = useRef<HTMLDivElement>(null);
  const placements = ['top', 'right', 'bottom', 'left'] as const;
  const [placementIndex, setPlacementIndex] = useState(0);
  
  const steps = [
    {
      target: targetRef,
      title: `Placement: ${placements[placementIndex]}`,
      description: 'The popover can appear on any side of the target.',
      placement: placements[placementIndex],
    },
  ];
  
  return (
      <div className="flex flex-col items-center gap-4">
        <div
          ref={targetRef}
          className="w-24 h-24 bg-primary text-primary-content flex items-center justify-center rounded-lg"
        >
          Target
        </div>
        <Space>
          <Button onClick={() => setPlacementIndex((i) => (i + 1) % 4)}>
            Change Placement
          </Button>
          <Button color="primary" onClick={() => setOpen(true)}>
            Show Tour
          </Button>
        </Space>
        <Tour
          open={open}
          steps={steps}
          onClose={() => setOpen(false)}
          showIndicators={false}
        />
      </div>
    )
}

export default App
PropiedadDescripciónTipoPredeterminado
openSi el tour es visiblebooleanfalse
stepsConfiguración de pasos del tourTourStepProps[]-
currentÍndice del paso actual (controlado)number-
onChangeCallback cuando cambia el paso(current: number) => void-
onCloseCallback cuando se cierra el tour() => void-
onFinishCallback cuando termina el tour() => void-
maskMostrar superposición de máscara con focobooleantrue
typeTipo de estilo de botón'default' | 'primary''default'
gapEspacio entre el foco y el objetivo [radio, desplazamiento] o númeronumber | [number, number]8
showSkipMostrar botón de omitirbooleantrue
showIndicatorsMostrar indicadores de pasobooleantrue
closeOnMaskClickCerrar al hacer clic en la máscarabooleantrue
closeOnEscapeCerrar con tecla Escapebooleantrue
scrollIntoViewDesplazar objetivo a la vistabooleantrue
prevButtonTextTexto para botón anteriorReact.ReactNode'Previous'
nextButtonTextTexto para botón siguienteReact.ReactNode'Next'
finishButtonTextTexto para botón finalizarReact.ReactNode'Finish'
skipButtonTextTexto para botón omitirReact.ReactNode'Skip'
zIndexz-index para superposición del tournumber1000
PropiedadDescripciónTipoPredeterminado
targetRef del elemento objetivo o función que devuelve elementoRefObject<HTMLElement> | (() => HTMLElement | null) | null-
titleTítulo del pasoReact.ReactNode-
descriptionDescripción del pasoReact.ReactNode-
coverImagen de portada o contenido sobre el títuloReact.ReactNode-
placementPosición del popover relativa al objetivoTourPlacement'bottom'
classNameClase personalizada para el popover del pasostring-
onOpenLlamado cuando el paso se activa() => void-
onCloseLlamado al salir del paso() => void-
  • El diálogo del tour tiene role=“dialog” y aria-modal=“true”
  • Las teclas de flecha navegan entre pasos
  • La tecla Escape cierra el tour
  • Los indicadores de paso son accesibles por teclado
  • El foco queda atrapado dentro del tour cuando está abierto