Add comprehensive CSS documentation to all Terra UI components

- Add "Selectores CSS" section documenting all data-* attributes
- Remove -root suffix from data attributes (data-component-root → data-component)
- Update attrs.ts to generate cleaner attribute names
- Update contracts.ts with new naming convention
- Update README.md documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
glm-5
dev 6 months ago
parent 978a6f3463
commit 0766cfe49f

@ -70,7 +70,7 @@
</Accordion.Header> </Accordion.Header>
<Accordion.Content class="acc-content"> <Accordion.Content class="acc-content">
El content expone <code>data-state="open|closed"</code> y El content expone <code>data-state="open|closed"</code> y
<code>--bits-accordion-content-height</code> para animar <code>--terra-accordion-content-height</code> para animar
con CSS sin JavaScript adicional. con CSS sin JavaScript adicional.
</Accordion.Content> </Accordion.Content>
</Accordion.Item> </Accordion.Item>

@ -527,7 +527,7 @@ export const CONTRACTS: Record<string, ComponentContract> = {
version: 1, version: 1,
parts: { parts: {
root: [ root: [
{ attr: 'data-switch-root', description: 'Siempre presente en el root' }, { attr: 'data-switch', description: 'Siempre presente en el root' },
{ attr: 'data-state', values: ['checked', 'unchecked'], description: 'Estado' }, { attr: 'data-state', values: ['checked', 'unchecked'], description: 'Estado' },
{ attr: 'data-disabled', description: 'Presente cuando disabled=true' }, { attr: 'data-disabled', description: 'Presente cuando disabled=true' },
], ],
@ -549,7 +549,7 @@ import { assertDataContract } from '$terra/utils/contracts';
readonly props = $derived.by(() => { readonly props = $derived.by(() => {
const props = { const props = {
"data-switch-root": "", "data-switch": "",
"data-state": getDataChecked(this.opts.checked.current), "data-state": getDataChecked(this.opts.checked.current),
// ... // ...
} as const; } as const;

@ -375,8 +375,8 @@ export class AccordionContentState {
"data-orientation": this.item.root.opts.orientation.current, "data-orientation": this.item.root.opts.orientation.current,
[accordionAttrs.content]: "", [accordionAttrs.content]: "",
style: { style: {
"--bits-accordion-content-height": `${this.dimensions.height}px`, "--terra-accordion-content-height": `${this.dimensions.height}px`,
"--bits-accordion-content-width": `${this.dimensions.width}px`, "--terra-accordion-content-width": `${this.dimensions.width}px`,
}, },
hidden: hidden:
this.opts.hiddenUntilFound.current && !this.item.isActive this.opts.hiddenUntilFound.current && !this.item.isActive

@ -1,4 +1,38 @@
<script lang="ts"> <script lang="ts">
/**
* # Accordion Content
*
* Contenido expansible de un item del acordeón.
* Solo se muestra cuando el item padre está abierto.
*
* ## Uso
* ```svelte
* <AccordionContent>
* <p>Este contenido solo se muestra cuando el item está abierto.</p>
* </AccordionContent>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Monta el contenido siempre (útil para transiciones)
* - `hiddenUntilFound`: boolean - Permite búsqueda del navegador
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura del contenido
*
* ## Selectores CSS
* ```
* [data-accordion-content] → Contenido del acordeón
* [data-state="open"] → Contenido visible
* [data-state="closed"] → Contenido oculto
* [data-disabled] → Hereda disabled del item
* [data-orientation="vertical"] → Hereda orientación del root
* [data-orientation="horizontal"] → Hereda orientación del root
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con atributos ARIA apropiados.
*/
import { import {
mergeProps, mergeProps,
readableActive, readableActive,

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Accordion Header
*
* Contenedor del encabezado de un item del acordeón.
* Debe contener un AccordionTrigger.
*
* ## Uso
* ```svelte
* <AccordionHeader level={3}>
* <AccordionTrigger>Título del item</AccordionTrigger>
* </AccordionHeader>
* ```
*
* ## Propiedades
* - `level`: 1 | 2 | 3 | 4 | 5 | 6 - Nivel de encabezado (h1-h6)
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-accordion-header] → Header del item
* [data-heading-level] → Nivel del heading (1-6)
* [data-state="open"] → Hereda estado del item
* [data-state="closed"] → Hereda estado del item
* [data-orientation="vertical"] → Hereda orientación del root
* [data-orientation="horizontal"] → Hereda orientación del root
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con el role de heading apropiado.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Accordion Item
*
* Componente que representa un item individual del acordeón.
* Debe contener un AccordionHeader y un AccordionContent.
*
* ## Uso
* ```svelte
* <AccordionItem value="item-1">
* <AccordionHeader>
* <AccordionTrigger>Título</AccordionTrigger>
* </AccordionHeader>
* <AccordionContent>Contenido</AccordionContent>
* </AccordionItem>
* ```
*
* ## Propiedades
* - `value`: string - Identificador único del item (se genera uno por defecto)
* - `disabled`: boolean - Deshabilita este item específico
* - `id`: string - ID del elemento (se genera uno por defecto)
*
* ## Selectores CSS
* ```
* [data-accordion-item] → Contenedor del item
* [data-state="open"] → Item abierto
* [data-state="closed"] → Item cerrado
* [data-disabled] → Presente cuando el item está disabled
* [data-orientation="vertical"] → Hereda orientación del root
* [data-orientation="horizontal"] → Hereda orientación del root
* ```
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,37 @@
<script lang="ts"> <script lang="ts">
/**
* # Accordion Trigger
*
* Botón que alterna el estado de apertura/cierre del item del acordeón.
* Debe estar dentro de un AccordionHeader.
*
* ## Uso
* ```svelte
* <AccordionHeader>
* <AccordionTrigger>
* Click para expandir {#if open()} ▲ {:else} ▼ {/if}
* </AccordionTrigger>
* </AccordionHeader>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el trigger
* - `id`: string - ID del elemento
* - `tabindex`: number - Índice de tabulación
*
* ## Selectores CSS
* ```
* [data-accordion-trigger] → Botón trigger
* [data-state="open"] → Item abierto
* [data-state="closed"] → Item cerrado
* [data-disabled] → Presente cuando disabled=true
* [data-orientation="vertical"] → Hereda orientación del root
* [data-orientation="horizontal"] → Hereda orientación del root
* ```
*
* ## Estilos
* Renderiza un elemento `<button>` con atributos ARIA apropiados.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,42 @@
<script lang="ts"> <script lang="ts">
/**
* # Accordion Root
*
* Componente raíz del acordeón que gestiona el estado de apertura/cierre de los items.
*
* ## Uso
* ```svelte
* <Accordion type="single" bind:value={openItem}>
* <AccordionItem value="item1">
* <AccordionHeader>
* <AccordionTrigger>Item 1</AccordionTrigger>
* </AccordionHeader>
* <AccordionContent>Contenido 1</AccordionContent>
* </AccordionItem>
* </Accordion>
* ```
*
* ## Propiedades
* - `type`: "single" | "multiple"
* - `value`: string | string[] - (bindable)
* - `onValueChange`: (value) => void
* - `disabled`: boolean
* - `loop`: boolean
* - `orientation`: "vertical" | "horizontal"
*
* ## Selectores CSS
* ```
* [data-accordion] → Root
* [data-accordion-item] → Item
* [data-accordion-trigger] → Trigger
* [data-accordion-content] → Content
* [data-accordion-header] → Header
* [data-state="open"] → Item abierto
* [data-state="closed"] → Item cerrado
* [data-disabled] → Deshabilitado
* [data-orientation="vertical"] → Orientación vertical
* ```
*/
import { watch } from "runed"; import { watch } from "runed";
import { import {
type State, type State,

@ -1,4 +1,28 @@
<script lang="ts"> <script lang="ts">
/**
* # Alert Dialog Action
*
* Botón de acción principal del diálogo de alerta (ej. "Confirmar", "Eliminar").
* Al hacer clic, cierra el diálogo.
*
* ## Uso
* ```svelte
* <AlertDialogAction onclick={() => confirmAction()}>
* Confirmar
* </AlertDialogAction>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-alert-dialog-action] → Botón de acción principal
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { readableActive, writableActive, mergeProps, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, createId } from '$terra/utils';
import { DialogActionState } from '../../dialog/dialog.svelte'; import { DialogActionState } from '../../dialog/dialog.svelte';
import type { AlertDialogActionProps } from '../types'; import type { AlertDialogActionProps } from '../types';

@ -1,4 +1,29 @@
<script lang="ts"> <script lang="ts">
/**
* # Alert Dialog Cancel
*
* Botón de cancelación del diálogo de alerta (ej. "Cancelar", "Cerrar").
* Al hacer clic, cierra el diálogo sin realizar la acción.
*
* ## Uso
* ```svelte
* <AlertDialogCancel>
* Cancelar
* </AlertDialogCancel>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el botón
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-alert-dialog-cancel] → Botón de cancelar
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { readableActive, writableActive, mergeProps, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, createId } from '$terra/utils';
import { AlertDialogCance$state } from '../../dialog/dialog.svelte'; import { AlertDialogCance$state } from '../../dialog/dialog.svelte';
import type { AlertDialogCancelProps } from '../types'; import type { AlertDialogCancelProps } from '../types';

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Alert Dialog Content
*
* Contenedor principal del contenido del diálogo de alerta.
* Incluye el overlay y maneja el trapping de foco.
*
* ## Uso
* ```svelte
* <AlertDialogContent>
* <p>Contenido de la alerta</p>
* </AlertDialogContent>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Fuerza el montaje del componente
* - `onOpenAutoFocus`: Callback cuando el diálogo gana foco al abrirse
* - `onCloseAutoFocus`: Callback cuando el diálogo pierde foco al cerrarse
* - `onEscapeKeydown`: Callback cuando se presiona Escape
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura del diálogo
*
* ## Selectores CSS
* ```
* [data-alert-dialog-content] → Contenedor del diálogo
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* ```
*/
import { noop } from '$lib/util/funcs'; import { noop } from '$lib/util/funcs';
import { readableActive, writableActive, mergeProps, afterSleep, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, afterSleep, createId } from '$terra/utils';
import { DialogContentState } from '../../dialog/dialog.svelte'; import { DialogContentState } from '../../dialog/dialog.svelte';

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Alert Dialog Root
*
* Componente raíz para un diálogo de alerta modal que requiere atención del usuario.
* A diferencia de un diálogo normal, el usuario debe interactuar con él antes de continuar.
*
* ## Uso
* ```svelte
* <AlertDialog bind:open={isOpen}>
* <AlertDialogTrigger>Abrir alerta</AlertDialogTrigger>
* <AlertDialogContent>
* <AlertDialogTitle>¿Estás seguro?</AlertDialogTitle>
* <AlertDialogDescription>
* Esta acción no se puede deshacer.
* </AlertDialogDescription>
* <AlertDialogCancel>Cancelar</AlertDialogCancel>
* <AlertDialogAction>Confirmar</AlertDialogAction>
* </AlertDialogContent>
* </AlertDialog>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado de apertura del diálogo (bindable)
* - `onOpenChange`: Callback cuando cambia el estado de apertura
* - `onOpenChangeComplete`: Callback cuando la animación de apertura/cierre termina
*
* ## Selectores CSS
* ```
* [data-alert-dialog-content] → Contenedor del diálogo
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-alert-dialog-trigger] → Trigger que abre el diálogo
* [data-alert-dialog-cancel] → Botón de cancelar
* [data-alert-dialog-action] → Botón de acción principal
* ```
*/
import { readableActive, writableActive } from '$terra/utils'; import { readableActive, writableActive } from '$terra/utils';
import { DialogRootState } from '../../dialog/dialog.svelte'; import { DialogRootState } from '../../dialog/dialog.svelte';
import type { AlertDialogRootProps } from '../types'; import type { AlertDialogRootProps } from '../types';

@ -1,4 +1,37 @@
<script lang="ts"> <script lang="ts">
/**
* # Aspect Ratio
*
* Componente que mantiene una relación de aspecto proporcional para su contenido.
*
* ## Uso
* ```svelte
* <AspectRatio ratio={16 / 9}>
* <img src="video-thumbnail.jpg" alt="Video" />
* </AspectRatio>
*
* <!-- Cuadrado -->
* <AspectRatio ratio={1}>
* <img src="avatar.jpg" alt="Avatar" />
* </AspectRatio>
* ```
*
* ## Propiedades
* - `ratio`: number - Relación de aspecto (ancho/alto). Ejemplos comunes:
* - 1 = Cuadrado (1:1)
* - 16/9 = Video widescreen
* - 4/3 = Video estándar
* - 21/9 = Ultrawide
*
* ## Estilos
* Usa padding-bottom para mantener la proporción. El contenido se posiciona
* de forma absoluta sobre el contenedor.
*
* ## Selectores CSS
* ```
* [data-aspect-ratio] → Contenedor con relación de aspecto
* ```
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Avatar Fallback
*
* Contenido alternativo que se muestra cuando la imagen no ha cargado
* o ha fallado.
*
* ## Uso
* ```svelte
* <Avatar>
* <AvatarImage src="/avatar.jpg" alt="Usuario" />
* <AvatarFallback>
* <UserIcon />
* </AvatarFallback>
* </Avatar>
*
* <!-- Con iniciales -->
* <Avatar>
* <AvatarImage src="/avatar.jpg" alt="Usuario" />
* <AvatarFallback>JD</AvatarFallback>
* </Avatar>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-avatar-fallback] → Fallback cuando no hay imagen
* [data-status="loading"] → Hereda estado de carga
* [data-status="loaded"] → Hereda estado de carga
* [data-status="error"] → Hereda estado de carga
* ```
*
* ## Estilos
* Renderiza un elemento `<span>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,37 @@
<script lang="ts"> <script lang="ts">
/**
* # Avatar Image
*
* Imagen del avatar. Se muestra cuando la carga es exitosa.
*
* ## Uso
* ```svelte
* <Avatar>
* <AvatarImage src="/avatar.jpg" alt="Usuario" />
* <AvatarFallback>US</AvatarFallback>
* </Avatar>
* ```
*
* ## Propiedades
* - `src`: string - URL de la imagen
* - `alt`: string - Texto alternativo de la imagen
* - `crossorigin`: string - Configuración CORS para la imagen
* - `referrerpolicy`: string - Política de referer
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Si la imagen carga correctamente, se muestra y oculta el fallback
* - Si la imagen falla al cargar, se muestra el fallback
* - `delayMs` del AvatarRoot controla el tiempo de espera antes de mostrar
*
* ## Selectores CSS
* ```
* [data-avatar-image] → Elemento de imagen
* [data-status="loading"] → Estado de carga
* [data-status="loaded"] → Imagen cargada
* [data-status="error"] → Error al cargar
* ```
*/
import { readableActive, writableActive, mergeProps, createId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, createId } from "$terra/utils";
import type { AvatarImageProps } from "../types"; import type { AvatarImageProps } from "../types";
import { AvatarImageState } from "../avatar.svelte"; import { AvatarImageState } from "../avatar.svelte";

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Avatar Root
*
* Componente raíz del avatar que muestra una imagen de usuario con un fallback.
*
* ## Uso
* ```svelte
* <Avatar>
* <AvatarImage src="/avatar.jpg" alt="Usuario" />
* <AvatarFallback>US</AvatarFallback>
* </Avatar>
* ```
*
* ## Propiedades
* - `delayMs`: number - Tiempo de espera en ms antes de mostrar la imagen
* evita parpadeo si la imagen carga muy rápido (default: 0)
* - `loadingStatus`: "loading" | "loaded" | "error" - Estado de carga (bindable)
* - `onLoadingStatusChange`: Callback cuando cambia el estado de carga
* - `id`: string - ID del elemento
*
* ## Contrato
* - Debe contener `AvatarImage` y opcionalmente `AvatarFallback`
* - El fallback se muestra cuando la imagen está cargando o ha fallado
*
* ## Selectores CSS
* ```
* [data-avatar] → Contenedor del avatar
* [data-status="loading"] → Imagen cargando
* [data-status="loaded"] → Imagen cargada
* [data-status="error"] → Error al cargar
* ```
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,43 @@
<script lang="ts"> <script lang="ts">
/**
* # Button
*
* Componente de botón polivalente que puede renderizar como `<button>` o `<a>`.
*
* ## Uso
* ```svelte
* <!-- Botón normal -->
* <Button onclick={() => console.log('click')}>
* Click me
* </Button>
*
* <!-- Como enlace -->
* <Button href="/page">
* Navigate
* </Button>
*
* <!-- Deshabilitado -->
* <Button disabled>
* Disabled
* </Button>
* ```
*
* ## Propiedades
* - `href`: string - Si se proporciona, renderiza como `<a>`
* - `type`: "button" | "submit" | "reset" - Tipo del botón
* - `disabled`: boolean - Deshabilita el botón
* - `ref`: HTMLElement | null - Referencia al elemento DOM
* - Todas las props de HTMLButtonAttributes o HTMLAnchorAttributes
*
* ## Selectores CSS
* ```
* [data-button] → Elemento raíz del botón
* ```
*
* ## Estilos
* - Usa el atributo `data-button` para estilos
* - Cuando es link con disabled, usa `aria-disabled` y `tabindex="-1"`
*/
import type { ButtonRootProps } from "../types.ts"; import type { ButtonRootProps } from "../types.ts";
let { let {
@ -13,7 +52,7 @@
<svelte:element <svelte:element
this={href ? "a" : "button"} this={href ? "a" : "button"}
data-button-root data-button
type={href ? undefined : type} type={href ? undefined : type}
href={href && !disabled ? href : undefined} href={href && !disabled ? href : undefined}
disabled={href ? undefined : disabled} disabled={href ? undefined : disabled}

@ -1,4 +1,49 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Cell
*
* Celda individual de la grilla del calendario que contiene un CalendarDay.
*
* ## Uso
* ```svelte
* {#each days as date (date.toString())}
* <CalendarCell {date} month={placeholder}>
* <CalendarDay />
* </CalendarCell>
* {/each}
* ```
*
* ## Propiedades
* - `date`: DateValue - Fecha de la celda
* - `month`: DateValue - Mes de referencia para calcular offset
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `date`: DateValue - Objeto de fecha
* - `isSelected`: boolean - Si la celda está seleccionada
* - `isDisabled`: boolean - Si la celda está deshabilitada
* - `isUnavailable`: boolean - Si la celda no está disponible
* - `isToday`: boolean - Si la celda es hoy
* - `outsideMonth`: boolean - Si la fecha está fuera del mes visible
*
* ## Selectores CSS
* ```
* [data-calendar-cell] → Celda individual del calendario
* [data-disabled] → Presente cuando la celda está deshabilitada
* [data-readonly] → Presente cuando readonly=true
* [data-unavailable] → Presente cuando la fecha no está disponible
* [data-today] → Presente si es la fecha de hoy
* [data-outside-month] → Presente si es de otro mes
* [data-outside-visible-months] → Presente si está fuera del rango visible
* [data-focused] → Presente si tiene foco
* [data-selected] → Presente si está seleccionada
* [data-value] → Valor de la fecha (ISO string)
* [data-type="day"] → Celda que representa un día
* ```
*
* ## Estilos
* Renderiza un elemento `<td>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import { CalendarCellState } from "../calendar.svelte"; import { CalendarCellState } from "../calendar.svelte";
import type { CalendarCellProps } from "../types"; import type { CalendarCellProps } from "../types";

@ -1,4 +1,47 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Day
*
* Representa un día individual en el calendario. Muestra el número del día
* y maneja la selección.
*
* ## Uso
* ```svelte
* <CalendarCell date={date} month={month}>
* <CalendarDay>
* {#snippet children(props)}
* <span class:selected={props.isSelected}>
* {props.date.day}
* </span>
* {/snippet}
* </CalendarDay>
* </CalendarCell>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `date`: DateValue - Objeto de fecha completo
* - `isSelected`: boolean - Si el día está seleccionado
* - `isDisabled`: boolean - Si el día está deshabilitado
* - `isUnavailable`: boolean - Si el día no está disponible
* - `isToday`: boolean - Si el día es hoy
*
* ## Selectores CSS
* ```
* [data-calendar-day] → Contenedor del día
* [data-disabled] → Presente cuando el día está deshabilitado
* [data-unavailable] → Presente cuando el día no está disponible
* [data-today] → Presente si es la fecha de hoy
* [data-outside-month] → Presente si es de otro mes
* [data-outside-visible-months] → Presente si está fuera del rango visible
* [data-focused] → Presente si tiene foco
* [data-selected] → Presente si está seleccionado
* [data-value] → Valor de la fecha (ISO string)
* [data-type="day"] → Tipo de celda (día)
* ```
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -38,4 +81,3 @@
</div> </div>
{/if} {/if}

@ -1,4 +1,38 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Grid Body
*
* Cuerpo de la grilla del calendario que contiene las filas de días.
*
* ## Uso
* ```svelte
* <CalendarGrid>
* <CalendarGridHead>...</CalendarGridHead>
* <CalendarGridBody>
* {#each weeks as week (week.id)}
* <CalendarGridRow>
* {#each week.days as date (date.id)}
* <CalendarCell {date} month={placeholder}>
* <CalendarDay />
* </CalendarCell>
* {/each}
* </CalendarGridRow>
* {/each}
* </CalendarGridBody>
* </CalendarGrid>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-grid-body] → Elemento tbody del cuerpo de la grilla
* ```
*
* ## Estilos
* Renderiza un elemento `<tbody>`.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { CalendarGridBodyState } from "../calendar.svelte"; import { CalendarGridBodyState } from "../calendar.svelte";
import type { CalendarGridBodyProps } from "../types"; import type { CalendarGridBodyProps } from "../types";

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Grid Head
*
* Encabezado de la grilla del calendario que contiene los nombres de los días.
*
* ## Uso
* ```svelte
* <CalendarGrid>
* <CalendarGridHead>
* <CalendarGridRow>
* {#each weekdays as day}
* <CalendarHeadCell>{day}</CalendarHeadCell>
* {/each}
* </CalendarGridRow>
* </CalendarGridHead>
* <CalendarGridBody>...</CalendarGridBody>
* </CalendarGrid>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-grid-head] → Encabezado de la grilla (thead)
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<thead>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -33,4 +65,3 @@
</thead> </thead>
{/if} {/if}

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Grid Row
*
* Fila de la grilla del calendario que contiene las celdas de días.
*
* ## Uso
* ```svelte
* <CalendarGridBody>
* <CalendarGridRow>
* <CalendarCell date={d1} month={month}><CalendarDay /></CalendarCell>
* <CalendarCell date={d2} month={month}><CalendarDay /></CalendarCell>
* <!-- ... -->
* </CalendarGridRow>
* </CalendarGridBody>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-grid-row] → Fila de la grilla (tr)
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<tr>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -33,4 +62,3 @@
</tr> </tr>
{/if} {/if}

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Grid
*
* Contenedor principal de la grilla del calendario. Renderiza una tabla
* con la estructura de días y semanas.
*
* ## Uso
* ```svelte
* <Calendar>
* <CalendarHeader>...</CalendarHeader>
* <CalendarGrid>
* <CalendarGridHead>
* <CalendarGridRow>
* <CalendarHeadCell />
* </CalendarGridRow>
* </CalendarGridHead>
* <CalendarGridBody>
* <!-- Días -->
* </CalendarGridBody>
* </CalendarGrid>
* </Calendar>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-grid] → Contenedor de la grilla (table)
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<table>`.
*/
import { readableActive, writableActive, mergeProps, useId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, useId } from '$terra/utils';
import { CalendarGridState } from "../calendar.svelte"; import { CalendarGridState } from "../calendar.svelte";
import type { CalendarGridProps } from "../types"; import type { CalendarGridProps } from "../types";
@ -28,4 +64,3 @@
</table> </table>
{/if} {/if}

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Head Cell
*
* Celda del encabezado que muestra el nombre de un día de la semana.
*
* ## Uso
* ```svelte
* <CalendarGridHead>
* <CalendarGridRow>
* <CalendarHeadCell>Dom</CalendarHeadCell>
* <CalendarHeadCell>Lun</CalendarHeadCell>
* <!-- ... -->
* </CalendarGridRow>
* </CalendarGridHead>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-head-cell] → Celda del encabezado (th)
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<th>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -32,4 +61,3 @@
{@render children?.()} {@render children?.()}
</th> </th>
{/if} {/if}

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Header
*
* Contenedor del encabezado del calendario. Contiene los controles de navegación
* y el título del mes/año.
*
* ## Uso
* ```svelte
* <Calendar>
* <CalendarHeader>
* <CalendarPrevButton />
* <CalendarHeading />
* <CalendarNextButton />
* </CalendarHeader>
* <!-- ... -->
* </Calendar>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-header] → Contenedor del header
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<header>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -33,4 +64,3 @@
</header> </header>
{/if} {/if}

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Heading
*
* Muestra el mes y año actual del calendario. Se actualiza automáticamente
* al navegar entre meses.
*
* ## Uso
* ```svelte
* <CalendarHeader>
* <CalendarPrevButton />
* <CalendarHeading />
* <CalendarNextButton />
* </CalendarHeader>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `headingValue`: string - Texto formateado del mes/año
*
* ## Selectores CSS
* ```
* [data-calendar-heading] → Contenedor del título
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Comportamiento
* Si no se proporcionan children, renderiza el texto automáticamente.
* El formato se controla con `monthFormat` y `yearFormat` del Calendar.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -38,4 +70,3 @@
</div> </div>
{/if} {/if}

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Month Select
*
* Selector desplegable para elegir el mes del calendario.
*
* ## Uso
* ```svelte
* <CalendarHeader>
* <CalendarMonthSelect />
* <CalendarYearSelect />
* </CalendarHeader>
* ```
*
* ## Propiedades
* - `months`: number[] - Array de números de mes a mostrar (1-12)
* - `monthFormat`: "long" | "numeric" | "2-digit" - Formato del nombre
* - `disabled`: boolean - Deshabilita el selector
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `monthItems`: Array<{value: string, label: string}> - Meses formateados
*
* ## Selectores CSS
* ```
* [data-calendar-month-select] → Selector de mes (select)
* [data-disabled] → Presente cuando disabled=true
* ```
*
* ## Estilos
* Renderiza un elemento `<select>`.
*/
import { readableActive, writableActive, mergeProps, useId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, useId } from '$terra/utils';
import { CalendarMonthSelectState } from "../calendar.svelte"; import { CalendarMonthSelectState } from "../calendar.svelte";
import type { CalendarMonthSelectProps } from "../types"; import type { CalendarMonthSelectProps } from "../types";
@ -42,4 +73,3 @@
</select> </select>
{/if} {/if}

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Next Button
*
* Botón para navegar al mes siguiente en el calendario.
*
* ## Uso
* ```svelte
* <CalendarHeader>
* <CalendarPrevButton>
* ←
* </CalendarPrevButton>
* <CalendarHeading />
* <CalendarNextButton>
* →
* </CalendarNextButton>
* </CalendarHeader>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-next-button] → Botón siguiente (button)
* [data-disabled] → Presente cuando el botón está deshabilitado
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { readableActive, writableActive, mergeProps, useId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, useId } from '$terra/utils';
import { CalendarNextButtonState } from "../calendar.svelte"; import { CalendarNextButtonState } from "../calendar.svelte";
import type { CalendarNextButtonProps } from "../types"; import type { CalendarNextButtonProps } from "../types";
@ -28,4 +58,3 @@
</button> </button>
{/if} {/if}

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Previous Button
*
* Botón para navegar al mes anterior en el calendario.
*
* ## Uso
* ```svelte
* <CalendarHeader>
* <CalendarPrevButton>
* ←
* </CalendarPrevButton>
* <CalendarHeading />
* <CalendarNextButton>
* →
* </CalendarNextButton>
* </CalendarHeader>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-calendar-prev-button] → Botón anterior (button)
* [data-disabled] → Presente cuando el botón está deshabilitado
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -33,4 +63,3 @@
</button> </button>
{/if} {/if}

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Year Select
*
* Selector desplegable para elegir el año del calendario.
*
* ## Uso
* ```svelte
* <CalendarHeader>
* <CalendarMonthSelect />
* <CalendarYearSelect />
* </CalendarHeader>
* ```
*
* ## Propiedades
* - `years`: number[] - Array de años a mostrar (default: rango calculado)
* - `yearFormat`: "numeric" | "2-digit" - Formato del año
* - `disabled`: boolean - Deshabilita el selector
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `yearItems`: Array<{value: string, label: string}> - Años formateados
*
* ## Selectores CSS
* ```
* [data-calendar-year-select] → Selector de año (select)
* [data-disabled] → Presente cuando disabled=true
* ```
*
* ## Estilos
* Renderiza un elemento `<select>`.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,
@ -45,4 +76,3 @@
</select> </select>
{/if} {/if}

@ -1,4 +1,77 @@
<script lang="ts"> <script lang="ts">
/**
* # Calendar Root
*
* Componente de calendario para seleccionar fechas. Soporta selección simple,
* múltiple y rangos.
*
* ## Uso
* ```svelte
* <Calendar
* type="single"
* bind:value={selectedDate}
* bind:placeholder={currentMonth}
* />
*
* <!-- Rango de fechas -->
* <Calendar
* type="range"
* bind:value={dateRange}
* numberOfMonths={2}
* />
* ```
*
* ## Propiedades
* - `type`: "single" | "multiple" | "range" - Tipo de selección
* - `value`: DateValue | DateValue[] - Fecha(s) seleccionada(s) (bindable)
* - `placeholder`: DateValue - Mes/año visible (bindable)
* - `onValueChange`: Callback cuando cambia la selección
* - `onPlaceholderChange`: Callback cuando cambia el mes visible
* - `weekdayFormat`: "narrow" | "short" | "long" - Formato de días de semana
* - `weekStartsOn`: number - Día de inicio de semana (0-6)
* - `pagedNavigation`: boolean - Navegación por meses en lugar de días
* - `isDateDisabled`: (date) => boolean - Función para deshabilitar fechas
* - `isDateUnavailable`: (date) => boolean - Función para marcar fechas no disponibles
* - `fixedWeeks`: boolean - Muestra siempre 6 semanas
* - `numberOfMonths`: number - Cantidad de meses a mostrar
* - `locale`: string - Configuración regional
* - `calendarLabel`: string - Etiqueta accesible del calendario
* - `disabled`: boolean - Deshabilita el calendario
* - `readonly`: boolean - Solo lectura
* - `minValue`: DateValue - Fecha mínima seleccionable
* - `maxValue`: DateValue - Fecha máxima seleccionable
* - `preventDeselect`: boolean - Evita deseleccionar la fecha actual
* - `disableDaysOutsideMonth`: boolean - Deshabilita días fuera del mes actual
* - `initialFocus`: boolean - Enfoca el calendario al montar
* - `maxDays`: number - Máximo de días para rangos
* - `monthFormat`: "long" | "numeric" | "2-digit" - Formato del mes
* - `yearFormat`: "numeric" | "2-digit" - Formato del año
*
* ## Snippet Props
* - `months`: DateValue[] - Array de meses visibles
* - `weekdays`: string[] - Nombres de días de la semana
* - `weekStartsOn`: number - Día de inicio de semana
*
* ## Selectores CSS
* ```
* [data-calendar] → Contenedor del calendario
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* [data-calendar-cell] → Celda individual del calendario
* [data-disabled] → Presente cuando la celda está deshabilitada
* [data-readonly] → Presente cuando readonly=true
* [data-unavailable] → Presente cuando la fecha no está disponible
* [data-today] → Presente si es la fecha de hoy
* [data-outside-month] → Presente si es de otro mes
* [data-outside-visible-months] → Presente si está fuera del rango visible
* [data-focused] → Presente si tiene foco
* [data-selected] → Presente si está seleccionada
* [data-value] → Valor de la fecha (ISO string)
* [data-type="day"] → Celda que representa un día
* [data-calendar-header] → Header con navegación
* [data-calendar-heading] → Título con mes/año
* ```
*/
import { watch } from "runed"; import { watch } from "runed";
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { DateValue } from "$terra/adapters/dates"; import type { DateValue } from "$terra/adapters/dates";

@ -1,4 +1,26 @@
<script lang="ts"> <script lang="ts">
/**
* # Checkbox Group Label
*
* Etiqueta para un grupo de checkboxes.
*
* ## Uso
* ```svelte
* <CheckboxGroup bind:value={values}>
* <CheckboxGroupLabel>Selecciona frutas</CheckboxGroupLabel>
* <Checkbox value="apple">Manzana</Checkbox>
* </CheckboxGroup>
* ```
*
* ## Selectores CSS
* ```
* [data-checkbox-group-label] → Etiqueta del grupo
* [data-disabled] → Hereda disabled del grupo
* ```
*
* ## Estilos
* Renderiza un elemento `<span>`.
*/
import { readableActive, writableActive, mergeProps, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, createId } from '$terra/utils';
import type { CheckboxGroupLabelProps } from "../types"; import type { CheckboxGroupLabelProps } from "../types";
import { CheckboxGroupLabelState } from "../checkbox.svelte"; import { CheckboxGroupLabelState } from "../checkbox.svelte";

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Checkbox Group
*
* Grupo de checkboxes que comparten estado y validación.
*
* ## Uso
* ```svelte
* <CheckboxGroup bind:value={selectedValues} name="fruits">
* <CheckboxItem value="apple">Manzana</CheckboxItem>
* <CheckboxItem value="banana">Banana</CheckboxItem>
* <CheckboxItem value="orange">Naranja</CheckboxItem>
* </CheckboxGroup>
* ```
*
* ## Propiedades
* - `value`: unknown[] - Valores seleccionados (bindable)
* - `onValueChange`: Callback cuando cambia la selección
* - `name`: string - Nombre del grupo para formularios
* - `disabled`: boolean - Deshabilita todo el grupo
* - `required`: boolean - Requiere al menos una selección
* - `readonly`: boolean - Solo lectura
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-checkbox-group] → Contenedor del grupo
* [data-disabled] → Presente cuando disabled=true
* ```
*/
import { noop } from "$lib/util/funcs"; import { noop } from "$lib/util/funcs";
import { import {
readableActive, readableActive,

@ -1,4 +1,49 @@
<script lang="ts"> <script lang="ts">
/**
* # Checkbox Root
*
* Casilla de verificación que puede estar checked, unchecked o indeterminate.
*
* ## Uso
* ```svelte
* <Checkbox
* bind:checked={agreed}
* bind:indeterminate={isPartial}
* disabled={false}
* >
* Acepto los términos
* </Checkbox>
* ```
*
* ## Propiedades
* - `checked`: boolean - Estado de selección (bindable)
* - `indeterminate`: boolean - Estado indeterminado (bindable)
* - `onCheckedChange`: Callback cuando cambia checked
* - `onIndeterminateChange`: Callback cuando cambia indeterminate
* - `disabled`: boolean - Deshabilita el checkbox
* - `required`: boolean - Requerido para formularios
* - `readonly`: boolean - Solo lectura
* - `name`: string - Nombre para formularios
* - `value`: string - Valor para formularios
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `checked`: boolean - Estado actual
* - `indeterminate`: boolean - Estado indeterminado
*
* ## Selectores CSS
* ```
* [data-checkbox] → Root (botón principal)
* [data-state="checked"] → Checkbox marcado
* [data-state="unchecked"] → Checkbox desmarcado
* [data-state="indeterminate"] → Checkbox indeterminado
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* ```
*
* ## Estilos
* Renderiza un elemento `<button role="checkbox">`.
*/
import { noop } from "$lib/util/funcs"; import { noop } from "$lib/util/funcs";
import { import {
readableActive, readableActive,

@ -1,4 +1,38 @@
<script lang="ts"> <script lang="ts">
/**
* # Collapsible Content
*
* Contenido que se muestra/oculta según el estado del Collapsible.
*
* ## Uso
* ```svelte
* <Collapsible bind:open={isOpen}>
* <CollapsibleTrigger>Toggle</CollapsibleTrigger>
* <CollapsibleContent>
* <p>Este contenido se expande/colapsa</p>
* </CollapsibleContent>
* </Collapsible>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Monta siempre el contenido (útil para transiciones)
* - `hiddenUntilFound`: boolean - Permite búsqueda del navegador
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura del contenido
*
* ## Selectores CSS
* ```
* [data-collapsible-content] → Contenido colapsable
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-disabled] → Hereda disabled del root
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con atributos ARIA apropiados.
*/
import { import {
mergeProps, mergeProps,
readableActive, readableActive,

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Collapsible Trigger
*
* Botón que alterna el estado de apertura del Collapsible.
*
* ## Uso
* ```svelte
* <Collapsible bind:open={isOpen}>
* <CollapsibleTrigger>
* {#if isOpen} ▲ {:else} ▼ {/if}
* Toggle
* </CollapsibleTrigger>
* <CollapsibleContent>...</CollapsibleContent>
* </Collapsible>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el trigger
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-collapsible-trigger] → Botón trigger
* [data-state="open"] → Estado abierto del collapsible
* [data-state="closed"] → Estado cerrado del collapsible
* [data-disabled] → Presente cuando disabled=true
* ```
*
* ## Estilos
* Renderiza un elemento `<button>` con atributos ARIA apropiados.
*/
import { import {
readableActive, readableActive,
writableActive, writableActive,

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Collapsible Root
*
* Componente colapsable que puede mostrar/ocultar contenido.
* Más simple que Accordion, ideal para toggle único.
*
* ## Uso
* ```svelte
* <Collapsible bind:open={isOpen}>
* <CollapsibleTrigger>Toggle</CollapsibleTrigger>
* <CollapsibleContent>
* <p>Contenido que se muestra/oculta</p>
* </CollapsibleContent>
* </Collapsible>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado de apertura (bindable)
* - `onOpenChange`: Callback cuando cambia el estado
* - `onOpenChangeComplete`: Callback cuando la animación termina
* - `disabled`: boolean - Deshabilita el colapsable
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-collapsible] → Contenedor root
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-disabled] → Presente cuando disabled=true
* ```
*/
import { noop } from "$lib/util/funcs"; import { noop } from "$lib/util/funcs";
import { import {
readableActive, readableActive,

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Alpha Slider
*
* Slider horizontal para seleccionar la transparencia (alpha) del color (0 a 1).
*
* ## Uso
* ```svelte
* <ColorPickerAlphaSlider />
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
*
* ## Comportamiento
* - Soporta interacción con mouse y touch
* - Navegable con teclado (flechas izquierda/derecha)
* - Muestra un patrón de cuadros para indicar transparencia
* - El fondo usa `--cp-alpha-bg` para mostrar el color con alpha
*
* ## Selectores CSS
* ```
* [data-color-picker-alpha-slider] → Slider de transparencia (alpha) del color
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="slider".
*/
import { ColorPickerAlphaSliderState } from "../color-picker.svelte"; import { ColorPickerAlphaSliderState } from "../color-picker.svelte";
import type { ColorPickerAlphaSliderProps } from "../types"; import type { ColorPickerAlphaSliderProps } from "../types";

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Area Thumb
*
* Indicador visual de la posición actual en el área de color.
*
* ## Uso
* ```svelte
* <ColorPickerArea>
* <ColorPickerAreaThumb />
* </ColorPickerArea>
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
*
* ## Comportamiento
* - Posicionado con `left` y `top` según la saturación y brillo
* - Soporta navegación con flechas del teclado
* - Usa Shift+flechas para movimientos de 10 unidades
* - Color disponible como `--cp-thumb-color`
*
* ## Selectores CSS
* ```
* [data-color-picker-area-thumb] → Indicador visual de posición en el área de color
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="slider".
*/
import { ColorPickerAreaState, ColorPickerRootState } from "../color-picker.svelte"; import { ColorPickerAreaState, ColorPickerRootState } from "../color-picker.svelte";
import type { ColorPickerAreaThumbProps } from "../types"; import type { ColorPickerAreaThumbProps } from "../types";

@ -1,4 +1,38 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Area
*
* Área de selección de saturación y brillo del color.
*
* ## Uso
* ```svelte
* <ColorPickerArea>
* <ColorPickerAreaThumb />
* </ColorPickerArea>
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
*
* ## Selectores CSS
* ```
* No aplica selectores de datos específicos.
* Use el elemento con role="presentation" para aplicar estilos.
* ```
*
* ## CSS Variables
* ```
* --cp-area-bg → Color de fondo (HSL del tono actual)
* ```
*
* ## Comportamiento
* - Soporta interacción con mouse y touch
* - Mantiene el color de fondo con `--cp-area-bg`
* - Actualiza saturación y brillo del color seleccionado
*
* ## Estilos
* Renderiza un elemento `<div>` con role="presentation".
*/
import { ColorPickerAreaState } from "../color-picker.svelte"; import { ColorPickerAreaState } from "../color-picker.svelte";
import type { ColorPickerAreaProps } from "../types"; import type { ColorPickerAreaProps } from "../types";

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Content
*
* Contenedor del panel del selector de color.
*
* ## Uso
* ```svelte
* <ColorPickerContent>
* <ColorPickerArea>
* <ColorPickerAreaThumb />
* </ColorPickerArea>
* <ColorPickerHueSlider />
* <ColorPickerAlphaSlider />
* <ColorPickerInput />
* </ColorPickerContent>
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
*
* ## Selectores CSS
* ```
* No aplica selectores de datos específicos.
* Use el elemento contenedor con role="dialog" para aplicar estilos.
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="dialog".
*/
import type { ColorPickerContentProps } from "../types"; import type { ColorPickerContentProps } from "../types";
let { let {

@ -1,4 +1,32 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Eye Dropper
*
* Botón para abrir la herramienta de selección de color del navegador.
*
* ## Uso
* ```svelte
* <ColorPickerEyeDropper>
* <EyeDropperIcon />
* </ColorPickerEyeDropper>
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
* - `children`: Snippet - Contenido del botón
*
* ## Comportamiento
* - Solo se renderiza si el navegador soporta la API EyeDropper
* - Al hacer clic, abre el selector de color del sistema
*
* ## Selectores CSS
* ```
* [data-color-picker-eyedropper] → Botón para abrir la herramienta de selección de color
* ```
*
* ## Estilos
* Renderiza un elemento `<button>` si es soportado.
*/
import { ColorPickerEyeDropperState } from "../color-picker.svelte"; import { ColorPickerEyeDropperState } from "../color-picker.svelte";
import type { ColorPickerEyeDropperProps } from "../types"; import type { ColorPickerEyeDropperProps } from "../types";

@ -1,4 +1,30 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Hue Slider
*
* Slider horizontal para seleccionar el matiz (hue) del color (0° a 360°).
*
* ## Uso
* ```svelte
* <ColorPickerHueSlider />
* ```
*
* ## Propiedades
* - `class`: string - Clases CSS adicionales
*
* ## Comportamiento
* - Soporta interacción con mouse y touch
* - Navegable con teclado (flechas izquierda/derecha)
* - El thumb se posiciona según el valor actual de hue
*
* ## Selectores CSS
* ```
* [data-color-picker-hue-slider] → Slider de matiz (hue) del color
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="slider".
*/
import { ColorPickerHueSliderState } from "../color-picker.svelte"; import { ColorPickerHueSliderState } from "../color-picker.svelte";
import type { ColorPickerHueSliderProps } from "../types"; import type { ColorPickerHueSliderProps } from "../types";

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Input
*
* Campo de texto para ingresar/editar el valor del color.
*
* ## Uso
* ```svelte
* <ColorPickerInput format="hex" />
* <ColorPickerInput format="rgb" />
* <ColorPickerInput format="hsl" />
* ```
*
* ## Propiedades
* - `format`: "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla" - Formato del color
* - `class`: string - Clases CSS adicionales
*
* ## Selectores CSS
* ```
* No aplica selectores de datos específicos.
* Use el elemento input[type="text"] para aplicar estilos.
* ```
*
* ## Comportamiento
* - Actualiza el color al escribir y presionar Enter o perder foco
* - Muestra el color actual en el formato especificado
* - Valida el formato antes de aplicar cambios
*
* ## Estilos
* Renderiza un elemento `<input type="text">`.
*/
import { readableActive } from '$terra/utils'; import { readableActive } from '$terra/utils';
import { ColorPickerInputState } from "../color-picker.svelte"; import { ColorPickerInputState } from "../color-picker.svelte";
import type { ColorPickerInputProps } from "../types"; import type { ColorPickerInputProps } from "../types";

@ -1,4 +1,41 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Root
*
* Componente raíz del selector de color que gestiona el estado del color seleccionado.
*
* ## Uso
* ```svelte
* <ColorPicker
* bind:value={selectedColor}
* format="hex"
* >
* <ColorPickerTrigger>
* <div class="color-preview" />
* </ColorPickerTrigger>
* <ColorPickerContent>
* <ColorPickerArea>
* <ColorPickerAreaThumb />
* </ColorPickerArea>
* <ColorPickerHueSlider />
* <ColorPickerAlphaSlider />
* </ColorPickerContent>
* </ColorPicker>
* ```
*
* ## Propiedades
* - `value`: ColorValue - Color seleccionado
* - `defaultValue`: ColorValue - Color inicial
* - `onValueChange`: Callback cuando cambia el color
* - `disabled`: boolean - Deshabilita el selector
* - `format`: "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla" - Formato del color
*
* ## Selectores CSS
* ```
* No aplica selectores de datos específicos.
* Use el elemento contenedor para aplicar estilos.
* ```
*/
import { readableActive } from '$terra/utils'; import { readableActive } from '$terra/utils';
import { ColorPickerRootState } from "../color-picker.svelte"; import { ColorPickerRootState } from "../color-picker.svelte";
import type { ColorPickerRootProps } from "../types"; import type { ColorPickerRootProps } from "../types";

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Swatch
*
* Muestra un color predefinido como opción seleccionable.
*
* ## Uso
* ```svelte
* <ColorPickerSwatch
* color="#ff0000"
* selected={selectedColor === '#ff0000'}
* onselect={() => selectColor('#ff0000')}
* />
* ```
*
* ## Propiedades
* - `color`: string - Color en formato hex
* - `selected`: boolean - Si está seleccionado
* - `onselect`: Callback al seleccionar
*
* ## Selectores CSS
* ```
* [data-color-picker-swatch] → Muestra un color predefinido como opción seleccionable
* [data-selected] → Estado cuando está seleccionado
* ```
*
* ## Estilos
* Renderiza un elemento `<button>` con role="radio".
* El color está disponible como `--cp-swatch-color`.
*/
import type { ColorPickerSwatchProps } from "../types"; import type { ColorPickerSwatchProps } from "../types";
let { let {

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Swatches
*
* Contenedor de muestras de colores predefinidos.
*
* ## Uso
* ```svelte
* <ColorPickerSwatches
* colors={['#ff0000', '#00ff00', '#0000ff']}
* onSelect={(color) => setColor(color)}
* />
* ```
*
* ## Propiedades
* - `colors`: string[] - Array de colores en formato hex
* - `onSelect`: (color: string) => void - Callback al seleccionar
* - `class`: string - Clases CSS adicionales
*
* ## Selectores CSS
* ```
* No aplica selectores de datos específicos.
* Use el elemento con role="group" para aplicar estilos.
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="group".
*/
import { readableActive } from '$terra/utils'; import { readableActive } from '$terra/utils';
import { ColorPickerSwatchesState } from "../color-picker.svelte"; import { ColorPickerSwatchesState } from "../color-picker.svelte";
import type { ColorPickerSwatchesProps } from "../types"; import type { ColorPickerSwatchesProps } from "../types";

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Color Picker Trigger
*
* Botón que abre/cierra el panel del selector de color.
*
* ## Uso
* ```svelte
* <ColorPicker bind:value={color}>
* <ColorPickerTrigger showColor={true}>
* <div class="preview" />
* </ColorPickerTrigger>
* <ColorPickerContent>...</ColorPickerContent>
* </ColorPicker>
* ```
*
* ## Propiedades
* - `showColor`: boolean - Muestra el color como CSS variable `--cp-trigger-color`
*
* ## Selectores CSS
* ```
* [data-disabled] → Presente cuando disabled=true
* ```
*
* ## CSS Variables
* ```
* --cp-trigger-color → Color actual en formato HEX
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`. Usa `data-disabled` cuando está deshabilitado.
*/
import { ColorPickerRootState } from "../color-picker.svelte"; import { ColorPickerRootState } from "../color-picker.svelte";
import type { ColorPickerTriggerProps } from "../types"; import type { ColorPickerTriggerProps } from "../types";

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Combobox Input
*
* Campo de texto para buscar y filtrar las opciones del combobox.
*
* ## Uso
* ```svelte
* <Combobox bind:inputValue={search}>
* <ComboboxInput
* placeholder="Buscar..."
* defaultValue=""
* />
* <ComboboxContent>...</ComboboxContent>
* </Combobox>
* ```
*
* ## Propiedades
* - `defaultValue`: string - Valor inicial del input
* - `clearOnDeselect`: boolean - Limpia el input al deseleccionar
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-combobox-input] → Input de texto del combobox
* [data-state="open"] → Estado del combobox abierto
* [data-state="closed"] → Estado del combobox cerrado
* [data-disabled] → Input deshabilitado
* ```
*
* ## Estilos
* Renderiza un elemento `<input>` sincronizado con el `inputValue` del Combobox.
*/
import { import {
mergeProps, mergeProps,
readableActive, readableActive,

@ -1,4 +1,32 @@
<script lang="ts"> <script lang="ts">
/**
* # Combobox Trigger
*
* Botón que abre/cierra el menú desplegable del combobox.
*
* ## Uso
* ```svelte
* <Combobox>
* <ComboboxInput />
* <ComboboxTrigger>
* <ChevronIcon />
* </ComboboxTrigger>
* <ComboboxContent>...</ComboboxContent>
* </Combobox>
* ```
*
* ## Propiedades
* - `type`: string - Tipo de botón (default: "button")
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-combobox-trigger] → Botón que abre/cierra el menú
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { import {
mergeProps, mergeProps,
readableActive, readableActive,

@ -1,4 +1,50 @@
<script lang="ts"> <script lang="ts">
/**
* # Combobox Root
*
* Combina un input de texto con un menú desplegable para selección con búsqueda.
*
* ## Uso
* ```svelte
* <Combobox
* type="single"
* bind:value={selectedValue}
* bind:inputValue={searchText}
* bind:open={isOpen}
* items={options}
* >
* <ComboboxInput placeholder="Buscar..." />
* <ComboboxTrigger>▼</ComboboxTrigger>
* <ComboboxContent>
* <!-- items del menú -->
* </ComboboxContent>
* </Combobox>
* ```
*
* ## Propiedades
* - `type`: "single" | "multiple" - Tipo de selección
* - `value`: string | string[] - Valor(es) seleccionado(s) (bindable)
* - `onValueChange`: Callback cuando cambia la selección
* - `inputValue`: string - Texto del input (bindable)
* - `open`: boolean - Estado del menú (bindable)
* - `onOpenChange`: Callback cuando cambia el estado del menú
* - `onOpenChangeComplete`: Callback cuando la animación termina
* - `name`: string - Nombre para formularios
* - `disabled`: boolean - Deshabilita el combobox
* - `required`: boolean - Requiere selección
* - `loop`: boolean - Navegación cíclica
* - `scrollAlignment`: "nearest" | "center" - Alineación del scroll
* - `items`: unknown[] - Items disponibles para filtrar
* - `allowDeselect`: boolean - Permite deseleccionar
*
* ## Selectores CSS
* ```
* [data-combobox-input] → Input de texto del combobox
* [data-state="open"] → Estado del combobox abierto
* [data-state="closed"] → Estado del combobox cerrado
* [data-disabled] → Combobox deshabilitado
* ```
*/
import FloatingLayer from '../../layers/floating/components/floating-layer.svelte'; import FloatingLayer from '../../layers/floating/components/floating-layer.svelte';
import { readableActive, writableActive, type State } from "$terra/utils"; import { readableActive, writableActive, type State } from "$terra/utils";
import { SelectRootState } from '../../select/select.svelte'; import { SelectRootState } from '../../select/select.svelte';

@ -1,23 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Label
*
* Etiqueta accesible para el paleta de comandos.
* Usado internamente por el componente Command.
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-command-label] → Etiqueta accesible para el paleta de comandos
* ```
*
* ## Estilos
* Renderiza un elemento `<label>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import { CommandLabe$state } from "../command.svelte"; import { CommandLabe$state } from "../command.svelte";
import type { TerraPrimitiveLabelAttributes } from "../../utils/attributes"; import type { TerraPrimitiveLabelAttributes } from "../../utils/attributes";
import type { WithChildren } from "../../utils/types"; import type { WithChildren } from "../../utils/types";
let { let {
id = useId(), id = useId(),
ref = $bindable(null), ref = $bindable(null),
children, children,
...restProps ...restProps
}: WithChildren<TerraPrimitiveLabelAttributes & { ref?: HTMLLabelElement | null }> = $props(); }: WithChildren<TerraPrimitiveLabelAttributes & { ref?: HTMLLabelElement | null }> = $props();
const labe$state = CommandLabe$state.create({ const labe$state = CommandLabe$state.create({
id: readableActive(() => id), id: readableActive(() => id),
ref: writableActive( ref: writableActive(
() => ref, () => ref,
(v) => (ref = v) (v) => (ref = v)
), ),
}); });
const mergedProps = $derived(mergeProps(restProps, labe$state.props)); const mergedProps = $derived(mergeProps(restProps, labe$state.props));
</script> </script>

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Empty
*
* Se muestra cuando no hay resultados de búsqueda.
*
* ## Uso
* ```svelte
* <CommandList>
* <CommandEmpty>
* No se encontraron resultados para "{search}"
* </CommandEmpty>
* <CommandGroup>...</CommandGroup>
* </CommandList>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Muestra siempre
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Solo se muestra cuando la búsqueda no coincide con ningún item
*
* ## Selectores CSS
* ```
* [data-command-empty] → Mensaje sin resultados
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandEmptyProps } from "../types"; import type { CommandEmptyProps } from "../types";
import { CommandEmptyState } from "../command.svelte"; import { CommandEmptyState } from "../command.svelte";

@ -1,4 +1,29 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Group Heading
*
* Encabezado opcional para un grupo de comandos.
*
* ## Uso
* ```svelte
* <CommandGroup>
* <CommandGroupHeading>Archivos</CommandGroupHeading>
* <CommandItem value="new-file">Nuevo archivo</CommandItem>
* <CommandItem value="open">Abrir archivo</CommandItem>
* </CommandGroup>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-command-group-heading] → Encabezado de un grupo de comandos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps } from "$terra/utils"; import { readableActive, writableActive, mergeProps } from "$terra/utils";
import { CommandGroupHeadingState } from "../command.svelte"; import { CommandGroupHeadingState } from "../command.svelte";
import type { CommandGroupHeadingProps } from "../types"; import type { CommandGroupHeadingProps } from "../types";

@ -1,24 +1,50 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Group Items
*
* Contenedor para los items de un grupo de comandos.
*
* ## Uso
* ```svelte
* <CommandGroup>
* <CommandGroupItems>
* <CommandItem value="new-file">Nuevo</CommandItem>
* <CommandItem value="open">Abrir</CommandItem>
* </CommandGroupItems>
* </CommandGroup>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-command-group-items] → Contenedor de items de un grupo de comandos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps } from "$terra/utils"; import { readableActive, writableActive, mergeProps } from "$terra/utils";
import type { CommandGroupItemsProps } from "../types"; import type { CommandGroupItemsProps } from "../types";
import { CommandGroupItemsState } from "../command.svelte"; import { CommandGroupItemsState } from "../command.svelte";
import { useId } from '$terra/utils'; import { useId } from '$terra/utils';
let { let {
id = useId(), id = useId(),
ref = $bindable(null), ref = $bindable(null),
children, children,
child, child,
...restProps ...restProps
}: CommandGroupItemsProps = $props(); }: CommandGroupItemsProps = $props();
const groupItemsState = CommandGroupItemsState.create({ const groupItemsState = CommandGroupItemsState.create({
id: readableActive(() => id), id: readableActive(() => id),
ref: writableActive( ref: writableActive(
() => ref, () => ref,
(v) => (ref = v) (v) => (ref = v)
), ),
}); });
const mergedProps = $derived(mergeProps(restProps, groupItemsState.props)); const mergedProps = $derived(mergeProps(restProps, groupItemsState.props));
</script> </script>

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Group
*
* Agrupa items relacionados con un encabezado opcional.
*
* ## Uso
* ```svelte
* <CommandGroup value="files">
* <CommandGroupHeading>Archivos</CommandGroupHeading>
* <CommandItem value="new-file">Nuevo</CommandItem>
* <CommandItem value="open">Abrir</CommandItem>
* </CommandGroup>
* ```
*
* ## Propiedades
* - `value`: string - Identificador del grupo
* - `forceMount`: boolean - Muestra siempre (ignora filtro)
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Se oculta si todos sus items están filtrados
* - Con `forceMount`, se muestra aunque esté vacío
*
* ## Selectores CSS
* ```
* [data-command-group] → Contenedor de grupo de comandos relacionados
* [data-hidden] → Estado cuando está oculto por filtro
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="group".
*/
import { readableActive, writableActive, mergeProps } from "$terra/utils"; import { readableActive, writableActive, mergeProps } from "$terra/utils";
import type { CommandGroupProps } from "../types"; import type { CommandGroupProps } from "../types";
import { CommandGroupContainerState } from "../command.svelte"; import { CommandGroupContainerState } from "../command.svelte";

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Input
*
* Campo de búsqueda para filtrar los comandos.
*
* ## Uso
* ```svelte
* <Command bind:value={search}>
* <CommandInput
* placeholder="Escribe un comando..."
* autofocus={true}
* />
* <CommandList>...</CommandList>
* </Command>
* ```
*
* ## Propiedades
* - `value`: string - Valor del input (bindable)
* - `autofocus`: boolean - Enfoca el input al montar
* - `id`: string - ID del elemento
*
* ## Atajos de teclado
* - Ctrl+J/K: Navegar hacia abajo/arriba (vim bindings)
* - Ctrl+N/P: Navegar hacia abajo/arriba (vim bindings)
* - Flechas: Navegar items
* - Enter: Seleccionar item actual
* - Escape: Limpiar búsqueda
*
* ## Selectores CSS
* ```
* [data-command-input] → Input de búsqueda del comando
* ```
*
* ## Estilos
* Renderiza un elemento `<input type="text">`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandInputProps } from "../types"; import type { CommandInputProps } from "../types";
import { CommandInputState } from "../command.svelte"; import { CommandInputState } from "../command.svelte";

@ -1,4 +1,47 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Item
*
* Item individual de la lista de comandos.
*
* ## Uso
* ```svelte
* <CommandItem
* value="new-file"
* keywords={["create", "add", "file"]}
* onSelect={() => createNewFile()}
* >
* <FileIcon />
* <span>Nuevo archivo</span>
* <kbd>⌘N</kbd>
* </CommandItem>
* ```
*
* ## Propiedades
* - `value`: string - Valor del item para filtrado
* - `keywords`: string[] - Palabras clave adicionales para búsqueda
* - `onSelect`: () => void - Callback al seleccionar
* - `disabled`: boolean - Deshabilita el item
* - `forceMount`: boolean - Muestra siempre (ignora filtro)
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Se filtra según `value` y `keywords`
* - Selecciona con Enter o Click
* - Usa `{#key}` para re-renderizar al cambiar la búsqueda
*
* ## Selectores CSS
* ```
* [data-command-item] → Item individual del menú
* [data-value] → Valor del item para filtrado
* [data-disabled] → Item deshabilitado
* [data-selected] → Item seleccionado
* [data-group] → Grupo al que pertenece el item
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con atributos de selección.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandItemProps } from "../types"; import type { CommandItemProps } from "../types";
import { CommandItemState } from "../command.svelte"; import { CommandItemState } from "../command.svelte";

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Link Item
*
* Item de comando que renderiza como enlace (<a>) en lugar de div.
*
* ## Uso
* ```svelte
* <CommandLinkItem
* value="docs"
* href="/docs"
* keywords={["documentation", "help"]}
* >
* <BookIcon />
* <span>Documentación</span>
* </CommandLinkItem>
* ```
*
* ## Propiedades
* - `value`: string - Valor para filtrado
* - `keywords`: string[] - Palabras clave adicionales
* - `onSelect`: () => void - Callback al seleccionar
* - `disabled`: boolean - Deshabilita el item
* - `forceMount`: boolean - Muestra siempre (ignora filtro)
* - `href`: string - URL del enlace
* - Todas las props de HTMLAnchorAttributes
*
* ## Selectores CSS
* ```
* [data-command-link-item] → Item de comando que renderiza como enlace
* [data-selected] → Estado cuando está seleccionado
* [data-disabled] → Estado cuando está deshabilitado
* ```
*
* ## Estilos
* Renderiza un elemento `<a>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandLinkItemProps } from "../types"; import type { CommandLinkItemProps } from "../types";
import { CommandItemState } from "../command.svelte"; import { CommandItemState } from "../command.svelte";

@ -1,4 +1,36 @@
<script lang="ts"> <script lang="ts">
/**
* # Command List
*
* Contenedor de la lista de comandos filtrados.
*
* ## Uso
* ```svelte
* <Command>
* <CommandInput />
* <CommandList aria-label="Opciones disponibles">
* <CommandEmpty>No hay resultados</CommandEmpty>
* <CommandGroup>...</CommandGroup>
* </CommandList>
* </Command>
* ```
*
* ## Propiedades
* - `aria-label`: string - Etiqueta accesible (default: "Suggestions...")
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Se re-renderiza cuando la búsqueda cambia
* - Usa `{#key}` para limpiar el DOM al buscar
*
* ## Selectores CSS
* ```
* [data-command-list] → Lista de items del comando
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandListProps } from "../types"; import type { CommandListProps } from "../types";
import { CommandListState } from "../command.svelte"; import { CommandListState } from "../command.svelte";

@ -1,4 +1,32 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Loading
*
* Indicador de carga para resultados asíncronos.
*
* ## Uso
* ```svelte
* <CommandList>
* <CommandLoading progress={loadingProgress}>
* <Spinner />
* Cargando resultados...
* </CommandLoading>
* <CommandEmpty>No hay resultados</CommandEmpty>
* </CommandList>
* ```
*
* ## Propiedades
* - `progress`: number - Progreso de carga (0-1)
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-command-loading] → Indicador de carga para resultados asíncronos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import type { CommandLoadingProps } from "../types"; import type { CommandLoadingProps } from "../types";
import { CommandLoadingState } from "../command.svelte"; import { CommandLoadingState } from "../command.svelte";

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Separator
*
* Separador visual entre grupos de comandos.
*
* ## Uso
* ```svelte
* <CommandGroup>...</CommandGroup>
* <CommandSeparator />
* <CommandGroup>...</CommandGroup>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Muestra siempre
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Solo se muestra cuando hay búsqueda activa
*
* ## Selectores CSS
* ```
* [data-command-separator] → Separador visual entre grupos de comandos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="separator".
*/
import { readableActive, writableActive, mergeProps, useId} from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId} from "$terra/utils";
import type { CommandSeparatorProps } from "../types"; import type { CommandSeparatorProps } from "../types";
import { CommandSeparatorState } from "../command.svelte"; import { CommandSeparatorState } from "../command.svelte";

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Viewport
*
* Viewport para virtualización de lista larga de comandos.
*
* ## Uso
* ```svelte
* <CommandList>
* <CommandViewport>
* {#each items as item}
* <CommandItem value={item.id}>{item.label}</CommandItem>
* {/each}
* </CommandViewport>
* </CommandList>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-command-viewport] → Viewport de virtualización de comandos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import { CommandViewportState } from "../command.svelte"; import { CommandViewportState } from "../command.svelte";
import type { CommandViewportProps } from "../types"; import type { CommandViewportProps } from "../types";

@ -1,4 +1,56 @@
<script lang="ts"> <script lang="ts">
/**
* # Command Root
*
* Componente de paleta de comandos typeahead similar a Cmd+K de VS Code.
*
* ## Uso
* ```svelte
* <Command bind:value={search}>
* <CommandInput placeholder="Buscar..." />
* <CommandList>
* <CommandEmpty>No se encontraron resultados</CommandEmpty>
* <CommandGroup heading="Archivos">
* <CommandItem value="new-file">Nuevo archivo</CommandItem>
* <CommandItem value="open">Abrir</CommandItem>
* </CommandGroup>
* </CommandList>
* </Command>
* ```
*
* ## Propiedades
* - `value`: string - Texto de búsqueda (bindable)
* - `onValueChange`: Callback cuando cambia la búsqueda
* - `onStateChange`: Callback cuando cambia el estado interno
* - `loop`: boolean - Navegación cíclica con flechas
* - `shouldFilter`: boolean - Si debe filtrar automáticamente
* - `filter`: (value: string, search: string) => number - Función de puntuación
* - `label`: string - Etiqueta accesible
* - `vimBindings`: boolean - Habilita atajos de vim (Ctrl+J/K/N/P)
* - `disablePointerSelection`: boolean - Deshabilita selección por mouse
* - `disableInitialScroll`: boolean - Deshabilita scroll inicial al seleccionado
* - `columns`: number - Número de columnas para grid
*
* ## APIs Imperativas
* - `updateSelectedToIndex(index)` - Selecciona item por índice
* - `updateSelectedByGroup(group)` - Selecciona primer item de grupo
* - `updateSelectedByItem(item)` - Selecciona item específico
* - `getValidItems()` - Obtiene items filtrados
*
* ## Selectores CSS
* ```
* [data-command] → Contenedor raíz del comando
* [data-command-input] → Input de búsqueda
* [data-command-list] → Lista de items
* [data-command-item] → Item individual del menú
* [data-value] → Valor del item para filtrado
* [data-disabled] → Item deshabilitado
* [data-selected] → Item seleccionado
* [data-group] → Grupo al que pertenece el item
* [data-command-separator] → Separador visual
* [data-command-empty] → Mensaje sin resultados
* ```
*/
import { readableActive, writableActive, mergeProps, useId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, useId } from "$terra/utils";
import { CommandRootState } from "../command.svelte"; import { CommandRootState } from "../command.svelte";
import type { CommandRootProps } from "../types"; import type { CommandRootProps } from "../types";

@ -1,4 +1,16 @@
<script lang="ts"> <script lang="ts">
/**
* # TerraConfig
*
* Componente proveedor de configuración global para componentes Terra.
*
* ## Selectores CSS
* ```
* Este componente no renderiza elementos HTML ni agrega atributos data.
* Es un componente proveedor de contexto que solo pasa configuración
* a sus componentes descendientes.
* ```
*/
import type { TerraConfigProps } from '../types.ts'; import type { TerraConfigProps } from '../types.ts';
import { useTerraConfig } from '../terra-config.ts'; import { useTerraConfig } from '../terra-config.ts';
import { readableActive } from '$terra/utils'; import { readableActive } from '$terra/utils';

@ -1,4 +1,49 @@
<script lang="ts"> <script lang="ts">
/**
* # Context Menu Content
*
* Contenedor del menú contextual con items.
*
* ## Uso
* ```svelte
* <ContextMenuContent
* side="right"
* align="start"
* sideOffset={4}
* >
* <ContextMenuItem value="copy">Copiar</ContextMenuItem>
* <ContextMenuSeparator />
* <ContextMenuItem value="paste">Pegar</ContextMenuItem>
* </ContextMenuContent>
* ```
*
* ## Propiedades
* - `side`: "top" | "right" | "bottom" | "left" - Posición del menú
* - `align`: "start" | "center" | "end" - Alineación del menú
* - `sideOffset`: number - Distancia desde el trigger
* - `loop`: boolean - Navegación cíclica con flechas
* - `forceMount`: boolean - Muestra siempre
* - `avoidCollisions`: boolean - Evita colisiones con bordes
* - `collisionPadding`: number - Padding para detección de colisiones
* - `arrowPadding`: number - Padding para la flecha
* - `sticky`: "partial" | "always" - Comportamiento sticky
* - `hideWhenDetached`: boolean - Oculta si está detached
* - `strategy`: "absolute" | "fixed" - Estrategia de posicionamiento
* - `onInteractOutside`: Callback al interactuar fuera
* - `onCloseAutoFocus`: Callback al cerrar y reenfocar
* - `onEscapeKeydown`: Callback al presionar Escape
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-context-menu-content] → Contenedor del menú contextual
* [data-state="open"] → Estado del menú abierto
* [data-state="closed"] → Estado del menú cerrado
* ```
*
* ## Estilos
* Renderiza un `<div>` anidado dentro de otro para posicionamiento.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import type { ContextMenuContentProps } from '../types'; import type { ContextMenuContentProps } from '../types';
import { CONTEXT_MENU_TRIGGER_ATTR, MenuContentState } from '../../menu/menu.svelte'; import { CONTEXT_MENU_TRIGGER_ATTR, MenuContentState } from '../../menu/menu.svelte';
@ -47,7 +92,7 @@
onInteractOutside(e); onInteractOutside(e);
if (e.defaultPrevented) return; if (e.defaultPrevented) return;
if (e.target && e.target instanceof Element) { if (e.target && e.target instanceof Element) {
const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr('sub-content')}]`; const subContentSelector = `[${contentState.parentMenu.root.getTerraAttr('sub-content')}]`;
if (e.target.closest(subContentSelector)) return; if (e.target.closest(subContentSelector)) return;
} }
contentState.parentMenu.onClose(); contentState.parentMenu.onClose();

@ -1,4 +1,35 @@
<script lang="ts"> <script lang="ts">
/**
* # Context Menu Trigger
*
* Área que al hacer clic derecho abre el menú contextual.
*
* ## Uso
* ```svelte
* <ContextMenu>
* <ContextMenuTrigger disabled={false}>
* <div>Clic derecho aquí</div>
* </ContextMenuTrigger>
* <ContextMenuContent>...</ContextMenuContent>
* </ContextMenu>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el trigger
* - `id`: string - ID del elemento
*
* ## Comportamiento
* - Abre el menú con clic derecho
* - Posiciona el menú en la posición del cursor
*
* ## Selectores CSS
* ```
* [data-context-menu-trigger] → Área que abre el menú al clic derecho
* ```
*
* ## Estilos
* Renderiza un `<div>` con `pointerEvents: auto`.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import type { ContextMenuTriggerProps } from '../types'; import type { ContextMenuTriggerProps } from '../types';
import { ContextMenuTriggerState } from '../../menu/menu.svelte'; import { ContextMenuTriggerState } from '../../menu/menu.svelte';

@ -1,4 +1,40 @@
<script lang="ts"> <script lang="ts">
/**
* # Context Menu Root
*
* Menú contextual que se abre al hacer clic derecho sobre un elemento.
*
* ## Uso
* ```svelte
* <ContextMenu bind:open={isOpen}>
* <ContextMenuTrigger>
* <div>Clic derecho para abrir</div>
* </ContextMenuTrigger>
* <ContextMenuContent>
* <ContextMenuItem>Copiar</ContextMenuItem>
* <ContextMenuItem>Cortar</ContextMenuItem>
* <ContextMenuItem>Pegar</ContextMenuItem>
* </ContextMenuContent>
* </ContextMenu>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado del menú (bindable)
* - `onOpenChange`: Callback cuando cambia el estado
* - `onOpenChangeComplete`: Callback cuando la animación termina
* - `dir`: "ltr" | "rtl" - Dirección del texto
*
* ## Selectores CSS
* ```
* [data-context-menu-content] → Contenedor del menú contextual
* [data-state="open"] → Estado del menú abierto
* [data-state="closed"] → Estado del menú cerrado
* [data-context-menu-item] → Item individual del menú
* [data-highlighted] → Item resaltado (hover/foco)
* [data-disabled] → Item deshabilitado
* [data-context-menu-separator] → Separador visual entre items
* ```
*/
import { readableActive, writableActive } from '$terra/utils'; import { readableActive, writableActive } from '$terra/utils';
import type { ContextMenuRootProps } from '../types'; import type { ContextMenuRootProps } from '../types';
import FloatingLayer from '../../layers/floating/components/floating-layer.svelte'; import FloatingLayer from '../../layers/floating/components/floating-layer.svelte';

@ -1,4 +1,17 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Field Hidden Input
*
* Input oculto para el campo de fecha.
*
* ## Uso
* Se utiliza internamente por DateField.
*
* ## Selectores CSS
* ```
* [data-date-field-hidden-input] → Input oculto para formularios
* ```
*/
import { DateFieldHiddenInputState } from "../date-field.svelte.js"; import { DateFieldHiddenInputState } from "../date-field.svelte.js";
import HiddenInput from "../../layers/hidden-input.svelte"; import HiddenInput from "../../layers/hidden-input.svelte";

@ -1,4 +1,15 @@
<script lang="ts"> <script lang="ts">
/**
* # DateField Input
*
* Contenedor de entrada para los segmentos del campo de fecha.
*
* ## Selectores CSS
* ```
* [data-date-field-input] → Contenedor de entrada
* [data-disabled] → Presente cuando disabled=true
* ```
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DateFieldInputState } from "../date-field.svelte.js"; import { DateFieldInputState } from "../date-field.svelte.js";
import type { DateFieldInputProps } from "../types.js"; import type { DateFieldInputProps } from "../types.js";

@ -1,4 +1,22 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Field Label
*
* Etiqueta para el campo de fecha.
*
* ## Uso
* ```svelte
* <DateField>
* <DateFieldLabel>Fecha de nacimiento</DateFieldLabel>
* <DateFieldInput />
* </DateField>
* ```
*
* ## Selectores CSS
* ```
* [data-date-field-label] → Etiqueta del campo de fecha
* ```
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DateFieldLabelState } from "../date-field.svelte.js"; import { DateFieldLabelState } from "../date-field.svelte.js";
import type { DateFieldLabelProps } from "../types.js"; import type { DateFieldLabelProps } from "../types.js";

@ -1,4 +1,16 @@
<script lang="ts"> <script lang="ts">
/**
* # DateField Segment
*
* Segmento individual del campo de fecha (día, mes, año, hora, minuto, segundo).
*
* ## Selectores CSS
* ```
* [data-date-field-segment] → Segmento individual
* [data-readonly] → Presente cuando el segmento es readonly
* [data-invalid] → Presente cuando el segmento es inválido
* ```
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DateFieldSegmentState } from "../date-field.svelte.js"; import { DateFieldSegmentState } from "../date-field.svelte.js";
import type { DateFieldSegmentProps } from "../types.js"; import type { DateFieldSegmentProps } from "../types.js";

@ -1,4 +1,20 @@
<script lang="ts"> <script lang="ts">
/**
* # DateField Root
*
* Componente de campo de fecha con segmentos editables.
*
* ## Selectores CSS
* ```
* [data-date-field] → Contenedor raíz
* [data-date-field-input] → Entrada del campo
* [data-date-field-label] → Etiqueta del campo
* [data-date-field-segment] → Segmento individual (día, mes, año, etc.)
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* [data-invalid] → Presente cuando el campo es inválido
* ```
*/
import { watch } from "runed"; import { watch } from "runed";
import { readableActive, writableActive } from '$terra/utils'; import { readableActive, writableActive } from '$terra/utils';
import { DateFieldRootState } from "../date-field.svelte.js"; import { DateFieldRootState } from "../date-field.svelte.js";

@ -1,4 +1,24 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Picker Calendar
*
* Componente de calendario utilizado dentro del DatePicker.
*
* ## Uso
* ```svelte
* <DatePicker>
* <DatePickerTrigger />
* <DatePickerContent>
* <DatePickerCalendar />
* </DatePickerContent>
* </DatePicker>
* ```
*
* ## Selectores CSS
* ```
* [data-date-picker-calendar] → Contenedor del calendario del date picker
* ```
*/
import { readableActive, writableActive, mergeProps, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, createId } from '$terra/utils';
import type { DatePickerCalendarProps } from '../types.ts'; import type { DatePickerCalendarProps } from '../types.ts';
import { DatePickerRootState } from '../date-picker.svelte.ts'; import { DatePickerRootState } from '../date-picker.svelte.ts';

@ -1,4 +1,24 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Picker Trigger
*
* Botón que abre el calendario del DatePicker.
*
* ## Uso
* ```svelte
* <DatePicker>
* <DatePickerTrigger />
* <DatePickerContent>
* <DatePickerCalendar />
* </DatePickerContent>
* </DatePicker>
* ```
*
* ## Selectores CSS
* ```
* [data-date-picker-trigger] → Botón que abre el calendario
* ```
*/
import { mergeProps } from '$terra/utils'; import { mergeProps } from '$terra/utils';
import type { DatePickerTriggerProps } from "../types.js"; import type { DatePickerTriggerProps } from "../types.js";
import PopoverTrigger from "../../popover/components/popover-trigger.svelte"; import PopoverTrigger from "../../popover/components/popover-trigger.svelte";
@ -12,7 +32,7 @@
function onKeydown(e: KeyboardEvent) { function onKeydown(e: KeyboardEvent) {
if (isSegmentNavigationKey(e.key)) { if (isSegmentNavigationKey(e.key)) {
const currNode = e.currentTarget as HTMLElement; const currNode = e.currentTarget as HTMLElement;
const datePickerRootNode = currNode.closest('[data-date-picker-root]') as HTMLElement; const datePickerRootNode = currNode.closest('[data-date-picker]') as HTMLElement;
if (!datePickerRootNode) return; if (!datePickerRootNode) return;
handleSegmentNavigation(e, datePickerRootNode); handleSegmentNavigation(e, datePickerRootNode);
} }

@ -1,4 +1,18 @@
<script lang="ts"> <script lang="ts">
/**
* # DatePicker Root
*
* Selector de fecha con campo de entrada y calendario emergente.
*
* ## Selectores CSS
* ```
* [data-date-picker] → Contenedor raíz
* [data-date-picker-trigger] → Trigger que abre el calendario
* [data-state="open"] → Estado del popover abierto
* [data-state="closed"] → Estado del popover cerrado
* [data-disabled] → Presente cuando disabled=true
* ```
*/
import { watch } from 'runed'; import { watch } from 'runed';
import type { DateValue } from '$terra/adapters/dates'; import type { DateValue } from '$terra/adapters/dates';
import { readableActive, writableActive, mergeProps, useId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, useId } from '$terra/utils';
@ -154,7 +168,7 @@
const mergedProps = $derived( const mergedProps = $derived(
mergeProps(restProps, { mergeProps(restProps, {
id, id,
'data-date-picker-root': '', 'data-date-picker': '',
}) })
); );
</script> </script>

@ -1,4 +1,21 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Range Field Input
*
* Input para seleccionar un rango de fechas.
*
* ## Uso
* ```svelte
* <DateRangeField>
* <DateRangeFieldInput />
* </DateRangeField>
* ```
*
* ## Selectores CSS
* ```
* [data-date-range-field-input] → Contenedor del input de rango de fechas
* ```
*/
import { readableActive, writableActive, mergeProps, createId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, createId } from "$terra/utils";
import type { DateRangeFieldInputProps } from "../types.ts"; import type { DateRangeFieldInputProps } from "../types.ts";
import { DateRangeFieldInputState } from "../date-range-field.svelte.ts"; import { DateRangeFieldInputState } from "../date-range-field.svelte.ts";

@ -1,4 +1,22 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Range Field Label
*
* Etiqueta para el campo de rango de fechas.
*
* ## Uso
* ```svelte
* <DateRangeField>
* <DateRangeFieldLabel>Selecciona un rango</DateRangeFieldLabel>
* <DateRangeFieldInput />
* </DateRangeField>
* ```
*
* ## Selectores CSS
* ```
* [data-date-range-field-label] → Etiqueta del campo de rango de fechas
* ```
*/
import { readableActive, writableActive, mergeProps, createId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, createId } from "$terra/utils";
import { DateRangeFieldLabelState } from "../date-range-field.svelte.ts"; import { DateRangeFieldLabelState } from "../date-range-field.svelte.ts";
import type { DateRangeFieldLabelProps } from "../types.ts"; import type { DateRangeFieldLabelProps } from "../types.ts";

@ -1,4 +1,18 @@
<script lang="ts"> <script lang="ts">
/**
* # DateRangeField Root
*
* Componente de campo de rango de fechas con segmentos editables.
*
* ## Selectores CSS
* ```
* [data-date-range-field] → Contenedor raíz
* [data-date-range-field-label] → Etiqueta del campo
* [data-disabled] → Presente cuando disabled=true
* [data-readonly] → Presente cuando readonly=true
* [data-invalid] → Presente cuando el campo es inválido
* ```
*/
import { watch } from "runed"; import { watch } from "runed";
import { readableActive, writableActive, mergeProps } from "$terra/utils"; import { readableActive, writableActive, mergeProps } from "$terra/utils";
import type { DateValue } from "$terra/adapters/dates"; import type { DateValue } from "$terra/adapters/dates";

@ -1,4 +1,24 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Range Picker Calendar
*
* Componente de calendario utilizado dentro del DateRangePicker.
*
* ## Uso
* ```svelte
* <DateRangePicker>
* <DateRangePickerTrigger />
* <DateRangePickerContent>
* <DateRangePickerCalendar />
* </DateRangePickerContent>
* </DateRangePicker>
* ```
*
* ## Selectores CSS
* ```
* [data-date-range-picker-calendar] → Contenedor del calendario del date range picker
* ```
*/
import { readableActive, writableActive, mergeProps, createId } from "$terra/utils"; import { readableActive, writableActive, mergeProps, createId } from "$terra/utils";
import type { DateRangePickerCalendarProps } from "../types.ts"; import type { DateRangePickerCalendarProps } from "../types.ts";
import { DateRangePickerRootState } from "../date-range-picker.svelte.ts"; import { DateRangePickerRootState } from "../date-range-picker.svelte.ts";

@ -1,4 +1,24 @@
<script lang="ts"> <script lang="ts">
/**
* # Date Range Picker Trigger
*
* Botón que abre el calendario del DateRangePicker.
*
* ## Uso
* ```svelte
* <DateRangePicker>
* <DateRangePickerTrigger />
* <DateRangePickerContent>
* <DateRangePickerCalendar />
* </DateRangePickerContent>
* </DateRangePicker>
* ```
*
* ## Selectores CSS
* ```
* [data-date-range-picker-trigger] → Botón que abre el calendario de rango
* ```
*/
import { mergeProps } from '$terra/utils'; import { mergeProps } from '$terra/utils';
import type { DateRangePickerTriggerProps } from "../types.js"; import type { DateRangePickerTriggerProps } from "../types.js";
import PopoverTrigger from "../../popover/components/popover-trigger.svelte"; import PopoverTrigger from "../../popover/components/popover-trigger.svelte";

@ -1,4 +1,18 @@
<script lang="ts"> <script lang="ts">
/**
* # DateRangePicker Root
*
* Selector de rango de fechas con campo de entrada y calendario emergente.
*
* ## Selectores CSS
* ```
* [data-date-range-picker] → Contenedor raíz
* [data-date-range-picker-trigger] → Trigger que abre el calendario
* [data-state="open"] → Estado del popover abierto
* [data-state="closed"] → Estado del popover cerrado
* [data-disabled] → Presente cuando disabled=true
* ```
*/
import { watch } from "runed"; import { watch } from "runed";
import type { DateValue } from "$terra/adapters/dates"; import type { DateValue } from "$terra/adapters/dates";
import { import {

@ -1,4 +1,34 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Close
*
* Botón que cierra el diálogo.
*
* ## Uso
* ```svelte
* <DialogContent>
* <DialogTitle>Diálogo</DialogTitle>
* <p>Contenido...</p>
* <DialogClose>Cerrar</DialogClose>
* <!-- También puede ser un icono -->
* <DialogClose>
* <CloseIcon />
* </DialogClose>
* </DialogContent>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el botón
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-terra-dialog-close] → Botón de cerrar
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DialogCloseState } from '../dialog.svelte'; import { DialogCloseState } from '../dialog.svelte';
import type { DialogCloseProps } from '../types'; import type { DialogCloseProps } from '../types';

@ -1,4 +1,45 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Content
*
* Contenedor principal del contenido del diálogo modal.
*
* ## Uso
* ```svelte
* <DialogContent>
* <DialogTitle>Título</DialogTitle>
* <DialogDescription>Descripción</DialogDescription>
* <p>Contenido...</p>
* </DialogContent>
* ```
*
* ## Propiedades
* - `forceMount`: boolean - Fuerza el montaje del componente
* - `onOpenAutoFocus`: Callback cuando el diálogo gana foco
* - `onCloseAutoFocus`: Callback cuando el diálogo pierde foco
* - `onEscapeKeydown`: Callback cuando se presiona Escape
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura del diálogo
*
* ## Comportamiento
* - Maneja el trapping de foco dentro del diálogo
* - Cierra con Escape
* - Enfoca automáticamente al abrir
*
* ## Selectores CSS
* ```
* [data-terra-dialog-content] → Contenedor del diálogo
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-nested] → Presente cuando el diálogo está anidado
* [data-nested-open] → Presente cuando hay diálogos anidados abiertos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="dialog".
*/
import { readableActive, writableActive, mergeProps, afterSleep } from '$terra/utils'; import { readableActive, writableActive, mergeProps, afterSleep } from '$terra/utils';
import { DialogContentState } from '../dialog.svelte'; import { DialogContentState } from '../dialog.svelte';
import type { DialogContentProps } from '../types'; import type { DialogContentProps } from '../types';

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Description
*
* Descripción opcional del diálogo que provee contexto adicional.
*
* ## Uso
* ```svelte
* <DialogContent>
* <DialogTitle>Confirmar acción</DialogTitle>
* <DialogDescription>
* Esta acción no se puede deshacer. ¿Estás seguro?
* </DialogDescription>
* <!-- acciones -->
* </DialogContent>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-terra-dialog-description] → Descripción del diálogo
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` asociado al diálogo.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DialogDescriptionState } from '../dialog.svelte'; import { DialogDescriptionState } from '../dialog.svelte';
import type { DialogDescriptionProps } from '../types'; import type { DialogDescriptionProps } from '../types';

@ -1,4 +1,30 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Overlay
*
* Fondo oscuro semi-transparente detrás del diálogo.
*
* ## Uso
* ```svelte
* <Dialog bind:open={isOpen}>
* <DialogTrigger>Abrir</DialogTrigger>
* <DialogOverlay />
* <DialogContent>...</DialogContent>
* </Dialog>
* ```
*
* ## Selectores CSS
* ```
* [data-terra-dialog-overlay] → Fondo del diálogo
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-nested] → Presente cuando el diálogo está anidado
* [data-nested-open] → Presente cuando hay diálogos anidados abiertos
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con position fixed.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DialogOverlayState } from '../dialog.svelte'; import { DialogOverlayState } from '../dialog.svelte';
import type { DialogOverlayProps } from '../types'; import type { DialogOverlayProps } from '../types';

@ -1,4 +1,33 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Title
*
* Título accesible del diálogo. Requerido para accesibilidad.
*
* ## Uso
* ```svelte
* <DialogContent>
* <DialogTitle level={2}>
* Título del diálogo
* </DialogTitle>
* <DialogDescription>
* Descripción opcional
* </DialogDescription>
* </DialogContent>
* ```
*
* ## Propiedades
* - `level`: 1 | 2 | 3 | 4 | 5 | 6 - Nivel de encabezado (default: 2)
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-terra-dialog-title] → Título del diálogo
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con role="heading".
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DialogTitleState } from '../dialog.svelte'; import { DialogTitleState } from '../dialog.svelte';
import type { DialogTitleProps } from '../types'; import type { DialogTitleProps } from '../types';

@ -1,4 +1,31 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Trigger
*
* Botón que abre el diálogo al hacer clic.
*
* ## Uso
* ```svelte
* <Dialog>
* <DialogTrigger>
* <button>Abrir</button>
* </DialogTrigger>
* <DialogContent>...</DialogContent>
* </Dialog>
* ```
*
* ## Propiedades
* - `disabled`: boolean - Deshabilita el trigger
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-terra-dialog-trigger] → Botón que abre el diálogo
* ```
*
* ## Estilos
* Renderiza un elemento `<button>`.
*/
import { readableActive, writableActive, mergeProps } from '$terra/utils'; import { readableActive, writableActive, mergeProps } from '$terra/utils';
import { DialogTriggerState } from '../dialog.svelte'; import { DialogTriggerState } from '../dialog.svelte';
import type { DialogTriggerProps } from '../types'; import type { DialogTriggerProps } from '../types';

@ -1,4 +1,30 @@
<script lang="ts"> <script lang="ts">
/**
* # Dialog Root
*
* Componente raíz de un diálogo modal que requiere interacción del usuario.
*
* ## Uso
* ```svelte
* <Dialog bind:open={isOpen}>
* <DialogTrigger>Abrir diálogo</DialogTrigger>
* <DialogContent>
* <DialogTitle>Título</DialogTitle>
* <DialogDescription>Descripción</DialogDescription>
* <p>Contenido del diálogo</p>
* <DialogClose>Cerrar</DialogClose>
* </DialogContent>
* </Dialog>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado de apertura del diálogo (bindable)
* - `onOpenChange`: Callback cuando cambia el estado
* - `onOpenChangeComplete`: Callback cuando la animación termina
*
* ## Selectores CSS
* El dialog usa atributos `data-terra-dialog-*` para sus partes.
*/
import { readableActive, writableActive } from '$terra/utils'; import { readableActive, writableActive } from '$terra/utils';
import { DialogRootState } from '../dialog.svelte'; import { DialogRootState } from '../dialog.svelte';
import type { DialogRootProps } from '../types'; import type { DialogRootProps } from '../types';

@ -110,7 +110,7 @@ export class DialogRootState {
this.opts.open.current = false; this.opts.open.current = false;
}; };
getBitsAttr: typeof dialogAttrs.getAttr = (part) => { getTerraAttr: typeof dialogAttrs.getAttr = (part) => {
return dialogAttrs.getAttr(part, this.opts.variant.current); return dialogAttrs.getAttr(part, this.opts.variant.current);
}; };
@ -171,7 +171,7 @@ export class DialogTriggerState {
"aria-haspopup": "dialog", "aria-haspopup": "dialog",
"aria-expanded": boolToStr(this.root.opts.open.current), "aria-expanded": boolToStr(this.root.opts.open.current),
"aria-controls": this.root.contentId, "aria-controls": this.root.contentId,
[this.root.getBitsAttr("trigger")]: "", [this.root.getTerraAttr("trigger")]: "",
onkeydown: this.onkeydown, onkeydown: this.onkeydown,
onclick: this.onclick, onclick: this.onclick,
disabled: boolToTrueOrUndef(this.opts.disabled.current), disabled: boolToTrueOrUndef(this.opts.disabled.current),
@ -218,7 +218,7 @@ export class DialogCloseState {
() => () =>
({ ({
id: this.opts.id.current, id: this.opts.id.current,
[this.root.getBitsAttr(this.opts.variant.current)]: "", [this.root.getTerraAttr(this.opts.variant.current)]: "",
onclick: this.onclick, onclick: this.onclick,
onkeydown: this.onkeydown, onkeydown: this.onkeydown,
disabled: boolToTrueOrUndef(this.opts.disabled.current), disabled: boolToTrueOrUndef(this.opts.disabled.current),
@ -250,7 +250,7 @@ export class DialogActionState {
() => () =>
({ ({
id: this.opts.id.current, id: this.opts.id.current,
[this.root.getBitsAttr("action")]: "", [this.root.getTerraAttr("action")]: "",
...this.root.sharedProps, ...this.root.sharedProps,
...this.attachment, ...this.attachment,
}) as const }) as const
@ -286,7 +286,7 @@ export class DialogTitleState {
id: this.opts.id.current, id: this.opts.id.current,
role: "heading", role: "heading",
"aria-level": this.opts.level.current, "aria-level": this.opts.level.current,
[this.root.getBitsAttr("title")]: "", [this.root.getTerraAttr("title")]: "",
...this.root.sharedProps, ...this.root.sharedProps,
...this.attachment, ...this.attachment,
}) as const }) as const
@ -320,7 +320,7 @@ export class DialogDescriptionState {
() => () =>
({ ({
id: this.opts.id.current, id: this.opts.id.current,
[this.root.getBitsAttr("description")]: "", [this.root.getTerraAttr("description")]: "",
...this.root.sharedProps, ...this.root.sharedProps,
...this.attachment, ...this.attachment,
}) as const }) as const
@ -357,7 +357,7 @@ export class DialogContentState {
"aria-modal": "true", "aria-modal": "true",
"aria-describedby": this.root.descriptionId, "aria-describedby": this.root.descriptionId,
"aria-labelledby": this.root.titleId, "aria-labelledby": this.root.titleId,
[this.root.getBitsAttr("content")]: "", [this.root.getTerraAttr("content")]: "",
style: { style: {
pointerEvents: "auto", pointerEvents: "auto",
outline: this.root.opts.variant.current === "alert-dialog" ? "none" : undefined, outline: this.root.opts.variant.current === "alert-dialog" ? "none" : undefined,
@ -401,7 +401,7 @@ export class DialogOverlayState {
() => () =>
({ ({
id: this.opts.id.current, id: this.opts.id.current,
[this.root.getBitsAttr("overlay")]: "", [this.root.getTerraAttr("overlay")]: "",
style: { style: {
pointerEvents: "auto", pointerEvents: "auto",
"--terra-dialog-depth": this.root.depth, "--terra-dialog-depth": this.root.depth,
@ -456,7 +456,7 @@ export class AlertDialogCance$state {
() => () =>
({ ({
id: this.opts.id.current, id: this.opts.id.current,
[this.root.getBitsAttr("cancel")]: "", [this.root.getTerraAttr("cancel")]: "",
onclick: this.onclick, onclick: this.onclick,
onkeydown: this.onkeydown, onkeydown: this.onkeydown,
tabindex: 0, tabindex: 0,

@ -1,4 +1,14 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Close
*
* Botón que cierra el drawer.
*
* ## Selectores CSS
* ```
* [data-drawer-close] → Elemento close del drawer
* ```
*/
import { Dialog } from '../../dialog'; import { Dialog } from '../../dialog';
import type { DrawerCloseProps } from '../types'; import type { DrawerCloseProps } from '../types';

@ -1,4 +1,45 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Content
*
* Contenedor del contenido del panel lateral deslizante.
*
* ## Uso
* ```svelte
* <DrawerContent side="right">
* <DrawerClose>
* <CloseIcon />
* </DrawerClose>
* <p>Contenido del drawer</p>
* </DrawerContent>
* ```
*
* ## Propiedades
* - `side`: "top" | "right" | "bottom" | "left" - Lado desde donde se abre
* - `forceMount`: boolean - Fuerza el montaje del componente
* - `onOpenAutoFocus`: Callback cuando el drawer gana foco
* - `onCloseAutoFocus`: Callback cuando el drawer pierde foco
* - `onEscapeKeydown`: Callback cuando se presiona Escape
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura
* - `side`: string - Lado de apertura
*
* ## Selectores CSS
* ```
* [data-drawer-content] → Contenedor del drawer
* [data-side="top"] → Drawer desde arriba
* [data-side="right"] → Drawer desde la derecha
* [data-side="bottom"] → Drawer desde abajo
* [data-side="left"] → Drawer desde la izquierda
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* ```
*
* ## Estilos
* Renderiza un elemento `<div>` con `data-side` y `data-drawer-content`.
*/
import { readableActive, writableActive, mergeProps, afterSleep } from '$terra/utils'; import { readableActive, writableActive, mergeProps, afterSleep } from '$terra/utils';
import { DialogContentState } from '../../dialog/dialog.svelte'; import { DialogContentState } from '../../dialog/dialog.svelte';
import type { DrawerContentProps } from '../types'; import type { DrawerContentProps } from '../types';

@ -1,4 +1,14 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Description
*
* Descripción opcional del drawer.
*
* ## Selectores CSS
* ```
* [data-drawer-description] → Elemento descripción del drawer
* ```
*/
import { Dialog } from '../../dialog'; import { Dialog } from '../../dialog';
import type { DrawerDescriptionProps } from '../types'; import type { DrawerDescriptionProps } from '../types';

@ -1,4 +1,16 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Overlay
*
* Fondo oscuro semitransparente que aparece detrás del drawer.
*
* ## Selectores CSS
* ```
* [data-drawer-overlay] → Elemento overlay del drawer
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* ```
*/
import { mergeProps } from '$terra/utils'; import { mergeProps } from '$terra/utils';
import { Dialog } from '../../dialog'; import { Dialog } from '../../dialog';
import type { DrawerOverlayProps } from '../types'; import type { DrawerOverlayProps } from '../types';

@ -1,4 +1,14 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Title
*
* Título del drawer.
*
* ## Selectores CSS
* ```
* [data-drawer-title] → Elemento título del drawer
* ```
*/
import { Dialog } from '../../dialog'; import { Dialog } from '../../dialog';
import type { DrawerTitleProps } from '../types'; import type { DrawerTitleProps } from '../types';

@ -1,4 +1,14 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Trigger
*
* Botón que abre el drawer.
*
* ## Selectores CSS
* ```
* [data-drawer-trigger] → Elemento trigger del drawer
* ```
*/
import { Dialog } from '../../dialog'; import { Dialog } from '../../dialog';
import type { DrawerTriggerProps } from '../types'; import type { DrawerTriggerProps } from '../types';

@ -1,4 +1,41 @@
<script lang="ts"> <script lang="ts">
/**
* # Drawer Root
*
* Panel lateral deslizante (drawer) que se abre desde un borde de la pantalla.
*
* ## Uso
* ```svelte
* <Drawer bind:open={isOpen}>
* <DrawerTrigger>Abrir drawer</DrawerTrigger>
* <DrawerContent side="right">
* <DrawerClose>Cerrar</DrawerClose>
* <p>Contenido del drawer</p>
* </DrawerContent>
* </Drawer>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado de apertura del drawer (bindable)
* - `onOpenChange`: Callback cuando cambia el estado
* - `onOpenChangeComplete`: Callback cuando la animación termina
*
* ## Selectores CSS
* ```
* [data-drawer-content] → Contenedor del drawer
* [data-side="top"] → Drawer desde arriba
* [data-side="right"] → Drawer desde la derecha
* [data-side="bottom"] → Drawer desde abajo
* [data-side="left"] → Drawer desde la izquierda
* [data-state="open"] → Estado abierto
* [data-state="closed"] → Estado cerrado
* [data-drawer-trigger] → Botón que abre el drawer
* [data-drawer-overlay] → Fondo del drawer
* [data-drawer-title] → Título del drawer
* [data-drawer-description] → Descripción del drawer
* [data-drawer-close] → Botón de cerrar
* ```
*/
import { readableActive, writableActive } from '$terra/utils'; import { readableActive, writableActive } from '$terra/utils';
import { DialogRootState } from '../../dialog/dialog.svelte'; import { DialogRootState } from '../../dialog/dialog.svelte';
import type { DrawerRootProps } from '../types'; import type { DrawerRootProps } from '../types';

@ -1,4 +1,52 @@
<script lang="ts"> <script lang="ts">
/**
* # Dropdown Menu Content
*
* Contenedor del menú desplegable con items.
*
* ## Uso
* ```svelte
* <DropdownMenuContent
* side="bottom"
* align="start"
* sideOffset={8}
* >
* <DropdownMenuItem value="edit">Editar</DropdownMenuItem>
* <DropdownMenuSeparator />
* <DropdownMenuItem value="delete">Eliminar</DropdownMenuItem>
* </DropdownMenuContent>
* ```
*
* ## Propiedades
* - `side`: "top" | "right" | "bottom" | "left" - Posición del menú
* - `align`: "start" | "center" | "end" - Alineación del menú
* - `sideOffset`: number - Distancia desde el trigger
* - `loop`: boolean - Navegación cíclica con flechas
* - `forceMount`: boolean - Muestra siempre
* - `avoidCollisions`: boolean - Evita colisiones con bordes
* - `collisionPadding`: number - Padding para colisiones
* - `arrowPadding`: number - Padding para la flecha
* - `sticky`: "partial" | "always" - Comportamiento sticky
* - `hideWhenDetached`: boolean - Oculta si está detached
* - `strategy`: "absolute" | "fixed" - Estrategia de posicionamiento
* - `onInteractOutside`: Callback al interactuar fuera
* - `onCloseAutoFocus`: Callback al cerrar y reenfocar
* - `onEscapeKeydown`: Callback al presionar Escape
* - `id`: string - ID del elemento
*
* ## Snippet Props
* - `open`: boolean - Estado de apertura
*
* ## Selectores CSS
* ```
* [data-dropdown-menu-content] → Contenedor del menú desplegable
* [data-state="open"] → Estado del menú abierto
* [data-state="closed"] → Estado del menú cerrado
* ```
*
* ## Estilos
* Renderiza un `<div>` anidado para posicionamiento.
*/
import { readableActive, writableActive, mergeProps } from "$terra/utils"; import { readableActive, writableActive, mergeProps } from "$terra/utils";
import type { DropdownMenuContentProps } from '../types'; import type { DropdownMenuContentProps } from '../types';
import { MenuContentState } from '../../menu/menu.svelte'; import { MenuContentState } from '../../menu/menu.svelte';
@ -54,7 +102,7 @@
onInteractOutside(e); onInteractOutside(e);
if (e.defaultPrevented) return; if (e.defaultPrevented) return;
if (e.target && e.target instanceof Element) { if (e.target && e.target instanceof Element) {
const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr('sub-content')}]`; const subContentSelector = `[${contentState.parentMenu.root.getTerraAttr('sub-content')}]`;
if (e.target.closest(subContentSelector)) return; if (e.target.closest(subContentSelector)) return;
} }
contentState.parentMenu.onClose(); contentState.parentMenu.onClose();

@ -1,4 +1,43 @@
<script lang="ts"> <script lang="ts">
/**
* # Dropdown Menu Root
*
* Menú desplegable que se muestra al hacer clic en un trigger.
*
* ## Uso
* ```svelte
* <DropdownMenu bind:open={isOpen}>
* <DropdownMenuTrigger>
* <button>Menu</button>
* </DropdownMenuTrigger>
* <DropdownMenuContent>
* <DropdownMenuItem value="edit">Editar</DropdownMenuItem>
* <DropdownMenuItem value="delete">Eliminar</DropdownMenuItem>
* </DropdownMenuContent>
* </DropdownMenu>
* ```
*
* ## Propiedades
* - `open`: boolean - Estado del menú (bindable)
* - `onOpenChange`: Callback cuando cambia el estado
* - `dir`: "ltr" | "rtl" - Dirección del texto
*
* ## Selectores CSS
* ```
* [data-dropdown-menu] → Contexto raíz del menú
* [data-dropdown-menu-trigger] → Trigger que abre el menú
* [data-dropdown-menu-content] → Contenedor del menú
* [data-state="open"] → Estado del menú abierto
* [data-state="closed"] → Estado del menú cerrado
* [data-dropdown-menu-item] → Item individual del menú
* [data-highlighted] → Item resaltado (hover/foco)
* [data-disabled] → Item deshabilitado
* [data-orientation] → Orientación del item
* [data-dropdown-menu-checkbox-item] → Item de tipo checkbox
* [data-dropdown-menu-radio-item] → Item de tipo radio
* [data-dropdown-menu-separator] → Separador visual
* ```
*/
import MenuRoot from "../../menu/components/menu.svelte"; import MenuRoot from "../../menu/components/menu.svelte";
import type { MenuRootProps } from "../../menu/types"; import type { MenuRootProps } from "../../menu/types";

@ -1,4 +1,28 @@
<script lang="ts"> <script lang="ts">
/**
* # Editable Area
*
* Contenedor del área editable.
*
* ## Uso
* ```svelte
* <Editable.Area>
* <Editable.Preview />
* <Editable.Input />
* </Editable.Area>
* ```
*
* ## Propiedades
* - `id`: string - ID del elemento
*
* ## Selectores CSS
* ```
* [data-editable-area] → Área contenedora
* ```
*
* ## Estilos
* Renderiza un elemento `<div>`.
*/
import { readableActive, writableActive, mergeProps, createId } from '$terra/utils'; import { readableActive, writableActive, mergeProps, createId } from '$terra/utils';
import type { EditableAreaProps } from '../types'; import type { EditableAreaProps } from '../types';
import { EditableAreaState } from '../editable.svelte'; import { EditableAreaState } from '../editable.svelte';

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.