@schumann-dev/ui 0.12.0

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 (48) hide show
  1. package/README.md +144 -0
  2. package/dist/atoms/Avatar/Avatar.d.ts +12 -0
  3. package/dist/atoms/Badge/Badge.d.ts +11 -0
  4. package/dist/atoms/Button/Button.d.ts +14 -0
  5. package/dist/atoms/Heading/Heading.d.ts +8 -0
  6. package/dist/atoms/Icon/Icon.d.ts +30 -0
  7. package/dist/atoms/IconButton/IconButton.d.ts +10 -0
  8. package/dist/atoms/Input/Input.d.ts +11 -0
  9. package/dist/atoms/Label/Label.d.ts +5 -0
  10. package/dist/atoms/ProgressBar/ProgressBar.d.ts +16 -0
  11. package/dist/atoms/Skeleton/Skeleton.d.ts +10 -0
  12. package/dist/atoms/Spinner/Spinner.d.ts +8 -0
  13. package/dist/atoms/Switch/Switch.d.ts +11 -0
  14. package/dist/atoms/Text/Text.d.ts +16 -0
  15. package/dist/chunks/Icon-xe35IPZg.js +141 -0
  16. package/dist/hooks/useControllableState.d.ts +8 -0
  17. package/dist/hooks/useFormField.d.ts +9 -0
  18. package/dist/icons/lucide.d.ts +1 -0
  19. package/dist/icons.js +16 -0
  20. package/dist/index.d.ts +72 -0
  21. package/dist/index.js +1814 -0
  22. package/dist/molecules/ColorPicker/ColorPicker.d.ts +19 -0
  23. package/dist/molecules/Combobox/Combobox.d.ts +18 -0
  24. package/dist/molecules/DateTimeInput/DateTimeInput.d.ts +10 -0
  25. package/dist/molecules/EmptyState/EmptyState.d.ts +14 -0
  26. package/dist/molecules/FormField/FormField.d.ts +16 -0
  27. package/dist/molecules/IconPicker/IconPicker.d.ts +17 -0
  28. package/dist/molecules/MoneyInput/MoneyInput.d.ts +12 -0
  29. package/dist/molecules/MonthPicker/MonthPicker.d.ts +20 -0
  30. package/dist/molecules/MultiSelect/MultiSelect.d.ts +21 -0
  31. package/dist/molecules/SegmentedControl/SegmentedControl.d.ts +19 -0
  32. package/dist/molecules/StatCard/StatCard.d.ts +18 -0
  33. package/dist/molecules/SwitchCard/SwitchCard.d.ts +11 -0
  34. package/dist/molecules/Tooltip/Tooltip.d.ts +17 -0
  35. package/dist/organisms/Card/Card.d.ts +18 -0
  36. package/dist/organisms/ConfirmModal/ConfirmModal.d.ts +19 -0
  37. package/dist/organisms/DataTable/DataTable.d.ts +41 -0
  38. package/dist/organisms/Menu/Menu.d.ts +24 -0
  39. package/dist/organisms/Modal/Modal.d.ts +30 -0
  40. package/dist/styles.css +1 -0
  41. package/dist/templates/AppShell/AppShell.d.ts +38 -0
  42. package/dist/templates/PageContainer/PageContainer.d.ts +7 -0
  43. package/dist/templates/PageHeader/PageHeader.d.ts +14 -0
  44. package/dist/utils/color.d.ts +10 -0
  45. package/dist/utils/cx.d.ts +3 -0
  46. package/dist/utils/dom.d.ts +19 -0
  47. package/dist/utils/text.d.ts +2 -0
  48. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Schumann.ui
