# @jcsoftdev/ui - full documentation > Token-driven React 19 component library (Radix, Tailwind CSS v4, no runtime CSS-in-JS): atoms, forms, containers, overlays, about one hundred pure-SVG charts, a spreadsheet-grade DataGrid, an AI chat kit, rich text, XLSX and brand tools, themed by data-style, data-density, data-radius, data-accent and data-theme attributes. Every documentation page below is also available on its own at .md. Index: https://ui.jcsoftdev.com/llms.txt --- # Introduction > What @jcsoftdev/ui is, what it ships and how this documentation is organised. Source: https://ui.jcsoftdev.com/docs/index `@jcsoftdev/ui` is a token-driven React 19 component library built on Radix primitives and Tailwind CSS v4. There is no runtime CSS-in-JS: the whole look comes from one tokens file that is compiled to CSS variables, and a handful of `data-*` attributes restyle everything at runtime. ## What is inside - **Atoms, forms, containers, overlays, navigation, states, shell**: the everyday building blocks, including a DataGrid with formulas, undo, XLSX export and integrated charts. - **Charts**: about one hundred pure React and SVG charts and chart parts (line, bar, donut, radar, gauge, heatmap, treemap, sankey, stock, globe, maps, crossfilter...) with no chart dependency. - **AI kit** (`@jcsoftdev/ui/ai`): conversation, streaming-friendly messages, markdown, code blocks, prompt input and tool calls. - **Rich text**, **XLSX** writer, **brand** tools (Logo Forge), calendar views and a command palette. Everything adapts to the width of its **container**, not the viewport, so a component behaves the same in a sidebar, a card or a dialog. ## How to read these docs 1. [Getting started](/docs/getting-started/) installs the package and wires the CSS. 2. [Theming and presets](/docs/theming/) explains `data-style`, `data-density`, `data-radius`, `data-accent` and `data-theme`. 3. Each page under **Components** is generated from the library source: import path, props with types and defaults, accessibility notes, a live example and links to Storybook. 4. Language models can read the same content as plain Markdown: see [Docs for LLMs](/docs/llms/). ## Conventions - Documentation and identifiers are in English. Sample data in examples is Spanish (a barbershop), because that is the product the library was built for. - Component pages are regenerated from `packages/ui/src` on every build, so props and import paths never drift from the code. --- # Getting started > Install @jcsoftdev/ui, import the token stylesheets and render your first component in Next.js, Astro or Vite. Source: https://ui.jcsoftdev.com/docs/getting-started ## Install ```bash pnpm add @jcsoftdev/ui ``` Peer dependencies are `react` and `react-dom` (19) and `tailwindcss` v4. Radix, `lucide-react`, `cmdk` and `sonner` are regular dependencies of the package. ## Import the styles The package ships its default theme already compiled. Import the three stylesheets after Tailwind and point Tailwind at the package so it can see the class names used by the components: ```css /* app/globals.css */ @import "tailwindcss"; @import "@jcsoftdev/ui/styles/tokens.css"; /* CSS variables: colors, radii, shadows, presets */ @import "@jcsoftdev/ui/styles/theme.css"; /* Tailwind v4 @theme mapping: bg-surface, text-ink, rounded-card... */ @import "@jcsoftdev/ui/styles/base.css"; /* focus ring, reduced motion, body defaults */ @source "../node_modules/@jcsoftdev/ui/dist"; /* lets Tailwind generate the utilities the components use */ ``` `@jcsoftdev/ui/styles/fonts.css` is optional: it imports Figtree from Google Fonts. Skip it when your app loads fonts itself and override `--font-sans`. ## Use a component ```tsx import { Button } from "@jcsoftdev/ui/atoms"; import { Kpi } from "@jcsoftdev/ui/containers"; export function Today() { return (
); } ``` Every component is also a single entry point, for example `@jcsoftdev/ui/atoms/button`. See [Tree-shaking and subpaths](/docs/subpaths/). ## Next.js Components that hold state are marked `"use client"`, so they work from Server Components as long as you pass serializable props. The package is plain ESM; no `transpilePackages` is required. ```tsx // app/layout.tsx import { Figtree } from "next/font/google"; import "./globals.css"; const figtree = Figtree({ subsets: ["latin"], variable: "--font-figtree" }); export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` ```css /* globals.css, after the imports */ :root { --font-sans: var(--font-figtree), ui-sans-serif, system-ui, sans-serif; } ``` ## Astro Add `@astrojs/react` and the Tailwind Vite plugin, import the same stylesheets in a global CSS file and render components as islands (`client:visible` for heavy ones such as charts). This site is built that way. ## Vite Use `@tailwindcss/vite`, import the stylesheets in your entry CSS and import components as usual. Nothing else is needed. ## Switch the look at runtime Set attributes on `` (or on any element, to restyle just its subtree): ```html ``` Read [Theming and presets](/docs/theming/) for every value and the precedence rules. --- # Tree-shaking and subpaths > Every @jcsoftdev/ui subpath and single-component entry point, and how to keep bundles small. Source: https://ui.jcsoftdev.com/docs/subpaths The package is unbundled ESM with `"sideEffects": ["**/*.css"]`: one output file per source file, so a bundler can reduce an import to the component you use and its own dependencies. ## Subpaths | Import path | Components | | --- | --- | | `@jcsoftdev/ui/ai` | 15 | | `@jcsoftdev/ui/atoms` | 17 | | `@jcsoftdev/ui/brand` | 2 | | `@jcsoftdev/ui/calendar` | 5 | | `@jcsoftdev/ui/charts` | 95 | | `@jcsoftdev/ui/containers` | 51 | | `@jcsoftdev/ui/forms` | 21 | | `@jcsoftdev/ui/navigation` | 8 | | `@jcsoftdev/ui/overlays` | 39 | | `@jcsoftdev/ui/palette` | 1 | | `@jcsoftdev/ui/rich-text` | 2 | | `@jcsoftdev/ui/shell` | 3 | | `@jcsoftdev/ui/states` | 5 | | `@jcsoftdev/ui/utils` | 0 | | `@jcsoftdev/ui/xlsx` | 0 | Also available: `@jcsoftdev/ui/styles/*` (CSS) and `@jcsoftdev/ui/tokens/*` (the tokens JSON). ## Single-component entries Inside a group, components that live in their own folder also have an entry point. 155 are available, for example: ```ts import {} from "@jcsoftdev/ui/ai/attachment"; import {} from "@jcsoftdev/ui/ai/chain-of-thought"; import {} from "@jcsoftdev/ui/ai/chat-list"; import {} from "@jcsoftdev/ui/ai/chat-message"; import {} from "@jcsoftdev/ui/ai/code-block"; import {} from "@jcsoftdev/ui/ai/conversation"; ``` ## Rules of thumb - Prefer the group entry (`@jcsoftdev/ui/atoms`) in application code: it tree-shakes and reads well. - Use a single-component entry when you need the smallest possible import graph, for example in an island that ships to the browser. - Heavy features load lazily: the DataGrid chart panel and the XLSX writer are imported on demand. - Add `@source` for the package `dist` folder so Tailwind generates the classes the components use. - Compile the TypeScript yourself with the `source` export condition, which points at `src/*/index.ts`. --- # Container queries > Components respond to the width of their container, not the viewport, so they behave the same in a sidebar, a card or a dialog. Source: https://ui.jcsoftdev.com/docs/container-queries Every component adapts to the width of the box it is placed in. The library uses Tailwind v4 container queries (`@container`, `@sm:`, `@md:`...) and never viewport breakpoints (`sm:`, `md:`) inside components. ## Why it matters A `KpiGroup` in a narrow sidebar and the same `KpiGroup` across a wide dashboard are the same component. No prop and no media query decides the layout; the container does. ```tsx
{/* stacks */}
{/* lays out in a row */}
``` ## Charts measure their container Charts use a `ResizeObserver` through `ChartFrame` and also adapt: fewer ticks, rotated or skipped labels, a legend that moves below, tooltips that stay inside the frame and data labels that hide when they do not fit. A chart fills its parent exactly, so give the parent a size: ```tsx
``` ## Guarantees - Nothing overflows horizontally at 320 px: long text truncates or wraps, tables scroll inside their own wrapper and toolbars wrap. - Nested containers are named (for example `@container/kpi`) so they do not clash. - The live examples on every component page have a width control (320, 480, 768, full) to check this. ## In your own layouts Mark a wrapper as a container and style its children with container variants: ```tsx
...
``` --- # Accessibility > Keyboard support, focus management, reduced motion, contrast and data alternatives built into the components. Source: https://ui.jcsoftdev.com/docs/accessibility Accessibility is part of each component, not an add-on. ## Keyboard and semantics - Interactive primitives (dialogs, menus, popovers, tabs, radio groups, switches, checkboxes) come from Radix, which implements the WAI-ARIA patterns. - `DataGrid` follows the ARIA grid pattern with a roving tabindex and full keyboard navigation (arrows, Home/End, Enter/F2 to edit, Escape to cancel, Ctrl+Z/Y for undo and redo, Ctrl+V and Ctrl+D/R to paste and fill). - Overlays return focus to the element that opened them. - The AI `Conversation` is a `role="log"` region that follows new content until the user scrolls up, then offers a "jump to latest" button. ## Focus A single token-driven focus ring is applied with `focus-visible` (`--focus-ring-width`, `--focus-ring-color`, `--focus-ring-offset`), so it follows every style preset. Controls never remove it. ## Motion All animations (entrances, shimmer, streaming caret, chart transitions) honor `prefers-reduced-motion`. The base stylesheet also collapses animation and transition durations for users who ask for less motion. ## Color and contrast Text and interactive tokens are chosen for contrast on their intended surfaces (the token notes list the measured ratios). Color is never the only signal: charts offer patterns, legends are toggleable buttons and series can be read as a data table. ## Charts Charts expose an accessible name, an optional data table (`ChartDataTable`) and keyboard navigation across data points where the chart supports it. Tooltips are available on focus as well as hover. ## Labels and language Every visible string and ARIA label is a prop, with English defaults. Pass translated strings for other locales. ## Testing Stories run with the Storybook accessibility addon; component-level notes appear in the **Accessibility** section of a component page whenever the source documents them with `@a11y`, `@keyboard` or `@accessibility` JSDoc tags. --- # Docs for LLMs > llms.txt, llms-full.txt and a Markdown version of every page, generated from the same source as the HTML docs. Source: https://ui.jcsoftdev.com/docs/llms This site is readable by language models and coding agents without scraping HTML. | URL | What it is | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | [`/llms.txt`](/llms.txt) | Index in the [llms.txt](https://llmstxt.org) format: a title, a one-line summary and sections of links to Markdown pages. | | [`/llms-full.txt`](/llms-full.txt) | Every documentation page concatenated into one file, including all components with their props. | | `/docs/.md` | The Markdown of a single page, for example [`/docs/getting-started.md`](/docs/getting-started.md) or `/docs/components/data-grid.md`. | | `/manifest.json` | Machine-readable list of every component: name, category, import path, props and Storybook story ids. | Every page has **Copy page as Markdown** and **Open .md** buttons under its title. ## Same source as the human docs The Markdown is produced from the same files as the HTML pages. Component pages are generated from the TypeScript source of `@jcsoftdev/ui` (exports, prop types, defaults, JSDoc) on every build, so an agent never sees stale props. ## Tips for agents - Start from `/llms.txt`, then fetch only the component pages you need. - Import path rule: a component is imported from its category, for example `@jcsoftdev/ui/containers`, or from a single-component entry such as `@jcsoftdev/ui/containers/data-grid`. - Theming is attribute driven: `data-theme`, `data-accent`, `data-style`, `data-density`, `data-radius` on `` or any element. - Use semantic Tailwind utilities (`bg-surface-card`, `text-ink`, `rounded-card`) instead of literal colors. --- # Theming and presets > Zero-runtime theming with data-style, data-density, data-radius, data-accent and data-theme, plus precedence and custom token files. Source: https://ui.jcsoftdev.com/docs/theming The whole look comes from one tokens file, `tokens/default.json`. A build step turns it into CSS custom properties (`tokens.css`) and a Tailwind v4 theme (`theme.css`). At runtime nothing is computed in JavaScript: five attributes only remap CSS variables. | Attribute | Values | Default (no attribute) | | -------------- | ------------------------------------------------------------- | ------------------------------ | | `data-theme` | `light`, `dark` | follows `prefers-color-scheme` | | `data-accent` | `durazno`, `menta`, `cielo`, `lavanda`, `orquidea`, `grafito` | Coral | | `data-style` | `soft`, `bordered`, `elevated`, `flat`, `glass`, `brutal` | `soft` | | `data-density` | `compact` (x0.875), `normal`, `comfortable` (x1.125) | `normal` | | `data-radius` | `none`, `sm`, `md`, `lg`, `full` | the preset's own radii | ```html ...
only this subtree is glass
``` ## Style presets Each preset changes shape, edge and elevation, not the palette: - `soft`: hairline shadows instead of borders, pill buttons (the default). - `bordered`: crisp 1px borders, no shadows, tighter radii. - `elevated`: real shadows and a lifted card surface; has light and dark variants. - `flat`: no shadows and no borders; surfaces separate by tone only. - `glass`: translucent surfaces with backdrop blur; has light and dark variants. - `brutal`: thick borders, hard offset shadows, square corners. ## Precedence On a single element the order is source order at equal specificity: theme, then accent, then `data-style`, then `data-density`, then `data-radius`. `data-radius` also wins over a preset set on a descendant, because presets read `var(--radius-card-override, )`. Presets never touch density tokens. There is no `!important` anywhere. ## Density Density is a unitless `--density` that scales control heights, control and card padding and the `gap-density*` scale with `calc()`. Tailwind's global `--spacing` scale is not scaled. ## Using tokens in your own code Use the semantic utilities so your UI follows the presets too: | Concern | Utilities | | ---------------- | --------------------------------------------------------------------------------------- | | Radius | `rounded-button`, `rounded-input`, `rounded-card`, `rounded-popover`, `rounded-chip`... | | Edge | `border-card`, `border-control` | | Shadow | `shadow-card`, `shadow-raised`, `shadow-overlay`, `shadow-control` | | Surface | `bg-surface-card`, `bg-surface-control`, `bg-surface-overlay`, `bg-surface-sunken` | | Density | `h-control`, `h-input`, `px-control-x`, `p-card`, `gap-density` | | Focus and motion | `focus-visible:focus-ring`, `pressable`, `ease-style` | The complete list of tokens, with light and dark values and usage notes, is generated on the [Design tokens](/docs/theming/tokens/) page. ## Your own tokens Copy `tokens/default.json`, edit values (keep the same names) and run the CLI: ```bash npx ui-theme build my-tokens.json --out src/theme ``` It writes `tokens.css`, `theme.css`, `fonts.css` and a Compose `Theme.kt` so a Kotlin app can share the tokens. Import your generated files instead of the shipped ones. ## Runtime switching with persistence ```ts const root = document.documentElement; root.dataset.style = "glass"; root.dataset.accent = "menta"; localStorage.setItem("preset", JSON.stringify({ style: "glass", accent: "menta" })); ``` Restore it from an inline script in `` before first paint to avoid a flash. This site does exactly that. --- # Design tokens > Every design token of the default theme, generated from tokens/default.json. Source: https://ui.jcsoftdev.com/docs/theming/tokens Generated from `tokens/default.json` ("Barbershop default", schema v2). Usage notes are kept in the language of the token file (Spanish). ## Color | Token | CSS variable | Light / dark | Usage | | --- | --- | --- | --- | | `bg` | `--bg` | `#f4f4f8` / `#000000` | Fondo de la página. En oscuro es negro puro: en pantallas AMOLED esos píxeles quedan apagados. | | `surface` | `--surface` | `#ffffff` / `#0e0e10` | Tarjetas, barra lateral, campos y filas. En oscuro va apenas encendida sobre el negro. | | `surface-2` | `--surface-2` | `#eeeef1` / `#1a1a1d` | Fila en hover, chip neutro y relleno de controles dentro de una tarjeta. | | `sunken` | `--sunken` | `#e7e7ed` / `#232327` | Fondo hundido: avatar neutro y zonas de arrastre. | | `float` | `--float` | `#ffffff` / `#141417` | Lo que flota sobre la página: diálogos, hojas, menús y la barra inferior de la app. En oscuro va un paso más clara que surface, porque ahí no hay sombras. | | `line` | `--line` | `#e3e3e6` / `#1f1f23` | Líneas divisorias, borde de chips sin relleno y de bloques apagados. Decorativa: no delimita controles. | | `line-strong` | `--line-strong` | `#d2d2dc` / `#303036` | Borde de bloques de cita y de botones de muestra. No llega a 3:1: el elemento se distingue por su relleno y su texto. | | `line-control` | `--line-control` | `#85858f` / `#6e6e7a` | Borde de campos de texto, selects y casillas. Da 3.7:1 sobre surface en claro y 3.8:1 en oscuro. | | `hair` | `--hair` | `rgba(0,0,0,.11)` / `rgba(255,255,255,.10)` | Filete de 0.67 px que rodea tarjetas y botones secundarios. Va dentro de shadow-flat y shadow-hero. | | `track` | `--track` | `#dedee2` / `#232327` | Pista de barras de avance y de nivel de stock. | | `seg-track` | `--seg-track` | `#e7e7ed` / `#151518` | Bandeja del control segmentado. | | `seg-on` | `--seg-on` | `#ffffff` / `#2b2b30` | Opción elegida del control segmentado. Es neutra: el color de marca no se usa para selectores. | | `ink` | `--ink` | `#000000` / `#f2f2f5` | Texto principal. En oscuro es un blanco roto para que no deslumbre sobre negro. | | `ink-2` | `--ink-2` | `#4b4b57` / `#b6b6c1` | Texto secundario y etiquetas, sobre cualquier superficie. | | `ink-3` | `--ink-3` | `#6d6d7a` / `#8c8c98` | Metadatos y encabezados de tabla, sobre bg y surface (4.6:1 sobre bg en claro). Sobre surface-2 usa ink-2. | | `accent` | `--accent` | `#faa2a2` / `#faa2a2` | Relleno de marca: la acción principal y lo elegido (día, hora, turno que sigue). Es un pastel y no sirve como color de texto. Por defecto es Coral. | | `on-accent` | `--on-accent` | `#3f191a` / `#3f191a` | Texto e iconos sobre un relleno accent: el tono profundo del mismo matiz (7.9:1). Igual en claro y en oscuro. | | `accent-ink` | `--accent-ink` | `#a43a41` / `#ffb4b3` | Texto e iconos en color de marca, foco de teclado y elemento activo de navegación. Da 6.4:1 sobre surface en claro y 11.4:1 en oscuro. | | `accent-word` | `--accent-word` | `#dc5d63` / `#faa2a2` | La palabra en color de un título grande y el interruptor encendido. Da 3.3:1 sobre bg: solo para texto de 24 px o más. | | `accent-soft` | `--accent-soft` | `#ffebea` / `#261112` | Fondo suave de marca: cita en atención, ítem activo de navegación, aviso informativo. | | `accent-line` | `--accent-line` | `#f6c2c1` / `#5b2e2f` | Filete de marca: borde de la cita en atención y de la tarjeta que resume lo que se está reservando. | | `accent-2` | `--accent-2` | `#fec79e` / `#fec79e` | Tono vecino, 38° más allá en el círculo de color. Solo para el degradado detrás de la rueda de hora. | | `pal-durazno-fill` | `--pal-durazno-fill` | `#efae75` / `#efae75` | Paleta Durazno: relleno. Reemplaza a accent con data-accent="durazno". | | `pal-durazno-deep` | `--pal-durazno-deep` | `#3b1f02` / `#3b1f02` | Paleta Durazno: texto sobre el relleno. Reemplaza a on-accent con data-accent="durazno". | | `pal-durazno-ink` | `--pal-durazno-ink` | `#905203` / `#f6be8e` | Paleta Durazno: texto en color. Reemplaza a accent-ink con data-accent="durazno". | | `pal-durazno-word` | `--pal-durazno-word` | `#c97405` / `#efae75` | Paleta Durazno: palabra de título. Reemplaza a accent-word con data-accent="durazno". | | `pal-durazno-soft` | `--pal-durazno-soft` | `#ffecde` / `#241406` | Paleta Durazno: fondo suave. Reemplaza a accent-soft con data-accent="durazno". | | `pal-durazno-line` | `--pal-durazno-line` | `#eec9a9` / `#553515` | Paleta Durazno: filete. Reemplaza a accent-line con data-accent="durazno". | | `pal-durazno-2` | `--pal-durazno-2` | `#e1d695` / `#e1d695` | Paleta Durazno: tono vecino. Reemplaza a accent-2 con data-accent="durazno". | | `pal-menta-fill` | `--pal-menta-fill` | `#77d3ad` / `#77d3ad` | Paleta Menta: relleno. Reemplaza a accent con data-accent="menta". | | `pal-menta-deep` | `--pal-menta-deep` | `#002f1f` / `#002f1f` | Paleta Menta: texto sobre el relleno. Reemplaza a on-accent con data-accent="menta". | | `pal-menta-ink` | `--pal-menta-ink` | `#047554` / `#91debc` | Paleta Menta: texto en color. Reemplaza a accent-ink con data-accent="menta". | | `pal-menta-word` | `--pal-menta-word` | `#03a578` / `#77d3ad` | Paleta Menta: palabra de título. Reemplaza a accent-word con data-accent="menta". | | `pal-menta-soft` | `--pal-menta-soft` | `#e0f7eb` / `#061d14` | Paleta Menta: fondo suave. Reemplaza a accent-soft con data-accent="menta". | | `pal-menta-line` | `--pal-menta-line` | `#addec7` / `#134834` | Paleta Menta: filete. Reemplaza a accent-line con data-accent="menta". | | `pal-menta-2` | `--pal-menta-2` | `#8ee5ed` / `#8ee5ed` | Paleta Menta: tono vecino. Reemplaza a accent-2 con data-accent="menta". | | `pal-cielo-fill` | `--pal-cielo-fill` | `#76c9f8` / `#76c9f8` | Paleta Cielo: relleno. Reemplaza a accent con data-accent="cielo". | | `pal-cielo-deep` | `--pal-cielo-deep` | `#002a3e` / `#002a3e` | Paleta Cielo: texto sobre el relleno. Reemplaza a on-accent con data-accent="cielo". | | `pal-cielo-ink` | `--pal-cielo-ink` | `#006c97` / `#8fd5fd` | Paleta Cielo: texto en color. Reemplaza a accent-ink con data-accent="cielo". | | `pal-cielo-word` | `--pal-cielo-word` | `#0097d2` / `#76c9f8` | Paleta Cielo: palabra de título. Reemplaza a accent-word con data-accent="cielo". | | `pal-cielo-soft` | `--pal-cielo-soft` | `#e1f3fe` / `#061b26` | Paleta Cielo: fondo suave. Reemplaza a accent-soft con data-accent="cielo". | | `pal-cielo-line` | `--pal-cielo-line` | `#abd8f3` / `#12425a` | Paleta Cielo: filete. Reemplaza a accent-line con data-accent="cielo". | | `pal-cielo-2` | `--pal-cielo-2` | `#c6d2ff` / `#c6d2ff` | Paleta Cielo: tono vecino. Reemplaza a accent-2 con data-accent="cielo". | | `pal-lavanda-fill` | `--pal-lavanda-fill` | `#bab3fe` / `#bab3fe` | Paleta Lavanda: relleno. Reemplaza a accent con data-accent="lavanda". | | `pal-lavanda-deep` | `--pal-lavanda-deep` | `#252142` / `#252142` | Paleta Lavanda: texto sobre el relleno. Reemplaza a on-accent con data-accent="lavanda". | | `pal-lavanda-ink` | `--pal-lavanda-ink` | `#6152ad` / `#c7c2ff` | Paleta Lavanda: texto en color. Reemplaza a accent-ink con data-accent="lavanda". | | `pal-lavanda-word` | `--pal-lavanda-word` | `#8979e6` / `#bab3fe` | Paleta Lavanda: palabra de título. Reemplaza a accent-word con data-accent="lavanda". | | `pal-lavanda-soft` | `--pal-lavanda-soft` | `#efeeff` / `#171627` | Paleta Lavanda: fondo suave. Reemplaza a accent-soft con data-accent="lavanda". | | `pal-lavanda-line` | `--pal-lavanda-line` | `#cecbf7` / `#3c375d` | Paleta Lavanda: filete. Reemplaza a accent-line con data-accent="lavanda". | | `pal-lavanda-2` | `--pal-lavanda-2` | `#f2c1f3` / `#f2c1f3` | Paleta Lavanda: tono vecino. Reemplaza a accent-2 con data-accent="lavanda". | | `pal-orquidea-fill` | `--pal-orquidea-fill` | `#eaa3d5` / `#eaa3d5` | Paleta Orquídea: relleno. Reemplaza a accent con data-accent="orquidea". | | `pal-orquidea-deep` | `--pal-orquidea-deep` | `#391a31` / `#391a31` | Paleta Orquídea: texto sobre el relleno. Reemplaza a on-accent con data-accent="orquidea". | | `pal-orquidea-ink` | `--pal-orquidea-ink` | `#933e7f` / `#f2b4df` | Paleta Orquídea: texto en color. Reemplaza a accent-ink con data-accent="orquidea". | | `pal-orquidea-word` | `--pal-orquidea-word` | `#c861ad` / `#eaa3d5` | Paleta Orquídea: palabra de título. Reemplaza a accent-word con data-accent="orquidea". | | `pal-orquidea-soft` | `--pal-orquidea-soft` | `#fee9f7` / `#23121e` | Paleta Orquídea: fondo suave. Reemplaza a accent-soft con data-accent="orquidea". | | `pal-orquidea-line` | `--pal-orquidea-line` | `#ecc2df` / `#532f49` | Paleta Orquídea: filete. Reemplaza a accent-line con data-accent="orquidea". | | `pal-orquidea-2` | `--pal-orquidea-2` | `#fec2c5` / `#fec2c5` | Paleta Orquídea: tono vecino. Reemplaza a accent-2 con data-accent="orquidea". | | `pal-grafito-fill` | `--pal-grafito-fill` | `#26262b` / `#ececf0` | Paleta Grafito: relleno. Reemplaza a accent con data-accent="grafito". | | `pal-grafito-deep` | `--pal-grafito-deep` | `#ffffff` / `#1a1a1e` | Paleta Grafito: texto sobre el relleno. Reemplaza a on-accent con data-accent="grafito". | | `pal-grafito-ink` | `--pal-grafito-ink` | `#26262b` / `#ececf0` | Paleta Grafito: texto en color. Reemplaza a accent-ink con data-accent="grafito". | | `pal-grafito-word` | `--pal-grafito-word` | `#8a8a94` / `#a3a3ad` | Paleta Grafito: palabra de título. Reemplaza a accent-word con data-accent="grafito". | | `pal-grafito-soft` | `--pal-grafito-soft` | `#ececf0` / `#1d1d21` | Paleta Grafito: fondo suave. Reemplaza a accent-soft con data-accent="grafito". | | `pal-grafito-line` | `--pal-grafito-line` | `#c6c6cf` / `#3a3a42` | Paleta Grafito: filete. Reemplaza a accent-line con data-accent="grafito". | | `pal-grafito-2` | `--pal-grafito-2` | `#b9b9c6` / `#5a5a66` | Paleta Grafito: tono vecino. Reemplaza a accent-2 con data-accent="grafito". | | `danger` | `--danger` | `#c51f1c` / `#ff9689` | Error, ausencia y stock bajo el mínimo. Como texto, sobre surface y danger-soft. Más saturado que Coral para no confundirse con la marca. | | `danger-soft` | `--danger-soft` | `#ffebe8` / `#300f0b` | Fondo de la cita con ausencia y del chip de error. | | `warning` | `--warning` | `#865900` / `#ebc166` | Algo que pide atención hoy: cliente que llegó y espera, stock cerca del mínimo. | | `warning-soft` | `--warning-soft` | `#feefcf` / `#241900` | Fondo de la cita cuyo cliente ya llegó y del chip de aviso. | | `success` | `--success` | `#0b7643` / `#80dba2` | Terminado y en nivel. Solo comunica estado. | | `success-soft` | `--success-soft` | `#dff8e6` / `#062111` | Fondo del chip de éxito y del aviso de proceso cerrado. | | `hatch` | `--hatch` | `#e6e6ec` / `#1b1b1f` | Trama diagonal: tiempo que no se puede reservar (fuera de horario, descanso, hora ocupada, reposo de un servicio). | | `scrim` | `--scrim` | `rgba(0,0,0,.2)` / `rgba(0,0,0,.72)` | Velo detrás de diálogos y hojas. | | `toast-bg` | `--toast-bg` | `#000000` / `#222226` | Fondo del aviso breve. En oscuro es un gris, no blanco: sería lo más brillante de la pantalla. | | `toast-ink` | `--toast-ink` | `#ffffff` / `#f2f2f5` | Texto y botón del aviso breve. | | `chart-cat-1` | `--chart-cat-1` | `#2f7fc1` / `#6db8f2` | Gráficos: color de la serie 2 (Azul cielo). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-2` | `--chart-cat-2` | `#12936f` / `#5fd0a6` | Gráficos: color de la serie 3 (Verde menta). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-3` | `--chart-cat-3` | `#c7820f` / `#f0b85a` | Gráficos: color de la serie 4 (Ámbar). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-4` | `--chart-cat-4` | `#6d5bd8` / `#aea3fb` | Gráficos: color de la serie 5 (Lavanda). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-5` | `--chart-cat-5` | `#bd4b95` / `#ee9bd2` | Gráficos: color de la serie 6 (Orquídea). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-6` | `--chart-cat-6` | `#5f6b7d` / `#a5aebb` | Gráficos: color de la serie 7 (Pizarra). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-7` | `--chart-cat-7` | `#788f22` / `#bcd56b` | Gráficos: color de la serie 8 (Oliva). La serie 1 siempre usa accent-word; las demás siguen este orden. | | `chart-cat-reserve` | `--chart-cat-reserve` | `#dc5d63` / `#f48f93` | Color de categoría de reserva: reemplaza al color de categoría que se parece al acento activo (ver chartSwaps). | | `chart-grid` | `--chart-grid` | `rgba(0,0,0,.06)` / `rgba(255,255,255,.07)` | Gráficos: líneas guía del fondo. Más suaves que line para que los datos manden. | | `chart-crosshair` | `--chart-crosshair` | `rgba(0,0,0,.30)` / `rgba(255,255,255,.34)` | Gráficos: línea vertical que sigue al puntero y franja de la categoría en barras. | | `chart-up` | `--chart-up` | `#0f8a55` / `#5fd69b` | Gráficos: valor que sube (vela alcista, aumento en cascada, línea ascendente). Verde propio, distinto de la serie Verde menta. | | `chart-down` | `--chart-down` | `#d23b35` / `#ff8f82` | Gráficos: valor que baja (vela bajista, disminución en cascada, línea descendente). | | `chart-total` | `--chart-total` | `#3e4656` / `#c3cad6` | Gráficos: totales y subtotales de cascada, y valores sin cambio. | ## Spacing | Token | CSS variable | Value | Usage | | --- | --- | --- | --- | | `space-2` | `--space-2` | `2px` | Separación dentro de un control segmentado. | | `space-4` | `--space-4` | `4px` | Margen interior de un bloque de cita. | | `space-6` | `--space-6` | `6px` | Entre icono y texto en un botón o chip. | | `space-8` | `--space-8` | `8px` | Entre botones de una barra de acciones. | | `space-10` | `--space-10` | `10px` | Entre icono y texto en la navegación. | | `space-12` | `--space-12` | `12px` | Relleno vertical de filas y cabeceras de tarjeta. | | `space-14` | `--space-14` | `14px` | Relleno del cuerpo de tarjeta y separación de campos en un formulario. | | `space-16` | `--space-16` | `16px` | Relleno horizontal de tarjetas, filas y celdas; separación entre tarjetas. | | `space-18` | `--space-18` | `18px` | Separación entre bloques de una vista. | | `space-28` | `--space-28` | `28px` | Margen lateral del contenido en escritorio. En móvil baja a space-16. | ## Radius | Token | CSS variable | Value | Usage | | --- | --- | --- | --- | | `radius-xs` | `--radius-xs` | `4px` | Rótulo sobre una trama y tecla. | | `radius-chip` | `--radius-chip` | `6px` | Chip cuadrado de tipo. | | `radius-event` | `--radius-event` | `10px` | Bloque de cita y botón de hora en el panel. | | `radius-control` | `--radius-control` | `12px` | Campos de texto, ítems de navegación y días de la semana. | | `radius-tile` | `--radius-tile` | `12px` | Marca del negocio y botón de usuario. | | `radius-banner` | `--radius-banner` | `14px` | Avisos dentro de la página. | | `radius-card` | `--radius-card` | `16px` | Tarjetas, chips altos de la app y bloques de la línea de tiempo. | | `radius-dialog` | `--radius-dialog` | `20px` | Diálogos del panel. | | `radius-sheet` | `--radius-sheet` | `36px` | Hoja inferior flotante de la app, a 8 px de los bordes. | | `radius-pill` | `--radius-pill` | `999px` | Botones, chips, bandejas y avatares. | ## Shadow | Token | CSS variable | Value | Usage | | --- | --- | --- | --- | | `shadow-flat` | `--shadow-flat` | `0 0 0 .67px rgba(0,0,0,.11),0 1px 2px rgba(0,0,0,.04)` / `0 0 0 1px rgba(255,255,255,.09)` | Tarjetas y botones secundarios: un filete y casi nada de sombra. | | `shadow-hero` | `--shadow-hero` | `0 0 0 .67px rgba(0,0,0,.11),0 4px 18px rgba(0,0,0,.10)` / `0 0 0 1px rgba(255,255,255,.10)` | La única tarjeta elevada de una vista: el cliente actual, o quien sigue en la cola. | | `shadow-cta` | `--shadow-cta` | `0 8px 36px rgba(0,0,0,.065)` / `0 0 0 0 rgba(0,0,0,0)` | Botón principal de 54 px en la app. Gris neutra, nunca teñida del color de marca. | | `shadow-sel` | `--shadow-sel` | `0 2px 8px rgba(0,0,0,.10)` / `0 0 0 0 rgba(0,0,0,0)` | Píldora elegida: día, hora, opción de un control segmentado. | | `shadow-pop` | `--shadow-pop` | `0 0 0 .67px rgba(0,0,0,.11),0 18px 48px -12px rgba(0,0,0,.22)` / `0 0 0 1px rgba(255,255,255,.12)` | Diálogos, hojas, menús y avisos. En oscuro no hay sombras: sobre negro no se ven, y la profundidad va en filetes. | ## Size | Token | CSS variable | Value | Usage | | --- | --- | --- | --- | | `side-width` | `--side-width` | `244px` | Ancho de la barra lateral. | | `top-height` | `--top-height` | `58px` | Alto de la barra superior. | | `control-height` | `--control-height` | `36px` | Alto de botones del panel. | | `control-height-sm` | `--control-height-sm` | `30px` | Alto de botones dentro de filas. | | `input-height` | `--input-height` | `38px` | Alto de campos de texto y de botones de hora. | | `agenda-hour` | `--agenda-hour` | `48px` | Alto de una hora en la agenda del panel. | | `agenda-col` | `--agenda-col` | `148px` | Ancho mínimo de la columna de un profesional. | | `m-button` | `--m-button` | `54px` | Alto del botón principal en la app. | | `m-tray` | `--m-tray` | `52px` | Alto de una bandeja en la app: control segmentado y muestras de color, con relleno interior de 4 px. | | `m-chip` | `--m-chip` | `60px` | Alto de un chip de sugerencia en la app. | | `m-hour` | `--m-hour` | `78px` | Alto de una hora en la línea de tiempo de la app. | ## Typography ### Títulos | Style | Size / line height | Weight | Usage | | --- | --- | --- | --- | | `kpi-number` | `30px / 1.15` | 800 | Cifra de un indicador: citas de hoy, en espera, ítems bajo mínimo. | | `page-title` | `26px / 1.18` | 800 | Título de página del panel. Uno por vista; puede llevar una palabra en accent-word. | | `dialog-title` | `16px / 1.4` | 750 | Título de diálogo y de panel lateral. | | `card-title` | `14px / 1.5` | 700 | Título de tarjeta. | ### Texto | Style | Size / line height | Weight | Usage | | --- | --- | --- | --- | | `lede` | `14.5px / 1.5` | 400 | Frase bajo el título de página, en ink-2. Máximo 68 caracteres por línea. | | `body` | `14px / 1.5` | 400 | Texto base del panel. | | `row-title` | `13.5px / 1.5` | 650 | Nombre del cliente, del servicio o del ítem en filas y tablas. | | `control` | `13px / 1.5` | 650 | Etiqueta de botones. | | `meta` | `12.5px / 1.5` | 400 | Metadatos bajo un título de fila, en ink-3. | | `chip-text` | `12px / 1` | 650 | Texto de chips de estado. | | `overline` | `11px / 1.5` | 700 | Encabezado de tabla y rótulo de grupo en el panel. En mayúsculas y en ink-3. No se usa en la app móvil. | ### Datos | Style | Size / line height | Weight | Usage | | --- | --- | --- | --- | | `clock` | `17px / 1` | 700 | Número del día en la tira de la semana. Cifras tabulares. | | `data` | `12.5px / 1.6` | 600 | Horas, duraciones, cantidades, precios y códigos. Misma familia, con cifras tabulares (clase mono). | | `count` | `11px / 1` | 700 | Contador en navegación y pestañas. | ### App móvil | Style | Size / line height | Weight | Usage | | --- | --- | --- | --- | | `m-title` | `34px / 41px` | 800 | Título de pantalla en la app, con una palabra en accent-word. | | `m-card-title` | `26px / 1.1` | 800 | Nombre del cliente en la tarjeta principal. | | `m-row-title` | `15.5px / 1.3` | 700 | Nombre en un bloque de la línea de tiempo y en filas. | | `m-body` | `15px / 1.45` | 400 | Texto bajo el título de pantalla. | | `m-button` | `15.5px / 1` | 700 | Etiqueta del botón principal de 54 px. | | `m-meta` | `13px / 1.4` | 400 | Segunda línea de un bloque o fila. | ## Style presets Selected with `data-style` on any element. Each preset remaps the style tokens below. | Preset | Attribute | Description | | --- | --- | --- | | Suave | `data-style="soft"` | El estilo por defecto: filetes finos en vez de bordes, sombras mínimas, botones píldora. | | Con bordes | `data-style="bordered"` | Bordes nítidos de 1 px y ninguna sombra. Radios más cerrados. | | Elevado | `data-style="elevated"` | Sombras en capas y ningún borde. En oscuro las superficies se aclaran por nivel. | | Plano | `data-style="flat"` | Sin bordes ni sombras: las tarjetas se separan por un relleno teñido. Los overlays conservan un filete para despegarse de la página. | | Vidrio | `data-style="glass"` | Superficies translúcidas con desenfoque y filetes claros, sobre un fondo de página degradado. | | Brutal | `data-style="brutal"` | Bordes gruesos de tinta, sombras duras desplazadas y esquinas rectas. | ### Style tokens | Token | CSS variable | Default (soft) | Usage | | --- | --- | --- | --- | | `radius-button` | `--radius-button` | `999px` | Botones. Píldora en el estilo suave. | | `radius-input` | `--radius-input` | `12px` | Campos de texto, selects y casillas de hora. | | `radius-badge` | `--radius-badge` | `999px` | Chips y pastillas de estado. | | `radius-avatar` | `--radius-avatar` | `999px` | Avatares. data-radius no lo cambia: un avatar sigue siendo redondo salvo que el estilo diga otra cosa. | | `radius-popover` | `--radius-popover` | `14px` | Menús, popovers y tooltips. | | `border-width-card` | `--border-width-card` | `0px` | Grosor del borde de tarjetas. En suave es 0: el filete va en shadow-card. | | `border-color-card` | `--border-color-card` | `var(--hair)` | Color del borde de tarjetas. | | `border-width-control` | `--border-width-control` | `1px` | Grosor del borde de campos y controles. | | `border-color-control` | `--border-color-control` | `var(--line-control)` | Color del borde de campos y controles. | | `border-width-divider` | `--border-width-divider` | `1px` | Grosor de las líneas divisorias. | | `border-color-divider` | `--border-color-divider` | `var(--line)` | Color de las líneas divisorias. | | `shadow-card` | `--shadow-card` | `var(--shadow-flat)` | Sombra de tarjeta. Va junto a border-card: en suave es el filete de shadow-flat. | | `shadow-raised` | `--shadow-raised` | `var(--shadow-hero)` | Tarjeta elevada. Incluye su propio filete. | | `shadow-overlay` | `--shadow-overlay` | `var(--shadow-pop)` | Diálogos, hojas, menús y popovers. Incluye su propio filete. | | `shadow-control` | `--shadow-control` | `var(--shadow-flat)` | Botón secundario y controles sin borde. | | `shadow-selected` | `--shadow-selected` | `var(--shadow-sel)` | Opción elegida de un control segmentado, día u hora. | | `shadow-inset` | `--shadow-inset` | `inset 0 1px 2px rgba(0,0,0,.06)` / `inset 0 0 0 1px rgba(255,255,255,.05)` | Zona hundida: pista, bandeja. | | `shadow-inset-accent` | `--shadow-inset-accent` | `inset 0 0 0 1px var(--accent-line)` | Filete interior de marca: chip o día destacado. | | `shadow-pinned-start` | `--shadow-pinned-start` | `6px 0 8px -6px rgba(0,0,0,.28)` / `1px 0 0 rgba(255,255,255,.10),6px 0 10px -6px rgba(0,0,0,.9)` | Borde de una columna fijada al inicio de una tabla cuando hay desplazamiento. | | `shadow-pinned-end` | `--shadow-pinned-end` | `-6px 0 8px -6px rgba(0,0,0,.28)` / `-1px 0 0 rgba(255,255,255,.10),-6px 0 10px -6px rgba(0,0,0,.9)` | Borde de una columna fijada al final de una tabla cuando hay desplazamiento. | | `surface-alpha` | `--surface-alpha` | `1` | Opacidad de las superficies (0 a 1). Solo baja en el estilo vidrio. | | `surface-blur` | `--surface-blur` | `0px` | Desenfoque detrás de superficies translúcidas. | | `surface-filter` | `--surface-filter` | `none` | backdrop-filter de tarjetas y overlays. none salvo en vidrio: un filtro activo crea un bloque contenedor. | | `surface-card` | `--surface-card` | `var(--surface)` | Fondo de tarjetas. | | `surface-control` | `--surface-control` | `var(--surface)` | Fondo de campos y botones secundarios. | | `surface-overlay` | `--surface-overlay` | `var(--float)` | Fondo de diálogos, hojas, menús y popovers. | | `surface-sunken` | `--surface-sunken` | `var(--sunken)` | Fondo hundido: pistas, zonas de arrastre. | | `surface-backdrop` | `--surface-backdrop` | `var(--scrim)` | Velo detrás de diálogos y hojas. | | `page-backdrop` | `--page-backdrop` | `none` | Imagen de fondo de la página. Solo el estilo vidrio la usa, para que la translucidez se note. | | `focus-ring-width` | `--focus-ring-width` | `2px` | Grosor del anillo de foco. | | `focus-ring-offset` | `--focus-ring-offset` | `2px` | Separación del anillo de foco. | | `focus-ring-color` | `--focus-ring-color` | `var(--accent-ink)` | Color del anillo de foco. | | `motion-duration` | `--motion-duration` | `180ms` | Duración de transiciones de estado. | | `motion-ease` | `--motion-ease` | `cubic-bezier(.2,.8,.2,1)` | Curva de las transiciones. | | `press-scale` | `--press-scale` | `.97` | Escala de un control al presionarlo. | | `font-scale` | `--font-scale` | `1` | Factor opcional para escalar texto. Ningún token de texto lo usa todavía. | ### Density tokens | Token | CSS variable | Default | Usage | | --- | --- | --- | --- | | `density` | `--density` | `1` | Factor de densidad sin unidad. Lo fija data-density; los altos y rellenos de abajo se multiplican por él. | | `pad-control-x` | `--pad-control-x` | `16px` | Relleno horizontal de botones y campos. | | `pad-card` | `--pad-card` | `16px` | Relleno de tarjetas. | | `gap-density-sm` | `--gap-density-sm` | `8px` | Separación corta entre elementos de un grupo. | | `gap-density` | `--gap-density` | `12px` | Separación entre elementos de una lista o formulario. | | `gap-density-lg` | `--gap-density-lg` | `18px` | Separación entre bloques de una vista. | Density levels (`data-density`): - `data-density="compact"`: Compacta - `data-density="normal"`: Normal - `data-density="comfortable"`: Cómoda Radius levels (`data-radius`): - `data-radius="none"`: Sin radio - `data-radius="sm"`: Pequeño - `data-radius="md"`: Medio - `data-radius="lg"`: Grande - `data-radius="full"`: Completo --- # Attachment > File chip or preview tile for prompt attachments, with an optional remove button. Source: https://ui.jcsoftdev.com/docs/components/attachment File chip or preview tile for prompt attachments, with an optional remove button. ## Import ```ts import { Attachment } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/attachment`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `name` * | `string` | | | | `size` | `string` | | Pre-formatted size, e.g. `240 KB`. | | `previewSrc` | `string` | | Image URL (or object URL). Without it a document icon is shown. | | `status` | `"done" \| "uploading" \| "error"` | `"done"` | | | `progress` | `number` | | 0-100, only for `uploading`. | | `variant` | `"chip" \| "preview"` | `"chip"` | `chip` is one compact line; `preview` is a tile with a larger thumbnail. | | `onRemove` | `(() => void)` | | Shows the remove button. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-attachment--default) - [Uploading](/storybook/?path=/story/ai-attachment--uploading) - [Failed](/storybook/?path=/story/ai-attachment--failed) - [Preview](/storybook/?path=/story/ai-attachment--preview) - [Narrow](/storybook/?path=/story/ai-attachment--narrow) - [Preset Brutal](/storybook/?path=/story/ai-attachment--preset-brutal) ## Source `packages/ui/src/ai/attachment/attachment.tsx` --- # ChainOfThought > Collapsible list of reasoning steps with a status rail. Source: https://ui.jcsoftdev.com/docs/components/chain-of-thought Collapsible list of reasoning steps with a status rail. ## Import ```ts import { ChainOfThought } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/chain-of-thought`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `steps` * | `ThoughtStep[]` | | | | `title` | `string` | `"Razonamiento"` | Header text; while any step is `active` it shimmers. | | `duration` | `string` | | Pre-formatted total time shown in the header, e.g. `4 s`. | | `open` | `boolean` | | | | `defaultOpen` | `boolean` | `false` | | | `onOpenChange` | `((open: boolean) => void)` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-chainofthought--default) - [Thinking](/storybook/?path=/story/ai-chainofthought--thinking) - [Collapsed](/storybook/?path=/story/ai-chainofthought--collapsed) - [Narrow](/storybook/?path=/story/ai-chainofthought--narrow) - [Preset Brutal](/storybook/?path=/story/ai-chainofthought--preset-brutal) ## Source `packages/ui/src/ai/chain-of-thought/chain-of-thought.tsx` --- # ChatList > Sidebar list of conversations grouped by date (Hoy, Ayer, Últimos 7 días…). Source: https://ui.jcsoftdev.com/docs/components/chat-list Sidebar list of conversations grouped by date (Hoy, Ayer, Últimos 7 días…). ## Import ```ts import { ChatList } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/chat-list`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `items` * | `ChatListItem[]` | | | | `activeId` | `string` | | | | `onSelect` | `((id: string) => void)` | | | | `onNew` | `(() => void)` | | | | `onDelete` | `((id: string) => void)` | | Shows a delete button per row. | | `now` | `string \| number \| Date` | | Reference date for the groups; defaults to the current time. Pass it for stable output. | | `label` | `string` | `"Conversaciones"` | Accessible name of the navigation landmark. | | `emptyText` | `string` | `"Aún no hay conversaciones."` | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-chatlist--default) - [Interactive](/storybook/?path=/story/ai-chatlist--interactive) - [Empty](/storybook/?path=/story/ai-chatlist--empty) - [Narrow](/storybook/?path=/story/ai-chatlist--narrow) - [Preset Brutal](/storybook/?path=/story/ai-chatlist--preset-brutal) ## Source `packages/ui/src/ai/chat-list/chat-list.tsx` --- # ChatMessage > One chat turn: avatar, bubble, status, streaming caret and an optional footer slot. Source: https://ui.jcsoftdev.com/docs/components/chat-message One chat turn: avatar, bubble, status, streaming caret and an optional footer slot. ## Import ```ts import { ChatMessage } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/chat-message`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `author` * | `"user" \| "assistant" \| "system"` | | | | `name` | `string` | | Display name, also the avatar's accessible name. | | `avatarSrc` | `string` | | | | `status` | `"done" \| "error" \| "sending" \| "streaming"` | `"done"` | `sending` and `streaming` show activity; `error` shows the failure line. | | `time` | `string` | | Time label shown under the bubble (already formatted). | | `content` | `string` | | Markdown text. Assistant messages render it as Markdown; user and system as plain text. | | `children` | `ReactNode` | | Rich body; replaces `content`. | | `footer` | `ReactNode` | | Slot under the bubble (e.g. MessageActions, sources). | | `errorText` | `string` | `"No se pudo enviar el mensaje."` | Text of the failure line when `status` is `error`. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-chatmessage--default) - [User](/storybook/?path=/story/ai-chatmessage--user) - [System](/storybook/?path=/story/ai-chatmessage--system) - [Streaming](/storybook/?path=/story/ai-chatmessage--streaming) - [Waiting](/storybook/?path=/story/ai-chatmessage--waiting) - [Failed](/storybook/?path=/story/ai-chatmessage--failed) - [With Actions](/storybook/?path=/story/ai-chatmessage--with-actions) - [Narrow](/storybook/?path=/story/ai-chatmessage--narrow) - [Preset Brutal](/storybook/?path=/story/ai-chatmessage--preset-brutal) ## Source `packages/ui/src/ai/chat-message/chat-message.tsx` --- # CodeBlock > Code with a language label, a copy button and a dependency-free syntax highlighter. Source: https://ui.jcsoftdev.com/docs/components/code-block Code with a language label, a copy button and a dependency-free syntax highlighter. ## Import ```ts import { CodeBlock } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/code-block`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `code` * | `string` | | | | `language` | `string` | | `ts`, `js`, `json`, `bash`, `go` or `sql` (aliases like `typescript` work); anything else is plain. | | `filename` | `string` | | Optional file name shown instead of the language label. | | `wrap` | `boolean` | | Wrap long lines instead of scrolling horizontally. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-codeblock--default) - [Narrow](/storybook/?path=/story/ai-codeblock--narrow) - [Json](/storybook/?path=/story/ai-codeblock--json) - [Bash](/storybook/?path=/story/ai-codeblock--bash) - [Go](/storybook/?path=/story/ai-codeblock--go) - [Sql](/storybook/?path=/story/ai-codeblock--sql) - [Preset Brutal](/storybook/?path=/story/ai-codeblock--preset-brutal) ## Source `packages/ui/src/ai/code-block/code-block.tsx` --- # Conversation > Scrollable message log that sticks to the bottom while new content streams in. Source: https://ui.jcsoftdev.com/docs/components/conversation Scrollable message log that sticks to the bottom while new content streams in. Scrolling up pauses the follow behavior and reveals a "jump to latest" button. Fills its parent's height. ## Import ```ts import { Conversation } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/conversation`. ## Usage ```tsx export const Default: Story = { render: (args) => ( ), }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `label` | `string` | `"Conversación"` | Accessible name of the message log. | | `jumpLabel` | `string` | `"Ir al último mensaje"` | Label of the "jump to latest" button. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-conversation--default) - [Growing History](/storybook/?path=/story/ai-conversation--growing-history) - [Narrow](/storybook/?path=/story/ai-conversation--narrow) - [Preset Brutal](/storybook/?path=/story/ai-conversation--preset-brutal) ## Source `packages/ui/src/ai/conversation/conversation.tsx` --- # Loader > Animated waiting indicator. Source: https://ui.jcsoftdev.com/docs/components/loader Animated waiting indicator. With reduced motion the dots stay still. ## Import ```ts import { Loader } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/loader`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | `"dots" \| "typing"` | `"dots"` | `dots` is the bare indicator; `typing` wraps it in a bubble with a label. | | `size` | `"sm" \| "md"` | `"md"` | | | `label` | `string` | `"Escribiendo…"` | Spoken label (`role="status"`); shown as text in the `typing` variant. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-loader--default) - [Typing](/storybook/?path=/story/ai-loader--typing) - [Narrow](/storybook/?path=/story/ai-loader--narrow) - [Preset Brutal](/storybook/?path=/story/ai-loader--preset-brutal) ## Source `packages/ui/src/ai/loader/loader.tsx` --- # Markdown > Safe Markdown renderer: headings, lists, emphasis, inline code, code fences, quotes, tables and links. Source: https://ui.jcsoftdev.com/docs/components/markdown Safe Markdown renderer: headings, lists, emphasis, inline code, code fences, quotes, tables and links. It builds React elements from a parsed AST, so no input ever reaches innerHTML. ## Import ```ts import { Markdown } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/markdown`. ## Usage ```tsx {SAMPLE} ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` * | `string` | | Markdown source. Raw HTML is shown as text; only http, https and mailto links are active. | | `streaming` | `boolean` | | Shows a blinking caret after the last character, for streaming answers. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-markdown--default) - [Narrow](/storybook/?path=/story/ai-markdown--narrow) - [Streaming](/storybook/?path=/story/ai-markdown--streaming) - [Safe By Default](/storybook/?path=/story/ai-markdown--safe-by-default) - [Preset Brutal](/storybook/?path=/story/ai-markdown--preset-brutal) ## Source `packages/ui/src/ai/markdown/markdown.tsx` --- # MessageActions > Copy, regenerate, like and dislike for an assistant message. Source: https://ui.jcsoftdev.com/docs/components/message-actions Copy, regenerate, like and dislike for an assistant message. Feedback toggles off on re-press. ## Import ```ts import { MessageActions } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/message-actions`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `text` * | `string` | | Text copied by the copy button. | | `onCopy` | `((text: string) => void)` | | | | `onRegenerate` | `(() => void)` | | Omit to hide the regenerate button. | | `onFeedback` | `((value: MessageFeedback) => void)` | | Omit to hide the like/dislike buttons. | | `feedback` | `null \| "like" \| "dislike"` | | | | `defaultFeedback` | `null \| "like" \| "dislike"` | `null` | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-messageactions--default) - [Liked](/storybook/?path=/story/ai-messageactions--liked) - [Copy Only](/storybook/?path=/story/ai-messageactions--copy-only) - [Narrow](/storybook/?path=/story/ai-messageactions--narrow) - [Preset Brutal](/storybook/?path=/story/ai-messageactions--preset-brutal) ## Source `packages/ui/src/ai/message-actions/message-actions.tsx` --- # PromptInput > Composer: autosizing textarea, Enter to send, Shift+Enter for a new line, attachments slot and a stop button while a response streams. Source: https://ui.jcsoftdev.com/docs/components/prompt-input Composer: autosizing textarea, Enter to send, Shift+Enter for a new line, attachments slot and a stop button while a response streams. ## Import ```ts import { PromptInput } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/prompt-input`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `string` | | | | `defaultValue` | `string` | `""` | | | `onValueChange` | `((value: string) => void)` | | | | `onSubmit` | `((value: string) => void)` | | Called with the trimmed text on Enter or send. Never called when empty. | | `streaming` | `boolean` | | While true the send button becomes a stop button. | | `onStop` | `(() => void)` | | | | `placeholder` | `string` | `"Escribe un mensaje…"` | | | `label` | `string` | `"Mensaje"` | Accessible name of the textarea. | | `disabled` | `boolean` | | | | `maxRows` | `number` | `6` | Rows after which the textarea scrolls instead of growing. | | `attachments` | `ReactNode` | | Row above the text (Attachment chips). | | `actions` | `ReactNode` | | Left of the send button (attach button, model picker…). | | `hint` | `ReactNode` | | Hint line under the field. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-promptinput--default) - [With Attachments](/storybook/?path=/story/ai-promptinput--with-attachments) - [Streaming](/storybook/?path=/story/ai-promptinput--streaming) - [Echo](/storybook/?path=/story/ai-promptinput--echo) - [Narrow](/storybook/?path=/story/ai-promptinput--narrow) - [Preset Brutal](/storybook/?path=/story/ai-promptinput--preset-brutal) ## Source `packages/ui/src/ai/prompt-input/prompt-input.tsx` --- # PromptSuggestion > Chip with a suggested prompt. Source: https://ui.jcsoftdev.com/docs/components/prompt-suggestion Chip with a suggested prompt. Pressing it hands the text to `onSelect`. ## Import ```ts import { PromptSuggestion } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/prompt-suggestion`. ## Usage ```tsx ¿Qué turnos libres hay mañana? ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `onSelect` | `((text: string) => void)` | | Receives the suggestion text when pressed (the visible label is the text). | | `children` * | `string` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-promptsuggestion--default) - [List](/storybook/?path=/story/ai-promptsuggestion--list) - [Narrow](/storybook/?path=/story/ai-promptsuggestion--narrow) - [Preset Brutal](/storybook/?path=/story/ai-promptsuggestion--preset-brutal) ## Source `packages/ui/src/ai/prompt-suggestion/prompt-suggestion.tsx` --- # PromptSuggestionList > Wrapping group of suggestion chips. Source: https://ui.jcsoftdev.com/docs/components/prompt-suggestion-list Wrapping group of suggestion chips. ## Import ```ts import { PromptSuggestionList } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/prompt-suggestion`. ## Usage ```tsx ¿Qué turnos libres hay mañana? ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `label` | `string` | `"Sugerencias"` | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-promptsuggestion--default) - [List](/storybook/?path=/story/ai-promptsuggestion--list) - [Narrow](/storybook/?path=/story/ai-promptsuggestion--narrow) - [Preset Brutal](/storybook/?path=/story/ai-promptsuggestion--preset-brutal) ## Source `packages/ui/src/ai/prompt-suggestion/prompt-suggestion.tsx` --- # Source > Citation chip with a hover/focus preview of the source (title, host and excerpt). Source: https://ui.jcsoftdev.com/docs/components/source Citation chip with a hover/focus preview of the source (title, host and excerpt). ## Import ```ts import { Source } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/source`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `index` | `number` | | Citation number shown in the chip. | | `title` * | `string` | | | | `url` * | `string` | | Only http(s) and mailto URLs are linked; anything else renders a non-clickable chip. | | `snippet` | `string` | | Short excerpt shown in the hover preview. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/ai-source--default) - [Group](/storybook/?path=/story/ai-source--group) - [Narrow](/storybook/?path=/story/ai-source--narrow) - [Preset Brutal](/storybook/?path=/story/ai-source--preset-brutal) ## Source `packages/ui/src/ai/source/source.tsx` --- # TextShimmer > Text with a light sweep, used for "thinking…" labels. Source: https://ui.jcsoftdev.com/docs/components/text-shimmer Text with a light sweep, used for "thinking…" labels. Static with reduced motion. ## Import ```ts import { TextShimmer } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/text-shimmer`. ## Usage ```tsx Revisando la agenda de hoy… ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` * | `ReactNode` | | | | `as` | `ElementType` | `"span"` | Element to render. | | `duration` | `number` | `2` | Seconds for one sweep. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-textshimmer--default) - [Narrow](/storybook/?path=/story/ai-textshimmer--narrow) - [Preset Brutal](/storybook/?path=/story/ai-textshimmer--preset-brutal) ## Source `packages/ui/src/ai/text-shimmer/text-shimmer.tsx` --- # ToolCall > Collapsible tool invocation with status, JSON arguments and JSON result. Source: https://ui.jcsoftdev.com/docs/components/tool-call Collapsible tool invocation with status, JSON arguments and JSON result. ## Import ```ts import { ToolCall } from "@jcsoftdev/ui/ai"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/ai/tool-call`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `name` * | `string` | | Tool identifier, e.g. `buscar_turnos`. | | `status` | `"done" \| "error" \| "pending" \| "running"` | `"pending"` | | | `args` | `unknown` | | Arguments sent to the tool; shown as formatted JSON. | | `result` | `unknown` | | Result returned by the tool; shown as formatted JSON. | | `error` | `string` | | Error text when `status` is `error`. | | `duration` | `string` | | Pre-formatted duration, e.g. `1,2 s`. | | `defaultOpen` | `boolean` | `false` | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/ai-toolcall--default) - [Running](/storybook/?path=/story/ai-toolcall--running) - [Failed](/storybook/?path=/story/ai-toolcall--failed) - [Narrow](/storybook/?path=/story/ai-toolcall--narrow) - [Preset Brutal](/storybook/?path=/story/ai-toolcall--preset-brutal) ## Source `packages/ui/src/ai/tool-call/tool-call.tsx` --- # Avatar > `Avatar` is part of the Atoms set, imported from `@jcsoftdev/ui/atoms`. Source: https://ui.jcsoftdev.com/docs/components/avatar `Avatar` is part of the Atoms set, imported from `@jcsoftdev/ui/atoms`. ## Import ```ts import { Avatar } from "@jcsoftdev/ui/atoms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/atoms/avatar`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `name` * | `string` | | Full name: used for the initials fallback and as the accessible name. | | `src` | `string` | | | | `size` | `"md" \| "lg"` | `"md"` | | | `highlighted` | `boolean` | | Fills the avatar with the accent color (e.g. the current user). | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/atoms-avatar--default) - [Large](/storybook/?path=/story/atoms-avatar--large) - [Highlighted](/storybook/?path=/story/atoms-avatar--highlighted) - [Single Name](/storybook/?path=/story/atoms-avatar--single-name) - [Team](/storybook/?path=/story/atoms-avatar--team) ## Source `packages/ui/src/atoms/avatar/avatar.tsx` --- # AvatarGroup > Stacked, overlapping avatars separated by a surface-colored ring. Source: https://ui.jcsoftdev.com/docs/components/avatar-group Stacked, overlapping avatars separated by a surface-colored ring. ## Import ```ts import { AvatarGroup } from "@jcsoftdev/ui/atoms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/atoms/avatar-group`. ## Usage ```tsx <> ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` | `ReactNode` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/atoms-avatargroup--default) - [Large](/storybook/?path=/story/atoms-avatargroup--large) - [Single](/storybook/?path=/story/atoms-avatargroup--single) ## Source `packages/ui/src/atoms/avatar-group/avatar-group.tsx` --- # BigDate > Prominent date or number, typically at the top of a card. Source: https://ui.jcsoftdev.com/docs/components/big-date Prominent date or number, typically at the top of a card. ## Import ```ts import { BigDate } from "@jcsoftdev/ui/atoms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/atoms/big-date`. ## Usage ```tsx Mié 8 oct ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | `"normal" \| "compact"` | `"normal"` | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/atoms-bigdate--default) - [Compact](/storybook/?path=/story/atoms-bigdate--compact) - [As Amount](/storybook/?path=/story/atoms-bigdate--as-amount) - [In Card](/storybook/?path=/story/atoms-bigdate--in-card) ## Source `packages/ui/src/atoms/big-date/big-date.tsx` --- # Button > `Button` is part of the Atoms set, imported from `@jcsoftdev/ui/atoms`. Source: https://ui.jcsoftdev.com/docs/components/button `Button` is part of the Atoms set, imported from `@jcsoftdev/ui/atoms`. ## Import ```ts import { Button } from "@jcsoftdev/ui/atoms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/atoms/button`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | `"primary" \| "secondary" \| "ghost" \| "danger"` | `"secondary"` | | | `size` | `"sm" \| "md"` | `"md"` | | | `loading` | `boolean` | | | | `asChild` | `boolean` | | Render the child element (via Radix Slot) instead of a ` ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-pageheader--default) - [Title Only](/storybook/?path=/story/containers-pageheader--title-only) - [Without Actions](/storybook/?path=/story/containers-pageheader--without-actions) - [Narrow](/storybook/?path=/story/containers-pageheader--narrow) ## Source `packages/ui/src/containers/page-header/page-header.tsx` --- # PageHeaderActions > `PageHeaderActions` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/page-header-actions `PageHeaderActions` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { PageHeaderActions } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/page-header`. ## Usage ```tsx <>
Sábado 11 de octubre Agenda de hoy 12 citas con 3 barberos. Quedan 2 horarios libres por la tarde.
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-pageheader--default) - [Title Only](/storybook/?path=/story/containers-pageheader--title-only) - [Without Actions](/storybook/?path=/story/containers-pageheader--without-actions) - [Narrow](/storybook/?path=/story/containers-pageheader--narrow) ## Source `packages/ui/src/containers/page-header/page-header.tsx` --- # PageHeaderEyebrow > `PageHeaderEyebrow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/page-header-eyebrow `PageHeaderEyebrow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { PageHeaderEyebrow } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/page-header`. ## Usage ```tsx <>
Sábado 11 de octubre Agenda de hoy 12 citas con 3 barberos. Quedan 2 horarios libres por la tarde.
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-pageheader--default) - [Title Only](/storybook/?path=/story/containers-pageheader--title-only) - [Without Actions](/storybook/?path=/story/containers-pageheader--without-actions) - [Narrow](/storybook/?path=/story/containers-pageheader--narrow) ## Source `packages/ui/src/containers/page-header/page-header.tsx` --- # PageHeaderLede > `PageHeaderLede` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/page-header-lede `PageHeaderLede` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { PageHeaderLede } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/page-header`. ## Usage ```tsx <>
Sábado 11 de octubre Agenda de hoy 12 citas con 3 barberos. Quedan 2 horarios libres por la tarde.
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-pageheader--default) - [Title Only](/storybook/?path=/story/containers-pageheader--title-only) - [Without Actions](/storybook/?path=/story/containers-pageheader--without-actions) - [Narrow](/storybook/?path=/story/containers-pageheader--narrow) ## Source `packages/ui/src/containers/page-header/page-header.tsx` --- # PageHeaderTitle > Page title. Source: https://ui.jcsoftdev.com/docs/components/page-header-title Page title. Wrap a word in `` to accent it. ## Import ```ts import { PageHeaderTitle } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/page-header`. ## Usage ```tsx <>
Sábado 11 de octubre Agenda de hoy 12 citas con 3 barberos. Quedan 2 horarios libres por la tarde.
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-pageheader--default) - [Title Only](/storybook/?path=/story/containers-pageheader--title-only) - [Without Actions](/storybook/?path=/story/containers-pageheader--without-actions) - [Narrow](/storybook/?path=/story/containers-pageheader--narrow) ## Source `packages/ui/src/containers/page-header/page-header.tsx` --- # ResizableHandle > Draggable and keyboard-resizable separator between two panels. Source: https://ui.jcsoftdev.com/docs/components/resizable-handle Draggable and keyboard-resizable separator between two panels. ## Import ```ts import { ResizableHandle } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/resizable`. ## Usage ```tsx export const Default: Story = { render: () => }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `label` | `string` | | Accessible name; the default describes the two neighbouring panels. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-resizable--default) - [Vertical](/storybook/?path=/story/containers-resizable--vertical) - [Narrow](/storybook/?path=/story/containers-resizable--narrow) - [Brutal Preset](/storybook/?path=/story/containers-resizable--brutal-preset) ## Source `packages/ui/src/containers/resizable/resizable.tsx` --- # ResizablePanel > A panel of a ResizablePanelGroup. Source: https://ui.jcsoftdev.com/docs/components/resizable-panel A panel of a ResizablePanelGroup. Sizes are percentages of the group. ## Import ```ts import { ResizablePanel } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/resizable`. ## Usage ```tsx export const Default: Story = { render: () => }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `defaultSize` | `number` | | Initial size in percent. Panels without one share what is left. | | `minSize` | `number` | | Percent, default 0. | | `maxSize` | `number` | | Percent, default 100. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-resizable--default) - [Vertical](/storybook/?path=/story/containers-resizable--vertical) - [Narrow](/storybook/?path=/story/containers-resizable--narrow) - [Brutal Preset](/storybook/?path=/story/containers-resizable--brutal-preset) ## Source `packages/ui/src/containers/resizable/resizable.tsx` --- # ResizablePanelGroup > Row or column of resizable panels. Source: https://ui.jcsoftdev.com/docs/components/resizable-panel-group Row or column of resizable panels. Put a ResizableHandle between every two panels. ## Import ```ts import { ResizablePanelGroup } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/resizable`. ## Usage ```tsx export const Default: Story = { render: () => }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `direction` | `"horizontal" \| "vertical"` | `"horizontal"` | | | `onLayout` | `((sizes: number[]) => void)` | | Called with the layout in percent after every change. | | `children` * | `ReactNode` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-resizable--default) - [Vertical](/storybook/?path=/story/containers-resizable--vertical) - [Narrow](/storybook/?path=/story/containers-resizable--narrow) - [Brutal Preset](/storybook/?path=/story/containers-resizable--brutal-preset) ## Source `packages/ui/src/containers/resizable/resizable.tsx` --- # Scrolly > Scrollytelling: text steps scroll past while a graphic stays in view and follows the active step. Source: https://ui.jcsoftdev.com/docs/components/scrolly Scrollytelling: text steps scroll past while a graphic stays in view and follows the active step. The active step is the one crossing a trigger line, found with an IntersectionObserver. Wide containers put the graphic beside the steps, narrow ones pin it above them (container queries, so it works inside a card or a dialog too). The text is real content in reading order, so it works with a screen reader and without scrolling effects. ## Import ```ts import { Scrolly } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/scrolly`. ## Usage ```tsx export const Default: Story = { render: (args) => (
), }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `graphic` * | `(state: ScrollyGraphicState) => ReactNode` | | The sticky graphic: receives the active step, e.g. to change the data of a chart. | | `children` * | `ReactNode` | | `ScrollyStep` elements, in reading order. | | `offset` | `number` | `0.5` | Where the trigger line sits in the scroll area: 0 top, 0.5 middle (default), 1 bottom. | | `root` | `HTMLElement \| null` | `null` | Scroll container the steps move in; the page by default. | | `graphicHeight` | `string` | `"min(55svh, 26rem)"` | Height of the sticky graphic, any CSS length. | | `graphicSide` | `"start" \| "end"` | `"end"` | Which side the graphic takes when the container is wide. | | `step` | `number` | | Controlled step; the scroll position decides when omitted. | | `onStepChange` | `((step: number) => void)` | | | | `aria-label` | `string` | | Accessible name of the narrative. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/containers-scrolly--default) - [Narrow](/storybook/?path=/story/containers-scrolly--narrow) - [With Step Indicator](/storybook/?path=/story/containers-scrolly--with-step-indicator) - [Brutal Preset](/storybook/?path=/story/containers-scrolly--brutal-preset) ## Source `packages/ui/src/containers/scrolly/scrolly.tsx` --- # ScrollyStep > One block of the narrative. Source: https://ui.jcsoftdev.com/docs/components/scrolly-step One block of the narrative. Marked `aria-current="step"` and `data-active` while it is the active one. ## Import ```ts import { ScrollyStep } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/scrolly`. ## Usage ```tsx export const Default: Story = { render: (args) => (
), }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `children` * | `ReactNode` | | | | `minHeight` | `string` | `"70svh"` | Minimum height of the step, any CSS length; a tall step gives the reader time with the graphic. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/containers-scrolly--default) - [Narrow](/storybook/?path=/story/containers-scrolly--narrow) - [With Step Indicator](/storybook/?path=/story/containers-scrolly--with-step-indicator) - [Brutal Preset](/storybook/?path=/story/containers-scrolly--brutal-preset) ## Source `packages/ui/src/containers/scrolly/scrolly.tsx` --- # SettingsLayout > Two-column settings grid (side nav + content). Source: https://ui.jcsoftdev.com/docs/components/settings-layout Two-column settings grid (side nav + content). Collapses to one column at 940px or less of the ancestor `@container/page`. ## Import ```ts import { SettingsLayout } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/settings-layout`. ## Usage ```tsx <> Negocio Horarios Servicios Notificaciones

