@majapisoftwares/ui 5.0.0 → 6.0.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/AGENTS.md +11 -1
- package/README.md +19 -11
- package/THIRD_PARTY_NOTICES.md +25 -1
- package/components.json +1 -1
- package/docs/MIGRATION-6.0.md +33 -0
- package/docs/STANDARDS.md +11 -6
- package/docs/VERSIONING.md +28 -0
- package/package.json +19 -10
- package/scripts/check-standards.mjs +2 -0
- package/src/components/ui/accordion.tsx +82 -0
- package/src/components/ui/alert-dialog.tsx +187 -0
- package/src/components/ui/alert.tsx +2 -2
- package/src/components/ui/avatar.tsx +108 -0
- package/src/components/ui/badge.tsx +1 -1
- package/src/components/ui/breadcrumb.tsx +125 -0
- package/src/components/ui/button-group.tsx +89 -0
- package/src/components/ui/button.tsx +12 -16
- package/src/components/ui/card.tsx +101 -0
- package/src/components/ui/checkbox.tsx +27 -0
- package/src/components/ui/collapsible.tsx +21 -0
- package/src/components/ui/context-menu.tsx +271 -0
- package/src/components/ui/dialog.tsx +161 -0
- package/src/components/ui/dropdown-menu.tsx +271 -0
- package/src/components/ui/empty.tsx +4 -4
- package/src/components/ui/field.tsx +6 -6
- package/src/components/ui/hover-card.tsx +50 -0
- package/src/components/ui/input-group.tsx +155 -0
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/kbd.tsx +28 -0
- package/src/components/ui/orb.css +1002 -0
- package/src/components/ui/orb.tsx +752 -0
- package/src/components/ui/popover.tsx +89 -0
- package/src/components/ui/progress.tsx +82 -0
- package/src/components/ui/radio-group.tsx +37 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +204 -0
- package/src/components/ui/sheet.tsx +8 -6
- package/src/components/ui/sidebar.tsx +1035 -0
- package/src/components/ui/skeleton.tsx +1 -1
- package/src/components/ui/slider.tsx +53 -0
- package/src/components/ui/sonner.tsx +44 -0
- package/src/components/ui/spinner.tsx +32 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/table.tsx +10 -4
- package/src/components/ui/tabs.tsx +2 -2
- package/src/components/ui/textarea.tsx +19 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +44 -0
- package/src/components/ui/tooltip.tsx +65 -0
- package/src/hooks/use-mobile.ts +20 -0
- package/src/lib/i18n.tsx +109 -0
- package/src/patterns/app-shell.tsx +158 -53
- package/src/patterns/data-table.tsx +2441 -180
- package/src/patterns/details-sheet.tsx +8 -6
- package/src/patterns/filter-tabs.tsx +53 -0
- package/src/patterns/majapi-logo.tsx +32 -0
- package/src/patterns/page-header.tsx +44 -22
- package/src/patterns/preferences.tsx +172 -0
- package/src/patterns/status-badge.tsx +4 -3
- package/src/styles.css +41 -341
- package/src/templates/admin-dashboard.tsx +14 -33
- package/src/templates/auth-layout.tsx +18 -24
- package/src/templates/login-form.tsx +97 -65
- package/src/templates/signup-form.tsx +139 -99
- package/src/components/ui/native-select.tsx +0 -66
- package/src/vite-env.d.ts +0 -1
package/AGENTS.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
# Padrão obrigatório do Workbench
|
|
2
2
|
|
|
3
|
+
- Apps e catálogo usam a versão estável mais recente do Next.js (confira com `npm view next version` antes de mudar dependências). O catálogo (`catalog/`) é um app Next.js como qualquer outro, com a mesma estrutura do starter; não use Vite nem outro framework.
|
|
4
|
+
- Toda mudança na biblioteca que afete apps entra no mesmo commit no starter (`starters/next-app`) e no catálogo. O starter sempre depende da versão atual da biblioteca (o teste `npm run test:starter` falha se divergir) e deve compilar e passar lint/typecheck/build com ela.
|
|
5
|
+
- Todo app é bilíngue: inglês (`en`) e português (`pt-BR`). Textos de UI ficam em catálogos `defineMessages` com as duas línguas; nada de texto fixo em componentes. Use `Preferences`/`PreferenceControls` da biblioteca para idioma e tema.
|
|
6
|
+
- Mantenha o texto mínimo: sem descrições, avisos ou rótulos que não ajudem a tarefa.
|
|
7
|
+
- `patterns/data-table` (TanStack Table, vindo da Numa) é a única tabela de dados: filtros por coluna, ordenação múltipla, colunas reordenáveis/ocultáveis/redimensionáveis, seleção, persistência e estados. Melhorias de tabela são feitas aqui e chegam a todos os apps por versão; apps não mantêm cópias próprias.
|
|
8
|
+
- Ao trazer componentes de outros apps, remova sobrescritas visuais (arredondamento, altura, sombra, padding, cores) e deixe os primitivos da biblioteca definirem o visual; containers usam os raios já adotados aqui (ex.: rounded-2xl em tabelas e listas).
|
|
9
|
+
- Seleção usa sempre o Select (Base UI) da biblioteca; não use select nativo nem NativeSelect (o check:standards bloqueia).
|
|
10
|
+
- Versionamento segue docs/VERSIONING.md (SemVer sobre a API pública). Prefira mudanças aditivas e deprecação a remoções; major só com aprovação explícita do responsável.
|
|
11
|
+
- Teste localmente com portless (`npm run dev` já roda via portless; o catálogo abre em https://majapi-ui.localhost). Não use portas fixas nem localhost:PORT nas instruções.
|
|
12
|
+
|
|
3
13
|
- Novos apps web devem partir de starters/next-app, criado por npm run create:app -- <diretorio-novo>. O starter usa a versão estável do Next.js fixada e validada no manifesto; atualizações devem manter lockfile, CI e revisão de compatibilidade.
|
|
4
14
|
|
|
5
|
-
- A base de primitivas é shadcn sobre Base UI (base-
|
|
15
|
+
- A base de primitivas é shadcn sobre Base UI (base-luma), não Radix. Use render para composição e nativeButton=false quando Button renderizar Link/a. Preserve as fronteiras use client da biblioteca em consumidores Next.js.
|
|
6
16
|
|
|
7
17
|
- Esta biblioteca pública é a base obrigatória de todos os apps atuais e futuros do Workbench, incluindo administrativos, dashboards, login e cadastro. Leia README.md e docs/STANDARDS.md antes de alterar interfaces.
|
|
8
18
|
- Antes de criar UI em um app, procure o componente, variante ou padrão existente aqui. Reutilize-o diretamente como dependência.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Majapi UI
|
|
2
2
|
|
|
3
|
-
Biblioteca pública `@majapisoftwares/ui`, base obrigatória de código, interface e experiência de **todos os apps atuais e futuros do Workbench**, baseada em shadcn/ui (**Base UI / base-
|
|
3
|
+
Biblioteca pública `@majapisoftwares/ui`, base obrigatória de código, interface e experiência de **todos os apps atuais e futuros do Workbench**, baseada em shadcn/ui (**Base UI / base-luma**), React e Tailwind CSS v4. Repositório: https://github.com/majapisoftwares/workbench-ui.
|
|
4
4
|
|
|
5
5
|
## Regra central
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ Composição de páginas, lógica de domínio, dados e permissões pertencem ao
|
|
|
10
10
|
|
|
11
11
|
## Criar um app Next.js
|
|
12
12
|
|
|
13
|
-
O starter completo fica em [starters/next-app](starters/next-app), com **Next.js 16.4.3** (
|
|
13
|
+
O starter completo fica em [starters/next-app](starters/next-app), com **Next.js 16.4.3** (versão estável mais recente; mantenha atualizada), React, App Router, TypeScript, Tailwind e esta biblioteca já configurados. A dependência da UI é uma versão npm fixa; não depende de caminhos para este checkout.
|
|
14
14
|
|
|
15
15
|
Dentro deste repositório:
|
|
16
16
|
|
|
@@ -21,22 +21,24 @@ npm ci
|
|
|
21
21
|
npm run dev
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
O comando não sobrescreve diretórios existentes. Copia dashboard, login, cadastro, carregamento/erro/404, regras de agentes, lockfile e CI, sem node_modules, builds ou secrets. Customize por componentes, props e slots. As telas de autenticação são demonstrativas e devem ser conectadas à autenticação real do produto.
|
|
24
|
+
O app gerado é bilíngue (en/pt-BR, textos em `src/messages.ts`) e roda via [portless](https://www.npmjs.com/package/portless) em `https://<nome>.localhost`. O comando não sobrescreve diretórios existentes. Copia dashboard, login, cadastro, carregamento/erro/404, regras de agentes, lockfile e CI, sem node_modules, builds ou secrets. Customize por componentes, props e slots. As telas de autenticação são demonstrativas e devem ser conectadas à autenticação real do produto.
|
|
25
25
|
|
|
26
26
|
## Catálogo visual
|
|
27
27
|
|
|
28
|
+
O catálogo em [catalog/](catalog) é um app Next.js com a mesma estrutura do starter, exportado estaticamente para S3 + CloudFront pelo workflow `deploy-catalog` a cada push na `main`.
|
|
29
|
+
|
|
28
30
|
```powershell
|
|
29
31
|
npm ci
|
|
30
32
|
npm run dev
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
Abra
|
|
35
|
+
Abra https://majapi-ui.localhost (via portless). O catálogo permite revisar componentes, temas claro/escuro, tabela com busca/ordenação/paginação/filtro, detalhes e estados de vazio/erro/carregamento. Usa dados demonstrativos explícitos, sem AWS ou credenciais.
|
|
34
36
|
|
|
35
37
|
## Consumir
|
|
36
38
|
|
|
37
|
-
Pacote público **@majapisoftwares/ui@
|
|
39
|
+
Pacote público **@majapisoftwares/ui@6.0.0**, publicado na organização npm existente. Instale com `npm install --save-exact @majapisoftwares/ui@6.0.0` e versione o lockfile. O pacote exporta fontes TSX para bundlers React/TypeScript (Vite ou Next.js), não para execução direta em Node sem transformação. O starter e o gerador permanecem neste repositório Git, separados do pacote npm da biblioteca.
|
|
38
40
|
|
|
39
|
-
O catálogo público está em **https://ui.majapi.com**. A versão 5 substitui a base 4.x com uma mudança incompatível de API e a base antes chamada @workbench/ui. Apps existentes em ^4 permanecem nessa linha até migração explícita.
|
|
41
|
+
O catálogo público está em **https://ui.majapi.com**. A versão 6 muda AppShell, AdminDashboard e os templates de autenticação; veja [docs/MIGRATION-6.0.md](docs/MIGRATION-6.0.md). A versão 5 substitui a base 4.x com uma mudança incompatível de API e a base antes chamada @workbench/ui. Apps existentes em ^4 permanecem nessa linha até migração explícita.
|
|
40
42
|
|
|
41
43
|
```tsx
|
|
42
44
|
import { Button } from "@majapisoftwares/ui/components/button";
|
|
@@ -45,18 +47,23 @@ import { AdminDashboard } from "@majapisoftwares/ui/templates/admin-dashboard";
|
|
|
45
47
|
import { AuthLayout } from "@majapisoftwares/ui/templates/auth-layout";
|
|
46
48
|
import { LoginForm } from "@majapisoftwares/ui/templates/login-form";
|
|
47
49
|
import { SignupForm } from "@majapisoftwares/ui/templates/signup-form";
|
|
50
|
+
import {
|
|
51
|
+
Preferences,
|
|
52
|
+
PreferenceControls,
|
|
53
|
+
} from "@majapisoftwares/ui/patterns/preferences";
|
|
54
|
+
import { defineMessages, useMessages } from "@majapisoftwares/ui/lib/i18n";
|
|
48
55
|
import "@majapisoftwares/ui/styles.css";
|
|
49
56
|
```
|
|
50
57
|
|
|
51
|
-
O CSS inclui os tokens, fontes locais e o Tailwind, com `@source` da biblioteca. O app precisa processar esse CSS com Tailwind v4.
|
|
58
|
+
O CSS inclui os tokens, fontes locais e o Tailwind, com `@source` da biblioteca. O app precisa processar esse CSS com Tailwind v4.
|
|
52
59
|
|
|
53
60
|
## Contribuir e validar
|
|
54
61
|
|
|
55
|
-
Templates iniciais: **AdminDashboard**, **AuthLayout**, **LoginForm** e **SignupForm**. Configure marca, navegação, textos, dados, ações e conteúdo por props/slots React. Variações de tema são definidas e documentadas na biblioteca. Formulários recebem callbacks tipados; autenticação real, validação no servidor, sessões e autorização pertencem ao app. O catálogo demonstra os templates sem enviar ou persistir senhas.
|
|
62
|
+
A sidebar do `AppShell` tem três modos (expandida, compacta e escondida), redimensionável pela borda, com troca de modo pela largura, menu de clique direito e Ctrl/⌘+B. Templates iniciais: **AdminDashboard**, **AuthLayout**, **LoginForm** e **SignupForm**. Configure marca, navegação, textos, dados, ações e conteúdo por props/slots React. Variações de tema são definidas e documentadas na biblioteca. Formulários recebem callbacks tipados; autenticação real, validação no servidor, sessões e autorização pertencem ao app. O catálogo demonstra os templates sem enviar ou persistir senhas.
|
|
56
63
|
|
|
57
64
|
1. Leia o padrão e procure o primitivo/padrão existente.
|
|
58
|
-
2. Adicione uma API reutilizável ou variante oficial, com defaults compatíveis.
|
|
59
|
-
3. Documente motivos, estados e migração; adicione exemplo no catálogo.
|
|
65
|
+
2. Adicione uma API reutilizável ou variante oficial, com defaults compatíveis e textos em en/pt-BR.
|
|
66
|
+
3. Documente motivos, estados e migração; adicione exemplo no catálogo e atualize o starter no mesmo commit.
|
|
60
67
|
4. Valide tipos, lint, padrões, build, teclado e visual desktop/mobile.
|
|
61
68
|
5. Publique o commit e atualize o consumidor para esse commit; registre no plano.
|
|
62
69
|
|
|
@@ -65,7 +72,8 @@ npm run typecheck
|
|
|
65
72
|
npm run lint
|
|
66
73
|
npm run check:standards
|
|
67
74
|
npm run build
|
|
75
|
+
npm run test:starter
|
|
68
76
|
git diff --check
|
|
69
77
|
```
|
|
70
78
|
|
|
71
|
-
Os componentes foram instalados pelo CLI shadcn 4.22.1, preset base-
|
|
79
|
+
Os componentes foram instalados pelo CLI shadcn 4.22.1, preset base-luma e Base UI 1.9.0. A versão 0.2 migra a base anterior Radix; veja [docs/MIGRATION-0.2.md](docs/MIGRATION-0.2.md). Atribuição upstream: [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). O Cloud Manager é o primeiro consumidor real.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
The primitives in src/components/ui were generated with shadcn/ui 4.22.1, base-
|
|
3
|
+
The primitives in src/components/ui were generated with shadcn/ui 4.22.1, base-luma preset (Base UI), from https://github.com/shadcn-ui/ui and https://ui.shadcn.com. They are distributed under the MIT License:
|
|
4
4
|
|
|
5
5
|
MIT License
|
|
6
6
|
|
|
@@ -12,4 +12,28 @@ The above copyright notice and this permission notice shall be included in all c
|
|
|
12
12
|
|
|
13
13
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
|
|
15
|
+
src/components/ui/orb.tsx and orb.css are adapted from AICSS Orbs (https://github.com/kvnkld/aicss, registry https://www.aicss.dev/r/orbs.json): colors mapped to theme tokens, labels translated, CSS module turned into orb-prefixed global CSS. MIT License:
|
|
16
|
+
|
|
17
|
+
MIT License
|
|
18
|
+
|
|
19
|
+
Copyright (c) 2026 AICSS
|
|
20
|
+
|
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
23
|
+
in the Software without restriction, including without limitation the rights
|
|
24
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
26
|
+
furnished to do so, subject to the following conditions:
|
|
27
|
+
|
|
28
|
+
The above copyright notice and this permission notice shall be included in all
|
|
29
|
+
copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
34
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
35
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
36
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
37
|
+
SOFTWARE.
|
|
38
|
+
|
|
15
39
|
Other dependencies retain their own licenses in their package metadata. This notice does not change ownership or licensing of Workbench-authored code.
|
package/components.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Migração para 6.0
|
|
2
|
+
|
|
3
|
+
Visual padrão do shadcn (tema neutral, Geist), textos em inglês e português e nova sidebar.
|
|
4
|
+
|
|
5
|
+
## Idiomas
|
|
6
|
+
|
|
7
|
+
Envolva o app com `Preferences` (idioma + tema) ou `LocaleProvider`. Os textos embutidos da biblioteca seguem o idioma ativo. Textos do app vão em `defineMessages({ en, "pt-BR" })` e são lidos com `useMessages`.
|
|
8
|
+
|
|
9
|
+
## AppShell / AdminDashboard
|
|
10
|
+
|
|
11
|
+
- `brand`, `brandMark` → `logo` (marca quadrada, fica fixa em todos os modos) e `name` (texto que some em fade no modo compacto).
|
|
12
|
+
- `navigation` passa a ser uma lista de grupos: `[{ label?, items: [...] }]`.
|
|
13
|
+
- `context` → `header` (ex.: breadcrumb) e `actions` (ex.: `PreferenceControls`).
|
|
14
|
+
- `defaultMode` (`open` | `compact` | `closed`) e `defaultWidth` opcionais; o estado é salvo no cookie `sidebar_state` (`parseSidebarCookie` lê no servidor).
|
|
15
|
+
- `AdminDashboard`: `actions` da página → `pageActions`; `description` opcional.
|
|
16
|
+
|
|
17
|
+
## Autenticação
|
|
18
|
+
|
|
19
|
+
- `AuthLayout`: `title`, `description`, `aside`, `brandMark` removidos; `brand` e `footer` opcionais.
|
|
20
|
+
- `LoginForm`/`SignupForm`: títulos e rótulos têm padrão traduzido; props de texto continuam aceitas para sobrescrever.
|
|
21
|
+
|
|
22
|
+
## Outros
|
|
23
|
+
|
|
24
|
+
- `PageHeader`: `eyebrow` removido, `description` opcional.
|
|
25
|
+
- `DetailsSheet`: `description` opcional.
|
|
26
|
+
- `DataTable` agora é a tabela completa da Numa, sobre TanStack Table:
|
|
27
|
+
- `columns` são `ColumnDef` do TanStack (`accessorKey`/`accessorFn`, `cell`, `meta: { label, align, filter }`); `rows` → `data`.
|
|
28
|
+
- Busca global embutida (`searchPlaceholder`, `initialGlobalFilter`); `searchValue`/`searchLabel`/`defaultQuery` saem.
|
|
29
|
+
- `onOpen`/`rowLabel` → `onRowClick`/`getRowLabel`; `filters` → `toolbarStart`/`toolbarEnd`/`toolbarBelow` (recebem a instância da tabela).
|
|
30
|
+
- Filtros por coluna (`text`, `multi` com incluir/excluir, `number-range`, `date-range`, `custom`), ordenação múltipla, colunas reordenáveis/ocultáveis/redimensionáveis, seleção de linhas e persistência em `localStorage` com `storageKey`.
|
|
31
|
+
- Estados mantidos: `loading`, `error` + `onRetry`, `warning`, `unavailable`, `emptyState`/`emptyMessage`.
|
|
32
|
+
- Classes `wb-*` removidas.
|
|
33
|
+
- `NativeSelect` removido: use `Select` (Base UI) com `items` para o rótulo do valor. O `check:ui` acusa imports de `native-select`. Variante `navigation` do Button removida.
|
package/docs/STANDARDS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Padrão v1 de código e UI/UX
|
|
2
2
|
|
|
3
|
-
Base atual: shadcn base-
|
|
3
|
+
Base atual: shadcn base-luma com @base-ui/react. Os componentes interativos expõem fronteiras use client para uso no Next.js App Router. A migração da API Radix está documentada em MIGRATION-0.2.md.
|
|
4
4
|
|
|
5
5
|
## Arquitetura e código
|
|
6
6
|
|
|
@@ -8,19 +8,21 @@ TypeScript em modo strict, React com componentes funcionais e composição. APIs
|
|
|
8
8
|
|
|
9
9
|
## Base visual
|
|
10
10
|
|
|
11
|
-
`src/styles.css` é a fonte dos tokens de cor, tipografia, raio, bordas, foco, estados e estrutura.
|
|
11
|
+
`src/styles.css` é a fonte dos tokens de cor, tipografia, raio, bordas, foco, estados e estrutura. Preset base-luma do shadcn (o mesmo da home de ui.shadcn.com: cantos bem arredondados, campos com fundo suave, sombras leves) sobre o tema neutral, fonte Geist, foco visível e espaço consistente. Cores são semânticas: background, foreground, primary, muted, destructive, success e warning. Temas claro/escuro preservam a semântica. Tokens e padrões podem evoluir nesta biblioteca, nunca por overrides locais em um produto.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Primitivos shadcn ficam em src/components/ui (Button, Badge, Card, Input, Table, Sheet, Sidebar, Tooltip, DropdownMenu, ContextMenu, Breadcrumb, Avatar, Checkbox, Collapsible, Alert, Empty, Select, Separator, Skeleton, Tabs, Field e Label). Padrões compostos: AppShell, PageHeader, MetricStrip, StatusBadge, DataTable, DetailsSheet, DetailList, Preferences, PreferenceControls e MajapiLogo. Templates React: AdminDashboard, AuthLayout, LoginForm e SignupForm. Marca, navegação, textos, dados, ações e slots são configuráveis. Todos os apps atuais e futuros devem consumir esta base pública; ela não conhece AWS ou outro domínio.
|
|
14
14
|
|
|
15
15
|
## Comportamentos de UX
|
|
16
16
|
|
|
17
17
|
- Ação primária destaca o objetivo; secundária usa outline/secondary; destrutiva usa variante própria e depende das autorizações do app.
|
|
18
|
-
- Busca, filtros, ordenação por coluna e paginação seguem DataTable. Filtros
|
|
18
|
+
- Busca, filtros, ordenação por coluna e paginação seguem DataTable (TanStack Table; origem: tabela da Numa). Filtros por coluna usam `meta.filter`; preferências do usuário persistem por `storageKey`. Telas centradas em uma tabela usam `AppShell fillHeight` + `DataTable fillHeight`: a tabela ocupa a altura restante e rola internamente, com cabeçalho, busca e paginação sempre visíveis.
|
|
19
|
+
- Áreas com rolagem interna usam `scroll-fade` do shadcn (só `scroll-fade-b` quando há cabeçalho fixo dentro do contêiner) e as barras de rolagem finas globais, que aparecem com o ponteiro sobre a área e seguem o tema (`color-scheme`).
|
|
20
|
+
- Espaçamento da página em uma escala só: padding, gap entre seções e entre cards de 16px no mobile e 24px a partir de md; o cabeçalho da página e o da sidebar têm a mesma altura (56px). Filtros de domínio são slots tipados do app. Não reconstruir tabelas por tela. Persistência não é habilitada por padrão para evitar guardar buscas sensíveis; quando necessária, deve evoluir como capacidade compartilhada com controle explícito.
|
|
19
21
|
- Estados com texto e cor: sucesso, aviso, erro e desconhecido. Nunca traduzir ausência de informação em zero ou sucesso.
|
|
20
22
|
- Carregamento usa Skeleton, vazio usa Empty, falhas usam Alert e detalhes usam DetailsSheet com título, descrição, foco preso ao overlay, Escape e devolução do foco ao fechar.
|
|
21
23
|
- Em telas pequenas, controles têm texto de pelo menos 16px e alvo de 44px, navegação se reorganiza e tabelas têm rolagem interna, sem rolagem horizontal da página.
|
|
22
24
|
- Preferência por movimento reduzido é respeitada. A ordem de leitura deve acompanhar a ordem visual. Ícones sozinhos exigem nome acessível.
|
|
23
|
-
- Distinguir dados demonstrativos de dados reais; mostrar observação e cobertura em telas de infraestrutura.
|
|
25
|
+
- Distinguir dados demonstrativos de dados reais; mostrar observação e cobertura em telas de infraestrutura. Todo texto existe em inglês e português (`defineMessages`); texto mínimo, sem descrições que não ajudem a tarefa.
|
|
24
26
|
|
|
25
27
|
## Evolução sem customizações isoladas
|
|
26
28
|
|
|
@@ -30,7 +32,10 @@ AGENTS.md nos apps exige contribuição upstream antes de uso. O verificador est
|
|
|
30
32
|
|
|
31
33
|
## Adaptações do upstream
|
|
32
34
|
|
|
33
|
-
-
|
|
35
|
+
- Imports internos relativos e `"use client"` são aplicados por `npm run normalize:ui` após o CLI do shadcn.
|
|
36
|
+
- Sheet traduz o nome acessível do fechamento pelo idioma ativo.
|
|
37
|
+
- Sidebar: três modos (open/compact/closed), largura redimensionável (208–448px) com troca de modo por largura, menu de clique direito, tooltip que fecha ao clicar e textos traduzidos.
|
|
38
|
+
- use-mobile usa useSyncExternalStore (compatível com SSR e com a regra de hooks).
|
|
34
39
|
- Field usa imports relativos. Button assume type=button para evitar submissões acidentais; formulários declaram type=submit. Badge inclui variantes success e warning reutilizadas por StatusBadge.
|
|
35
40
|
- Tokens de identidade, estados semânticos e padrões compostos são mantidos aqui.
|
|
36
41
|
- Mudanças posteriores no upstream devem ser avaliadas com o diff do CLI, preservando estas decisões e o contrato público.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Versionamento
|
|
2
|
+
|
|
3
|
+
`@majapisoftwares/ui` segue [SemVer](https://semver.org) sobre a **API pública**: subpaths exportados no `package.json`, nomes de componentes, props e seus tipos, variantes, tokens CSS, classes documentadas (ex.: `orb-*`) e comportamento que um app possa ter usado.
|
|
4
|
+
|
|
5
|
+
## Qual número subir
|
|
6
|
+
|
|
7
|
+
| Mudança | Versão |
|
|
8
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
|
9
|
+
| Correção de bug, acessibilidade, tradução, ajuste visual que não muda a API | **patch** |
|
|
10
|
+
| Componente, padrão, export, prop opcional ou variante novos; mudança de visual padrão (preset, tokens) que não exige alteração no código do app; deprecação | **minor** |
|
|
11
|
+
| Remover ou renomear export, componente, prop, variante ou token; tornar prop obrigatória; mudar o tipo ou o significado de uma prop; mudança de comportamento que obriga o app a mudar código | **major** |
|
|
12
|
+
|
|
13
|
+
Na dúvida, a pergunta é: **um app que compilava com a versão anterior continua compilando e funcionando sem alterações?** Se sim, não é major.
|
|
14
|
+
|
|
15
|
+
## Evitar majors
|
|
16
|
+
|
|
17
|
+
- Prefira mudanças aditivas: nova prop ao lado da antiga, novo componente em vez de mudar o existente.
|
|
18
|
+
- Para trocar uma API, mantenha a antiga funcionando, marque-a com `@deprecated` (JSDoc, com a alternativa) e só remova no próximo major planejado.
|
|
19
|
+
- Agrupe remoções num único major, com `docs/MIGRATION-<versão>.md` e os consumidores conhecidos atualizados em seguida.
|
|
20
|
+
- Um major precisa de aprovação explícita do responsável antes da publicação; o agente propõe e justifica.
|
|
21
|
+
|
|
22
|
+
## Publicar
|
|
23
|
+
|
|
24
|
+
1. Escolha o número pela tabela acima e justifique no commit (`feat:` → minor, `fix:` → patch, `feat!:`/`BREAKING CHANGE:` → major).
|
|
25
|
+
2. Atualize `version` no `package.json`; o starter acompanha a mesma versão no mesmo commit (`npm run test:starter` verifica).
|
|
26
|
+
3. Valide (typecheck, lint, check:standards, build, test:starter, starter contra o pacote empacotado).
|
|
27
|
+
4. `npm publish`, tag `v<versão>` no GitHub e registre no plano.
|
|
28
|
+
5. Apps fixam a versão exata (`--save-exact`) e atualizam por PR.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@majapisoftwares/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Shared Workbench UI and UX standards based on shadcn/ui",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -26,18 +26,21 @@
|
|
|
26
26
|
"./components/*": "./src/components/ui/*.tsx",
|
|
27
27
|
"./patterns/*": "./src/patterns/*.tsx",
|
|
28
28
|
"./templates/*": "./src/templates/*.tsx",
|
|
29
|
+
"./hooks/*": "./src/hooks/*.ts",
|
|
29
30
|
"./styles.css": "./src/styles.css",
|
|
30
|
-
"./lib/utils": "./src/lib/utils.ts"
|
|
31
|
+
"./lib/utils": "./src/lib/utils.ts",
|
|
32
|
+
"./lib/i18n": "./src/lib/i18n.tsx"
|
|
31
33
|
},
|
|
32
34
|
"scripts": {
|
|
33
35
|
"create:app": "node scripts/create-app.mjs",
|
|
34
36
|
"test:starter": "node --test scripts/create-app.test.mjs",
|
|
35
|
-
"dev": "
|
|
36
|
-
"build": "tsc --noEmit &&
|
|
37
|
+
"dev": "npm run dev -w catalog",
|
|
38
|
+
"build": "node scripts/write-release.mjs && tsc --noEmit && npm run build -w catalog",
|
|
37
39
|
"typecheck": "tsc --noEmit",
|
|
38
40
|
"lint": "eslint . --max-warnings=0",
|
|
39
41
|
"format:check": "prettier --check src examples scripts *.json *.ts *.md docs/*.md",
|
|
40
|
-
"check:standards": "node scripts/check-standards.mjs"
|
|
42
|
+
"check:standards": "node scripts/check-standards.mjs",
|
|
43
|
+
"normalize:ui": "node scripts/normalize-ui.mjs && prettier --write src/components/ui src/hooks"
|
|
41
44
|
},
|
|
42
45
|
"peerDependencies": {
|
|
43
46
|
"react": "19.3.1",
|
|
@@ -48,28 +51,34 @@
|
|
|
48
51
|
},
|
|
49
52
|
"dependencies": {
|
|
50
53
|
"@base-ui/react": "1.9.0",
|
|
54
|
+
"@dnd-kit/core": "6.3.1",
|
|
55
|
+
"@dnd-kit/modifiers": "9.0.0",
|
|
56
|
+
"@dnd-kit/sortable": "10.0.0",
|
|
57
|
+
"@dnd-kit/utilities": "3.2.2",
|
|
51
58
|
"@fontsource-variable/geist": "^5.3.0",
|
|
59
|
+
"@tanstack/react-table": "8.21.3",
|
|
52
60
|
"class-variance-authority": "0.7.1",
|
|
53
61
|
"clsx": "2.1.1",
|
|
54
62
|
"cn": "^0.5.0",
|
|
55
63
|
"lucide-react": "1.61.0",
|
|
56
64
|
"shadcn": "^4.22.1",
|
|
65
|
+
"sonner": "^2.0.8",
|
|
57
66
|
"tailwind-merge": "3.7.0",
|
|
58
67
|
"tw-animate-css": "^1.4.0"
|
|
59
68
|
},
|
|
60
69
|
"devDependencies": {
|
|
61
70
|
"@eslint/js": "10.0.1",
|
|
62
|
-
"@tailwindcss/vite": "4.3.3",
|
|
63
71
|
"@types/node": "26.6.5",
|
|
64
72
|
"@types/react": "19.3.0",
|
|
65
73
|
"@types/react-dom": "19.3.0",
|
|
66
|
-
"@vitejs/plugin-react": "6.1.2",
|
|
67
74
|
"eslint": "10.13.0",
|
|
68
75
|
"eslint-plugin-react-hooks": "7.1.1",
|
|
69
76
|
"prettier": "3.9.10",
|
|
70
77
|
"tailwindcss": "4.3.3",
|
|
71
78
|
"typescript": "6.0.3",
|
|
72
|
-
"typescript-eslint": "8.72.0"
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
"typescript-eslint": "8.72.0"
|
|
80
|
+
},
|
|
81
|
+
"workspaces": [
|
|
82
|
+
"catalog"
|
|
83
|
+
]
|
|
75
84
|
}
|
|
@@ -19,6 +19,8 @@ async function visit(path) {
|
|
|
19
19
|
if (!consumer && name.startsWith("components/ui/")) continue;
|
|
20
20
|
if (consumer && /(?:^|\/)components\/ui\//.test(name))
|
|
21
21
|
violations.push(`${name}: local UI primitive copies are forbidden`);
|
|
22
|
+
if (/components\/native-select|<NativeSelect\b/.test(text))
|
|
23
|
+
violations.push(`${name}: use Select (Base UI), not a native select`);
|
|
22
24
|
if (/<(?:button|input|select|table|dialog)(?:\s|>)/.test(text))
|
|
23
25
|
violations.push(`${name}: use the shared UI primitive`);
|
|
24
26
|
if (
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
|
4
|
+
import { cn } from "cn";
|
|
5
|
+
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
6
|
+
|
|
7
|
+
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<AccordionPrimitive.Root
|
|
10
|
+
data-slot="accordion"
|
|
11
|
+
className={cn(
|
|
12
|
+
"flex w-full flex-col overflow-hidden rounded-2xl border",
|
|
13
|
+
className,
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
|
|
21
|
+
return (
|
|
22
|
+
<AccordionPrimitive.Item
|
|
23
|
+
data-slot="accordion-item"
|
|
24
|
+
className={cn("not-last:border-b data-open:bg-muted/50", className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function AccordionTrigger({
|
|
31
|
+
className,
|
|
32
|
+
children,
|
|
33
|
+
...props
|
|
34
|
+
}: AccordionPrimitive.Trigger.Props) {
|
|
35
|
+
return (
|
|
36
|
+
<AccordionPrimitive.Header className="flex">
|
|
37
|
+
<AccordionPrimitive.Trigger
|
|
38
|
+
data-slot="accordion-trigger"
|
|
39
|
+
className={cn(
|
|
40
|
+
"group/accordion-trigger relative flex flex-1 items-start justify-between gap-6 border border-transparent p-4 text-left text-sm font-medium transition-all outline-none hover:underline aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
<ChevronDownIcon
|
|
47
|
+
data-slot="accordion-trigger-icon"
|
|
48
|
+
className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
|
|
49
|
+
/>
|
|
50
|
+
<ChevronUpIcon
|
|
51
|
+
data-slot="accordion-trigger-icon"
|
|
52
|
+
className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
|
|
53
|
+
/>
|
|
54
|
+
</AccordionPrimitive.Trigger>
|
|
55
|
+
</AccordionPrimitive.Header>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function AccordionContent({
|
|
60
|
+
className,
|
|
61
|
+
children,
|
|
62
|
+
...props
|
|
63
|
+
}: AccordionPrimitive.Panel.Props) {
|
|
64
|
+
return (
|
|
65
|
+
<AccordionPrimitive.Panel
|
|
66
|
+
data-slot="accordion-content"
|
|
67
|
+
className="overflow-hidden px-4 text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
<div
|
|
71
|
+
className={cn(
|
|
72
|
+
"h-(--accordion-panel-height) pt-0 pb-4 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
|
|
73
|
+
className,
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
{children}
|
|
77
|
+
</div>
|
|
78
|
+
</AccordionPrimitive.Panel>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
|
|
5
|
+
import { cn } from "cn";
|
|
6
|
+
|
|
7
|
+
import { Button } from "./button";
|
|
8
|
+
|
|
9
|
+
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
|
|
10
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
|
|
14
|
+
return (
|
|
15
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
|
|
20
|
+
return (
|
|
21
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function AlertDialogOverlay({
|
|
26
|
+
className,
|
|
27
|
+
...props
|
|
28
|
+
}: AlertDialogPrimitive.Backdrop.Props) {
|
|
29
|
+
return (
|
|
30
|
+
<AlertDialogPrimitive.Backdrop
|
|
31
|
+
data-slot="alert-dialog-overlay"
|
|
32
|
+
className={cn(
|
|
33
|
+
"fixed inset-0 isolate z-50 bg-black/30 duration-100 supports-backdrop-filter:backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function AlertDialogContent({
|
|
42
|
+
className,
|
|
43
|
+
size = "default",
|
|
44
|
+
...props
|
|
45
|
+
}: AlertDialogPrimitive.Popup.Props & {
|
|
46
|
+
size?: "default" | "sm";
|
|
47
|
+
}) {
|
|
48
|
+
return (
|
|
49
|
+
<AlertDialogPortal>
|
|
50
|
+
<AlertDialogOverlay />
|
|
51
|
+
<AlertDialogPrimitive.Popup
|
|
52
|
+
data-slot="alert-dialog-content"
|
|
53
|
+
data-size={size}
|
|
54
|
+
className={cn(
|
|
55
|
+
"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-4xl bg-popover p-6 text-popover-foreground shadow-xl ring-1 ring-foreground/5 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
</AlertDialogPortal>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function AlertDialogHeader({
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}: React.ComponentProps<"div">) {
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
data-slot="alert-dialog-header"
|
|
71
|
+
className={cn(
|
|
72
|
+
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
|
|
73
|
+
className,
|
|
74
|
+
)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function AlertDialogFooter({
|
|
81
|
+
className,
|
|
82
|
+
...props
|
|
83
|
+
}: React.ComponentProps<"div">) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-slot="alert-dialog-footer"
|
|
87
|
+
className={cn(
|
|
88
|
+
"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
|
|
89
|
+
className,
|
|
90
|
+
)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function AlertDialogMedia({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<"div">) {
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
data-slot="alert-dialog-media"
|
|
103
|
+
className={cn(
|
|
104
|
+
"mb-2 inline-flex size-16 items-center justify-center rounded-full bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
|
|
105
|
+
className,
|
|
106
|
+
)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function AlertDialogTitle({
|
|
113
|
+
className,
|
|
114
|
+
...props
|
|
115
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
116
|
+
return (
|
|
117
|
+
<AlertDialogPrimitive.Title
|
|
118
|
+
data-slot="alert-dialog-title"
|
|
119
|
+
className={cn(
|
|
120
|
+
"font-heading text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function AlertDialogDescription({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
132
|
+
return (
|
|
133
|
+
<AlertDialogPrimitive.Description
|
|
134
|
+
data-slot="alert-dialog-description"
|
|
135
|
+
className={cn(
|
|
136
|
+
"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
137
|
+
className,
|
|
138
|
+
)}
|
|
139
|
+
{...props}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function AlertDialogAction({
|
|
145
|
+
className,
|
|
146
|
+
...props
|
|
147
|
+
}: React.ComponentProps<typeof Button>) {
|
|
148
|
+
return (
|
|
149
|
+
<Button
|
|
150
|
+
data-slot="alert-dialog-action"
|
|
151
|
+
className={cn(className)}
|
|
152
|
+
{...props}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function AlertDialogCancel({
|
|
158
|
+
className,
|
|
159
|
+
variant = "outline",
|
|
160
|
+
size = "default",
|
|
161
|
+
...props
|
|
162
|
+
}: AlertDialogPrimitive.Close.Props &
|
|
163
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
164
|
+
return (
|
|
165
|
+
<AlertDialogPrimitive.Close
|
|
166
|
+
data-slot="alert-dialog-cancel"
|
|
167
|
+
className={cn(className)}
|
|
168
|
+
render={<Button variant={variant} size={size} />}
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
AlertDialog,
|
|
176
|
+
AlertDialogAction,
|
|
177
|
+
AlertDialogCancel,
|
|
178
|
+
AlertDialogContent,
|
|
179
|
+
AlertDialogDescription,
|
|
180
|
+
AlertDialogFooter,
|
|
181
|
+
AlertDialogHeader,
|
|
182
|
+
AlertDialogMedia,
|
|
183
|
+
AlertDialogOverlay,
|
|
184
|
+
AlertDialogPortal,
|
|
185
|
+
AlertDialogTitle,
|
|
186
|
+
AlertDialogTrigger,
|
|
187
|
+
};
|
|
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
5
5
|
import { cn } from "cn";
|
|
6
6
|
|
|
7
7
|
const alertVariants = cva(
|
|
8
|
-
"group/alert relative grid w-full gap-0.5 rounded-
|
|
8
|
+
"group/alert relative grid w-full gap-0.5 rounded-2xl border px-4 py-3 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
@@ -68,7 +68,7 @@ function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
68
68
|
return (
|
|
69
69
|
<div
|
|
70
70
|
data-slot="alert-action"
|
|
71
|
-
className={cn("absolute top-2 right-
|
|
71
|
+
className={cn("absolute top-2.5 right-3", className)}
|
|
72
72
|
{...props}
|
|
73
73
|
/>
|
|
74
74
|
);
|