componente · @solu30/ui-kit/feedback
SheetRoot
Root provider for sheet composition. Manages open state and provides context to child components.
144 sitios de import en 6 de 15 verticales — un archivo que la importa cuenta una vez, monte una instancia o veinte.
- cmp-packages
- elliot
- gestorsalon
- luigi
- raquetea
- zentrya
El componente, montado
Cargando el espécimen…
export function SheetCompositionMatrix({ abiertoAlMontar = false }: { abiertoAlMontar?: boolean }) {
const [open, setOpen] = useState(abiertoAlMontar)
const [lado, setLado] = useState<(typeof SHEET_LADOS)[number]>('right')
return (
<Stage label="Sheet composable · SheetRoot + Trigger + Content + Close, y el panel replicado adentro" tall wide>
<div className="flex flex-col items-center gap-3">
<div className="flex flex-col items-center gap-4 sm:flex-row sm:items-start sm:justify-center">
<SheetRoot open={open} onOpenChange={setOpen}>
<SheetTrigger
type="button"
className="rounded-md border border-content/10 bg-container px-3 py-1.5 text-xs font-medium text-content transition-colors hover:bg-upper"
>
Abrir el panel de filtros
</SheetTrigger>
<SheetContent side={lado} manageHistory={false}>
<SheetHeader>
<SheetTitle>Filtros de reservas</SheetTitle>
<SheetDescription>Se aplican sobre la agenda del mes en curso.</SheetDescription>
</SheetHeader>
<div className="flex flex-col gap-3 px-4 py-3">
<p className="text-sm text-content/70">
Los cuatro lados que acepta SheetContent. El control vive adentro del panel porque el
backdrop tapa todo lo de afuera.
</p>
<div className="flex flex-wrap gap-2">
{SHEET_LADOS.map((l) => (
<button
key={l}
type="button"
onClick={() => setLado(l)}
aria-pressed={l === lado}
className={
l === lado
? 'rounded-md border border-content/30 bg-upper px-3 py-1.5 font-mono text-[11px] text-content'
: 'rounded-md border border-content/10 bg-container px-3 py-1.5 font-mono text-[11px] text-content/60 transition-colors hover:bg-upper'
}
>
{l}
</button>
))}
</div>
</div>
<SheetFooter>
<SheetClose
type="button"
className="rounded-md border border-content/10 bg-container px-3 py-1.5 text-xs font-medium text-content transition-colors hover:bg-upper"
>
Cerrar sin aplicar
</SheetClose>
</SheetFooter>
</SheetContent>
</SheetRoot>
<ReplicaContenida nota={`réplica del panel · side="${lado}"`}>
<div className="flex flex-col gap-2 p-4">
<p className="text-sm font-medium text-content">Filtros de reservas</p>
<p className="text-xs text-content/60">Se aplican sobre la agenda del mes en curso.</p>
<p className="border-t border-content/10 pt-2 text-xs text-content/70">
Los cuatro lados que acepta SheetContent. El control vive adentro del panel porque el
backdrop tapa todo lo de afuera.
</p>
<div className="flex flex-wrap gap-1.5">
{SHEET_LADOS.map((l) => (
<span
key={l}
className={
l === lado
? 'rounded-md border border-content/30 bg-upper px-2.5 py-1 font-mono text-[10px] text-content'
: 'rounded-md border border-content/10 bg-container px-2.5 py-1 font-mono text-[10px] text-content/60'
}
>
{l}
</span>
))}
</div>
<div className="flex justify-end border-t border-content/10 pt-2">
<span className="rounded-md border border-content/10 bg-container px-3 py-1.5 text-xs text-content">
Cerrar sin aplicar
</span>
</div>
</div>
</ReplicaContenida>
</div>
<p className="max-w-[520px] text-center text-[11px] text-content/50">
El componente REAL es el de la izquierda y abre de verdad: su panel sale por un portal a
document.body y se dibuja fijo sobre la página, no adentro de este recuadro — por eso acá al
lado va la misma forma replicada, que sí se puede mirar sin que tape la ficha. El botón es
SheetTrigger; el del pie del panel, SheetClose. Los cuatro lados se prueban abriéndolo.
</p>
</div>
</Stage>
)
}De specimens/feedback.tsx · SheetCompositionMatrix: el espécimen del Muestrario, no un ejemplo oficial del paquete. Muestra cómo se usa la pieza de verdad, montada contra los tipos instalados —eso es lo que vale— pero no es documentación del kit.
Cómo se usa
import {
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetRoot,
SheetTitle,
SheetTrigger,
} from '@solu30/ui-kit/feedback'Anatomía
Las partes que componen SheetRoot se importan del mismo subpath. Sueltas no significan nada: se montan siempre dentro de su padre.
SheetRoot
├── SheetClose
├── SheetContent
├── SheetDescription
├── SheetFooter
├── SheetHeader
├── SheetTitle
└── SheetTriggerProps
| Prop | Requerida | Tipo | Qué hace |
|---|---|---|---|
| open | sí | boolean | — |
| onOpenChange | sí | (open: boolean) => void | — |
| children | sí | React__default.ReactNode | — |
Ejemplo del paquete
// La versión compuesta, para cuando el disparador vive adentro.
<SheetRoot open={abierto} onOpenChange={setAbierto}>
<SheetTrigger asChild><Button>Filtros</Button></SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Filtros</SheetTitle>
<SheetDescription>Se aplican al listado de abajo.</SheetDescription>
</SheetHeader>
</SheetContent>
</SheetRoot>Del @example del JSDoc de @solu30/ui-kit, sin editar: son 65 de los 541 símbolos. La sangría y los renglones en blanco son los del paquete.