Recordatorios

} /> } />

Cobros

} />
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-settingslayout--default) - [Narrow Page](/storybook/?path=/story/containers-settingslayout--narrow-page) - [Narrow](/storybook/?path=/story/containers-settingslayout--narrow) ## Source `packages/ui/src/containers/settings-layout/settings-layout.tsx` --- # SettingsLayoutMain > Content column: a single stack that becomes a 2-column masonry at 1180px of page width, where each direct child (a card) is not split across columns. Source: https://ui.jcsoftdev.com/docs/components/settings-layout-main Content column: a single stack that becomes a 2-column masonry at 1180px of page width, where each direct child (a card) is not split across columns. ## Import ```ts import { SettingsLayoutMain } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/settings-layout`. ## Usage ```tsx <> Negocio Horarios Servicios Notificaciones

Recordatorios

} /> } />

Cobros

} />
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-settingslayout--default) - [Narrow Page](/storybook/?path=/story/containers-settingslayout--narrow-page) - [Narrow](/storybook/?path=/story/containers-settingslayout--narrow) ## Source `packages/ui/src/containers/settings-layout/settings-layout.tsx` --- # SettingsLayoutNav > Sticky side nav that becomes a scrollable horizontal row on narrow pages. Source: https://ui.jcsoftdev.com/docs/components/settings-layout-nav Sticky side nav that becomes a scrollable horizontal row on narrow pages. ## Import ```ts import { SettingsLayoutNav } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/settings-layout`. ## Usage ```tsx <> Negocio Horarios Servicios Notificaciones

