@astra-kit/ui 1.0.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +14 -3
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/dist/components/button-link.d.ts +15 -0
  5. package/dist/components/button-link.js +70 -0
  6. package/dist/components/button-recipe.d.ts +27 -0
  7. package/dist/components/button-recipe.js +44 -0
  8. package/dist/components/button.d.ts +3 -5
  9. package/dist/components/button.js +1 -25
  10. package/dist/components/empty-state.d.ts +20 -0
  11. package/dist/components/empty-state.js +357 -0
  12. package/dist/components/metric-card.d.ts +22 -0
  13. package/dist/components/metric-card.js +378 -0
  14. package/dist/components/radio-group.d.ts +5 -3
  15. package/dist/components/radio-group.js +88 -85
  16. package/dist/components/stepper.d.ts +39 -0
  17. package/dist/components/stepper.js +693 -0
  18. package/dist/components/timeline.d.ts +51 -0
  19. package/dist/components/timeline.js +1013 -0
  20. package/dist/components/usage-meter.d.ts +39 -0
  21. package/dist/components/usage-meter.js +1093 -0
  22. package/dist/constants/empty-state.d.ts +12 -0
  23. package/dist/constants/empty-state.js +12 -0
  24. package/dist/constants/metric-card.d.ts +12 -0
  25. package/dist/constants/metric-card.js +12 -0
  26. package/dist/constants/stepper.d.ts +52 -0
  27. package/dist/constants/stepper.js +23 -0
  28. package/dist/constants/timeline.d.ts +62 -0
  29. package/dist/constants/timeline.js +31 -0
  30. package/dist/constants/usage-meter.d.ts +100 -0
  31. package/dist/constants/usage-meter.js +38 -0
  32. package/dist/hooks/use-has-entered-view.d.ts +9 -0
  33. package/dist/hooks/use-has-entered-view.js +46 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.js +8 -0
  36. package/dist/motion/arc-odometer.d.ts +53 -0
  37. package/dist/motion/arc-odometer.js +424 -0
  38. package/dist/motion/arc-text-swap.d.ts +22 -0
  39. package/dist/motion/arc-text-swap.js +142 -0
  40. package/dist/motion/arc-tokens.d.ts +1 -0
  41. package/dist/motion/arc-tokens.js +2 -1
  42. package/dist/styles.css +1 -1
  43. package/package.json +31 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,38 @@ Todos los cambios relevantes de `@astra-kit/ui` se documentan en este archivo co
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.2.1] - 2026-10-19
8
+
9
+ ### Fixed
10
+
11
+ - `EmptyState` ya no puede trabar la página en WebKit (Safari y navegadores basados en WebKit, sobre todo en Linux) mientras entra su ícono: la animación de entrada solo anima opacidad y escala, sin desenfoque.
12
+ - `UsageMeter` redondea cada segmento a la precisión de `decimals` antes de calcular todo, así la barra, la insignia, la leyenda y el resumen accesible coinciden (por ejemplo, 200,4 con límite 200 y sin decimales ya no dibuja un excedente que la insignia no muestra).
13
+ - `UsageMeter` acepta un segmento con `id="free"` sin confundirlo con el espacio libre de la leyenda.
14
+ - La leyenda de `UsageMeter` sigue alcanzable con Tab cuando se quitan segmentos después de mover el foco entre sus ítems.
15
+ - La insignia de estado de `UsageMeter` con un texto largo se recorta dentro del ancho del medidor en lugar de desbordarlo.
16
+ - `Stepper` muestra el contorno de foco del teclado en el paso actual al llegar con las flechas o End.
17
+ - `Timeline` etiqueta como "Ayer" el día calendario anterior en la zona horaria elegida, también en los cambios de horario de verano.
18
+ - `Timeline` vuelve a anunciar una actualización nueva aunque su resumen sea igual al anterior.
19
+ - `Timeline` ya no vuelve al principio del historial cuando solo cambia la preferencia de movimiento reducido; solo lo hace ante una actualización nueva.
20
+ - Los números de `MetricCard` y `UsageMeter` se detienen en su valor si se activa el movimiento reducido mientras ruedan.
21
+
22
+ ## [1.2.0] - 2026-10-19
23
+
24
+ ### Added
25
+
26
+ - `UsageMeter`: barra segmentada de cupo (por ejemplo, códigos y avisos enviados hoy contra el límite diario) con total animado, insignia de estado (libre, casi lleno, excedido), leyenda navegable con teclado y anuncios para lectores de pantalla. Todo el copy viene en español y se reemplaza con `freeLabel`, `overLabel` y `messages`; los números usan `locale` (por defecto `es-AR`).
27
+ - `MetricCard`: tarjeta compacta para un número con contexto, con dígitos que ruedan al cambiar y un chip de variación (`change`) que se tiñe según el signo. Acepta `locale` (por defecto `es-AR`).
28
+ - `EmptyState`: estado vacío centrado con ícono, título, descripción y acción opcional; al cambiar el copy, el bloque se ajusta de alto sin saltos.
29
+ - `Timeline`: historial de eventos agrupado por día, del más reciente al más antiguo, con encabezados fijos, filas que se expanden en el lugar, tiempos relativos y anuncios de nuevas actualizaciones. Fechas en `es-AR` por defecto; el copy se reemplaza con `messages`.
30
+ - `Stepper`: indicador de pasos horizontal o vertical, con navegación opcional a pasos completados (`onStepSelect`), estado de error por paso y modo compacto automático en contenedores angostos. Textos de accesibilidad en español, reemplazables con `label`, `completeLabel` y `messages`.
31
+
32
+ ## [1.1.0] - 2026-10-19
33
+
34
+ ### Added
35
+
36
+ - `ButtonLink`: un link con el aspecto de `Button` (`variant` y `size`) que rutea con el adaptador del provider y sigue siendo un enlace, para navegar sin estilos propios en cada app. También se exporta `buttonClassName({ variant, size, className })`, con las mismas clases para otros elementos, como un `<label>` que abre un selector de archivos.
37
+ - `RadioGroup` acepta `hideLabel` (por defecto `false`), como `Select`: la leyenda sigue nombrando el grupo para lectores de pantalla pero no se ve ni ocupa espacio, para layouts que ya muestran su propio título. Ya no hace falta ocultarla con CSS propio.
38
+
7
39
  ## [1.0.0] - 2026-10-18
