@ishtar-sink/vega 0.0.0-stage → 0.2.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.
- package/LICENSE +661 -0
- package/README.md +135 -2
- package/dist/app-shell/app-shell.constants.d.ts +13 -0
- package/dist/app-shell/app-shell.d.ts +6 -0
- package/dist/app-shell/app-shell.types.d.ts +20 -0
- package/dist/app-shell/bottom-nav.d.ts +3 -0
- package/dist/app-shell/bottom-nav.types.d.ts +12 -0
- package/dist/app-shell/nav-link.d.ts +11 -0
- package/dist/app-shell/nav.types.d.ts +22 -0
- package/dist/app-shell/sidebar.d.ts +3 -0
- package/dist/app-shell/sidebar.types.d.ts +22 -0
- package/dist/app-shell/topbar.d.ts +3 -0
- package/dist/app-shell/topbar.types.d.ts +9 -0
- package/dist/app-shell/use-focus-trap.d.ts +6 -0
- package/dist/app-shell/use-media-query.d.ts +2 -0
- package/dist/autocomplete/autocomplete.d.ts +37 -0
- package/dist/badge/badge.d.ts +8 -0
- package/dist/bottom-sheet/bottom-sheet.constants.d.ts +3 -0
- package/dist/bottom-sheet/bottom-sheet.d.ts +3 -0
- package/dist/bottom-sheet/bottom-sheet.types.d.ts +26 -0
- package/dist/bottom-sheet/use-bottom-sheet.d.ts +14 -0
- package/dist/brand-logo/brand-logo.d.ts +9 -0
- package/dist/button/button.d.ts +15 -0
- package/dist/calendar/calendar.d.ts +28 -0
- package/dist/callout/callout.constants.d.ts +4 -0
- package/dist/callout/callout.d.ts +3 -0
- package/dist/callout/callout.types.d.ts +14 -0
- package/dist/card/card.d.ts +9 -0
- package/dist/card-link/card-button.d.ts +3 -0
- package/dist/card-link/card-link.d.ts +3 -0
- package/dist/card-link/card-link.types.d.ts +10 -0
- package/dist/checkbox/checkbox.d.ts +6 -0
- package/dist/color-field/color-field.d.ts +20 -0
- package/dist/color-field/color-picker.d.ts +42 -0
- package/dist/color-field/color.d.ts +11 -0
- package/dist/confirm-dialog/confirm-dialog.d.ts +15 -0
- package/dist/date-field/date-field.d.ts +38 -0
- package/dist/date-time-field/date-time-field.d.ts +33 -0
- package/dist/dialog/dialog.d.ts +21 -0
- package/dist/disclosure/accordion-context.d.ts +5 -0
- package/dist/disclosure/accordion.d.ts +3 -0
- package/dist/disclosure/disclosure.d.ts +3 -0
- package/dist/disclosure/disclosure.types.d.ts +24 -0
- package/dist/disclosure/use-disclosure.d.ts +22 -0
- package/dist/empty-state/empty-state.d.ts +10 -0
- package/dist/error-state/error-state.d.ts +12 -0
- package/dist/focus-header/focus-header.constants.d.ts +2 -0
- package/dist/focus-header/focus-header.d.ts +3 -0
- package/dist/focus-header/focus-header.types.d.ts +24 -0
- package/dist/form-layout/form-layout.d.ts +17 -0
- package/dist/icon-button/icon-button.d.ts +10 -0
- package/dist/icons/icon.d.ts +10 -0
- package/dist/icons/icon.types.d.ts +5 -0
- package/dist/icons/index.d.ts +4 -0
- package/dist/icons/interface-icons.d.ts +144 -0
- package/dist/icons/view-icons.d.ts +17 -0
- package/dist/index.d.ts +102 -0
- package/dist/index.js +3782 -0
- package/dist/item-swatch/item-swatch.d.ts +10 -0
- package/dist/item-swatch/palette.d.ts +6 -0
- package/dist/loading-state/loading-state.d.ts +13 -0
- package/dist/menu-button/menu-button.d.ts +26 -0
- package/dist/money-field/money-field.d.ts +13 -0
- package/dist/money-field/money-mask.d.ts +6 -0
- package/dist/page-header/page-header.d.ts +20 -0
- package/dist/period-field/period-field.d.ts +47 -0
- package/dist/period-field/period.d.ts +31 -0
- package/dist/progress-bar/progress-bar.d.ts +14 -0
- package/dist/prose/index.d.ts +2 -0
- package/dist/prose/prose.constants.d.ts +2 -0
- package/dist/prose/prose.d.ts +2 -0
- package/dist/prose/prose.types.d.ts +23 -0
- package/dist/prose/prose.utils.d.ts +4 -0
- package/dist/prose.js +91 -0
- package/dist/radio-group/radio-group.constants.d.ts +4 -0
- package/dist/radio-group/radio-group.d.ts +2 -0
- package/dist/radio-group/radio-group.types.d.ts +41 -0
- package/dist/radio-group/radio-option.d.ts +12 -0
- package/dist/segmented-field/segmented-field.d.ts +24 -0
- package/dist/select-field/select-field.d.ts +24 -0
- package/dist/style.css +2 -0
- package/dist/switch/switch.d.ts +3 -0
- package/dist/switch/switch.types.d.ts +11 -0
- package/dist/tabs/tabs.d.ts +19 -0
- package/dist/tag-field/tag-field.d.ts +20 -0
- package/dist/text-area-field/text-area-field.d.ts +2 -0
- package/dist/text-area-field/text-area-field.types.d.ts +17 -0
- package/dist/text-area-field/use-auto-resize.d.ts +7 -0
- package/dist/text-field/text-field.d.ts +10 -0
- package/dist/theme/contrast.d.ts +16 -0
- package/dist/theme/index.d.ts +5 -0
- package/dist/theme/theme.d.ts +15 -0
- package/dist/theme/tokens.d.ts +138 -0
- package/dist/time-field/parse-time.d.ts +4 -0
- package/dist/time-field/time-field.d.ts +20 -0
- package/dist/toast/toast.d.ts +11 -0
- package/dist/tokens.css +166 -0
- package/dist/toolbar/toolbar.d.ts +16 -0
- package/dist/view-switcher/view-switcher.d.ts +19 -0
- package/fonts/OFL-Inter.txt +92 -0
- package/fonts/OFL-Outfit.txt +93 -0
- package/fonts/inter-variable.woff2 +0 -0
- package/fonts/outfit-variable.ttf +0 -0
- package/package.json +78 -4
package/README.md
CHANGED
|
@@ -1,3 +1,136 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Vega
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Biblioteca de componentes React e temas do ecossistema [Ishtar Sink](https://github.com/Ishtar-Sink). Todo produto da organização monta a interface com as mesmas peças (botões, campos, diálogos, avisos, abas, cartões) e recebe daqui o tema. O tema do Ishtar Sink é o padrão: quando ele muda aqui, todos os produtos que o usam acompanham na próxima atualização. Quem precisar pode trocar a paleta pela sua.
|
|
4
|
+
|
|
5
|
+
Código aberto (AGPL-3.0) e aberto a qualquer projeto, dentro ou fora do ecossistema.
|
|
6
|
+
|
|
7
|
+
A Vega nasce da extração do `@atria/ui` e do `@atria/theme`, a biblioteca e o tema que o [Atria](https://github.com/Ishtar-Sink/Atria) construiu para a própria interface, e é publicada como `@ishtar-sink/vega`. As mudanças de cada versão estão no [CHANGELOG](CHANGELOG.md).
|
|
8
|
+
|
|
9
|
+
## Temas
|
|
10
|
+
|
|
11
|
+
- **Tema Ishtar Sink, padrão.** É a paleta das [diretrizes do ecossistema](https://github.com/Ishtar-Sink/.github/blob/main/docs/identidade-ecossistema.md), nos temas claro e escuro, junto com a tipografia (Outfit e Inter), os raios, o espaço e o movimento.
|
|
12
|
+
- **Paleta própria.** Uma aplicação cria o próprio tema com a API de tema da Vega, preenchendo os mesmos tokens (`bg`, `surface`, `primary`, `success`, os `*Soft`…) nos dois temas, e passa esse tema para os componentes. Nenhum componente tem cor fixa.
|
|
13
|
+
- **Contraste verificado.** A Vega traz as verificações de contraste que o tema padrão usa (AA para texto), para que um tema próprio passe pelas mesmas regras nos testes da aplicação.
|
|
14
|
+
- **Troca em tempo de execução.** A camada de marca pode ser sobrescrita sem rebuild, o que permite o white label por instância nos produtos que o oferecem.
|
|
15
|
+
|
|
16
|
+
## Componentes
|
|
17
|
+
|
|
18
|
+
| Grupo | Componentes e funções |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Ações | `Button` (com `size` e `block` desde a 0.2.0), `IconButton`, `MenuButton` |
|
|
21
|
+
| Campos | `TextField`, `SelectField`, `Checkbox`, `SegmentedField`, `Autocomplete`, `TagField`, `ColorField`, `ColorPicker`, `DEFAULT_COLOR_FIELD_LABELS`, `hexToRgb`, `rgbToHex`, `hslToRgb`, `rgbToHsl`; na 0.2.0, `Switch`, `RadioGroup`, `TextAreaField` |
|
|
22
|
+
| Data e hora | `Calendar`, `DateField`, `TimeField`, `DateTimeField`, `PeriodField`, `parseTime`, `maskTime`, `resolvePeriod` |
|
|
23
|
+
| Dinheiro | `MoneyField`, `maskMoneyInput`, `parseMoneyInput`, `formatCents` |
|
|
24
|
+
| Estrutura | `Card`, `PageHeader`, `Toolbar`, `Tabs`, `ViewSwitcher`, `FormGrid`, `FormActions`; na 0.2.0, `CardLink`, `CardButton`, `FocusHeader`, `Disclosure`, `Accordion` |
|
|
25
|
+
| Diálogos e avisos | `Dialog`, `ConfirmDialog`, `Toast`, `ToastRegion`; na 0.2.0, `BottomSheet`, `Callout` |
|
|
26
|
+
| Estados | `EmptyState`, `LoadingState`, `Skeleton`, `ErrorState`, `ProgressBar` (com `valueText` e `indeterminate` desde a 0.2.0) |
|
|
27
|
+
| Marca e itens | `BrandLogo`, `Badge`, `ItemSwatch`, `ListIcon`, `GridIcon`, `ShelfIcon`, `TableIcon`, `DayIcon`, `TimelineIcon` |
|
|
28
|
+
| Ícones de interface | Os 36 da seção [Ícones](#ícones), na 0.2.0 |
|
|
29
|
+
| Navegação | `AppShell`, `Sidebar`, `BottomNav`, `Topbar`, na 0.2.0 |
|
|
30
|
+
| Conteúdo | `Prose`, na 0.2.0, pela entrada `@ishtar-sink/vega/prose` |
|
|
31
|
+
|
|
32
|
+
Os grupos Ações, Campos, Data e hora, Dinheiro, Estrutura, Diálogos e avisos, Estados e Marca e itens entraram na 0.1.0; o que a tabela marca com 0.2.0, e os grupos Ícones de interface, Navegação e Conteúdo, entraram na 0.2.0.
|
|
33
|
+
|
|
34
|
+
## Princípios
|
|
35
|
+
|
|
36
|
+
- **Uma fonte para a identidade.** Os componentes leem os tokens do tema e não declaram cor, raio, espaço nem fonte próprios.
|
|
37
|
+
- **Acessível por padrão.** Cada componente é testado com axe e com navegação por teclado, e o contraste dos tokens é verificado em AA.
|
|
38
|
+
- **Tema claro e escuro.** Os dois funcionam sem configuração, com o claro como padrão.
|
|
39
|
+
- **Sem dependência de serviço externo.** Fontes e ícones vêm junto com o pacote, nunca de um CDN em tempo de execução.
|
|
40
|
+
- **Nenhum produto do ecossistema recria um componente que já existe aqui.** Se faltar algo, o componente entra na Vega, não no produto.
|
|
41
|
+
|
|
42
|
+
## Instalação
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add @ishtar-sink/vega react react-dom
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`react` e `react-dom` `^19.3.1` são peer dependencies.
|
|
49
|
+
|
|
50
|
+
## Estilos
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import '@ishtar-sink/vega/tokens.css';
|
|
54
|
+
import '@ishtar-sink/vega/styles.css';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
O `tokens.css` traz as variáveis dos dois temas e as fontes; o `styles.css`, o CSS dos componentes. Importe os dois uma vez, na entrada da aplicação, nessa ordem.
|
|
58
|
+
|
|
59
|
+
O tema claro é o padrão. Para o escuro, use `data-theme="dark"` num elemento ancestral, como o `<html>`. A marca pode ser sobrescrita por variáveis como `--primary` num contêiner, sem rebuild.
|
|
60
|
+
|
|
61
|
+
## Uso
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { Button, Card } from '@ishtar-sink/vega';
|
|
65
|
+
|
|
66
|
+
export function Exemplo() {
|
|
67
|
+
return (
|
|
68
|
+
<Card>
|
|
69
|
+
<Button variant="primary">Salvar</Button>
|
|
70
|
+
</Card>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Ícones
|
|
76
|
+
|
|
77
|
+
Os 36 ícones de interface vêm do [Lucide](https://lucide.dev), pelo pacote `lucide-react` (licença ISC), com os nomes da Vega: `HomeIcon`, `BookOpenIcon`, `LayersIcon`, `TimerIcon`, `UsersIcon`, `MenuIcon`, `ChevronLeftIcon`, `ChevronRightIcon`, `ChevronDownIcon`, `ArrowLeftIcon`, `CloseIcon`, `PlusIcon`, `MinusIcon`, `DownloadIcon`, `UploadIcon`, `FlagIcon`, `RefreshIcon`, `EyeIcon`, `CheckIcon`, `CircleCheckIcon`, `InfoIcon`, `AlertTriangleIcon`, `CircleAlertIcon`, `WifiOffIcon`, `CloudCheckIcon`, `UserIcon`, `SettingsIcon`, `LogOutIcon`, `SunIcon`, `MoonIcon`, `LightbulbIcon`, `ClockIcon`, `CalendarIcon`, `PencilIcon`, `SearchIcon` e `TrashIcon`.
|
|
78
|
+
|
|
79
|
+
Os ícones são sempre decorativos (`aria-hidden`), usam a cor do texto (`currentColor`) e têm tamanho 16, 20 ou 24, com 20 por padrão. O nome acessível fica no elemento que contém o ícone.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { Button, HomeIcon } from '@ishtar-sink/vega';
|
|
83
|
+
|
|
84
|
+
export function Inicio() {
|
|
85
|
+
return (
|
|
86
|
+
<Button variant="primary">
|
|
87
|
+
<HomeIcon size={16} />
|
|
88
|
+
Início
|
|
89
|
+
</Button>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Texto formatado (Prose)
|
|
95
|
+
|
|
96
|
+
O `Prose` sai numa entrada própria, `@ishtar-sink/vega/prose`, para que quem não usa Markdown não carregue o parser. O HTML cru do texto é ignorado, e links com `javascript:`, `data:` ou `vbscript:` são bloqueados.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { Prose } from '@ishtar-sink/vega/prose';
|
|
100
|
+
|
|
101
|
+
export function Licao({ texto }: { texto: string }) {
|
|
102
|
+
return <Prose markdown={texto} size="reading" />;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Extensões do produto, como fórmulas de matemática, entram por `remarkPlugins` (sintaxe nova) e `components` (como cada elemento é renderizado), sem mudar a Vega.
|
|
107
|
+
|
|
108
|
+
## Tema próprio
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { dark, defineTheme, light } from '@ishtar-sink/vega';
|
|
112
|
+
|
|
113
|
+
export const meuTema = defineTheme({
|
|
114
|
+
light: { ...light, primary: '#115e59' },
|
|
115
|
+
dark: { ...dark, primary: '#5eead4' },
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Um teste da aplicação confere que o tema passa nas mesmas regras de contraste do tema padrão:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { checkThemeContrast } from '@ishtar-sink/vega';
|
|
123
|
+
import { meuTema } from './tema';
|
|
124
|
+
|
|
125
|
+
it('o tema próprio passa no contraste AA', () => {
|
|
126
|
+
expect(checkThemeContrast(meuTema)).toEqual([]);
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Sobre o nome
|
|
131
|
+
|
|
132
|
+
Vega, a estrela mais brilhante da Lira, é a referência de brilho da astronomia: por séculos, o brilho de todas as outras estrelas foi medido em relação a ela, que é o ponto zero da escala de magnitude. A biblioteca é a referência visual contra a qual todos os produtos do Ishtar Sink se medem, mesmo os que escolhem uma cor própria.
|
|
133
|
+
|
|
134
|
+
## Licença
|
|
135
|
+
|
|
136
|
+
[AGPL-3.0](LICENSE).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Textos padrão da `Sidebar` e da `BottomNav`. */
|
|
2
|
+
export declare const DEFAULT_NAV_LABELS: {
|
|
3
|
+
readonly navigation: "Principal";
|
|
4
|
+
};
|
|
5
|
+
/** Textos padrão do `AppShell`. */
|
|
6
|
+
export declare const DEFAULT_APP_SHELL_LABELS: {
|
|
7
|
+
readonly skipToContent: "Pular para o conteúdo";
|
|
8
|
+
readonly openMenu: "Abrir menu";
|
|
9
|
+
};
|
|
10
|
+
/** Abaixo de 720 px a navegação vira gaveta ou barra inferior, como o `@media` dos estilos. */
|
|
11
|
+
export declare const COMPACT_QUERY: string;
|
|
12
|
+
/** Elementos que recebem foco dentro da gaveta. */
|
|
13
|
+
export declare const FOCUSABLE = "a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AppShellProps } from './app-shell.types';
|
|
2
|
+
/**
|
|
3
|
+
* Estrutura da aplicação: link de pular, `Sidebar`, `Topbar` e `<main>`. Abaixo de 720 px, a
|
|
4
|
+
* navegação vira gaveta com botão de menu ou `BottomNav`, conforme `mobileNav`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function AppShell({ sidebar, topbar, mobileNav, hideNavigation, children, labels, className, ...rest }: AppShellProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { SidebarProps } from './sidebar.types';
|
|
3
|
+
import { TopbarProps } from './topbar.types';
|
|
4
|
+
export interface AppShellProps extends ComponentPropsWithRef<'div'> {
|
|
5
|
+
/** Props da `Sidebar`; a gaveta é controlada pelo próprio `AppShell`. */
|
|
6
|
+
sidebar: Omit<SidebarProps, 'drawer' | 'open' | 'onClose'>;
|
|
7
|
+
/** Props da `Topbar`; sem ela, a barra só aparece no modo gaveta, com o botão de menu. */
|
|
8
|
+
topbar?: TopbarProps;
|
|
9
|
+
/** Navegação abaixo de 720 px: gaveta com botão de menu ou barra inferior. Padrão: `drawer`. */
|
|
10
|
+
mobileNav?: 'drawer' | 'bottom';
|
|
11
|
+
/** Esconde toda a navegação (barra lateral, gaveta, barra inferior e link de pular). */
|
|
12
|
+
hideNavigation?: boolean;
|
|
13
|
+
/** Conteúdo da página, dentro do `<main>`. */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/** Textos visíveis e nomes acessíveis. Padrão: `Pular para o conteúdo` e `Abrir menu`. */
|
|
16
|
+
labels?: Partial<{
|
|
17
|
+
skipToContent: string;
|
|
18
|
+
openMenu: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { NavItem, RenderNavLink } from './nav.types';
|
|
3
|
+
export interface BottomNavProps extends ComponentPropsWithRef<'nav'> {
|
|
4
|
+
/** De 3 a 5 destinos; fora disso, um aviso no console em desenvolvimento. */
|
|
5
|
+
items: readonly NavItem[];
|
|
6
|
+
/** Desenha cada link com o roteador do produto; sem ele, um `<a href>` simples. */
|
|
7
|
+
renderLink?: RenderNavLink;
|
|
8
|
+
/** Textos visíveis e nomes acessíveis. Padrão: `{ navigation: 'Principal' }`. */
|
|
9
|
+
labels?: Partial<{
|
|
10
|
+
navigation: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NavItem, RenderNavLink } from './nav.types';
|
|
2
|
+
interface NavLinkProps {
|
|
3
|
+
item: NavItem;
|
|
4
|
+
className: string | undefined;
|
|
5
|
+
iconClassName?: string | undefined;
|
|
6
|
+
badgeClassName?: string | undefined;
|
|
7
|
+
renderLink?: RenderNavLink;
|
|
8
|
+
}
|
|
9
|
+
/** Link de um destino: usa o `renderLink` do produto ou, sem ele, um `<a href>` simples. */
|
|
10
|
+
export declare function NavLink({ item, className, iconClassName, badgeClassName, renderLink, }: NavLinkProps): string | number | bigint | boolean | Iterable<import('react').ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<import('react').ReactNode> | null | undefined> | import('react').JSX.Element | null | undefined;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/** Destino da navegação, usado pela `Sidebar`, pela `BottomNav` e pelo `AppShell`. */
|
|
3
|
+
export interface NavItem {
|
|
4
|
+
/** Identificador estável do destino, usado como chave. */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Rótulo visível do destino. */
|
|
7
|
+
label: string;
|
|
8
|
+
/** Ícone em SVG inline; fica dentro de um `<span aria-hidden="true">`. */
|
|
9
|
+
icon: ReactNode;
|
|
10
|
+
/** Endereço do destino, usado pelo `<a>` simples ou pelo `renderLink`. */
|
|
11
|
+
href: string;
|
|
12
|
+
/** Marca o destino atual com `aria-current="page"`. */
|
|
13
|
+
current?: boolean;
|
|
14
|
+
/** Selo opcional ao lado do rótulo (ex.: a contagem de pendências). */
|
|
15
|
+
badge?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
/** Desenha o link com o componente do roteador do produto, repassando as props recebidas. */
|
|
18
|
+
export type RenderNavLink = (item: NavItem, props: {
|
|
19
|
+
className: string;
|
|
20
|
+
'aria-current'?: 'page';
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
}) => ReactNode;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { SidebarProps } from './sidebar.types';
|
|
2
|
+
/** Barra lateral com a marca, a navegação principal e o rodapé; vira gaveta com `drawer`. */
|
|
3
|
+
export declare function Sidebar({ brand, items, renderLink, footer, drawer, open, onClose, labels, className, onKeyDown, ref, ...rest }: SidebarProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { NavItem, RenderNavLink } from './nav.types';
|
|
3
|
+
export interface SidebarProps extends ComponentPropsWithRef<'aside'> {
|
|
4
|
+
/** Marca do produto, no topo da barra. */
|
|
5
|
+
brand: ReactNode;
|
|
6
|
+
/** Destinos da navegação principal. */
|
|
7
|
+
items: readonly NavItem[];
|
|
8
|
+
/** Desenha cada link com o roteador do produto; sem ele, um `<a href>` simples. */
|
|
9
|
+
renderLink?: RenderNavLink;
|
|
10
|
+
/** Conteúdo do rodapé (ex.: conta, tema, ajustes). */
|
|
11
|
+
footer?: ReactNode;
|
|
12
|
+
/** Modo gaveta: barra fixa sobre o conteúdo, com foco preso enquanto aberta. Padrão: `false`. */
|
|
13
|
+
drawer?: boolean;
|
|
14
|
+
/** Gaveta aberta; fechada, ela fica `inert`. Só vale com `drawer`. */
|
|
15
|
+
open?: boolean;
|
|
16
|
+
/** Chamado no Escape e ao escolher um link com a gaveta aberta. */
|
|
17
|
+
onClose?: () => void;
|
|
18
|
+
/** Textos visíveis e nomes acessíveis. Padrão: `{ navigation: 'Principal' }`. */
|
|
19
|
+
labels?: Partial<{
|
|
20
|
+
navigation: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
export interface TopbarProps extends ComponentPropsWithRef<'header'> {
|
|
3
|
+
/** Slot do início da barra (ex.: o botão de menu ou o voltar). */
|
|
4
|
+
start?: ReactNode;
|
|
5
|
+
/** Slot do meio da barra (ex.: o título da tela). */
|
|
6
|
+
center?: ReactNode;
|
|
7
|
+
/** Slot do fim da barra (ex.: ações e busca). */
|
|
8
|
+
end?: ReactNode;
|
|
9
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { KeyboardEvent, RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Prende o foco dentro de `ref` enquanto `active`: foca o primeiro item ao ativar, faz o Tab dar a
|
|
4
|
+
* volta e entrega o Escape a `onEscape`. Devolve o `onKeyDown` a ligar no elemento.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFocusTrap(ref: RefObject<HTMLElement | null>, active: boolean, onEscape?: () => void): (event: KeyboardEvent<HTMLElement>) => void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface AutocompleteOption<T extends string | number> {
|
|
3
|
+
value: T;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
interface AutocompleteBaseProps<T extends string | number> extends Omit<ComponentPropsWithRef<'input'>, 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'multiple' | 'type' | 'role' | 'children'> {
|
|
7
|
+
/** Rótulo visível do campo. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Opções da lista. */
|
|
10
|
+
options: readonly AutocompleteOption<T>[];
|
|
11
|
+
/** Texto de ajuda abaixo do campo. */
|
|
12
|
+
help?: string;
|
|
13
|
+
/** Mensagem de erro; aparece com `role="alert"` e marca o campo como inválido. */
|
|
14
|
+
error?: string;
|
|
15
|
+
/** Chamada quando o campo perde o foco com a lista fechada. */
|
|
16
|
+
onBlur?: () => void;
|
|
17
|
+
/** Texto mostrado quando nenhuma opção combina com o que foi digitado; padrão `Nenhuma opção encontrada`. */
|
|
18
|
+
emptyText?: string;
|
|
19
|
+
/** Nome da lista de pílulas, só no modo múltiplo; padrão `{label} escolhidas`. */
|
|
20
|
+
listLabel?: string;
|
|
21
|
+
/** Nome do "×" de cada pílula, só no modo múltiplo; padrão `Remover {opção}`. */
|
|
22
|
+
removeLabel?: (label: string) => string;
|
|
23
|
+
}
|
|
24
|
+
export interface AutocompleteSingleProps<T extends string | number> extends AutocompleteBaseProps<T> {
|
|
25
|
+
multiple?: false;
|
|
26
|
+
value: T | null;
|
|
27
|
+
onChange: (value: T | null) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface AutocompleteMultipleProps<T extends string | number> extends AutocompleteBaseProps<T> {
|
|
30
|
+
multiple: true;
|
|
31
|
+
value: readonly T[];
|
|
32
|
+
onChange: (value: T[]) => void;
|
|
33
|
+
}
|
|
34
|
+
export type AutocompleteProps<T extends string | number> = AutocompleteSingleProps<T> | AutocompleteMultipleProps<T>;
|
|
35
|
+
export declare function Autocomplete<T extends string | number>(props: AutocompleteSingleProps<T>): React.JSX.Element;
|
|
36
|
+
export declare function Autocomplete<T extends string | number>(props: AutocompleteMultipleProps<T>): React.JSX.Element;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export type BadgeTone = 'neutral' | 'primary' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
3
|
+
export interface BadgeProps extends ComponentPropsWithRef<'span'> {
|
|
4
|
+
/** Tom do selo; o fundo é sempre o *Soft do tom e o texto diz o estado, sem depender só da cor. Padrão: primary. */
|
|
5
|
+
tone?: BadgeTone;
|
|
6
|
+
}
|
|
7
|
+
/** Selo curto de estado ou categoria. */
|
|
8
|
+
export declare function Badge({ tone, className, ...rest }: BadgeProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BottomSheetProps } from './bottom-sheet.types';
|
|
2
|
+
/** Folha modal sobre o `<dialog>` nativo: embaixo em telas estreitas e na lateral a partir de 720 px. */
|
|
3
|
+
export declare function BottomSheet({ open, onClose, title, description, footer, placement, labels, children, className, ref, ...rest }: BottomSheetProps): import('react').JSX.Element | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
/** Posição da folha: `auto` fica embaixo abaixo de 720 px e na lateral a partir daí. */
|
|
3
|
+
export type BottomSheetPlacement = 'auto' | 'bottom' | 'side';
|
|
4
|
+
/** Textos visíveis do `BottomSheet`. */
|
|
5
|
+
export interface BottomSheetLabels {
|
|
6
|
+
/** Nome acessível do botão de fechar. Padrão: `Fechar`. */
|
|
7
|
+
close: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BottomSheetProps extends Omit<ComponentPropsWithRef<'dialog'>, 'title' | 'open'> {
|
|
10
|
+
/** Abre a folha como modal (`showModal()`); ao ficar `false`, fecha e devolve o foco. */
|
|
11
|
+
open: boolean;
|
|
12
|
+
/** Chamado no Esc, no clique no fundo e no botão de fechar. */
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
/** Título, lido como nome acessível. */
|
|
15
|
+
title: ReactNode;
|
|
16
|
+
/** Descrição curta, ligada ao diálogo por `aria-describedby`. */
|
|
17
|
+
description?: ReactNode;
|
|
18
|
+
/** Rodapé fixo, fora da rolagem do conteúdo. */
|
|
19
|
+
footer?: ReactNode;
|
|
20
|
+
/** Posição da folha. Padrão: `auto`. */
|
|
21
|
+
placement?: BottomSheetPlacement;
|
|
22
|
+
/** Sobrescreve os textos padrão. */
|
|
23
|
+
labels?: Partial<BottomSheetLabels>;
|
|
24
|
+
/** Conteúdo rolável. */
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { KeyboardEvent, MouseEvent, Ref, SyntheticEvent } from 'react';
|
|
2
|
+
interface UseBottomSheetArgs {
|
|
3
|
+
open: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
ref?: Ref<HTMLDialogElement>;
|
|
6
|
+
}
|
|
7
|
+
/** Abre o `<dialog>` como modal, prende o Tab e devolve o foco a quem abriu. */
|
|
8
|
+
export declare function useBottomSheet({ open, onClose, ref }: UseBottomSheetArgs): {
|
|
9
|
+
dialogRef: import('react').RefObject<HTMLDialogElement | null>;
|
|
10
|
+
onKeyDown: (event: KeyboardEvent<HTMLDialogElement>) => void;
|
|
11
|
+
onCancel: (event: SyntheticEvent<HTMLDialogElement>) => void;
|
|
12
|
+
onClick: (event: MouseEvent<HTMLDialogElement>) => void;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
export interface BrandLogoProps extends ComponentPropsWithRef<'div'> {
|
|
3
|
+
/** Nome do produto ao lado da marca, já traduzido por quem usa. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** Desenho da marca (SVG ou imagem), mostrado no quadrado em gradiente; é decorativo, o nome é o texto acessível. */
|
|
6
|
+
mark: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** Marca de um produto: quadrado em gradiente com o desenho recebido e o nome em texto com gradiente. */
|
|
9
|
+
export declare function BrandLogo({ name, mark, className, ...rest }: BrandLogoProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'muted' | 'success';
|
|
3
|
+
export interface ButtonProps extends ComponentPropsWithRef<'button'> {
|
|
4
|
+
/** Variação visual. Padrão: `secondary`. */
|
|
5
|
+
variant?: ButtonVariant;
|
|
6
|
+
/** Mostra o indicador, anuncia `aria-busy` e bloqueia o clique. */
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
/** Cor CSS usada pela variação `muted` (ex.: a cor de uma categoria). */
|
|
9
|
+
tint?: string;
|
|
10
|
+
/** `lg`: altura mínima de 48 px. Padrão: `md`. */
|
|
11
|
+
size?: 'md' | 'lg';
|
|
12
|
+
/** Ocupa a largura toda do contêiner. */
|
|
13
|
+
block?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function Button({ variant, loading, tint, size, block, type, disabled, className, style, children, ...rest }: ButtonProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface CalendarValue {
|
|
3
|
+
/** `YYYY-MM-DD` ou `''`. */
|
|
4
|
+
from: string;
|
|
5
|
+
to?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CalendarLabels {
|
|
8
|
+
previous: string;
|
|
9
|
+
next: string;
|
|
10
|
+
/** Sufixo do dia atual no nome acessível ("hoje"). */
|
|
11
|
+
today: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CalendarProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'> {
|
|
14
|
+
/** `single` escolhe um dia; `range` escolhe um intervalo com dois cliques. */
|
|
15
|
+
mode: 'single' | 'range';
|
|
16
|
+
/** Mês exibido, `YYYY-MM`. */
|
|
17
|
+
month: string;
|
|
18
|
+
onMonthChange: (month: string) => void;
|
|
19
|
+
value: CalendarValue;
|
|
20
|
+
onChange: (value: CalendarValue) => void;
|
|
21
|
+
/** Dia atual, `YYYY-MM-DD`. */
|
|
22
|
+
today: string;
|
|
23
|
+
/** Locale das datas e dos nomes de mês e dia. Padrão: `pt-BR`. */
|
|
24
|
+
locale?: string;
|
|
25
|
+
/** Textos do calendário; o que faltar usa o padrão em pt-br, qualquer que seja o `locale`. */
|
|
26
|
+
labels?: Partial<CalendarLabels>;
|
|
27
|
+
}
|
|
28
|
+
export declare function Calendar({ mode, month, onMonthChange, value, onChange, today, locale, labels, className, ref, ...rest }: CalendarProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
export type CalloutTone = 'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
|
|
3
|
+
export interface CalloutProps extends Omit<ComponentPropsWithRef<'aside'>, 'title'> {
|
|
4
|
+
/** Tom do aviso, que define o fundo, a cor e o ícone. Padrão: `neutral`. */
|
|
5
|
+
tone?: CalloutTone;
|
|
6
|
+
/** Título do aviso; também dá o nome acessível ao `<aside>`. */
|
|
7
|
+
title?: ReactNode;
|
|
8
|
+
/** Ícone no lugar do padrão do tom; `false` remove o ícone. */
|
|
9
|
+
icon?: ReactNode | false;
|
|
10
|
+
/** Ação no fim do aviso, como um botão ou um link. */
|
|
11
|
+
action?: ReactNode;
|
|
12
|
+
/** `polite` anuncia o aviso como região viva (`role="status"`). Padrão: `off`. */
|
|
13
|
+
live?: 'off' | 'polite';
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export type CardTone = 'default' | 'primary' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
3
|
+
export interface CardProps extends ComponentPropsWithRef<'div'> {
|
|
4
|
+
/** Elemento HTML da raiz. Padrão: `div`. */
|
|
5
|
+
as?: 'div' | 'section' | 'article';
|
|
6
|
+
/** Tom do fundo e da borda. Padrão: `default`. */
|
|
7
|
+
tone?: CardTone;
|
|
8
|
+
}
|
|
9
|
+
export declare function Card({ as: Tag, tone, className, ...rest }: CardProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { CardTone } from '../card/card';
|
|
3
|
+
export interface CardLinkProps extends ComponentPropsWithRef<'a'> {
|
|
4
|
+
/** Tom do fundo e da borda, o mesmo do `Card`. Padrão: `default`. */
|
|
5
|
+
tone?: CardTone;
|
|
6
|
+
}
|
|
7
|
+
export interface CardButtonProps extends ComponentPropsWithRef<'button'> {
|
|
8
|
+
/** Tom do fundo e da borda, o mesmo do `Card`. Padrão: `default`. */
|
|
9
|
+
tone?: CardTone;
|
|
10
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface CheckboxProps extends Omit<ComponentPropsWithRef<'input'>, 'type'> {
|
|
3
|
+
/** Rótulo visível ao lado da caixa. */
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function Checkbox({ label, id, className, style, ...rest }: CheckboxProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { ColorFieldLabels } from './color-picker';
|
|
3
|
+
export type { ColorFieldLabels } from './color-picker';
|
|
4
|
+
export interface ColorFieldProps extends Omit<ComponentPropsWithRef<'button'>, 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'children' | 'type'> {
|
|
5
|
+
/** Rótulo visível do campo. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** HEX atual. */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Chamado com o HEX `#RRGGBB` ao aplicar. */
|
|
10
|
+
onChange: (hex: string) => void;
|
|
11
|
+
/** Chamado quando o diálogo fecha. */
|
|
12
|
+
onBlur?: () => void;
|
|
13
|
+
/** Textos do campo e do seletor; os que faltarem usam o padrão em pt-br. */
|
|
14
|
+
labels?: Partial<ColorFieldLabels>;
|
|
15
|
+
/** Mensagem de erro, anunciada com `role="alert"`. */
|
|
16
|
+
error?: string;
|
|
17
|
+
/** Texto de ajuda sob o campo. */
|
|
18
|
+
help?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function ColorField({ label, value, onChange, onBlur, labels, error, help, id, className, style, ref, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, ...rest }: ColorFieldProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
/** Textos do campo de cor e do seletor. */
|
|
3
|
+
export interface ColorFieldLabels {
|
|
4
|
+
/** Título do diálogo. */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Rótulo do controle de luminosidade. */
|
|
7
|
+
lightness: string;
|
|
8
|
+
/** Rótulo do campo HEX. */
|
|
9
|
+
hex: string;
|
|
10
|
+
/** Legenda do grupo RGB. */
|
|
11
|
+
rgb: string;
|
|
12
|
+
/** Rótulo do canal vermelho. */
|
|
13
|
+
red: string;
|
|
14
|
+
/** Rótulo do canal verde. */
|
|
15
|
+
green: string;
|
|
16
|
+
/** Rótulo do canal azul. */
|
|
17
|
+
blue: string;
|
|
18
|
+
/** Legenda do grupo HSL. */
|
|
19
|
+
hsl: string;
|
|
20
|
+
/** Rótulo do matiz. */
|
|
21
|
+
hue: string;
|
|
22
|
+
/** Rótulo da saturação. */
|
|
23
|
+
saturation: string;
|
|
24
|
+
/** Texto do botão que cancela. */
|
|
25
|
+
cancel: string;
|
|
26
|
+
/** Texto do botão que aplica. */
|
|
27
|
+
apply: string;
|
|
28
|
+
/** Nome da roda de matiz e saturação. */
|
|
29
|
+
wheel: string;
|
|
30
|
+
/** Texto do valor da roda para leitores de tela. */
|
|
31
|
+
wheelValue: (hue: number, saturation: number) => string;
|
|
32
|
+
}
|
|
33
|
+
export declare const DEFAULT_COLOR_FIELD_LABELS: ColorFieldLabels;
|
|
34
|
+
export interface ColorPickerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children' | 'defaultValue'> {
|
|
35
|
+
/** Cor inicial (HEX); o seletor guarda o próprio estado depois disso. */
|
|
36
|
+
value: string;
|
|
37
|
+
/** Chamado com o HEX `#RRGGBB` a cada mudança. */
|
|
38
|
+
onChange: (hex: string) => void;
|
|
39
|
+
/** Textos do seletor; os que faltarem usam o padrão em pt-br. */
|
|
40
|
+
labels?: Partial<ColorFieldLabels>;
|
|
41
|
+
}
|
|
42
|
+
export declare function ColorPicker({ value, onChange, labels, className, style, ...rest }: ColorPickerProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Rgb = [number, number, number];
|
|
2
|
+
/** Limita `value` ao intervalo de `min` a `max`. */
|
|
3
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
4
|
+
/** Converte HSL (matiz, saturação e luminosidade) em RGB (0 a 255 por canal). */
|
|
5
|
+
export declare function hslToRgb(h: number, s: number, l: number): Rgb;
|
|
6
|
+
/** Converte RGB (0 a 255 por canal) em HSL (matiz, saturação e luminosidade). */
|
|
7
|
+
export declare function rgbToHsl(r: number, g: number, b: number): Rgb;
|
|
8
|
+
/** Converte os canais RGB em `#RRGGBB` maiúsculo. */
|
|
9
|
+
export declare function rgbToHex(rgb: readonly number[]): string;
|
|
10
|
+
/** Aceita 3 ou 6 dígitos, com ou sem `#`; `null` se inválido. */
|
|
11
|
+
export declare function hexToRgb(hex: string): Rgb | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DialogProps } from '../dialog/dialog';
|
|
2
|
+
export interface ConfirmDialogProps extends Omit<DialogProps, 'children' | 'actions' | 'role' | 'onClose'> {
|
|
3
|
+
/** Texto explicativo do corpo, lido como descrição do diálogo. */
|
|
4
|
+
description: string;
|
|
5
|
+
/** Rótulo do botão de confirmar. Padrão: `Confirmar`. */
|
|
6
|
+
confirmLabel?: string;
|
|
7
|
+
/** Rótulo do botão de cancelar. Padrão: `Cancelar`. */
|
|
8
|
+
cancelLabel?: string;
|
|
9
|
+
/** Chamado ao confirmar. */
|
|
10
|
+
onConfirm: () => void;
|
|
11
|
+
/** Chamado ao cancelar ou ao apertar Esc. */
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
}
|
|
14
|
+
/** Confirmação simples, montada sobre o `Dialog`. */
|
|
15
|
+
export declare function ConfirmDialog({ description, confirmLabel, cancelLabel, onConfirm, onCancel, ...rest }: ConfirmDialogProps): import('react').JSX.Element;
|