Recordatorios

} /> } />

Cobros

} />
``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-settingslayout--default) - [Narrow Page](/storybook/?path=/story/containers-settingslayout--narrow-page) - [Narrow](/storybook/?path=/story/containers-settingslayout--narrow) ## Source `packages/ui/src/containers/settings-layout/settings-layout.tsx` --- # SettingsLayoutNavItem > `SettingsLayoutNavItem` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/settings-layout-nav-item `SettingsLayoutNavItem` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { SettingsLayoutNavItem } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/settings-layout`. ## Usage ```tsx <> Negocio Horarios Servicios Notificaciones

Recordatorios

} /> } />

Cobros

} />
``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `active` | `boolean` | | Currently visible section. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-settingslayout--default) - [Narrow Page](/storybook/?path=/story/containers-settingslayout--narrow-page) - [Narrow](/storybook/?path=/story/containers-settingslayout--narrow) ## Source `packages/ui/src/containers/settings-layout/settings-layout.tsx` --- # SettingsRow > `SettingsRow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/settings-row `SettingsRow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { SettingsRow } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/settings-row`. ## Usage ```tsx } /> ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `title` * | `ReactNode` | | | | `description` | `ReactNode` | | | | `control` | `ReactNode` | | Control on the right: a switch, a button, etc. | | `titleId` | `string` | | Id for the title element, so the control can reference it with `aria-labelledby`. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-settingsrow--default) - [With Button](/storybook/?path=/story/containers-settingsrow--with-button) - [Without Description](/storybook/?path=/story/containers-settingsrow--without-description) - [Without Control](/storybook/?path=/story/containers-settingsrow--without-control) - [Narrow](/storybook/?path=/story/containers-settingsrow--narrow) ## Source `packages/ui/src/containers/settings-row/settings-row.tsx` --- # Table > Table inside its own horizontal scroll wrapper. Source: https://ui.jcsoftdev.com/docs/components/table Table inside its own horizontal scroll wrapper. Give columns a `columnId` (header and cells) and mark header cells `pinnable` to let the user pin them to the left or right edge: pinned columns stay sticky while the rest scrolls. ## Import ```ts import { Table } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> ProductoSKUStockPrecio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))}
``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `pinnedColumns` | `PinnedColumns` | | Controlled pinned columns (ids of `columnId`). Pair it with `onPinnedColumnsChange`. | | `defaultPinnedColumns` | `PinnedColumns` | | Initial pins when uncontrolled. | | `onPinnedColumnsChange` | `((pinned: { left: string[]; right: string[]; }) => void)` | | | | `pinStorageKey` | `string` | | localStorage key that remembers the user's pins (uncontrolled only). | | `labels` | `Partial` | | Texts of the pin buttons (Spanish by default). | | `wrapperClassName` | `string` | | Classes of the scroll wrapper. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableBody > `TableBody` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/table-body `TableBody` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { TableBody } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableCell > `TableCell` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/table-cell `TableCell` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { TableCell } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `alignRight` | `boolean` | | | | `columnId` | `string` | | Identifies the column so it can be pinned. Use the same id on the header and its cells. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableHead > `TableHead` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/table-head `TableHead` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { TableHead } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableHeaderCell > `TableHeaderCell` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/table-header-cell `TableHeaderCell` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { TableHeaderCell } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `alignRight` | `boolean` | | | | `columnId` | `string` | | Identifies the column so it can be pinned. Use the same id on the header and its cells. | | `pinnable` | `boolean` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableLinkRow > Fully navigable table row: the real link lives in the first cell and, via a stretched link (positioned `` + anchor `::before` at `inset-0`), its click area covers the whole ro… Source: https://ui.jcsoftdev.com/docs/components/table-link-row Fully navigable table row: the real link lives in the first cell and, via a stretched link (positioned `` + anchor `::before` at `inset-0`), its click area covers the whole row without duplicating the link per cell. ## Import ```ts import { TableLinkRow } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `href` * | `string` | | Row destination: rendered as a real `` in the first cell. | | `primary` * | `ReactNode` | | Content of the first cell, wrapped by the anchor. | | `primaryColumnId` | `string` | | `columnId` of the first cell, so that column can be pinned. | | `children` | `ReactNode` | | Additional `` cells of the row. | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # TableRow > `TableRow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. Source: https://ui.jcsoftdev.com/docs/components/table-row `TableRow` is part of the Containers set, imported from `@jcsoftdev/ui/containers`. ## Import ```ts import { TableRow } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/table`. ## Usage ```tsx <> Producto SKU Stock Precio {inventory.map((item) => ( {item.name} {item.low ? Stock bajo : null} {item.sku} {item.stock} {item.price} ))} ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-table--default) - [Link Rows](/storybook/?path=/story/containers-table--link-rows) - [Empty](/storybook/?path=/story/containers-table--empty) - [PinnedColumns](/storybook/?path=/story/containers-table--pinned-left-and-right) - [User Pinning](/storybook/?path=/story/containers-table--user-pinning) - [Controlled Pinning](/storybook/?path=/story/containers-table--controlled-pinning) - [Narrow](/storybook/?path=/story/containers-table--narrow) ## Source `packages/ui/src/containers/table/table.tsx` --- # Timeline > Vertical activity feed: marker rail on the left, grouped by day, newest first by convention. Source: https://ui.jcsoftdev.com/docs/components/timeline Vertical activity feed: marker rail on the left, grouped by day, newest first by convention. ## Import ```ts import { Timeline } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/timeline`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `items` * | `TimelineFeedItem[]` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-timeline--default) - [Ungrouped](/storybook/?path=/story/containers-timeline--ungrouped) - [Narrow](/storybook/?path=/story/containers-timeline--narrow) - [Brutal Preset](/storybook/?path=/story/containers-timeline--brutal-preset) ## Source `packages/ui/src/containers/timeline/timeline.tsx` --- # Toolbar > Row of filters/controls above a table or grid. Source: https://ui.jcsoftdev.com/docs/components/toolbar Row of filters/controls above a table or grid. ## Import ```ts import { Toolbar } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/toolbar`. ## Usage ```tsx <> 12 citas ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-toolbar--default) - [Filters Only](/storybook/?path=/story/containers-toolbar--filters-only) - [Narrow](/storybook/?path=/story/containers-toolbar--narrow) ## Source `packages/ui/src/containers/toolbar/toolbar.tsx` --- # ToolbarRight > Group pushed to the right edge of the toolbar. Source: https://ui.jcsoftdev.com/docs/components/toolbar-right Group pushed to the right edge of the toolbar. ## Import ```ts import { ToolbarRight } from "@jcsoftdev/ui/containers"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/containers/toolbar`. ## Usage ```tsx <> 12 citas ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/containers-toolbar--default) - [Filters Only](/storybook/?path=/story/containers-toolbar--filters-only) - [Narrow](/storybook/?path=/story/containers-toolbar--narrow) ## Source `packages/ui/src/containers/toolbar/toolbar.tsx` --- # AccentPicker > Exclusive swatch picker. Source: https://ui.jcsoftdev.com/docs/components/accent-picker Exclusive swatch picker. Controlled or uncontrolled; the root exposes `data-accent` with the active option so consumers can read it. Applying the value to the document is the consumer's responsibility. ## Import ```ts import { AccentPicker } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/accent-picker`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `options` * | `AccentOption[]` | | | | `value` | `string` | | | | `defaultValue` | `string` | | | | `onValueChange` | `((value: string) => void)` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-accentpicker--default) - [Disabled](/storybook/?path=/story/forms-accentpicker--disabled) - [Controlled](/storybook/?path=/story/forms-accentpicker--controlled) ## Source `packages/ui/src/forms/accent-picker/accent-picker.tsx` --- # CheckboxButtonGroup > Multi-select where each option is a button-like card; native checkboxes underneath. Source: https://ui.jcsoftdev.com/docs/components/checkbox-button-group Multi-select where each option is a button-like card; native checkboxes underneath. ## Import ```ts import { CheckboxButtonGroup } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/checkbox-button-group`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `options` * | `ButtonOption[]` | | | | `value` | `string[]` | | | | `defaultValue` | `string[]` | `[]` | | | `onValueChange` | `((value: string[]) => void)` | | | | `name` | `string` | | Form field name shared by the checkboxes. | | `disabled` | `boolean` | | | | `aria-label` | `string` | | | | `aria-labelledby` | `string` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-checkboxbuttongroup--default) - [Disabled](/storybook/?path=/story/forms-checkboxbuttongroup--disabled) - [Narrow](/storybook/?path=/story/forms-checkboxbuttongroup--narrow) - [Brutal Preset](/storybook/?path=/story/forms-checkboxbuttongroup--brutal-preset) ## Source `packages/ui/src/forms/checkbox-button-group/checkbox-button-group.tsx` --- # Dropzone > `Dropzone` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. Source: https://ui.jcsoftdev.com/docs/components/dropzone `Dropzone` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. ## Import ```ts import { Dropzone } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/dropzone`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `onFiles` * | `(files: File[]) => void` | | | | `onReject` | `((rejections: DropzoneRejection[]) => void)` | | Called with the rejected files; the caller composes the user-facing message. | | `acceptedTypes` | `string[]` | | Accepted MIME types; supports wildcards such as `image/*`. | | `maxSizeBytes` | `number` | | | | `multiple` | `boolean` | `true` | | | `title` * | `string` | | | | `hint` | `string` | | | | `browseLabel` * | `string` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-dropzone--default) - [Single File](/storybook/?path=/story/forms-dropzone--single-file) - [Only Pdf](/storybook/?path=/story/forms-dropzone--only-pdf) - [With Feedback](/storybook/?path=/story/forms-dropzone--with-feedback) - [Narrow](/storybook/?path=/story/forms-dropzone--narrow) ## Source `packages/ui/src/forms/dropzone/dropzone.tsx` --- # EmojiPicker > Emoji panel with search, category tabs and a keyboard-navigable grid (arrows, Home/End; Enter or Space picks). Source: https://ui.jcsoftdev.com/docs/components/emoji-picker Emoji panel with search, category tabs and a keyboard-navigable grid (arrows, Home/End; Enter or Space picks). The panel adapts to its container width and holds no portal, so it works inline or inside a popover. ## Import ```ts import { EmojiPicker } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/emoji-picker`. ## Usage ```tsx export const Default: Story = { render: () => }; ``` _Source of the Storybook story._ ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `onSelect` | `((emoji: string) => void)` | | | | `categories` | `EmojiCategory[]` | `EMOJI_CATEGORIES` | Replaces the built-in dataset (`EMOJI_CATEGORIES`). | | `defaultCategory` | `string` | | Initial category id. | | `searchPlaceholder` | `string` | `"Buscar emoji"` | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-emojipicker--default) - [Narrow](/storybook/?path=/story/forms-emojipicker--narrow) - [Brutal Preset](/storybook/?path=/story/forms-emojipicker--brutal-preset) ## Source `packages/ui/src/forms/emoji-picker/emoji-picker.tsx` --- # EmojiReactionBar > Row of reaction chips plus an "add reaction" button that opens an emoji picker. Source: https://ui.jcsoftdev.com/docs/components/emoji-reaction-bar Row of reaction chips plus an "add reaction" button that opens an emoji picker. ## Import ```ts import { EmojiReactionBar } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/emoji-reaction-button`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `reactions` * | `Reaction[]` | | | | `onReact` | `((emoji: string, reacted: boolean) => void)` | | Called with the emoji and the new reacted state, from a chip or from the picker. | | `container` | `HTMLElement \| null` | | Portal target for the picker; pass an element to keep a scoped `data-style`. | | `addLabel` | `string` | `"Añadir reacción"` | | | `disabled` | `boolean` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-emojireactionbutton--default) - [Reacted](/storybook/?path=/story/forms-emojireactionbutton--reacted) - [With Picker](/storybook/?path=/story/forms-emojireactionbutton--with-picker) - [Narrow](/storybook/?path=/story/forms-emojireactionbutton--narrow) - [Brutal Preset](/storybook/?path=/story/forms-emojireactionbutton--brutal-preset) ## Source `packages/ui/src/forms/emoji-reaction-button/emoji-reaction-button.tsx` --- # EmojiReactionButton > Reaction chip: an emoji with its count, pressed when the current user reacted. Source: https://ui.jcsoftdev.com/docs/components/emoji-reaction-button Reaction chip: an emoji with its count, pressed when the current user reacted. ## Import ```ts import { EmojiReactionButton } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/emoji-reaction-button`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `emoji` * | `string` | | | | `count` * | `number` | | | | `reacted` | `boolean` | `false` | Whether the current user has used this reaction. | | `onToggle` | `((reacted: boolean) => void)` | | | | `disabled` | `boolean` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-emojireactionbutton--default) - [Reacted](/storybook/?path=/story/forms-emojireactionbutton--reacted) - [With Picker](/storybook/?path=/story/forms-emojireactionbutton--with-picker) - [Narrow](/storybook/?path=/story/forms-emojireactionbutton--narrow) - [Brutal Preset](/storybook/?path=/story/forms-emojireactionbutton--brutal-preset) ## Source `packages/ui/src/forms/emoji-reaction-button/emoji-reaction-button.tsx` --- # Field > `Field` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. Source: https://ui.jcsoftdev.com/docs/components/field `Field` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. ## Import ```ts import { Field } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/field`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `label` * | `string` | | | | `hint` | `string` | | | | `error` | `string` | | | | `id` | `string` | | | | `children` * | `ReactElement>` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-field--default) - [With Error](/storybook/?path=/story/forms-field--with-error) - [Hint And Error](/storybook/?path=/story/forms-field--hint-and-error) - [With Select](/storybook/?path=/story/forms-field--with-select) - [With Textarea](/storybook/?path=/story/forms-field--with-textarea) - [Controlled Form](/storybook/?path=/story/forms-field--controlled-form) ## Source `packages/ui/src/forms/field/field.tsx` --- # FormGrid > Grid for pairs of fields. Source: https://ui.jcsoftdev.com/docs/components/form-grid Grid for pairs of fields. One column in a narrow container, two columns from 620px of container width (the wrapper is the size container; the grid keeps `className` and props). ## Import ```ts import { FormGrid } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/form-grid`. ## Usage ```tsx export const Default: Story = { render: (args) => ( ), }; ``` _Source of the Storybook story._ ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-formgrid--default) - [New Appointment](/storybook/?path=/story/forms-formgrid--new-appointment) - [Narrow](/storybook/?path=/story/forms-formgrid--narrow) ## Source `packages/ui/src/forms/form-grid/form-grid.tsx` --- # InlineSelect > Borderless select that reads as part of a sentence or a row ("Repetir cada [semana v]"). Source: https://ui.jcsoftdev.com/docs/components/inline-select Borderless select that reads as part of a sentence or a row ("Repetir cada [semana v]"). Native ` ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-input--default) - [With Value](/storybook/?path=/story/forms-input--with-value) - [Telephone](/storybook/?path=/story/forms-input--telephone) - [Invalid](/storybook/?path=/story/forms-input--invalid) - [Disabled](/storybook/?path=/story/forms-input--disabled) - [Read Only](/storybook/?path=/story/forms-input--read-only) ## Source `packages/ui/src/forms/input/input.tsx` --- # InputIcon > `InputIcon` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. Source: https://ui.jcsoftdev.com/docs/components/input-icon `InputIcon` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. ## Import ```ts import { InputIcon } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/input-icon`. ## Usage ```tsx } placeholder="Buscar cliente o servicio" aria-label="Buscar" /> ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `icon` * | `ReactNode` | | Leading icon element (e.g. a lucide-react icon). | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-inputicon--default) - [Telephone](/storybook/?path=/story/forms-inputicon--telephone) - [Invalid](/storybook/?path=/story/forms-inputicon--invalid) - [Disabled](/storybook/?path=/story/forms-inputicon--disabled) ## Source `packages/ui/src/forms/input-icon/input-icon.tsx` --- # Label > `Label` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. Source: https://ui.jcsoftdev.com/docs/components/label `Label` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. ## Import ```ts import { Label } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/label`. ## Usage ```tsx ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-label--default) - [Servicio](/storybook/?path=/story/forms-label--servicio) ## Source `packages/ui/src/forms/label/label.tsx` --- # NativeSelect > Styled native `` (keeps the system picker on touch devices). It extends the existing `Select` styling with a data-driven `options` API, optgroups, a placeholder and a compact size. ## Import ```ts import { NativeSelect } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/native-select`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `options` | `(NativeSelectOption \| NativeSelectGroup)[]` | | Data-driven alternative to ``. | | `placeholder` | `string` | | Disabled first option shown while nothing is chosen. | | `size` | `"sm" \| "md"` | `"md"` | | | `invalid` | `boolean` | | | `*` marks a required prop. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-nativeselect--default) - [Small](/storybook/?path=/story/forms-nativeselect--small) - [Invalid](/storybook/?path=/story/forms-nativeselect--invalid) - [Narrow](/storybook/?path=/story/forms-nativeselect--narrow) - [Brutal Preset](/storybook/?path=/story/forms-nativeselect--brutal-preset) ## Source `packages/ui/src/forms/native-select/native-select.tsx` --- # NumberStepper > Counter with minus/plus buttons and a typeable value; ArrowUp/ArrowDown step it, Home/End jump. Source: https://ui.jcsoftdev.com/docs/components/number-stepper Counter with minus/plus buttons and a typeable value; ArrowUp/ArrowDown step it, Home/End jump. ## Import ```ts import { NumberStepper } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/number-stepper`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `number` | | | | `defaultValue` | `number` | `0` | | | `onValueChange` | `((value: number) => void)` | | | | `min` | `number` | `Number.NEGATIVE_INFINITY` | | | `max` | `number` | `Number.POSITIVE_INFINITY` | | | `step` | `number` | `1` | | | `disabled` | `boolean` | | | | `unit` | `string` | | Text after the number, e.g. "min" or "unid."; read by screen readers through aria-valuetext. | | `name` | `string` | | | | `aria-label` | `string` | | | | `aria-labelledby` | `string` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-numberstepper--default) - [With Unit](/storybook/?path=/story/forms-numberstepper--with-unit) - [Decimals](/storybook/?path=/story/forms-numberstepper--decimals) - [Disabled](/storybook/?path=/story/forms-numberstepper--disabled) - [Controlled Value](/storybook/?path=/story/forms-numberstepper--controlled-value) - [Narrow](/storybook/?path=/story/forms-numberstepper--narrow) - [Brutal Preset](/storybook/?path=/story/forms-numberstepper--brutal-preset) - [In Shrink Wrap Row](/storybook/?path=/story/forms-numberstepper--in-shrink-wrap-row) ## Source `packages/ui/src/forms/number-stepper/number-stepper.tsx` --- # PinInput > Masked numeric PIN. Source: https://ui.jcsoftdev.com/docs/components/pin-input Masked numeric PIN. `autocomplete` is disabled on purpose so browsers do not mistake it for a one-time code. ## Import ```ts import { PinInput } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/pin-input`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `length` | `number` | `4` | | | `value` | `string` | | | | `defaultValue` | `string` | `""` | | | `onValueChange` | `((value: string) => void)` | | | | `label` | `string` | `"PIN"` | Accessible name of the input. | | `statusLabel` | `((entered: number, length: number) => string)` | `defaultStatusLabel` | Builds the polite live-region announcement. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-pininput--default) - [Six Digits](/storybook/?path=/story/forms-pininput--six-digits) - [Prefilled](/storybook/?path=/story/forms-pininput--prefilled) - [Spanish Status](/storybook/?path=/story/forms-pininput--spanish-status) - [Controlled](/storybook/?path=/story/forms-pininput--controlled) - [Narrow](/storybook/?path=/story/forms-pininput--narrow) ## Source `packages/ui/src/forms/pin-input/pin-input.tsx` --- # RadioButtonGroup > Exclusive choice where each option is a button-like card. Source: https://ui.jcsoftdev.com/docs/components/radio-button-group Exclusive choice where each option is a button-like card. Native radios underneath, so arrow keys, form submission and the `radiogroup` semantics come from the browser. Distinct from `RadioGroup` (dot indicator) and `Segmented` (2-4 compact options). ## Import ```ts import { RadioButtonGroup } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/radio-button-group`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `options` * | `ButtonOption[]` | | | | `value` | `string` | | | | `defaultValue` | `string` | | | | `onValueChange` | `((value: string) => void)` | | | | `name` | `string` | | | | `disabled` | `boolean` | | | | `aria-label` | `string` | | | | `aria-labelledby` | `string` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-radiobuttongroup--default) - [Disabled](/storybook/?path=/story/forms-radiobuttongroup--disabled) - [Narrow](/storybook/?path=/story/forms-radiobuttongroup--narrow) - [Brutal Preset](/storybook/?path=/story/forms-radiobuttongroup--brutal-preset) ## Source `packages/ui/src/forms/radio-button-group/radio-button-group.tsx` --- # Rating > Star rating. Source: https://ui.jcsoftdev.com/docs/components/rating Star rating. Editable ratings are a single `role="slider"` (arrows, Home/End); read-only ones are an `img` with the value as its label. Half values render as a half-filled star. ## Import ```ts import { Rating } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/rating`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `number` | | | | `defaultValue` | `number` | `0` | | | `onValueChange` | `((value: number) => void)` | | | | `max` | `number` | `5` | | | `precision` | `1 \| 0.5` | `1` | 0.5 allows half stars. | | `readOnly` | `boolean` | | | | `disabled` | `boolean` | | | | `size` | `"sm" \| "md" \| "lg"` | `"md"` | | | `showValue` | `boolean` | | Shows the numeric value after the stars. | | `aria-label` | `string` | | | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-rating--default) - [Half Stars](/storybook/?path=/story/forms-rating--half-stars) - [Read Only](/storybook/?path=/story/forms-rating--read-only) - [Sizes](/storybook/?path=/story/forms-rating--sizes) - [Controlled Value](/storybook/?path=/story/forms-rating--controlled-value) - [Narrow](/storybook/?path=/story/forms-rating--narrow) - [Brutal Preset](/storybook/?path=/story/forms-rating--brutal-preset) ## Source `packages/ui/src/forms/rating/rating.tsx` --- # Select > Wraps the native `` (keeps the system picker on mobile) and draws the chevron with an icon. ## Import ```ts import { Select } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/select`. ## Usage ```tsx ``` ## Props This component declares no props of its own. It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers). ## Storybook stories - [Default](/storybook/?path=/story/forms-select--default) - [With Selection](/storybook/?path=/story/forms-select--with-selection) - [Invalid](/storybook/?path=/story/forms-select--invalid) - [Disabled](/storybook/?path=/story/forms-select--disabled) ## Source `packages/ui/src/forms/select/select.tsx` --- # Slider > Single or range slider. Source: https://ui.jcsoftdev.com/docs/components/slider Single or range slider. The value shape decides the mode: a number gives one thumb and a `[from, to]` tuple gives two. Each thumb is a `role="slider"` with arrow, Page and Home/End keys. ## Import ```ts import { Slider } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/slider`. ## Usage ```tsx ``` ## Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | `number \| RangeValue` | | | | `defaultValue` | `number \| RangeValue` | | | | `onValueChange` | `((value: number) => void) \| ((value: RangeValue) => void)` | | | | `min` | `number` | | | | `max` | `number` | | | | `step` | `number` | | | | `pageStep` | `number` | | Step used by PageUp/PageDown. Defaults to 10 steps. | | `minGap` | `number` | | Minimum distance between the two thumbs of a range. | | `disabled` | `boolean` | | | | `marks` | `SliderMark[]` | | Ticks on the track; a `label` renders as a caption under it. | | `showValue` | `boolean` | | Shows the current value above each thumb; it is emphasized while dragged or focused. | | `formatValue` | `((value: number) => string)` | | | | `aria-label` | `string` | | Accessible name; thumbs of a range get "mínimo"/"máximo" appended. | | `aria-labelledby` | `string` | | | | `name` | `string` | | Form field name; a range submits `${name}-min` and `${name}-max`. | | `className` | `string` | | | `*` marks a required prop. ## Storybook stories - [Default](/storybook/?path=/story/forms-slider--default) - [With Marks](/storybook/?path=/story/forms-slider--with-marks) - [Range](/storybook/?path=/story/forms-slider--range) - [Disabled](/storybook/?path=/story/forms-slider--disabled) - [Controlled Value](/storybook/?path=/story/forms-slider--controlled-value) - [Narrow](/storybook/?path=/story/forms-slider--narrow) - [Brutal Preset](/storybook/?path=/story/forms-slider--brutal-preset) ## Source `packages/ui/src/forms/slider/slider.tsx` --- # Textarea > `Textarea` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. Source: https://ui.jcsoftdev.com/docs/components/textarea `Textarea` is part of the Forms set, imported from `@jcsoftdev/ui/forms`. ## Import ```ts import { Textarea } from "@jcsoftdev/ui/forms"; ``` Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/textarea`. ## Usage ```tsx