8
40
 
9
41
  ### Changed
package/README.md CHANGED
@@ -47,7 +47,16 @@ import { Avatar, Button, Calendar, DataTable } from "@astra-kit/ui";
47
47
  <Avatar name="Ana Núñez" src="/ana.jpg" />;
48
48
  ```
49
49
 
50
- Los componentes adoptados de [Arc](https://uiarc.dev) usan la API pública de Arc: `Switch`, `Checkbox`, `RadioGroup`, `Badge`, `Avatar`, `AvatarGroup`, `Skeleton`, `Card`, `Alert`, `Tooltip`, `HoverCard`, `DropdownMenu`, `Select`, `Pagination`, `Calendar` y `Carousel` son componentes cerrados que se configuran por props (`items`, `options`, `members`, `content`, `title`); `Dialog` (`Dialog`, `DialogTrigger`, `DialogContent` con `title` y `description`, `DialogClose`), `Popover` y `Tabs` conservan las partes de Arc. Cada uno suma solo las extensiones que Arc no cubre, con copy en español por defecto, por ejemplo `getHref` en `Pagination`, `trigger` e ítems con `href` en `DropdownMenu`, `onOpenChange` en `HoverCard`, `footer` y el modo `alert` en `Dialog` (reemplaza a `AlertDialog`), `hideLabel` en `Select` y `onSettle` en `Carousel`. La tabla de migración desde `beez-ui` 2.x está en [`docs/history/beez-ui-changelog.md`](https://github.com/guidomodarelli/astra-ui/blob/main/docs/history/beez-ui-changelog.md).
50
+ Los componentes adoptados de [Arc](https://uiarc.dev) usan la API pública de Arc: `Switch`, `Checkbox`, `RadioGroup`, `Badge`, `Avatar`, `AvatarGroup`, `Skeleton`, `Card`, `Alert`, `Tooltip`, `HoverCard`, `DropdownMenu`, `Select`, `Pagination`, `Calendar` y `Carousel` son componentes cerrados que se configuran por props (`items`, `options`, `members`, `content`, `title`); `Dialog` (`Dialog`, `DialogTrigger`, `DialogContent` con `title` y `description`, `DialogClose`), `Popover` y `Tabs` conservan las partes de Arc. Cada uno suma solo las extensiones que Arc no cubre, con copy en español por defecto, por ejemplo `getHref` en `Pagination`, `trigger` e ítems con `href` en `DropdownMenu`, `onOpenChange` en `HoverCard`, `footer` y el modo `alert` en `Dialog` (reemplaza a `AlertDialog`), `hideLabel` en `Select` y `RadioGroup`, y `onSettle` en `Carousel`. Los displays de datos de Arc `UsageMeter`, `MetricCard`, `EmptyState`, `Timeline` y `Stepper` también son cerrados y se configuran por props; sus textos visibles y anunciados vienen en español y se reemplazan con `messages` (y con `freeLabel`/`overLabel`, `label` o `completeLabel` donde Arc ya los define), y `locale` formatea números y fechas (`es-AR` por defecto). La tabla de migración desde `beez-ui` 2.x está en [`docs/history/beez-ui-changelog.md`](https://github.com/guidomodarelli/astra-ui/blob/main/docs/history/beez-ui-changelog.md).
51
+
52
+ `Button` es para acciones y no tiene `asChild`. Una navegación con aspecto de botón es un `ButtonLink`: el `Link` del provider (rutea con el adaptador configurado y sigue siendo un enlace, que se puede abrir en otra pestaña o copiar) con la receta de `Button` y sus `variant` y `size`. Para otro elemento con aspecto de botón, como un `<label>` que abre un selector de archivos, `buttonClassName({ variant, size, className })` devuelve las mismas clases. Ninguno de los dos incluye la presión ni el spinner de `Button`.
53
+
54
+ ```tsx
55
+ import { ButtonLink, buttonClassName } from "@astra-kit/ui";
56
+
57
+ <ButtonLink href="/" variant="secondary">Volver al inicio</ButtonLink>;
58
+ <label className={buttonClassName({ variant: "ghost", size: "sm" })}>Adjuntar<input type="file" hidden /></label>;
59
+ ```
51
60
 
52
61
  Agrupar los imports de componentes desde la raíz. El paquete publica JavaScript ESM y declaraciones TypeScript en `dist`; el consumidor no necesita transpilar el código fuente de la librería. La gramática de filtros y los helpers de mes-año son independientes de React.
53
62
 
@@ -99,8 +108,10 @@ no tiemblan al pasar a `aria-invalid="true"`.
99
108
  a 0.97 (un poco más los de solo ícono y menos los anchos) y vuelven con `snappy`; los
100
109
  disparadores de menús, popovers y diálogos responden solo con color.
101
110
  - `Checkbox`, `RadioGroup`, `Switch`, `Tabs`, `Calendar`, `Carousel`, `Card`, `Avatar`,
102
- `AvatarGroup`, `Badge`, `Alert`, `ActionButton` y `SplitButton` usan el movimiento de sus
103
- componentes de Arc.
111
+ `AvatarGroup`, `Badge`, `Alert`, `ActionButton`, `SplitButton`, `UsageMeter`, `MetricCard`,
112
+ `EmptyState`, `Timeline` y `Stepper` usan el movimiento de sus componentes de Arc. Los
113
+ números de `UsageMeter` y `MetricCard` ruedan como un odómetro y sus segmentos o dígitos
114
+ entran la primera vez que el componente se ve; con movimiento reducido saltan al valor final.
104
115
  - Una `Card` interactiva se eleva 2 px con el borde fuerte y la sombra `--shadow-raised` de
105
116
  Arc al pasar un puntero fino.
106
117
  - `Tooltip`, `Popover` y `HoverCard` se acercan desde su trigger con escala y fundido.
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Arc
6
6
 
7
- The theme tokens (`theme.css`, from Arc's `foundation.css`) and the `Button` API, styles and motion (`src/components/button.tsx`, `src/components/button-label.tsx`, `src/components/control-button.tsx`, `src/motion/arc-press.ts`, `src/motion/arc-tokens.ts`, `src/motion/use-morph-width.ts`), and the `ActionButton` and `SplitButton` components and their label morph (`src/components/action-button.tsx`, `src/components/split-button.tsx`, `src/components/morph-text.tsx`), the `Input` and `Textarea` fields with their animated helper and error rows (`src/components/input.tsx`, `src/components/textarea.tsx`, `src/components/field.tsx`), the `Switch`, `Checkbox` and `RadioGroup` controls (`src/components/switch.tsx`, `src/components/checkbox.tsx`, `src/components/radio-group.tsx`, `src/constants/switch.ts`, `src/constants/checkbox.ts`, `src/constants/radio-group.ts`), the `Badge`, `Avatar`, `AvatarGroup`, `Skeleton`, `Card` and `Alert` displays (`src/components/badge.tsx`, `src/components/avatar.tsx`, `src/components/skeleton.tsx`, `src/components/card.tsx`, `src/components/alert.tsx`, `src/constants/avatar.ts`, `src/constants/card.ts`, `src/constants/alert.ts`), the `Tooltip`, `Popover` and `HoverCard` overlays and their motion (`src/components/tooltip.tsx`, `src/components/popover.tsx`, `src/components/hover-card.tsx`, `src/motion/arc-floating-slot.tsx`, `src/motion/overlay-warmth.ts`, `src/constants/tooltip.ts`, `src/constants/popover.ts`, `src/constants/hover-card.ts`), the `DropdownMenu` and `Select` menus (`src/components/dropdown-menu.tsx`, `src/components/select.tsx`), the `Tabs` and `Pagination` navigation (`src/components/tabs.tsx`, `src/components/pagination.tsx`, `src/constants/tabs.ts`), the `Dialog` surface and its `alert` mode (`src/components/dialog.tsx`, `src/components/dialog-surface.tsx`, `src/constants/dialog.ts`), the `Calendar` and `Carousel` (`src/components/calendar.tsx`, `src/components/carousel.tsx`, `src/constants/calendar.ts`, `src/constants/carousel.ts`, `src/hooks/use-today.ts`), and the internal compositions those public components are built on (`src/components/primitives/`) are adapted from the free Arc library: https://uiarc.dev, https://github.com/kuratlielia/arc-library
7
+ The theme tokens (`theme.css`, from Arc's `foundation.css`) and the `Button` API, styles and motion (`src/components/button.tsx`, `src/components/button-label.tsx`, `src/components/control-button.tsx`, `src/motion/arc-press.ts`, `src/motion/arc-tokens.ts`, `src/motion/use-morph-width.ts`), and the `ActionButton` and `SplitButton` components and their label morph (`src/components/action-button.tsx`, `src/components/split-button.tsx`, `src/components/morph-text.tsx`), the `Input` and `Textarea` fields with their animated helper and error rows (`src/components/input.tsx`, `src/components/textarea.tsx`, `src/components/field.tsx`), the `Switch`, `Checkbox` and `RadioGroup` controls (`src/components/switch.tsx`, `src/components/checkbox.tsx`, `src/components/radio-group.tsx`, `src/constants/switch.ts`, `src/constants/checkbox.ts`, `src/constants/radio-group.ts`), the `Badge`, `Avatar`, `AvatarGroup`, `Skeleton`, `Card` and `Alert` displays (`src/components/badge.tsx`, `src/components/avatar.tsx`, `src/components/skeleton.tsx`, `src/components/card.tsx`, `src/components/alert.tsx`, `src/constants/avatar.ts`, `src/constants/card.ts`, `src/constants/alert.ts`), the `Tooltip`, `Popover` and `HoverCard` overlays and their motion (`src/components/tooltip.tsx`, `src/components/popover.tsx`, `src/components/hover-card.tsx`, `src/motion/arc-floating-slot.tsx`, `src/motion/overlay-warmth.ts`, `src/constants/tooltip.ts`, `src/constants/popover.ts`, `src/constants/hover-card.ts`), the `DropdownMenu` and `Select` menus (`src/components/dropdown-menu.tsx`, `src/components/select.tsx`), the `Tabs` and `Pagination` navigation (`src/components/tabs.tsx`, `src/components/pagination.tsx`, `src/constants/tabs.ts`), the `Dialog` surface and its `alert` mode (`src/components/dialog.tsx`, `src/components/dialog-surface.tsx`, `src/constants/dialog.ts`), the `Calendar` and `Carousel` (`src/components/calendar.tsx`, `src/components/carousel.tsx`, `src/constants/calendar.ts`, `src/constants/carousel.ts`, `src/hooks/use-today.ts`), the `EmptyState`, `MetricCard`, `UsageMeter`, `Timeline` and `Stepper` data displays and their shared text swap and rolling digits (`src/components/empty-state.tsx`, `src/components/metric-card.tsx`, `src/components/usage-meter.tsx`, `src/components/timeline.tsx`, `src/components/stepper.tsx`, `src/constants/empty-state.ts`, `src/constants/metric-card.ts`, `src/constants/usage-meter.ts`, `src/constants/timeline.ts`, `src/constants/stepper.ts`, `src/motion/arc-text-swap.tsx`, `src/motion/arc-odometer.tsx`), and the internal compositions those public components are built on (`src/components/primitives/`) are adapted from the free Arc library: https://uiarc.dev, https://github.com/kuratlielia/arc-library
8
8
 
9
9
  ```
