@umain-works/ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -0
- package/dist/index.d.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +139 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# @umain.works/ui — Umain Design System
|
|
2
|
+
|
|
3
|
+
Biblioteca de componentes React partilhada pela Umain. Publicada no [npmjs.com](https://www.npmjs.com/package/@umain.works/ui) como pacote público.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Desenvolvimento de componentes
|
|
8
|
+
|
|
9
|
+
O Storybook é o ambiente de desenvolvimento principal — desenvolves e vês os componentes em isolamento, sem precisar de levantar nenhum projecto React.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm run storybook
|
|
13
|
+
# → http://localhost:6006
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Só precisas de instalar o `@umain.works/ui` num projecto quando quiseres testar a **integração real** numa aplicação.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Como funciona (GitLab + npmjs.com)
|
|
21
|
+
|
|
22
|
+
São duas coisas independentes:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
GITLAB (código-fonte) → git push
|
|
26
|
+
src/, .storybook/, etc. para a equipa trabalhar
|
|
27
|
+
|
|
28
|
+
NPMJS.COM (pacote compilado) ← npm publish
|
|
29
|
+
dist/index.js só o dist/ é publicado
|
|
30
|
+
dist/index.mjs (o código-fonte não aparece no npm)
|
|
31
|
+
dist/index.d.ts
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- O **GitLab** tem o código-fonte — commits, pull requests, Storybook, tudo.
|
|
35
|
+
- O **npmjs.com** tem apenas o resultado compilado (`dist/`) para os projectos instalarem.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Setup inicial
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Clonar o repo
|
|
43
|
+
git clone https://gitlab.umain.works/umain/tools/design-system-umain/design-system.git
|
|
44
|
+
cd design-system
|
|
45
|
+
|
|
46
|
+
# Instalar dependências
|
|
47
|
+
npm install
|
|
48
|
+
|
|
49
|
+
# Iniciar Storybook (ambiente de desenvolvimento)
|
|
50
|
+
npm run storybook
|
|
51
|
+
|
|
52
|
+
# Build do pacote
|
|
53
|
+
npm run build
|
|
54
|
+
|
|
55
|
+
# Build em modo watch (útil ao desenvolver)
|
|
56
|
+
npm run dev
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Publicar no npmjs.com
|
|
62
|
+
|
|
63
|
+
### Pré-requisitos (apenas 1 vez)
|
|
64
|
+
|
|
65
|
+
1. **Criar conta** em [npmjs.com](https://npmjs.com) se não tens
|
|
66
|
+
2. **Organização `umain.works`** já criada em npmjs.com
|
|
67
|
+
3. **Gerar um Access Token com bypass 2FA:**
|
|
68
|
+
`npmjs.com` → Avatar → **Access Tokens** → **Generate New Token** → **Granular Access Token**
|
|
69
|
+
- Packages and scopes: **Read and write**
|
|
70
|
+
- Activa **"Bypass 2FA"** ✅
|
|
71
|
+
Copia o token (começa com `npm_...`)
|
|
72
|
+
|
|
73
|
+
### Publicar
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Exportar o token como variável de ambiente
|
|
77
|
+
export NPM_TOKEN=npm_xxxxxxxxxxxxxxxxxxxx
|
|
78
|
+
|
|
79
|
+
# Publicar (o build corre automaticamente antes)
|
|
80
|
+
npm publish
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Verificar
|
|
84
|
+
|
|
85
|
+
Após publicar, o pacote aparece em:
|
|
86
|
+
**`https://www.npmjs.com/package/@umain.works/ui`**
|
|
87
|
+
|
|
88
|
+
### Apagar (para demos)
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Podes apagar nas primeiras 72 horas sem restrições
|
|
92
|
+
npm unpublish @umain.works/ui@0.0.1
|
|
93
|
+
|
|
94
|
+
# Ou apagar o pacote inteiro
|
|
95
|
+
npm unpublish @umain.works/ui --force
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Instalar num projecto consumidor
|
|
101
|
+
|
|
102
|
+
Como é um pacote público no npmjs.com, **não precisas de nenhum `.npmrc` especial** — funciona como qualquer outro pacote:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install @umain.works/ui
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Usar nos componentes
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { Button } from '@umain.works/ui';
|
|
112
|
+
|
|
113
|
+
export function LoginPage() {
|
|
114
|
+
return (
|
|
115
|
+
<Button color="Primary" size="base" onClick={handleLogin}>
|
|
116
|
+
Entrar
|
|
117
|
+
</Button>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Componentes disponíveis
|
|
125
|
+
|
|
126
|
+
| Componente | Versão | Descrição |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `Button` | 0.0.1 | Botão com 7 variantes de cor, 5 tamanhos, estados loading/disabled/active |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Estrutura do projecto
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
design-system/
|
|
136
|
+
├── src/
|
|
137
|
+
│ ├── components/
|
|
138
|
+
│ │ └── Button/
|
|
139
|
+
│ │ ├── Button.tsx ← implementação
|
|
140
|
+
│ │ ├── Button.types.ts ← tipos TypeScript
|
|
141
|
+
│ │ ├── Button.stories.tsx ← documentação Storybook
|
|
142
|
+
│ │ └── index.ts ← re-exports
|
|
143
|
+
│ └── index.ts ← export central do pacote
|
|
144
|
+
├── .storybook/
|
|
145
|
+
│ ├── main.ts ← config Storybook (Vite + React)
|
|
146
|
+
│ └── preview.ts ← globals e decorators
|
|
147
|
+
├── dist/ ← gerado pelo build (não commitar)
|
|
148
|
+
├── .npmrc ← token do npmjs.com (não commitar o token!)
|
|
149
|
+
├── package.json
|
|
150
|
+
├── tsconfig.json
|
|
151
|
+
└── tsup.config.ts ← config do builder (ESM + CJS + types)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Adicionar um novo componente
|
|
157
|
+
|
|
158
|
+
1. Cria a pasta `src/components/NomeComponente/`
|
|
159
|
+
2. Segue o padrão do Button:
|
|
160
|
+
- `NomeComponente.tsx` — implementação
|
|
161
|
+
- `NomeComponente.types.ts` — tipos
|
|
162
|
+
- `NomeComponente.stories.tsx` — stories do Storybook
|
|
163
|
+
- `index.ts` — re-exports
|
|
164
|
+
3. Exporta em `src/index.ts`:
|
|
165
|
+
```ts
|
|
166
|
+
export { NomeComponente } from "./components/NomeComponente";
|
|
167
|
+
export type { NomeComponenteProps } from "./components/NomeComponente";
|
|
168
|
+
```
|
|
169
|
+
4. Testa no Storybook: `npm run storybook`
|
|
170
|
+
5. Faz build: `npm run build`
|
|
171
|
+
6. Bumpa a versão e publica: `npm version minor && npm publish`
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Scripts
|
|
176
|
+
|
|
177
|
+
| Script | Descrição |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `npm run build` | Build do pacote para `dist/` (ESM + CJS + types) |
|
|
180
|
+
| `npm run dev` | Build em modo watch |
|
|
181
|
+
| `npm run storybook` | Storybook em modo desenvolvimento (porta 6006) |
|
|
182
|
+
| `npm run build-storybook` | Build estático do Storybook |
|
|
183
|
+
| `npm run lint` | Verificação de tipos TypeScript |
|
|
184
|
+
| `npm publish` | Publica no npmjs.com (build automático antes) |
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Versionamento
|
|
189
|
+
|
|
190
|
+
Usamos [Semantic Versioning](https://semver.org/):
|
|
191
|
+
|
|
192
|
+
- `PATCH` (0.0.x) — bug fixes
|
|
193
|
+
- `MINOR` (0.x.0) — novos componentes ou funcionalidades (não breaking)
|
|
194
|
+
- `MAJOR` (x.0.0) — breaking changes na API
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npm version patch # 0.0.1 → 0.0.2
|
|
198
|
+
npm version minor # 0.0.1 → 0.1.0
|
|
199
|
+
npm version major # 0.0.1 → 1.0.0
|
|
200
|
+
|
|
201
|
+
npm publish # build automático + publish no npmjs.com
|
|
202
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type ButtonSize = "xxs" | "xs" | "sm" | "base" | "l";
|
|
4
|
+
type ButtonColor = "Primary" | "PrimaryWhite" | "PrimaryTertiary" | "BlackWhite" | "Black" | "WhiteBordered" | "BlackTertiary";
|
|
5
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
/** Tamanho do botão */
|
|
7
|
+
size?: ButtonSize;
|
|
8
|
+
/** Variante de cor */
|
|
9
|
+
color?: ButtonColor;
|
|
10
|
+
/** Mostra spinner de loading e desativa o botão */
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
/** Ícone personalizado para o estado de loading */
|
|
13
|
+
loadingIcon?: React.ReactNode;
|
|
14
|
+
/** Modo icon-only: padding quadrado sem gap */
|
|
15
|
+
iconOnly?: boolean;
|
|
16
|
+
/** Padding responsivo automático (adapta-se ao viewport) */
|
|
17
|
+
responsiveSize?: boolean;
|
|
18
|
+
/** Estado activo (ex: botão toggle pressionado) */
|
|
19
|
+
active?: boolean;
|
|
20
|
+
/** Padding quadrado igual em todos os lados */
|
|
21
|
+
squarePadding?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ## Button
|
|
26
|
+
*
|
|
27
|
+
* Componente de botão do Umain Design System.
|
|
28
|
+
*
|
|
29
|
+
* ### Variantes de cor
|
|
30
|
+
* `Primary` | `PrimaryWhite` | `PrimaryTertiary` | `BlackWhite` | `Black` | `WhiteBordered` | `BlackTertiary`
|
|
31
|
+
*
|
|
32
|
+
* ### Tamanhos
|
|
33
|
+
* `xxs` | `xs` | `sm` | `base` | `l`
|
|
34
|
+
*
|
|
35
|
+
* ### Estados
|
|
36
|
+
* `default`, `hover`, `focus`, `active`, `disabled`, `loading`
|
|
37
|
+
*/
|
|
38
|
+
declare const Button: React.FC<ButtonProps>;
|
|
39
|
+
|
|
40
|
+
export { Button, type ButtonColor, type ButtonProps, type ButtonSize };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type ButtonSize = "xxs" | "xs" | "sm" | "base" | "l";
|
|
4
|
+
type ButtonColor = "Primary" | "PrimaryWhite" | "PrimaryTertiary" | "BlackWhite" | "Black" | "WhiteBordered" | "BlackTertiary";
|
|
5
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
/** Tamanho do botão */
|
|
7
|
+
size?: ButtonSize;
|
|
8
|
+
/** Variante de cor */
|
|
9
|
+
color?: ButtonColor;
|
|
10
|
+
/** Mostra spinner de loading e desativa o botão */
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
/** Ícone personalizado para o estado de loading */
|
|
13
|
+
loadingIcon?: React.ReactNode;
|
|
14
|
+
/** Modo icon-only: padding quadrado sem gap */
|
|
15
|
+
iconOnly?: boolean;
|
|
16
|
+
/** Padding responsivo automático (adapta-se ao viewport) */
|
|
17
|
+
responsiveSize?: boolean;
|
|
18
|
+
/** Estado activo (ex: botão toggle pressionado) */
|
|
19
|
+
active?: boolean;
|
|
20
|
+
/** Padding quadrado igual em todos os lados */
|
|
21
|
+
squarePadding?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ## Button
|
|
26
|
+
*
|
|
27
|
+
* Componente de botão do Umain Design System.
|
|
28
|
+
*
|
|
29
|
+
* ### Variantes de cor
|
|
30
|
+
* `Primary` | `PrimaryWhite` | `PrimaryTertiary` | `BlackWhite` | `Black` | `WhiteBordered` | `BlackTertiary`
|
|
31
|
+
*
|
|
32
|
+
* ### Tamanhos
|
|
33
|
+
* `xxs` | `xs` | `sm` | `base` | `l`
|
|
34
|
+
*
|
|
35
|
+
* ### Estados
|
|
36
|
+
* `default`, `hover`, `focus`, `active`, `disabled`, `loading`
|
|
37
|
+
*/
|
|
38
|
+
declare const Button: React.FC<ButtonProps>;
|
|
39
|
+
|
|
40
|
+
export { Button, type ButtonColor, type ButtonProps, type ButtonSize };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
|
|
5
|
+
// src/components/Button/Button.tsx
|
|
6
|
+
var LoadingSpinner = ({
|
|
7
|
+
className,
|
|
8
|
+
dark = false
|
|
9
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10
|
+
"svg",
|
|
11
|
+
{
|
|
12
|
+
className: `animate-spin ${className ?? "h-4 w-4"}`,
|
|
13
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14
|
+
fill: "none",
|
|
15
|
+
viewBox: "0 0 24 24",
|
|
16
|
+
"aria-hidden": "true",
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19
|
+
"circle",
|
|
20
|
+
{
|
|
21
|
+
className: "opacity-25",
|
|
22
|
+
cx: "12",
|
|
23
|
+
cy: "12",
|
|
24
|
+
r: "10",
|
|
25
|
+
stroke: dark ? "#1a1a1a" : "currentColor",
|
|
26
|
+
strokeWidth: "4"
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
30
|
+
"path",
|
|
31
|
+
{
|
|
32
|
+
className: "opacity-75",
|
|
33
|
+
fill: dark ? "#1a1a1a" : "currentColor",
|
|
34
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
var Button = ({
|
|
41
|
+
children,
|
|
42
|
+
className = "",
|
|
43
|
+
size = "base",
|
|
44
|
+
color = "Primary",
|
|
45
|
+
loading = false,
|
|
46
|
+
loadingIcon,
|
|
47
|
+
disabled,
|
|
48
|
+
iconOnly = false,
|
|
49
|
+
responsiveSize = false,
|
|
50
|
+
active = false,
|
|
51
|
+
squarePadding = false,
|
|
52
|
+
...props
|
|
53
|
+
}) => {
|
|
54
|
+
const baseClasses = "inline-flex items-center justify-center font-semibold outline-none transition cursor-pointer disabled:cursor-not-allowed focus-visible:ring-0 focus-visible:ring-offset-2 disabled:opacity-60";
|
|
55
|
+
const base = iconOnly ? baseClasses : `${baseClasses} gap-2`;
|
|
56
|
+
const colors = {
|
|
57
|
+
Primary: "rounded-xs bg-primary-500 enabled:hover:bg-primary-600 enabled:active:bg-primary-700 disabled:text-darkgrey-300 disabled:bg-darkgrey-100 text-white focus-visible:ring-primary-200 border border-transparent",
|
|
58
|
+
PrimaryWhite: "rounded-xs bg-white enabled:hover:bg-umainblack-50 enabled:active:bg-white text-primary-500 enabled:hover:text-primary-700 enabled:active:text-primary-700 focus-visible:ring-primary-200 border border-transparent",
|
|
59
|
+
PrimaryTertiary: "rounded-xs bg-transparent enabled:active:bg-umainblack-50 text-primary-500 enabled:hover:text-primary-700 focus-visible:ring-umainblack-300 border border-transparent",
|
|
60
|
+
BlackWhite: "rounded-xs bg-transparent enabled:hover:bg-darkgrey-50 enabled:active:bg-umainblack-50 text-umainblack-500 hover:text-umainblack-500",
|
|
61
|
+
Black: "rounded-xs bg-umainblack-500 enabled:hover:bg-umainblack-900 enabled:active:bg-umainblack-500 text-white enabled:hover:text-white enabled:active:text-white focus-visible:ring-umainblack-300 border border-transparent",
|
|
62
|
+
WhiteBordered: "rounded-xs bg-white enabled:hover:bg-darkgrey-50 enabled:active:bg-white disabled:bg-darkgrey-100 text-umainblack-500 enabled:hover:text-primary-500 enabled:active:text-primary-700 focus-visible:ring-primary-200 focus-visible:border-primary-500 border border-umainblack-50",
|
|
63
|
+
BlackTertiary: "rounded-xs bg-transparent text-umainblack-500 enabled:hover:bg-primary-50 enabled:focus:bg-primary-50 enabled:focus:text-primary-500 enabled:focus:ring-primary-200 disabled:bg-darkgrey-100 disabled:text-darkgrey-300 border border-transparent"
|
|
64
|
+
};
|
|
65
|
+
const activeColors = {
|
|
66
|
+
Primary: "bg-primary-700 text-white active:bg-primary-700 focus-visible:ring-primary-200 focus:ring-3 border border-transparent",
|
|
67
|
+
PrimaryWhite: "rounded-sm bg-primary-50 hover:bg-darkgrey-50 text-primary-500 hover:text-primary-700 focus-visible:ring-primary-200 border border-transparent focus:border-[3px] focus:border-umainblack-200",
|
|
68
|
+
PrimaryTertiary: "rounded-sm bg-umainblack-50 text-red-500 focus-visible:ring-umainblack-300 border border-transparent focus:border-[3px] focus:border-primary-200",
|
|
69
|
+
BlackWhite: "rounded-sm bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-700 border border-umainblack-700 focus:border-[3px] focus:border-umainwhite-700",
|
|
70
|
+
WhiteBordered: "bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-300 border border-umainblack-50 focus:border focus:border-umainwhite-200",
|
|
71
|
+
Black: "bg-umainblack-900 text-white active:bg-umainblack-900 focus-visible:ring-umainblack-300 focus:ring-3 border border-transparent",
|
|
72
|
+
BlackTertiary: "bg-primary-50 text-primary-500 ring-1 ring-primary-500"
|
|
73
|
+
};
|
|
74
|
+
const loadingColors = {
|
|
75
|
+
Primary: "rounded-sm bg-primary-300 text-primary-100 border border-transparent",
|
|
76
|
+
PrimaryWhite: "rounded-sm bg-white text-primary-500 border border-transparent",
|
|
77
|
+
PrimaryTertiary: "rounded-sm bg-white text-primary-500 border border-transparent",
|
|
78
|
+
BlackWhite: "rounded-sm bg-white text-umainblack-500 border border-umainblack-500",
|
|
79
|
+
Black: "rounded-sm bg-umainblack-500 text-white border border-transparent",
|
|
80
|
+
WhiteBordered: "rounded-sm bg-white text-umainblack-500 border border-umainblack-50",
|
|
81
|
+
BlackTertiary: "rounded-sm bg-transparent text-umainblack-200 border border-transparent"
|
|
82
|
+
};
|
|
83
|
+
const sizes = {
|
|
84
|
+
xxs: "py-1 px-2 text-xs font-semibold",
|
|
85
|
+
xs: "py-2 px-3 text-xs font-semibold",
|
|
86
|
+
sm: "py-2 px-3 text-sm font-semibold",
|
|
87
|
+
base: "py-2.5 px-5 text-sm font-semibold",
|
|
88
|
+
l: "py-3 px-5 text-base font-semibold"
|
|
89
|
+
};
|
|
90
|
+
const iconSizes = {
|
|
91
|
+
xxs: "w-6 h-6 p-1",
|
|
92
|
+
xs: "w-8 h-8 p-1",
|
|
93
|
+
sm: "w-9 h-9 p-2",
|
|
94
|
+
base: "w-10 h-10 p-2.5",
|
|
95
|
+
l: "w-12 h-12 p-3"
|
|
96
|
+
};
|
|
97
|
+
const squarePaddingSizes = {
|
|
98
|
+
xxs: "p-0.5",
|
|
99
|
+
xs: "p-1",
|
|
100
|
+
sm: "p-2",
|
|
101
|
+
base: "p-2.5",
|
|
102
|
+
l: "p-3"
|
|
103
|
+
};
|
|
104
|
+
const getButtonColors = () => {
|
|
105
|
+
if (loading) return loadingColors[color];
|
|
106
|
+
if (active) return activeColors[color];
|
|
107
|
+
return colors[color];
|
|
108
|
+
};
|
|
109
|
+
const getResponsiveSize = () => {
|
|
110
|
+
if (!responsiveSize) return "";
|
|
111
|
+
return [
|
|
112
|
+
"py-2 px-2 w-auto h-auto rounded gap-1 text-sm font-semibold",
|
|
113
|
+
"sm:py-2 sm:px-3 sm:w-auto sm:h-auto sm:rounded sm:gap-2 sm:text-xs sm:font-semibold",
|
|
114
|
+
"md:py-2 md:px-3 md:w-auto md:h-auto md:rounded md:gap-2 md:text-sm md:font-semibold"
|
|
115
|
+
].join(" ");
|
|
116
|
+
};
|
|
117
|
+
const isLightBackgroundButton = color !== "Primary" && color !== "Black";
|
|
118
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
119
|
+
"button",
|
|
120
|
+
{
|
|
121
|
+
className: `${base} ${getButtonColors()} ${responsiveSize ? getResponsiveSize() : squarePadding ? `${squarePaddingSizes[size]} rounded-xs` : iconOnly ? `${iconSizes[size]} rounded-xs` : `${sizes[size]} rounded-xs`} ${className}`,
|
|
122
|
+
disabled: disabled || loading,
|
|
123
|
+
"aria-busy": loading || void 0,
|
|
124
|
+
...props,
|
|
125
|
+
children: [
|
|
126
|
+
loading && (loadingIcon ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
127
|
+
LoadingSpinner,
|
|
128
|
+
{
|
|
129
|
+
className: "h-4 w-4",
|
|
130
|
+
dark: isLightBackgroundButton
|
|
131
|
+
}
|
|
132
|
+
)),
|
|
133
|
+
children
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
exports.Button = Button;
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button/Button.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import React from \"react\";\nimport type { ButtonProps, ButtonColor, ButtonSize } from \"./Button.types\";\n\n// Spinner SVG inline — sem dependência de ícones externos\nconst LoadingSpinner = ({\n className,\n dark = false,\n}: {\n className?: string;\n dark?: boolean;\n}) => (\n <svg\n className={`animate-spin ${className ?? \"h-4 w-4\"}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={dark ? \"#1a1a1a\" : \"currentColor\"}\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill={dark ? \"#1a1a1a\" : \"currentColor\"}\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n);\n\n/**\n * ## Button\n *\n * Componente de botão do Umain Design System.\n *\n * ### Variantes de cor\n * `Primary` | `PrimaryWhite` | `PrimaryTertiary` | `BlackWhite` | `Black` | `WhiteBordered` | `BlackTertiary`\n *\n * ### Tamanhos\n * `xxs` | `xs` | `sm` | `base` | `l`\n *\n * ### Estados\n * `default`, `hover`, `focus`, `active`, `disabled`, `loading`\n */\nexport const Button: React.FC<ButtonProps> = ({\n children,\n className = \"\",\n size = \"base\",\n color = \"Primary\",\n loading = false,\n loadingIcon,\n disabled,\n iconOnly = false,\n responsiveSize = false,\n active = false,\n squarePadding = false,\n ...props\n}) => {\n const baseClasses =\n \"inline-flex items-center justify-center font-semibold outline-none transition cursor-pointer disabled:cursor-not-allowed \" +\n \"focus-visible:ring-0 focus-visible:ring-offset-2 \" +\n \"disabled:opacity-60\";\n\n const base = iconOnly ? baseClasses : `${baseClasses} gap-2`;\n\n const colors: Record<ButtonColor, string> = {\n Primary:\n \"rounded-xs bg-primary-500 enabled:hover:bg-primary-600 enabled:active:bg-primary-700 disabled:text-darkgrey-300 disabled:bg-darkgrey-100 text-white focus-visible:ring-primary-200 border border-transparent\",\n PrimaryWhite:\n \"rounded-xs bg-white enabled:hover:bg-umainblack-50 enabled:active:bg-white text-primary-500 enabled:hover:text-primary-700 enabled:active:text-primary-700 focus-visible:ring-primary-200 border border-transparent\",\n PrimaryTertiary:\n \"rounded-xs bg-transparent enabled:active:bg-umainblack-50 text-primary-500 enabled:hover:text-primary-700 focus-visible:ring-umainblack-300 border border-transparent\",\n BlackWhite:\n \"rounded-xs bg-transparent enabled:hover:bg-darkgrey-50 enabled:active:bg-umainblack-50 text-umainblack-500 hover:text-umainblack-500\",\n Black:\n \"rounded-xs bg-umainblack-500 enabled:hover:bg-umainblack-900 enabled:active:bg-umainblack-500 text-white enabled:hover:text-white enabled:active:text-white focus-visible:ring-umainblack-300 border border-transparent\",\n WhiteBordered:\n \"rounded-xs bg-white enabled:hover:bg-darkgrey-50 enabled:active:bg-white disabled:bg-darkgrey-100 text-umainblack-500 enabled:hover:text-primary-500 enabled:active:text-primary-700 focus-visible:ring-primary-200 focus-visible:border-primary-500 border border-umainblack-50\",\n BlackTertiary:\n \"rounded-xs bg-transparent text-umainblack-500 enabled:hover:bg-primary-50 enabled:focus:bg-primary-50 enabled:focus:text-primary-500 enabled:focus:ring-primary-200 disabled:bg-darkgrey-100 disabled:text-darkgrey-300 border border-transparent\",\n };\n\n const activeColors: Record<ButtonColor, string> = {\n Primary:\n \"bg-primary-700 text-white active:bg-primary-700 focus-visible:ring-primary-200 focus:ring-3 border border-transparent\",\n PrimaryWhite:\n \"rounded-sm bg-primary-50 hover:bg-darkgrey-50 text-primary-500 hover:text-primary-700 focus-visible:ring-primary-200 border border-transparent focus:border-[3px] focus:border-umainblack-200\",\n PrimaryTertiary:\n \"rounded-sm bg-umainblack-50 text-red-500 focus-visible:ring-umainblack-300 border border-transparent focus:border-[3px] focus:border-primary-200\",\n BlackWhite:\n \"rounded-sm bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-700 border border-umainblack-700 focus:border-[3px] focus:border-umainwhite-700\",\n WhiteBordered:\n \"bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-300 border border-umainblack-50 focus:border focus:border-umainwhite-200\",\n Black:\n \"bg-umainblack-900 text-white active:bg-umainblack-900 focus-visible:ring-umainblack-300 focus:ring-3 border border-transparent\",\n BlackTertiary: \"bg-primary-50 text-primary-500 ring-1 ring-primary-500\",\n };\n\n const loadingColors: Record<ButtonColor, string> = {\n Primary: \"rounded-sm bg-primary-300 text-primary-100 border border-transparent\",\n PrimaryWhite: \"rounded-sm bg-white text-primary-500 border border-transparent\",\n PrimaryTertiary: \"rounded-sm bg-white text-primary-500 border border-transparent\",\n BlackWhite: \"rounded-sm bg-white text-umainblack-500 border border-umainblack-500\",\n Black: \"rounded-sm bg-umainblack-500 text-white border border-transparent\",\n WhiteBordered: \"rounded-sm bg-white text-umainblack-500 border border-umainblack-50\",\n BlackTertiary: \"rounded-sm bg-transparent text-umainblack-200 border border-transparent\",\n };\n\n const sizes: Record<ButtonSize, string> = {\n xxs: \"py-1 px-2 text-xs font-semibold\",\n xs: \"py-2 px-3 text-xs font-semibold\",\n sm: \"py-2 px-3 text-sm font-semibold\",\n base: \"py-2.5 px-5 text-sm font-semibold\",\n l: \"py-3 px-5 text-base font-semibold\",\n };\n\n const iconSizes: Record<ButtonSize, string> = {\n xxs: \"w-6 h-6 p-1\",\n xs: \"w-8 h-8 p-1\",\n sm: \"w-9 h-9 p-2\",\n base: \"w-10 h-10 p-2.5\",\n l: \"w-12 h-12 p-3\",\n };\n\n const squarePaddingSizes: Record<ButtonSize, string> = {\n xxs: \"p-0.5\",\n xs: \"p-1\",\n sm: \"p-2\",\n base: \"p-2.5\",\n l: \"p-3\",\n };\n\n const getButtonColors = () => {\n if (loading) return loadingColors[color];\n if (active) return activeColors[color];\n return colors[color];\n };\n\n const getResponsiveSize = () => {\n if (!responsiveSize) return \"\";\n return [\n \"py-2 px-2 w-auto h-auto rounded gap-1 text-sm font-semibold\",\n \"sm:py-2 sm:px-3 sm:w-auto sm:h-auto sm:rounded sm:gap-2 sm:text-xs sm:font-semibold\",\n \"md:py-2 md:px-3 md:w-auto md:h-auto md:rounded md:gap-2 md:text-sm md:font-semibold\",\n ].join(\" \");\n };\n\n const isLightBackgroundButton = color !== \"Primary\" && color !== \"Black\";\n\n return (\n <button\n className={`${base} ${getButtonColors()} ${\n responsiveSize\n ? getResponsiveSize()\n : squarePadding\n ? `${squarePaddingSizes[size]} rounded-xs`\n : iconOnly\n ? `${iconSizes[size]} rounded-xs`\n : `${sizes[size]} rounded-xs`\n } ${className}`}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading &&\n (loadingIcon ?? (\n <LoadingSpinner\n className=\"h-4 w-4\"\n dark={isLightBackgroundButton}\n />\n ))}\n {children}\n </button>\n );\n};\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
// src/components/Button/Button.tsx
|
|
4
|
+
var LoadingSpinner = ({
|
|
5
|
+
className,
|
|
6
|
+
dark = false
|
|
7
|
+
}) => /* @__PURE__ */ jsxs(
|
|
8
|
+
"svg",
|
|
9
|
+
{
|
|
10
|
+
className: `animate-spin ${className ?? "h-4 w-4"}`,
|
|
11
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12
|
+
fill: "none",
|
|
13
|
+
viewBox: "0 0 24 24",
|
|
14
|
+
"aria-hidden": "true",
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"circle",
|
|
18
|
+
{
|
|
19
|
+
className: "opacity-25",
|
|
20
|
+
cx: "12",
|
|
21
|
+
cy: "12",
|
|
22
|
+
r: "10",
|
|
23
|
+
stroke: dark ? "#1a1a1a" : "currentColor",
|
|
24
|
+
strokeWidth: "4"
|
|
25
|
+
}
|
|
26
|
+
),
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
"path",
|
|
29
|
+
{
|
|
30
|
+
className: "opacity-75",
|
|
31
|
+
fill: dark ? "#1a1a1a" : "currentColor",
|
|
32
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
var Button = ({
|
|
39
|
+
children,
|
|
40
|
+
className = "",
|
|
41
|
+
size = "base",
|
|
42
|
+
color = "Primary",
|
|
43
|
+
loading = false,
|
|
44
|
+
loadingIcon,
|
|
45
|
+
disabled,
|
|
46
|
+
iconOnly = false,
|
|
47
|
+
responsiveSize = false,
|
|
48
|
+
active = false,
|
|
49
|
+
squarePadding = false,
|
|
50
|
+
...props
|
|
51
|
+
}) => {
|
|
52
|
+
const baseClasses = "inline-flex items-center justify-center font-semibold outline-none transition cursor-pointer disabled:cursor-not-allowed focus-visible:ring-0 focus-visible:ring-offset-2 disabled:opacity-60";
|
|
53
|
+
const base = iconOnly ? baseClasses : `${baseClasses} gap-2`;
|
|
54
|
+
const colors = {
|
|
55
|
+
Primary: "rounded-xs bg-primary-500 enabled:hover:bg-primary-600 enabled:active:bg-primary-700 disabled:text-darkgrey-300 disabled:bg-darkgrey-100 text-white focus-visible:ring-primary-200 border border-transparent",
|
|
56
|
+
PrimaryWhite: "rounded-xs bg-white enabled:hover:bg-umainblack-50 enabled:active:bg-white text-primary-500 enabled:hover:text-primary-700 enabled:active:text-primary-700 focus-visible:ring-primary-200 border border-transparent",
|
|
57
|
+
PrimaryTertiary: "rounded-xs bg-transparent enabled:active:bg-umainblack-50 text-primary-500 enabled:hover:text-primary-700 focus-visible:ring-umainblack-300 border border-transparent",
|
|
58
|
+
BlackWhite: "rounded-xs bg-transparent enabled:hover:bg-darkgrey-50 enabled:active:bg-umainblack-50 text-umainblack-500 hover:text-umainblack-500",
|
|
59
|
+
Black: "rounded-xs bg-umainblack-500 enabled:hover:bg-umainblack-900 enabled:active:bg-umainblack-500 text-white enabled:hover:text-white enabled:active:text-white focus-visible:ring-umainblack-300 border border-transparent",
|
|
60
|
+
WhiteBordered: "rounded-xs bg-white enabled:hover:bg-darkgrey-50 enabled:active:bg-white disabled:bg-darkgrey-100 text-umainblack-500 enabled:hover:text-primary-500 enabled:active:text-primary-700 focus-visible:ring-primary-200 focus-visible:border-primary-500 border border-umainblack-50",
|
|
61
|
+
BlackTertiary: "rounded-xs bg-transparent text-umainblack-500 enabled:hover:bg-primary-50 enabled:focus:bg-primary-50 enabled:focus:text-primary-500 enabled:focus:ring-primary-200 disabled:bg-darkgrey-100 disabled:text-darkgrey-300 border border-transparent"
|
|
62
|
+
};
|
|
63
|
+
const activeColors = {
|
|
64
|
+
Primary: "bg-primary-700 text-white active:bg-primary-700 focus-visible:ring-primary-200 focus:ring-3 border border-transparent",
|
|
65
|
+
PrimaryWhite: "rounded-sm bg-primary-50 hover:bg-darkgrey-50 text-primary-500 hover:text-primary-700 focus-visible:ring-primary-200 border border-transparent focus:border-[3px] focus:border-umainblack-200",
|
|
66
|
+
PrimaryTertiary: "rounded-sm bg-umainblack-50 text-red-500 focus-visible:ring-umainblack-300 border border-transparent focus:border-[3px] focus:border-primary-200",
|
|
67
|
+
BlackWhite: "rounded-sm bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-700 border border-umainblack-700 focus:border-[3px] focus:border-umainwhite-700",
|
|
68
|
+
WhiteBordered: "bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-300 border border-umainblack-50 focus:border focus:border-umainwhite-200",
|
|
69
|
+
Black: "bg-umainblack-900 text-white active:bg-umainblack-900 focus-visible:ring-umainblack-300 focus:ring-3 border border-transparent",
|
|
70
|
+
BlackTertiary: "bg-primary-50 text-primary-500 ring-1 ring-primary-500"
|
|
71
|
+
};
|
|
72
|
+
const loadingColors = {
|
|
73
|
+
Primary: "rounded-sm bg-primary-300 text-primary-100 border border-transparent",
|
|
74
|
+
PrimaryWhite: "rounded-sm bg-white text-primary-500 border border-transparent",
|
|
75
|
+
PrimaryTertiary: "rounded-sm bg-white text-primary-500 border border-transparent",
|
|
76
|
+
BlackWhite: "rounded-sm bg-white text-umainblack-500 border border-umainblack-500",
|
|
77
|
+
Black: "rounded-sm bg-umainblack-500 text-white border border-transparent",
|
|
78
|
+
WhiteBordered: "rounded-sm bg-white text-umainblack-500 border border-umainblack-50",
|
|
79
|
+
BlackTertiary: "rounded-sm bg-transparent text-umainblack-200 border border-transparent"
|
|
80
|
+
};
|
|
81
|
+
const sizes = {
|
|
82
|
+
xxs: "py-1 px-2 text-xs font-semibold",
|
|
83
|
+
xs: "py-2 px-3 text-xs font-semibold",
|
|
84
|
+
sm: "py-2 px-3 text-sm font-semibold",
|
|
85
|
+
base: "py-2.5 px-5 text-sm font-semibold",
|
|
86
|
+
l: "py-3 px-5 text-base font-semibold"
|
|
87
|
+
};
|
|
88
|
+
const iconSizes = {
|
|
89
|
+
xxs: "w-6 h-6 p-1",
|
|
90
|
+
xs: "w-8 h-8 p-1",
|
|
91
|
+
sm: "w-9 h-9 p-2",
|
|
92
|
+
base: "w-10 h-10 p-2.5",
|
|
93
|
+
l: "w-12 h-12 p-3"
|
|
94
|
+
};
|
|
95
|
+
const squarePaddingSizes = {
|
|
96
|
+
xxs: "p-0.5",
|
|
97
|
+
xs: "p-1",
|
|
98
|
+
sm: "p-2",
|
|
99
|
+
base: "p-2.5",
|
|
100
|
+
l: "p-3"
|
|
101
|
+
};
|
|
102
|
+
const getButtonColors = () => {
|
|
103
|
+
if (loading) return loadingColors[color];
|
|
104
|
+
if (active) return activeColors[color];
|
|
105
|
+
return colors[color];
|
|
106
|
+
};
|
|
107
|
+
const getResponsiveSize = () => {
|
|
108
|
+
if (!responsiveSize) return "";
|
|
109
|
+
return [
|
|
110
|
+
"py-2 px-2 w-auto h-auto rounded gap-1 text-sm font-semibold",
|
|
111
|
+
"sm:py-2 sm:px-3 sm:w-auto sm:h-auto sm:rounded sm:gap-2 sm:text-xs sm:font-semibold",
|
|
112
|
+
"md:py-2 md:px-3 md:w-auto md:h-auto md:rounded md:gap-2 md:text-sm md:font-semibold"
|
|
113
|
+
].join(" ");
|
|
114
|
+
};
|
|
115
|
+
const isLightBackgroundButton = color !== "Primary" && color !== "Black";
|
|
116
|
+
return /* @__PURE__ */ jsxs(
|
|
117
|
+
"button",
|
|
118
|
+
{
|
|
119
|
+
className: `${base} ${getButtonColors()} ${responsiveSize ? getResponsiveSize() : squarePadding ? `${squarePaddingSizes[size]} rounded-xs` : iconOnly ? `${iconSizes[size]} rounded-xs` : `${sizes[size]} rounded-xs`} ${className}`,
|
|
120
|
+
disabled: disabled || loading,
|
|
121
|
+
"aria-busy": loading || void 0,
|
|
122
|
+
...props,
|
|
123
|
+
children: [
|
|
124
|
+
loading && (loadingIcon ?? /* @__PURE__ */ jsx(
|
|
125
|
+
LoadingSpinner,
|
|
126
|
+
{
|
|
127
|
+
className: "h-4 w-4",
|
|
128
|
+
dark: isLightBackgroundButton
|
|
129
|
+
}
|
|
130
|
+
)),
|
|
131
|
+
children
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export { Button };
|
|
138
|
+
//# sourceMappingURL=index.mjs.map
|
|
139
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button/Button.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import React from \"react\";\nimport type { ButtonProps, ButtonColor, ButtonSize } from \"./Button.types\";\n\n// Spinner SVG inline — sem dependência de ícones externos\nconst LoadingSpinner = ({\n className,\n dark = false,\n}: {\n className?: string;\n dark?: boolean;\n}) => (\n <svg\n className={`animate-spin ${className ?? \"h-4 w-4\"}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={dark ? \"#1a1a1a\" : \"currentColor\"}\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill={dark ? \"#1a1a1a\" : \"currentColor\"}\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n);\n\n/**\n * ## Button\n *\n * Componente de botão do Umain Design System.\n *\n * ### Variantes de cor\n * `Primary` | `PrimaryWhite` | `PrimaryTertiary` | `BlackWhite` | `Black` | `WhiteBordered` | `BlackTertiary`\n *\n * ### Tamanhos\n * `xxs` | `xs` | `sm` | `base` | `l`\n *\n * ### Estados\n * `default`, `hover`, `focus`, `active`, `disabled`, `loading`\n */\nexport const Button: React.FC<ButtonProps> = ({\n children,\n className = \"\",\n size = \"base\",\n color = \"Primary\",\n loading = false,\n loadingIcon,\n disabled,\n iconOnly = false,\n responsiveSize = false,\n active = false,\n squarePadding = false,\n ...props\n}) => {\n const baseClasses =\n \"inline-flex items-center justify-center font-semibold outline-none transition cursor-pointer disabled:cursor-not-allowed \" +\n \"focus-visible:ring-0 focus-visible:ring-offset-2 \" +\n \"disabled:opacity-60\";\n\n const base = iconOnly ? baseClasses : `${baseClasses} gap-2`;\n\n const colors: Record<ButtonColor, string> = {\n Primary:\n \"rounded-xs bg-primary-500 enabled:hover:bg-primary-600 enabled:active:bg-primary-700 disabled:text-darkgrey-300 disabled:bg-darkgrey-100 text-white focus-visible:ring-primary-200 border border-transparent\",\n PrimaryWhite:\n \"rounded-xs bg-white enabled:hover:bg-umainblack-50 enabled:active:bg-white text-primary-500 enabled:hover:text-primary-700 enabled:active:text-primary-700 focus-visible:ring-primary-200 border border-transparent\",\n PrimaryTertiary:\n \"rounded-xs bg-transparent enabled:active:bg-umainblack-50 text-primary-500 enabled:hover:text-primary-700 focus-visible:ring-umainblack-300 border border-transparent\",\n BlackWhite:\n \"rounded-xs bg-transparent enabled:hover:bg-darkgrey-50 enabled:active:bg-umainblack-50 text-umainblack-500 hover:text-umainblack-500\",\n Black:\n \"rounded-xs bg-umainblack-500 enabled:hover:bg-umainblack-900 enabled:active:bg-umainblack-500 text-white enabled:hover:text-white enabled:active:text-white focus-visible:ring-umainblack-300 border border-transparent\",\n WhiteBordered:\n \"rounded-xs bg-white enabled:hover:bg-darkgrey-50 enabled:active:bg-white disabled:bg-darkgrey-100 text-umainblack-500 enabled:hover:text-primary-500 enabled:active:text-primary-700 focus-visible:ring-primary-200 focus-visible:border-primary-500 border border-umainblack-50\",\n BlackTertiary:\n \"rounded-xs bg-transparent text-umainblack-500 enabled:hover:bg-primary-50 enabled:focus:bg-primary-50 enabled:focus:text-primary-500 enabled:focus:ring-primary-200 disabled:bg-darkgrey-100 disabled:text-darkgrey-300 border border-transparent\",\n };\n\n const activeColors: Record<ButtonColor, string> = {\n Primary:\n \"bg-primary-700 text-white active:bg-primary-700 focus-visible:ring-primary-200 focus:ring-3 border border-transparent\",\n PrimaryWhite:\n \"rounded-sm bg-primary-50 hover:bg-darkgrey-50 text-primary-500 hover:text-primary-700 focus-visible:ring-primary-200 border border-transparent focus:border-[3px] focus:border-umainblack-200\",\n PrimaryTertiary:\n \"rounded-sm bg-umainblack-50 text-red-500 focus-visible:ring-umainblack-300 border border-transparent focus:border-[3px] focus:border-primary-200\",\n BlackWhite:\n \"rounded-sm bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-700 border border-umainblack-700 focus:border-[3px] focus:border-umainwhite-700\",\n WhiteBordered:\n \"bg-darkgrey-50 text-primary-500 focus-visible:ring-umainblack-300 border border-umainblack-50 focus:border focus:border-umainwhite-200\",\n Black:\n \"bg-umainblack-900 text-white active:bg-umainblack-900 focus-visible:ring-umainblack-300 focus:ring-3 border border-transparent\",\n BlackTertiary: \"bg-primary-50 text-primary-500 ring-1 ring-primary-500\",\n };\n\n const loadingColors: Record<ButtonColor, string> = {\n Primary: \"rounded-sm bg-primary-300 text-primary-100 border border-transparent\",\n PrimaryWhite: \"rounded-sm bg-white text-primary-500 border border-transparent\",\n PrimaryTertiary: \"rounded-sm bg-white text-primary-500 border border-transparent\",\n BlackWhite: \"rounded-sm bg-white text-umainblack-500 border border-umainblack-500\",\n Black: \"rounded-sm bg-umainblack-500 text-white border border-transparent\",\n WhiteBordered: \"rounded-sm bg-white text-umainblack-500 border border-umainblack-50\",\n BlackTertiary: \"rounded-sm bg-transparent text-umainblack-200 border border-transparent\",\n };\n\n const sizes: Record<ButtonSize, string> = {\n xxs: \"py-1 px-2 text-xs font-semibold\",\n xs: \"py-2 px-3 text-xs font-semibold\",\n sm: \"py-2 px-3 text-sm font-semibold\",\n base: \"py-2.5 px-5 text-sm font-semibold\",\n l: \"py-3 px-5 text-base font-semibold\",\n };\n\n const iconSizes: Record<ButtonSize, string> = {\n xxs: \"w-6 h-6 p-1\",\n xs: \"w-8 h-8 p-1\",\n sm: \"w-9 h-9 p-2\",\n base: \"w-10 h-10 p-2.5\",\n l: \"w-12 h-12 p-3\",\n };\n\n const squarePaddingSizes: Record<ButtonSize, string> = {\n xxs: \"p-0.5\",\n xs: \"p-1\",\n sm: \"p-2\",\n base: \"p-2.5\",\n l: \"p-3\",\n };\n\n const getButtonColors = () => {\n if (loading) return loadingColors[color];\n if (active) return activeColors[color];\n return colors[color];\n };\n\n const getResponsiveSize = () => {\n if (!responsiveSize) return \"\";\n return [\n \"py-2 px-2 w-auto h-auto rounded gap-1 text-sm font-semibold\",\n \"sm:py-2 sm:px-3 sm:w-auto sm:h-auto sm:rounded sm:gap-2 sm:text-xs sm:font-semibold\",\n \"md:py-2 md:px-3 md:w-auto md:h-auto md:rounded md:gap-2 md:text-sm md:font-semibold\",\n ].join(\" \");\n };\n\n const isLightBackgroundButton = color !== \"Primary\" && color !== \"Black\";\n\n return (\n <button\n className={`${base} ${getButtonColors()} ${\n responsiveSize\n ? getResponsiveSize()\n : squarePadding\n ? `${squarePaddingSizes[size]} rounded-xs`\n : iconOnly\n ? `${iconSizes[size]} rounded-xs`\n : `${sizes[size]} rounded-xs`\n } ${className}`}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading &&\n (loadingIcon ?? (\n <LoadingSpinner\n className=\"h-4 w-4\"\n dark={isLightBackgroundButton}\n />\n ))}\n {children}\n </button>\n );\n};\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@umain-works/ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Umain Design System — componentes React partilhados",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"design-system",
|
|
7
|
+
"react",
|
|
8
|
+
"components",
|
|
9
|
+
"umain"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"module": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.mjs",
|
|
19
|
+
"require": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"dev": "tsup --watch",
|
|
28
|
+
"storybook": "storybook dev -p 6006",
|
|
29
|
+
"build-storybook": "storybook build",
|
|
30
|
+
"lint": "tsc --noEmit",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": ">=18",
|
|
35
|
+
"react-dom": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@chromatic-com/storybook": "^3",
|
|
39
|
+
"@storybook/addon-essentials": "^8",
|
|
40
|
+
"@storybook/addon-interactions": "^8",
|
|
41
|
+
"@storybook/addon-onboarding": "^8",
|
|
42
|
+
"@storybook/blocks": "^8",
|
|
43
|
+
"@storybook/react": "^8",
|
|
44
|
+
"@storybook/react-vite": "^8",
|
|
45
|
+
"@storybook/test": "^8",
|
|
46
|
+
"@tailwindcss/vite": "^4.3.0",
|
|
47
|
+
"@types/react": "^19",
|
|
48
|
+
"@types/react-dom": "^19",
|
|
49
|
+
"react": "^19",
|
|
50
|
+
"react-dom": "^19",
|
|
51
|
+
"storybook": "^8",
|
|
52
|
+
"tailwindcss": "^4.3.0",
|
|
53
|
+
"tsup": "^8",
|
|
54
|
+
"typescript": "^5",
|
|
55
|
+
"vite": "^6"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public",
|
|
59
|
+
"registry": "https://registry.npmjs.org/"
|
|
60
|
+
}
|
|
61
|
+
}
|