2
+
3
+ Biblioteca de componentes React **dark-first**, orientada a tokens, extraída do design system do FinTrackr e desacoplada de qualquer regra de negócio.
4
+
5
+ - **Tipada** (TypeScript) · **acessível** (Radix + ARIA) · **temável** (CSS custom properties) · **tree-shakeable** (ESM + `sideEffects` só em CSS).
6
+ - Documentada e desenvolvida no **Storybook**.
7
+
8
+ ## Instalação
9
+
10
+ ```bash
11
+ npm install @schumann-dev/ui
12
+ # peers (provavelmente já instalados no seu app):
13
+ npm install react react-dom
14
+ ```
15
+
16
+ ## Uso
17
+
18
+ Importe os componentes e **o stylesheet uma única vez** (na raiz do app):
19
+
20
+ ```tsx
21
+ import '@schumann-dev/ui/styles.css';
22
+ import { Button, Card, Input } from '@schumann-dev/ui';
23
+
24
+ export function Exemplo() {
25
+ return (
26
+ <Card>
27
+ <Card.Header>
28
+ <Card.Title>Resumo</Card.Title>
29
+ </Card.Header>
30
+ <Card.Content>
31
+ <Input placeholder="Buscar..." />
32
+ </Card.Content>
33
+ <Card.Footer>
34
+ <Button variant="primary">Salvar</Button>
35
+ </Card.Footer>
36
+ </Card>
37
+ );
38
+ }
39
+ ```
40
+
41
+ ## Temas
42
+
43
+ O tema **dark é o padrão**. Para trocar, defina `data-theme` no `<html>`:
44
+
45
+ ```html
46
+ <html data-theme="light"> … </html>
47
+ ```
48
+
49
+ Customização pontual = redefinir a CSS var num escopo:
50
+
51
+ ```css
52
+ .minha-area { --interactive-primary: #0ea5e9; }
53
+ ```
54
+
55
+ Os componentes aceitam `className` e `style`, permitindo sobrescrita controlada sem alterar a biblioteca.
56
+
57
+ ## Tipografia
58
+
59
+ A fonte padrão é **Roboto**. A lib **não embute fontes** (responsabilidade do app) — carregue a família com os pesos que o DS usa (400/500/600/700/800):
60
+
61
+ ```html
62
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
63
+ ```
64
+
65
+ A família é o token `--font-sans`. Para trocar por outra fonte, sobrescreva a variável:
66
+
67
+ ```css
68
+ :root { --font-sans: 'Inter', system-ui, sans-serif; }
69
+ ```
70
+
71
+ (O mono `--font-mono` — JetBrains Mono, usado em valores/códigos — segue o mesmo princípio.)
72
+
73
+ ## Ícones (~2.000)
74
+
75
+ O set base do DS vem embutido. Para o set **Lucide completo** (~2.000 ícones, ISC), importe o entry opt-in uma vez no bootstrap do app:
76
+
77
+ ```tsx
78
+ import '@schumann-dev/ui/icons'; // registra tudo (~100 kB gzip — só quem importa paga)
79
+
80
+ <Icon name="rocket" /> // qualquer nome kebab-case do Lucide
81
+ <IconPicker icons={getIconNames()} ... /> // picker com todos + busca
82
+ ```
83
+
84
+ - Os nomes originais do DS (`menu`, `chevDown`, `tag`…) têm precedência e não são sobrescritos.
85
+ - Ícones próprios: `registerIcons({ nome: '<path .../>' })`. Nomes legados: `registerIconAliases({ FiHome: 'home' })`.
86
+ - Precisa de mais? O mesmo mecanismo aceita qualquer set do Iconify (ex.: `@iconify-json/tabler`, ~5.900 ícones).
87
+
88
+ ## Desenvolvimento
89
+
90
+ ```bash
91
+ npm run storybook # ambiente de dev/documentação
92
+ npm run test # Vitest + Testing Library + jest-axe
93
+ npm run build # gera dist/ (ESM + styles.css + .d.ts)
94
+ npm run lint
95
+ ```
96
+
97
+ ## Componentes (v0.2.0)
98
+
99
+ **Atoms:** `Button`, `IconButton`, `Input`, `Text`, `Heading`, `Label`, `Badge`, `Spinner`, `Icon`/`IconBox` (registro extensível via `registerIcons`/`registerIconAliases`), `Avatar`, `Switch`, `Skeleton`, `ProgressBar`.
100
+ **Molecules:** `FormField`, `Combobox`, `MultiSelect`, `SegmentedControl` (pill/card/tab), `SwitchCard`, `MoneyInput`, `DateTimeInput`, `MonthPicker`, `ColorPicker`, `IconPicker` (busca embutida), `StatCard`, `EmptyState`, `Tooltip`.
101
+ **Organisms:** `Card`, `Modal`, `ConfirmModal`, `Menu`, `DataTable`.
102
+ **Templates:** `PageContainer`, `AppShell`, `PageHeader`.
103
+
104
+ ### Mapeamento frontend-v3 → Schumann.ui
105
+
106
+ | App (frontend-v3) | Lib | Observação |
107
+ |---|---|---|
108
+ | `Field` | `FormField` | fiação ARIA automática via contexto |
109
+ | `TextInput` | `Input` | addons via `leftAddon`/`rightAddon` |
110
+ | `MoneyInput` / `DateTimeInput` | idem | moeda configurável; máscara pt-BR |
111
+ | `Select` / `IconSelect` | `Combobox` | um só componente; visual da opção via `leading` (app monta o `AccountLogo`) |
112
+ | `MultiSelect` | `MultiSelect` | igual |
113
+ | `StatusSegment` | `SegmentedControl` (pill) | opções vêm do app |
114
+ | `BucketPick` | `SegmentedControl` (card) | opções 50/30/20 ficam no app |
115
+ | `Toggle` / `ToggleCard` | `Switch` / `SwitchCard` | role="switch" acessível |
116
+ | `ColorSwatches`/`ColorSelect`/`HSVColorPicker` | `ColorPicker` | visual V2 (handoff `ColorPickerV2.dc.html`): swatches + botão de cor personalizada + painel inline hex/rgb; paleta via prop `swatches` |
117
+ | `IconPick` | `IconPicker` | ícones via prop |
118
+ | `Icon`/`IconBox` | idem | aliases legados: `registerIconAliases()` no bootstrap do app |
119
+ | `Avatar` | `Avatar` | app resolve a URL antes (`resolveImageUrl`) |
120
+ | `RowMenu` | `Menu` | ícone por nome ou ReactNode |
121
+ | `DataGrid` | `DataTable` | mesma API; strings via props/`labels` |
122
+ | `Modal`/`ModalHeader` | `Modal` + `Modal.Content` | Radix (focus-trap/ESC) |
123
+ | `ConfirmModal` | `ConfirmModal` | mapa de erros do backend vai em `formatError` |
124
+ | `Shell` (layout) | `AppShell` | nav/slots via props; router/logout ficam no app |
125
+ | stepper de mês do topbar (`Shell`) | `MonthPicker` | mesma pill `‹ mês ›`, agora com painel 4×3 |
126
+ | cabeçalho inline (eyebrow + h1) das páginas | `PageHeader` | 12/12 páginas usavam o mesmo bloco |
127
+ | barra de progresso inline (orçamento/fatura) | `ProgressBar` | limiar de perigo embutido |
128
+ | tiles de resumo do dashboard | `StatCard` | acento por cor via prop |
129
+ | lista/card vazio ("Nenhum…") | `EmptyState` | o DataTable já cobre o caso de tabela |
130
+ | barra de abas inline (Settings/Categorias…) | `SegmentedControl` variante `tab` | sem componente novo |
131
+ | hint `title=` nativo | `Tooltip` | acessível (Radix), hover + teclado |
132
+ | `AccountLogo`, `FamilyCard`, `TransferModal` | — (ficam no app) | domínio; compõem sobre os genéricos |
133
+
134
+ ## Atualização
135
+
136
+ Versionamento por [SemVer](https://semver.org/) com [Changesets](https://github.com/changesets/changesets). Veja o [CHANGELOG](./CHANGELOG.md). Para gravar uma mudança:
137
+
138
+ ```bash
139
+ npx changeset # descreve a mudança + tipo (patch/minor/major)
140
+ ```
141
+
142
+ - **patch** — correção compatível.
143
+ - **minor** — novo componente/variante/prop.
144
+ - **major** — quebra de API ou remoção de prop (props depreciadas emitem `console.warn` por 1 minor antes da remoção).
@@ -0,0 +1,12 @@
1
+ import { CSSProperties } from 'react';
2
+ export interface AvatarProps {
3
+ /** Final image URL (the consumer resolves relative/upload paths). */
4
+ src?: string | null;
5
+ /** Used for the initials fallback. */
6
+ name: string;
7
+ size?: number;
8
+ className?: string;
9
+ style?: CSSProperties;
10
+ }
11
+ /** Round profile picture with initials fallback. */
12
+ export declare function Avatar({ src, name, size, className, style }: AvatarProps): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { HTMLAttributes, ReactNode } from 'react';
2
+ export type BadgeStatus = 'neutral' | 'brand' | 'success' | 'error' | 'warning' | 'info';
3
+ export type BadgeSize = 'sm' | 'md';
4
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
5
+ status?: BadgeStatus;
6
+ size?: BadgeSize;
7
+ /** Show a leading status dot. */
8
+ dot?: boolean;
9
+ leftIcon?: ReactNode;
10
+ }
11
+ export declare function Badge({ status, size, dot, leftIcon, className, children, ...rest }: BadgeProps): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ export type ButtonVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'ghost';
3
+ export type ButtonSize = 'sm' | 'md' | 'lg';
4
+ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
5
+ variant?: ButtonVariant;
6
+ size?: ButtonSize;
7
+ /** Show a spinner and block interaction. Keeps width stable. */
8
+ loading?: boolean;
9
+ fullWidth?: boolean;
10
+ leftIcon?: ReactNode;
11
+ rightIcon?: ReactNode;
12
+ type?: 'button' | 'submit' | 'reset';
13
+ }
14
+ export declare const Button: import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,8 @@
1
+ import { ElementType, HTMLAttributes } from 'react';
2
+ export type HeadingLevel = 1 | 2 | 3 | 4;
3
+ export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
4
+ /** Semantic + visual level (1 = largest). Override the tag with `as` if needed. */
5
+ level?: HeadingLevel;
6
+ as?: ElementType;
7
+ }
8
+ export declare function Heading({ level, as, className, ...rest }: HeadingProps): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ /** True when `value` looks like an image URL/data URI rather than an icon name. */
3
+ export declare function isImageIconSource(value?: string | null): boolean;
4
+ export declare const ICON_PATHS: Record<string, string>;
5
+ /** Extend the icon set with app-specific paths (same `<path/>` inner-SVG format). */
6
+ export declare function registerIcons(paths: Record<string, string>): void;
7
+ /** Map app-specific/legacy names onto existing icons (e.g. "FiHome" → "home"). */
8
+ export declare function registerIconAliases(aliases: Record<string, string>): void;
9
+ /** All currently registered icon names (grows when `@schumann/ui/icons` is imported). */
10
+ export declare function getIconNames(): string[];
11
+ export interface IconProps {
12
+ /** Icon name from the registry — or an image URL/data URI, rendered as an <img>. */
13
+ name: string;
14
+ size?: number;
15
+ color?: string;
16
+ strokeWidth?: number;
17
+ className?: string;
18
+ style?: CSSProperties;
19
+ }
20
+ export declare function Icon({ name, size, color, strokeWidth, className, style, }: IconProps): import("react").JSX.Element;
21
+ export interface IconBoxProps {
22
+ size: number;
23
+ radius: number;
24
+ bg: string;
25
+ className?: string;
26
+ style?: CSSProperties;
27
+ children: ReactNode;
28
+ }
29
+ /** Colored rounded box wrapping an icon — the DS "icon chip". */
30
+ export declare function IconBox({ size, radius, bg, className, style, children }: IconBoxProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
3
+ /** Obrigatório: botões só-ícone precisam de nome acessível. */
4
+ 'aria-label': string;
5
+ variant?: 'ghost' | 'outline' | 'primary';
6
+ size?: 'sm' | 'md' | 'lg';
7
+ shape?: 'circle' | 'square';
8
+ children: ReactNode;
9
+ }
10
+ export declare const IconButton: import('react').ForwardRefExoticComponent<IconButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,11 @@
1
+ import { InputHTMLAttributes, ReactNode } from 'react';
2
+ export type InputSize = 'sm' | 'md' | 'lg';
3
+ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
4
+ inputSize?: InputSize;
5
+ invalid?: boolean;
6
+ /** Adornment rendered inside the field, before the text (e.g. "R$" or an icon). */
7
+ leftAddon?: ReactNode;
8
+ /** Adornment rendered inside the field, after the text. */
9
+ rightAddon?: ReactNode;
10
+ }
11
+ export declare const Input: import('react').ForwardRefExoticComponent<InputProps & import('react').RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,5 @@
1
+ import { LabelHTMLAttributes } from 'react';
2
+ export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
3
+ required?: boolean;
4
+ }
5
+ export declare function Label({ required, className, children, ...rest }: LabelProps): import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ export interface ProgressBarProps {
2
+ /** 0–1 (fração) ou 0–100 quando `max` é fornecido. */
3
+ value: number;
4
+ max?: number;
5
+ /** Cor do preenchimento. Default: brand. */
6
+ color?: string;
7
+ /** Cor do preenchimento quando `value/max` passa de `dangerThreshold`. */
8
+ dangerColor?: string;
9
+ /** Fração (0–1) a partir da qual usa `dangerColor`. Default 0.85. */
10
+ dangerThreshold?: number;
11
+ height?: number;
12
+ label?: string;
13
+ className?: string;
14
+ }
15
+ /** Barra de progresso fina. Vira `dangerColor` quando passa do limiar (uso: orçamentos, faturas). */
16
+ export declare function ProgressBar({ value, max, color, dangerColor, dangerThreshold, height, label, className, }: ProgressBarProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { CSSProperties } from 'react';
2
+ export interface SkeletonProps {
3
+ width?: number | string;
4
+ height?: number | string;
5
+ radius?: number | string;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /** Shimmer de carregamento. */
10
+ export declare function Skeleton({ width, height, radius, className, style }: SkeletonProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ export interface SpinnerProps {
2
+ /** Diameter in px. */
3
+ size?: number;
4
+ /** Accessible label; omit to hide from the accessibility tree (decorative). */
5
+ label?: string;
6
+ className?: string;
7
+ }
8
+ export declare function Spinner({ size, label, className }: SpinnerProps): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ export interface SwitchProps {
2
+ checked?: boolean;
3
+ defaultChecked?: boolean;
4
+ onCheckedChange?: (checked: boolean) => void;
5
+ disabled?: boolean;
6
+ id?: string;
7
+ 'aria-label'?: string;
8
+ className?: string;
9
+ }
10
+ /** Toggle acessível (button role="switch") — controlado ou não-controlado. */
11
+ export declare function Switch({ checked, defaultChecked, onCheckedChange, disabled, id, className, ...rest }: SwitchProps): import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { ElementType, HTMLAttributes } from 'react';
2
+ export type TextSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl';
3
+ export type TextWeight = 'regular' | 'medium' | 'semibold' | 'bold';
4
+ export type TextTone = 'primary' | 'secondary' | 'muted' | 'brand' | 'success' | 'error' | 'warning';
5
+ export interface TextProps extends HTMLAttributes<HTMLElement> {
6
+ as?: ElementType;
7
+ size?: TextSize;
8
+ weight?: TextWeight;
9
+ tone?: TextTone;
10
+ align?: 'start' | 'center' | 'end';
11
+ /** Truncate to a single line with an ellipsis. */
12
+ truncate?: boolean;
13
+ /** Use the monospace/numeric font (tabular figures) — for money and codes. */
14
+ mono?: boolean;
15
+ }
16
+ export declare function Text({ as: Tag, size, weight, tone, align, truncate, mono, className, ...rest }: TextProps): import("react").JSX.Element;
@@ -0,0 +1,141 @@
1
+ import { jsx as M } from "react/jsx-runtime";
2
+ function l(...a) {
3
+ return a.filter(Boolean).join(" ");
4
+ }
5
+ function p(a) {
6
+ if (!a) return !1;
7
+ const h = a.trim();
8
+ return h.startsWith("data:image/") || h.startsWith("blob:") || /^https?:\/\//i.test(h) || h.startsWith("/") || h.startsWith("uploads/");
9
+ }
10
+ const r = {
11
+ menu: '<path d="M3 6h18M3 12h18M3 18h18"/>',
12
+ search: '<circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/>',
13
+ eye: '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/>',
14
+ eyeOff: '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20C5 20 2 12 2 12a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 10 8 10 8a18.5 18.5 0 0 1-2.16 3.19"/><path d="M1 1l22 22"/><path d="M9.5 9.5a3 3 0 0 0 4.24 4.24"/>',
15
+ grid: '<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>',
16
+ list: '<path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/>',
17
+ building: '<path d="M3 21h18M5 21V9l7-4 7 4v12M9 21v-5h6v5"/>',
18
+ tag: '<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/>',
19
+ trending: '<path d="M21 21H4a1 1 0 0 1-1-1V3"/><path d="M7 14l4-4 3 3 5-6"/>',
20
+ repeat: '<path d="M17 1l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 23l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/>',
21
+ user: '<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>',
22
+ users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
23
+ settings: '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>',
24
+ arrowUp: '<path d="M12 19V5M5 12l7-7 7 7"/>',
25
+ arrowDown: '<path d="M12 5v14M5 12l7 7 7-7"/>',
26
+ card: '<rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20"/>',
27
+ utensils: '<path d="M4 3v7a3 3 0 0 0 6 0V3M7 10v11M18 3c-1.5 0-3 1.8-3 5s1.5 4 3 4v9"/>',
28
+ car: '<path d="M5 17h14M6 17l-1-5 2-5h10l2 5-1 5M7 12h10"/><circle cx="7.5" cy="17.5" r="1.5"/><circle cx="16.5" cy="17.5" r="1.5"/>',
29
+ gamepad: '<rect x="2" y="7" width="20" height="11" rx="4"/><path d="M7 12h2m-1-1v2M15.5 12h.01M18 13h.01"/>',
30
+ heart: '<path d="M20.8 5.6a5.5 5.5 0 0 0-7.8 0L12 6.6l-1-1a5.5 5.5 0 0 0-7.8 7.8l1 1L12 22l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8z"/>',
31
+ briefcase: '<path d="M20 7h-4V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2H4a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1zM10 5h4v2h-4z"/>',
32
+ plus: '<path d="M12 5v14M5 12h14"/>',
33
+ minus: '<path d="M5 12h14"/>',
34
+ edit: '<path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4z"/>',
35
+ trash: '<path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2m2 0v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6"/><path d="M10 11v6M14 11v6"/>',
36
+ copy: '<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>',
37
+ check: '<path d="M20 6L9 17l-5-5"/>',
38
+ close: '<path d="M18 6L6 18M6 6l12 12"/>',
39
+ filter: '<path d="M22 3H2l8 9.46V19l4 2v-8.54z"/>',
40
+ chevDown: '<path d="M6 9l6 6 6-6"/>',
41
+ chevUp: '<path d="M18 15l-6-6-6 6"/>',
42
+ archive: '<rect x="3" y="4" width="18" height="4" rx="1"/><path d="M5 8v11a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8"/><path d="M10 12h4"/>',
43
+ gift: '<rect x="3" y="8" width="18" height="4" rx="1"/><path d="M12 8v13M5 12v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-8"/><path d="M12 8S9.5 4 7.5 4a2.5 2.5 0 0 0 0 5M12 8s2.5-4 4.5-4a2.5 2.5 0 0 1 0 5"/>',
44
+ plane: '<path d="M17.8 19.2 16 11l3.5-3.5a2.1 2.1 0 0 0-3-3L13 8 4.8 6.2a1 1 0 0 0-.9 1.7l5.1 3-1.6 3.2-2.6.4a1 1 0 0 0-.6 1.7l3 3 3 3a1 1 0 0 0 1.7-.6l.4-2.6 3.2-1.6a1 1 0 0 0 .3-.3z"/>',
45
+ home: '<path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"/><path d="M9 21v-6h6v6"/>',
46
+ coffee: '<path d="M18 8h1a3 3 0 0 1 0 6h-1"/><path d="M2 8h16v6a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5z"/><path d="M6 2v2M10 2v2M14 2v2"/>',
47
+ book: '<path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 5v14"/>',
48
+ music: '<circle cx="6" cy="18" r="2.5"/><circle cx="17" cy="16" r="2.5"/><path d="M8.5 18V6l11-2v10"/>',
49
+ phone: '<rect x="6" y="2" width="12" height="20" rx="2"/><path d="M11 18h2"/>',
50
+ tool: '<path d="M14.7 6.3a4 4 0 0 0 5 5l-9 9a2.8 2.8 0 0 1-4-4l9-9z"/><path d="M14.7 6.3 18 3l3 3-3.3 3.3"/>',
51
+ pet: '<circle cx="11" cy="4" r="2"/><circle cx="18" cy="8" r="2"/><circle cx="4" cy="8" r="2"/><path d="M8 14c0-2 1.8-4 4-4s4 2 4 4c0 2.5-2 3-4 5-2-2-4-2.5-4-5z"/>',
52
+ shirt: '<path d="M8 2 4 5l2 3 2-1v13h8V7l2 1 2-3-4-3-2 2h-4z"/>',
53
+ fuel: '<path d="M3 22V4a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v18M2 22h13"/><path d="M13 8h3l3 3v7a2 2 0 0 1-4 0V13h-2"/>',
54
+ pill: '<rect x="3" y="9" width="18" height="8" rx="4" transform="rotate(-45 12 13)"/><path d="M9 9l6 6"/>',
55
+ chevLeft: '<path d="M15 18l-6-6 6-6"/>',
56
+ chevRight: '<path d="M9 18l6-6-6-6"/>',
57
+ dots: '<circle cx="5" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/>',
58
+ dotsV: '<circle cx="12" cy="5" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="12" cy="19" r="1.6"/>',
59
+ download: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/>',
60
+ calendar: '<rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/>',
61
+ alert: '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4M12 17h.01"/>',
62
+ info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8h.01"/>',
63
+ bell: '<path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>',
64
+ target: '<circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/>',
65
+ wallet: '<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h3v-4z"/>',
66
+ logout: '<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5M21 12H9"/>',
67
+ lock: '<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
68
+ mail: '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="M22 6l-10 7L2 6"/>',
69
+ external: '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14L21 3"/>',
70
+ shopping: '<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/>',
71
+ dollar: '<path d="M12 1v22"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>',
72
+ sparkles: '<path d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z"/>',
73
+ pause: '<rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/>',
74
+ play: '<path d="M6 3l15 9-15 9V3z"/>',
75
+ star: '<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.86L12 17.77 5.82 21 7 14.14l-5-4.87 6.91-1.01z"/>',
76
+ smile: '<circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01"/>',
77
+ percent: '<path d="M19 5L5 19"/><circle cx="6.5" cy="6.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/>',
78
+ shield: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>',
79
+ cart: '<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>',
80
+ lifebuoy: '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="4"/><path d="M4.93 4.93l4.24 4.24M14.83 14.83l4.24 4.24M14.83 9.17l4.24-4.24M4.93 19.07l4.24-4.24"/>'
81
+ }, i = {};
82
+ function x(a) {
83
+ Object.assign(r, a);
84
+ }
85
+ function o(a) {
86
+ Object.assign(i, a);
87
+ }
88
+ function v() {
89
+ return Object.keys(r);
90
+ }
91
+ function n({
92
+ name: a,
93
+ size: h = 16,
94
+ color: e = "currentColor",
95
+ strokeWidth: d = 2,
96
+ className: t,
97
+ style: c
98
+ }) {
99
+ return p(a) ? /* @__PURE__ */ M(
100
+ "img",
101
+ {
102
+ src: a,
103
+ alt: "",
104
+ width: h,
105
+ height: h,
106
+ className: l("sui-icon-img", t),
107
+ style: c
108
+ }
109
+ ) : /* @__PURE__ */ M(
110
+ "svg",
111
+ {
112
+ viewBox: "0 0 24 24",
113
+ width: h,
114
+ height: h,
115
+ className: l("sui-icon", t),
116
+ "aria-hidden": "true",
117
+ style: { stroke: e, strokeWidth: d, ...c },
118
+ dangerouslySetInnerHTML: { __html: r[i[a] ?? a] ?? r.tag }
119
+ }
120
+ );
121
+ }
122
+ function y({ size: a, radius: h, bg: e, className: d, style: t, children: c }) {
123
+ return /* @__PURE__ */ M(
124
+ "span",
125
+ {
126
+ className: l("sui-iconbox", d),
127
+ style: { width: a, height: a, borderRadius: h, background: e, ...t },
128
+ children: c
129
+ }
130
+ );
131
+ }
132
+ export {
133
+ r as I,
134
+ n as a,
135
+ y as b,
136
+ l as c,
137
+ o as d,
138
+ v as g,
139
+ p as i,
140
+ x as r
141
+ };
@@ -0,0 +1,8 @@
1
+ interface Options<T> {
2
+ value?: T;
3
+ defaultValue: T;
4
+ onChange?: (value: T) => void;
5
+ }
6
+ /** Support both controlled (`value` provided) and uncontrolled (`defaultValue`) usage. */
7
+ export declare function useControllableState<T>({ value, defaultValue, onChange, }: Options<T>): [T, (next: T) => void];
8
+ export {};
@@ -0,0 +1,9 @@
1
+ export interface FormFieldContextValue {
2
+ id: string;
3
+ invalid: boolean;
4
+ /** id(s) of hint/error text, for aria-describedby. */
5
+ describedBy?: string;
6
+ }
7
+ export declare const FormFieldContext: import('react').Context<FormFieldContextValue | null>;
8
+ /** Read the surrounding FormField wiring, if any. Controls opt in automatically. */
9
+ export declare function useFormField(): FormFieldContextValue | null;
@@ -0,0 +1 @@
1
+ export {};
package/dist/icons.js ADDED
@@ -0,0 +1,16 @@
1
+ import { icons as c } from "lucide";
2
+ import { I as i, r as s } from "./chunks/Icon-xe35IPZg.js";
3
+ function $(e) {
4
+ return e.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([a-zA-Z])(\d)/g, "$1-$2").toLowerCase();
5
+ }
6
+ function m(e) {
7
+ return e.map(
8
+ ([o, n]) => `<${o} ${Object.entries(n).map(([t, a]) => `${t}="${a}"`).join(" ")}/>`
9
+ ).join("");
10
+ }
11
+ const r = {};
12
+ for (const [e, o] of Object.entries(c)) {
13
+ const n = $(e);
14
+ n in i || (r[n] = m(o));
15
+ }
16
+ s(r);
@@ -0,0 +1,72 @@
1
+ export { Button } from './atoms/Button/Button';
2
+ export type { ButtonProps, ButtonVariant, ButtonSize } from './atoms/Button/Button';
3
+ export { IconButton } from './atoms/IconButton/IconButton';
4
+ export type { IconButtonProps } from './atoms/IconButton/IconButton';
5
+ export { Input } from './atoms/Input/Input';
6
+ export type { InputProps, InputSize } from './atoms/Input/Input';
7
+ export { Text } from './atoms/Text/Text';
8
+ export type { TextProps, TextSize, TextWeight, TextTone } from './atoms/Text/Text';
9
+ export { Heading } from './atoms/Heading/Heading';
10
+ export type { HeadingProps, HeadingLevel } from './atoms/Heading/Heading';
11
+ export { Label } from './atoms/Label/Label';
12
+ export type { LabelProps } from './atoms/Label/Label';
13
+ export { Badge } from './atoms/Badge/Badge';
14
+ export type { BadgeProps, BadgeStatus, BadgeSize } from './atoms/Badge/Badge';
15
+ export { Spinner } from './atoms/Spinner/Spinner';
16
+ export type { SpinnerProps } from './atoms/Spinner/Spinner';
17
+ export { Icon, IconBox, ICON_PATHS, isImageIconSource, registerIcons, registerIconAliases, getIconNames, } from './atoms/Icon/Icon';
18
+ export type { IconProps, IconBoxProps } from './atoms/Icon/Icon';
19
+ export { Avatar } from './atoms/Avatar/Avatar';
20
+ export type { AvatarProps } from './atoms/Avatar/Avatar';
21
+ export { Switch } from './atoms/Switch/Switch';
22
+ export type { SwitchProps } from './atoms/Switch/Switch';
23
+ export { Skeleton } from './atoms/Skeleton/Skeleton';
24
+ export type { SkeletonProps } from './atoms/Skeleton/Skeleton';
25
+ export { ProgressBar } from './atoms/ProgressBar/ProgressBar';
26
+ export type { ProgressBarProps } from './atoms/ProgressBar/ProgressBar';
27
+ export { FormField } from './molecules/FormField/FormField';
28
+ export type { FormFieldProps } from './molecules/FormField/FormField';
29
+ export { Combobox } from './molecules/Combobox/Combobox';
30
+ export type { ComboboxProps, ComboboxOption } from './molecules/Combobox/Combobox';
31
+ export { MultiSelect } from './molecules/MultiSelect/MultiSelect';
32
+ export type { MultiSelectProps, MultiSelectOption } from './molecules/MultiSelect/MultiSelect';
33
+ export { SegmentedControl } from './molecules/SegmentedControl/SegmentedControl';
34
+ export type { SegmentedControlProps, SegmentedOption, } from './molecules/SegmentedControl/SegmentedControl';
35
+ export { SwitchCard } from './molecules/SwitchCard/SwitchCard';
36
+ export type { SwitchCardProps } from './molecules/SwitchCard/SwitchCard';
37
+ export { MoneyInput } from './molecules/MoneyInput/MoneyInput';
38
+ export type { MoneyInputProps } from './molecules/MoneyInput/MoneyInput';
39
+ export { DateTimeInput } from './molecules/DateTimeInput/DateTimeInput';
40
+ export type { DateTimeInputProps } from './molecules/DateTimeInput/DateTimeInput';
41
+ export { MonthPicker } from './molecules/MonthPicker/MonthPicker';
42
+ export type { MonthPickerProps, MonthPickerValue } from './molecules/MonthPicker/MonthPicker';
43
+ export { ColorPicker, DEFAULT_SWATCHES } from './molecules/ColorPicker/ColorPicker';
44
+ export type { ColorPickerProps } from './molecules/ColorPicker/ColorPicker';
45
+ export { IconPicker, DEFAULT_PICKER_ICONS } from './molecules/IconPicker/IconPicker';
46
+ export type { IconPickerProps } from './molecules/IconPicker/IconPicker';
47
+ export { StatCard } from './molecules/StatCard/StatCard';
48
+ export type { StatCardProps } from './molecules/StatCard/StatCard';
49
+ export { EmptyState } from './molecules/EmptyState/EmptyState';
50
+ export type { EmptyStateProps } from './molecules/EmptyState/EmptyState';
51
+ export { Tooltip, TooltipProvider } from './molecules/Tooltip/Tooltip';
52
+ export type { TooltipProps } from './molecules/Tooltip/Tooltip';
53
+ export { Card } from './organisms/Card/Card';
54
+ export type { CardProps } from './organisms/Card/Card';
55
+ export { Modal } from './organisms/Modal/Modal';
56
+ export type { ModalProps, ModalContentProps } from './organisms/Modal/Modal';
57
+ export { ConfirmModal } from './organisms/ConfirmModal/ConfirmModal';
58
+ export type { ConfirmModalProps } from './organisms/ConfirmModal/ConfirmModal';
59
+ export { Menu } from './organisms/Menu/Menu';
60
+ export type { MenuProps, MenuItem } from './organisms/Menu/Menu';
61
+ export { DataTable } from './organisms/DataTable/DataTable';
62
+ export type { DataTableProps, DataTableColumn, DataTableLabels, } from './organisms/DataTable/DataTable';
63
+ export { PageContainer } from './templates/PageContainer/PageContainer';
64
+ export type { PageContainerProps } from './templates/PageContainer/PageContainer';
65
+ export { AppShell } from './templates/AppShell/AppShell';
66
+ export type { AppShellProps, AppShellNavGroup, AppShellNavItem, } from './templates/AppShell/AppShell';
67
+ export { PageHeader } from './templates/PageHeader/PageHeader';
68
+ export type { PageHeaderProps } from './templates/PageHeader/PageHeader';
69
+ export { useControllableState } from './hooks/useControllableState';
70
+ export { cx } from './utils/cx';
71
+ export { hexA } from './utils/color';
72
+ export { normalizeSearch } from './utils/text';