10
10
  MIT License
@@ -0,0 +1,15 @@
1
+ import { type ButtonSize, type ButtonVariant } from "./button-recipe.js";
2
+ import { type LinkProps } from "./link.js";
3
+ export type ButtonLinkProps = LinkProps & {
4
+ /** Visual weight, as in `Button`. Defaults to `primary`. */
5
+ variant?: ButtonVariant;
6
+ /** Height and padding, as in `Button`. Defaults to `md`. */
7
+ size?: ButtonSize;
8
+ };
9
+ /**
10
+ * A link styled as a button, such as "Volver al inicio" on an error page.
11
+ * @param props - Variant, size and every `Link` prop, including `href`, `prefetch` and `component`.
12
+ * @returns The link.
13
+ */
14
+ declare function ButtonLink({ variant, size, className, ...props }: ButtonLinkProps): import("react").JSX.Element;
15
+ export { ButtonLink };
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ /**
4
+ * Navigation that looks like Arc's Button (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): the
5
+ * provider's `Link`, so it routes through the configured adapter, with the button recipe. A link stays a link for
6
+ * assistive technology and the browser (it opens in a new tab, it can be copied), which a `Button` cannot.
7
+ */
8
+ import { cn } from "../lib/utils.js";
9
+ import { buttonClassName } from "./button-recipe.js";
10
+ import { Link } from "./link.js";
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ /**
13
+ * A link styled as a button, such as "Volver al inicio" on an error page.
14
+ * @param props - Variant, size and every `Link` prop, including `href`, `prefetch` and `component`.
15
+ * @returns The link.
16
+ */
17
+ function ButtonLink(t0) {
18
+ const $ = _c(14);
19
+ let className;
20
+ let props;
21
+ let t1;
22
+ let t2;
23
+ if ($[0] !== t0) {
24
+ ({variant: t1, size: t2, className, ...props} = t0);
25
+ $[0] = t0;
26
+ $[1] = className;
27
+ $[2] = props;
28
+ $[3] = t1;
29
+ $[4] = t2;
30
+ } else {
31
+ className = $[1];
32
+ props = $[2];
33
+ t1 = $[3];
34
+ t2 = $[4];
35
+ }
36
+ const variant = t1 === undefined ? "primary" : t1;
37
+ const size = t2 === undefined ? "md" : t2;
38
+ let t3;
39
+ if ($[5] !== className || $[6] !== size || $[7] !== variant) {
40
+ t3 = cn(buttonClassName({
41
+ variant,
42
+ size
43
+ }), className);
44
+ $[5] = className;
45
+ $[6] = size;
46
+ $[7] = variant;
47
+ $[8] = t3;
48
+ } else {
49
+ t3 = $[8];
50
+ }
51
+ let t4;
52
+ if ($[9] !== props || $[10] !== size || $[11] !== t3 || $[12] !== variant) {
53
+ t4 = /* @__PURE__ */ _jsx(Link, {
54
+ "data-slot": "button-link",
55
+ "data-variant": variant,
56
+ "data-size": size,
57
+ ...props,
58
+ className: t3
59
+ });
60
+ $[9] = props;
61
+ $[10] = size;
62
+ $[11] = t3;
63
+ $[12] = variant;
64
+ $[13] = t4;
65
+ } else {
66
+ t4 = $[13];
67
+ }
68
+ return t4;
69
+ }
70
+ export { ButtonLink };
@@ -0,0 +1,27 @@
1
+ /** Visual weight, as in Arc: one primary action per surface. */
2
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
3
+ /** Height and padding, from Arc's control heights. */
4
+ export type ButtonSize = "sm" | "md" | "lg";
5
+ /**
6
+ * Arc's button recipe on its tokens. Press scale is driven by Motion alone, so `transform` never gets a CSS
7
+ * transition, and anchors of floating layers never scale because Radix measures them on pointerdown. Keyboard focus
8
+ * uses the foundation's shared outline; pointer focus draws no ring.
9
+ */
10
+ export declare const buttonVariants: (props?: ({
11
+ variant?: "danger" | "ghost" | "primary" | "secondary" | null | undefined;
12
+ size?: "lg" | "md" | "sm" | null | undefined;
13
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
14
+ /** Options of {@link buttonClassName}. */
15
+ export type ButtonClassNameOptions = {
16
+ variant?: ButtonVariant;
17
+ size?: ButtonSize;
18
+ /** Extra classes merged after the recipe, so they win on conflicts. */
19
+ className?: string;
20
+ };
21
+ /**
22
+ * Arc's button classes for an element that is not a `Button`, such as a `<label>` that opens a file picker. Links
23
+ * use {@link ButtonLink} instead. The press scale and the loading label are effects of `Button` and are not included.
24
+ * @param options - Variant, size and extra classes. Defaults to `primary` and `md`.
25
+ * @returns The class list.
26
+ */
27
+ export declare function buttonClassName({ variant, size, className }?: ButtonClassNameOptions): string;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Arc's Button recipe (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): variants, sizes and the helper
3
+ * that applies them. It has no client directive, so `buttonClassName` also runs in React Server Components; the
4
+ * `Button` and `ButtonLink` components import it from here.
5
+ */
6
+ import { cva } from "class-variance-authority";
7
+ import { cn } from "../lib/utils.js";
8
+ /**
9
+ * Arc's button recipe on its tokens. Press scale is driven by Motion alone, so `transform` never gets a CSS
10
+ * transition, and anchors of floating layers never scale because Radix measures them on pointerdown. Keyboard focus
11
+ * uses the foundation's shared outline; pointer focus draws no ring.
12
+ */
13
+ export const buttonVariants = cva("relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-(--radius-control) border border-transparent px-4 font-sans text-sm leading-(--leading-body) font-medium whitespace-nowrap select-none [-webkit-tap-highlight-color:transparent] transition-[color,background-color,border-color,opacity,box-shadow] duration-(--duration-fast) ease-(--ease-standard) disabled:cursor-not-allowed disabled:opacity-[.52] aria-busy:cursor-progress motion-reduce:transition-none [&:is([aria-haspopup]:not([aria-haspopup=false]),[data-state],[role=combobox])]:transform-none! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
14
+ variants: {
15
+ variant: {
16
+ primary: "border-foreground bg-foreground text-background hover-fine:not-disabled:opacity-[.91] hover-fine:not-disabled:shadow-(--shadow-resting) active:not-disabled:opacity-[.84]",
17
+ secondary: "border-border bg-surface text-foreground hover-fine:not-disabled:bg-surface-muted hover-fine:not-disabled:shadow-(--shadow-resting) active:not-disabled:bg-surface-muted disabled:bg-surface-muted disabled:text-text-muted disabled:opacity-100",
18
+ ghost: "bg-transparent text-text-secondary hover-fine:not-disabled:bg-surface-muted hover-fine:not-disabled:text-foreground active:not-disabled:bg-surface-muted active:not-disabled:text-foreground disabled:text-text-muted disabled:opacity-100",
19
+ danger: "border-border bg-surface text-danger hover-fine:not-disabled:border-danger hover-fine:not-disabled:bg-surface-muted active:not-disabled:border-danger active:not-disabled:bg-surface-muted disabled:bg-surface-muted disabled:text-[color-mix(in_oklab,var(--danger)_55%,var(--surface-muted))] disabled:opacity-100"
20
+ },
21
+ size: {
22
+ sm: "min-h-(--control-height-sm) px-3",
23
+ md: "min-h-(--control-height-md)",
24
+ lg: "min-h-(--control-height-lg) px-5"
25
+ }
26
+ },
27
+ defaultVariants: {
28
+ variant: "primary",
29
+ size: "md"
30
+ }
31
+ });
32
+ /**
33
+ * Arc's button classes for an element that is not a `Button`, such as a `<label>` that opens a file picker. Links
34
+ * use {@link ButtonLink} instead. The press scale and the loading label are effects of `Button` and are not included.
35
+ * @param options - Variant, size and extra classes. Defaults to `primary` and `md`.
36
+ * @returns The class list.
37
+ */
38
+ export function buttonClassName({ variant = "primary", size = "md", className } = {}) {
39
+ return cn(buttonVariants({
40
+ variant,
41
+ size,
42
+ className
43
+ }));
44
+ }
@@ -1,13 +1,10 @@
1
1
  /**
2
2
  * Arc's Button (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): its variants, sizes, tokens and motion,
3
3
  * with width-aware press feedback, a label that springs to its new width and a loading spinner. It renders a native
4
- * button; style links as links instead. Composite components that need icon sizes use the internal `ControlButton`.
4
+ * button: navigation that looks like a button is a `ButtonLink`, and other elements take `buttonClassName`. Composite components that need icon sizes use the internal `ControlButton`.
5
5
  */
6
6
  import type { ComponentProps } from "react";
7
- /** Visual weight, as in Arc: one primary action per surface. */
8
- export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
9
- /** Height and padding, from Arc's control heights. */
10
- export type ButtonSize = "sm" | "md" | "lg";
7
+ import { type ButtonSize, type ButtonVariant } from "./button-recipe.js";
11
8
  export type ButtonProps = ComponentProps<"button"> & {
12
9
  variant?: ButtonVariant;
13
10
  size?: ButtonSize;
@@ -21,3 +18,4 @@ export type ButtonProps = ComponentProps<"button"> & {
21
18
  */
22
19
  declare function Button({ className, variant, size, loading, type, children, ref, ...props }: ButtonProps): import("react").JSX.Element;
23
20
  export { Button };
21
+ export type { ButtonSize, ButtonVariant } from "./button-recipe.js";
@@ -1,39 +1,15 @@
1
1
  "use client";
2
2
  import { c as _c } from "react/compiler-runtime";
3
- import { cva } from "class-variance-authority";
4
3
  import { useIsPresent } from "motion/react";
5
4
  import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
6
5
  import { cn } from "../lib/utils.js";
6
+ import { buttonVariants } from "./button-recipe.js";
7
7
  import { useArcPress } from "../motion/arc-press.js";
8
8
  import { useAttachedElement } from "../motion/use-attached-element.js";
9
9
  import { ButtonLabel } from "./button-label.js";
10
10
  import { LEAVING_ATTRIBUTES, LOADING_INERT_HANDLERS } from "./button-interaction.js";
11
11
  import { jsx as _jsx } from "react/jsx-runtime";
12
12
  /**
13
- * Arc's button recipe on its tokens. Press scale is driven by Motion alone, so `transform` never gets a CSS
14
- * transition, and anchors of floating layers never scale because Radix measures them on pointerdown. Keyboard focus
15
- * uses the foundation's shared outline; pointer focus draws no ring.
16
- */
17
- const buttonVariants = cva("relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-(--radius-control) border border-transparent px-4 font-sans text-sm leading-(--leading-body) font-medium whitespace-nowrap select-none [-webkit-tap-highlight-color:transparent] transition-[color,background-color,border-color,opacity,box-shadow] duration-(--duration-fast) ease-(--ease-standard) disabled:cursor-not-allowed disabled:opacity-[.52] aria-busy:cursor-progress motion-reduce:transition-none [&:is([aria-haspopup]:not([aria-haspopup=false]),[data-state],[role=combobox])]:transform-none! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
18
- variants: {
19
- variant: {
20
- primary: "border-foreground bg-foreground text-background hover-fine:not-disabled:opacity-[.91] hover-fine:not-disabled:shadow-(--shadow-resting) active:not-disabled:opacity-[.84]",
21
- secondary: "border-border bg-surface text-foreground hover-fine:not-disabled:bg-surface-muted hover-fine:not-disabled:shadow-(--shadow-resting) active:not-disabled:bg-surface-muted disabled:bg-surface-muted disabled:text-text-muted disabled:opacity-100",
22
- ghost: "bg-transparent text-text-secondary hover-fine:not-disabled:bg-surface-muted hover-fine:not-disabled:text-foreground active:not-disabled:bg-surface-muted active:not-disabled:text-foreground disabled:text-text-muted disabled:opacity-100",
23
- danger: "border-border bg-surface text-danger hover-fine:not-disabled:border-danger hover-fine:not-disabled:bg-surface-muted active:not-disabled:border-danger active:not-disabled:bg-surface-muted disabled:bg-surface-muted disabled:text-[color-mix(in_oklab,var(--danger)_55%,var(--surface-muted))] disabled:opacity-100"
24
- },
25
- size: {
26
- sm: "min-h-(--control-height-sm) px-3",
27
- md: "min-h-(--control-height-md)",
28
- lg: "min-h-(--control-height-lg) px-5"
29
- }
30
- },
31
- defaultVariants: {
32
- variant: "primary",
33
- size: "md"
34
- }
35
- });
36
- /**
37
13
  * A single action on a page, form or dialog. Defaults to `type="button"`, so it only submits a form when asked to.
38
14
  * @param props - Variant, size, loading state and native button attributes, including `ref`.
39
15
  * @returns The native button.
@@ -0,0 +1,20 @@
1
+ import type { ComponentProps, ReactNode } from "react";
2
+ export type EmptyStateProps = Omit<ComponentProps<"section">, "title" | "children"> & {
3
+ /** Headline. A new title rises in while the old one leaves. */
4
+ title: string;
5
+ /** One or two sentences on why it is empty and what to do. */
6
+ description: string;
7
+ /** Call to action, usually a button. */
8
+ action?: ReactNode;
9
+ /** Leading icon; defaults to a folder. A different icon component crossfades in. */
10
+ icon?: ReactNode;
11
+ /** Accessible name of the section region. */
12
+ label?: string;
13
+ };
14
+ /**
15
+ * A centered placeholder for empty views with an icon, a title, a description and an optional action.
16
+ * @param props - Copy, icon, action, accessible name and native section attributes.
17
+ * @returns The empty state section.
18
+ */
19
+ declare function EmptyState({ title, description, action, icon, label, className, ...props }: EmptyStateProps): import("react").JSX.Element;
20
+ export { EmptyState };