@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 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
+ ```
@@ -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 };
@@ -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
+ }