@grazziotin/react-components-next 1.0.0 → 1.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 CHANGED
@@ -1,132 +1,205 @@
1
- # React Components Library
1
+ # Grazziotin React Components Library
2
2
 
3
- Biblioteca de componentes React reutilizáveis, construída com TypeScript e Tailwind CSS.
3
+ Biblioteca de componentes React reutilizáveis para o projeto Grazziotin, construída com TypeScript, Tailwind CSS, Material UI e Mantine.
4
4
 
5
5
  ## Instalação
6
6
 
7
7
  ```bash
8
- npm install react-components-next
8
+ npm install @grazziotin/react-components-next
9
9
  ```
10
10
 
11
- > **Atenção:** esta biblioteca usa classes do Tailwind CSS. Certifique-se de que o Tailwind esteja configurado no seu projeto.
11
+ ### Requisitos
12
+
13
+ - React `>= 18`
14
+ - Tailwind CSS v4 configurado no projeto consumidor
15
+ - `ThemeProvider` do MUI e `MantineProvider` do Mantine envolvendo a aplicação
16
+
17
+ ### Configuração no projeto consumidor
18
+
19
+ Importe os estilos da biblioteca e configure as variáveis CSS do tema:
20
+
21
+ ```tsx
22
+ import "@grazziotin/react-components-next/styles";
23
+
24
+ import { CssBaseline, ThemeProvider, createTheme } from "@mui/material";
25
+ import { MantineProvider } from "@mantine/core";
26
+ import "@mantine/core/styles.css";
27
+
28
+ const theme = createTheme({
29
+ typography: { fontFamily: "var(--font-family, inherit)" },
30
+ });
31
+
32
+ export function AppProviders({ children }: { children: React.ReactNode }) {
33
+ return (
34
+ <ThemeProvider theme={theme}>
35
+ <CssBaseline />
36
+ <MantineProvider>{children}</MantineProvider>
37
+ </ThemeProvider>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ```css
43
+ :root {
44
+ --primary-color: #00b2a6;
45
+ --font-family: "Poppins", sans-serif;
46
+ }
47
+ ```
48
+
49
+ > **Atenção:** vários componentes usam classes do Tailwind CSS e dependem do MUI/Mantine. Certifique-se de que o Tailwind esteja configurado e os providers estejam na raiz da aplicação.
12
50
 
13
51
  ## Componentes disponíveis
14
52
 
15
- | Componente | Descrição |
16
- | ---------- | ------------------------------------------------ |
17
- | `Button` | Botão com variantes, tamanhos, loading e ícones |
18
- | `Input` | Campo de entrada com label, hint, erro e addons |
19
- | `Card` | Container com header, content e footer compostos |
20
- | `Badge` | Etiqueta colorida para status e categorias |
21
- | `Avatar` | Foto de perfil com fallback de iniciais |
53
+ | Componente | Descrição |
54
+ | ------------ | --------------------------------------------------------------- |
55
+ | `Card` | Container com cabeçalho colorido, título, ícone e tooltip |
56
+ | `Dialog` | Modal baseado no MUI com título, conteúdo e ações opcionais |
57
+ | `DataTable` | Tabela de dados com MUI DataGrid, filtros e textos em português |
58
+ | `Tab`/`Tabs` | Abas estilizadas com indicador e tipografia customizáveis |
59
+
60
+ ## Funções utilitárias
61
+
62
+ | Função | Descrição |
63
+ | --------------- | ------------------------------------------------ |
64
+ | `cn` | Mescla classes CSS com `clsx` e `tailwind-merge` |
65
+ | `nvl` | Retorna valor padrão quando `null`/`undefined` |
66
+ | `formatCpfCnpj` | Formata CPF ou CNPJ |
67
+ | `formatPhoneBr` | Formata telefone brasileiro |
22
68
 
23
69
  ## Uso
24
70
 
25
71
  ```tsx
26
72
  import {
27
- Button,
28
73
  Card,
29
- CardHeader,
30
- CardTitle,
31
- CardContent,
32
- Input,
33
- Badge,
34
- Avatar,
35
- } from "react-components-next";
74
+ Dialog,
75
+ DataTable,
76
+ Tab,
77
+ Tabs,
78
+ cn,
79
+ formatCpfCnpj,
80
+ } from "@grazziotin/react-components-next";
81
+ import type { GridColDef } from "@mui/x-data-grid";
82
+
83
+ const colunas: GridColDef[] = [
84
+ { field: "id", headerName: "ID", width: 80 },
85
+ { field: "nome", headerName: "Nome", flex: 1 },
86
+ { field: "documento", headerName: "CPF/CNPJ", width: 180 },
87
+ ];
88
+
89
+ const linhas = [
90
+ { id: 1, nome: "Ana Silva", documento: formatCpfCnpj("12345678901") },
91
+ ];
36
92
 
37
93
  export function Example() {
38
94
  return (
39
- <Card>
40
- <CardHeader>
41
- <CardTitle>Perfil</CardTitle>
42
- </CardHeader>
43
- <CardContent>
44
- <div className="flex items-center gap-3">
45
- <Avatar fallback="João Silva" size="md" />
46
- <div>
47
- <p>João Silva</p>
48
- <Badge variant="success" dot>
49
- Online
50
- </Badge>
51
- </div>
52
- </div>
53
- <Input label="E-mail" type="email" placeholder="joao@exemplo.com" />
54
- <Button variant="primary" fullWidth>
55
- Salvar
56
- </Button>
57
- </CardContent>
95
+ <Card title="Colaboradores" toolTip className={cn("max-w-3xl")}>
96
+ <DataTable rows={linhas} columns={colunas} pageSizeOptions={[10, 20]} />
58
97
  </Card>
59
98
  );
60
99
  }
61
100
  ```
62
101
 
102
+ ## Entry points
103
+
104
+ A biblioteca expõe múltiplos pontos de entrada:
105
+
106
+ | Import | Conteúdo |
107
+ | --------------------------------------------- | ---------------------------------------- |
108
+ | `@grazziotin/react-components-next` | Componentes e funções (export principal) |
109
+ | `@grazziotin/react-components-next/ui` | Apenas componentes de UI |
110
+ | `@grazziotin/react-components-next/functions` | Apenas funções utilitárias |
111
+ | `@grazziotin/react-components-next/styles` | CSS compilado da biblioteca |
112
+
63
113
  ## Componentes
64
114
 
65
- ### Button
115
+ ### Card
66
116
 
67
117
  ```tsx
68
- <Button
69
- variant="primary" // "primary" | "secondary" | "outline" | "ghost" | "destructive"
70
- size="md" // "sm" | "md" | "lg"
71
- loading={false} // boolean
72
- fullWidth={false} // boolean
73
- leftIcon={<Icon />} // ReactNode
74
- rightIcon={<Icon />} // ReactNode
118
+ <Card
119
+ title="Título do card"
120
+ toolTip={false}
121
+ width="100%"
122
+ height="auto"
123
+ titleColor="var(--primary-color)"
124
+ borderRadius="10px"
125
+ borderTitle="10px 10px 0 0"
126
+ icon={<Icon />}
127
+ onClick={() => {}}
128
+ className="text-sm"
75
129
  >
76
- Clique aqui
77
- </Button>
130
+ Conteúdo do card
131
+ </Card>
78
132
  ```
79
133
 
80
- ### Input
134
+ ### Dialog
81
135
 
82
136
  ```tsx
83
- <Input
84
- label="Nome"
85
- placeholder="Digite..."
86
- hint="Texto de ajuda"
87
- error="Mensagem de erro"
88
- size="md" // "sm" | "md" | "lg"
89
- leftAddon={<Icon />} // ReactNode
90
- rightAddon={<Icon />} // ReactNode
91
- fullWidth={false}
92
- />
137
+ <Dialog
138
+ open={open}
139
+ title="Confirmar exclusão"
140
+ onClose={() => setOpen(false)}
141
+ maxWidth="sm"
142
+ blurBackdrop={false}
143
+ actions={<button onClick={() => setOpen(false)}>OK</button>}
144
+ >
145
+ Deseja realmente excluir este item?
146
+ </Dialog>
93
147
  ```
94
148
 
95
- ### Card
149
+ ### DataTable
150
+
151
+ Wrapper sobre o MUI `DataGrid` com estilização, textos em português e operador de filtro "entre" automático para colunas `string` e `number`. Aceita todas as props do `DataGrid`.
96
152
 
97
153
  ```tsx
98
- <Card shadow="sm" padding="md" hoverable bordered>
99
- <CardHeader>
100
- <CardTitle>Título</CardTitle>
101
- <CardDescription>Descrição</CardDescription>
102
- </CardHeader>
103
- <CardContent>Conteúdo</CardContent>
104
- <CardFooter>
105
- <Button>Ação</Button>
106
- </CardFooter>
107
- </Card>
154
+ <DataTable
155
+ rows={dados}
156
+ columns={colunas}
157
+ loading={carregando}
158
+ pageSizeOptions={[10, 20, 50]}
159
+ />
108
160
  ```
109
161
 
110
- ### Badge
162
+ ### Tab / Tabs
111
163
 
112
164
  ```tsx
113
- <Badge
114
- variant="success" // "default" | "primary" | "success" | "warning" | "danger" | "info"
115
- dot={false} // boolean - exibe um ponto colorido
165
+ const [value, setValue] = useState(0);
166
+
167
+ <Tabs
168
+ value={value}
169
+ onChange={(_, newValue) => setValue(newValue)}
170
+ color="var(--primary-color)"
116
171
  >
117
- Online
118
- </Badge>
172
+ <Tab label="Geral" />
173
+ <Tab label="Detalhes" />
174
+ </Tabs>;
175
+ ```
176
+
177
+ ## Funções
178
+
179
+ ### cn
180
+
181
+ ```tsx
182
+ cn("px-4 py-2", condicao && "bg-teal-500", "px-6");
119
183
  ```
120
184
 
121
- ### Avatar
185
+ ### nvl
122
186
 
123
187
  ```tsx
124
- <Avatar
125
- src="https://..." // URL da imagem (opcional)
126
- alt="Nome do usuário"
127
- fallback="João Silva" // usado para gerar as iniciais
128
- size="md" // "xs" | "sm" | "md" | "lg" | "xl"
129
- />
188
+ nvl(valor, "padrão"); // retorna "padrão" se valor for null/undefined
189
+ ```
190
+
191
+ ### formatCpfCnpj
192
+
193
+ ```tsx
194
+ formatCpfCnpj("12345678901"); // "123.456.789-01"
195
+ formatCpfCnpj("12345678000199"); // "12.345.678/0001-99"
196
+ ```
197
+
198
+ ### formatPhoneBr
199
+
200
+ ```tsx
201
+ formatPhoneBr("11987654321"); // "(11) 98765-4321"
202
+ formatPhoneBr("1133334444"); // "(11) 3333-4444"
130
203
  ```
131
204
 
132
205
  ## Desenvolvimento
@@ -135,17 +208,20 @@ export function Example() {
135
208
  # Instalar dependências
136
209
  npm install
137
210
 
138
- # Rodar servidor de desenvolvimento com showcase
139
- npm run dev
211
+ # Storybook (visualização e documentação dos componentes)
212
+ npm run storybook
213
+
214
+ # Build estático do Storybook
215
+ npm run build-storybook
140
216
 
141
217
  # Build da biblioteca para npm
142
218
  npm run build:lib
143
219
 
144
- # Build completo (biblioteca + Next.js)
145
- npm run build:all
146
-
147
220
  # Verificar tipos TypeScript
148
221
  npm run type-check
222
+
223
+ # Lint
224
+ npm run lint
149
225
  ```
150
226
 
151
227
  ## Publicar no npm
@@ -162,24 +238,27 @@ npm publish
162
238
 
163
239
  ```
164
240
  src/
165
- ├── app/ # Next.js App Router (showcase)
166
- │ ├── page.tsx # Página inicial com lista de componentes
167
- └── showcase/ # Páginas de demonstração
168
- ├── button/
169
- ├── input/
170
- ├── card/
171
- │ ├── badge/
172
- │ └── avatar/
173
- ├── components/ # Biblioteca de componentes (publicada no npm)
174
- │ ├── index.ts # Entrypoint principal
241
+ ├── app/ # Next.js App Router (página inicial mínima)
242
+ │ ├── globals.css # Variáveis CSS e tema
243
+ ├── layout.tsx # Providers MUI + Mantine
244
+ └── page.tsx
245
+ ├── components/
246
+ ├── index.ts
175
247
  │ └── ui/
176
- │ ├── Button/
177
- │ ├── Input/
178
- │ ├── Card/
179
- ├── Badge/
180
- │ └── Avatar/
181
- └── lib/
182
- └── utils.ts # Utilitário cn() para classes CSS
248
+ │ ├── card/
249
+ │ ├── dialog/
250
+ │ ├── data-table/
251
+ └── tab/
252
+ ├── core/ # Utilitários internos
253
+ ├── functions/
254
+ │ ├── cn/
255
+ │ ├── nvl/
256
+ │ ├── format-cpf-cnpj/
257
+ │ └── format-phone-br/
258
+ ├── providers/
259
+ ├── styles/
260
+ │ └── index.css # Entrada do Tailwind para o build CSS
261
+ └── index.ts # Entrypoint principal da biblioteca
183
262
  ```
184
263
 
185
264
  ## Licença
@@ -2,6 +2,8 @@ import { twMerge } from 'tailwind-merge';
2
2
  import { clsx } from 'clsx';
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
+ var __defProps = Object.defineProperties;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
7
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -17,6 +19,19 @@ var __spreadValues = (a, b) => {
17
19
  }
18
20
  return a;
19
21
  };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __objRest = (source, exclude) => {
24
+ var target = {};
25
+ for (var prop in source)
26
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
27
+ target[prop] = source[prop];
28
+ if (source != null && __getOwnPropSymbols)
29
+ for (var prop of __getOwnPropSymbols(source)) {
30
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
31
+ target[prop] = source[prop];
32
+ }
33
+ return target;
34
+ };
20
35
  function cn(...values) {
21
36
  return twMerge(clsx(values));
22
37
  }
@@ -59,6 +74,6 @@ function formatPhoneBr(phone) {
59
74
  return digits.replace(/(\d{2})(\d{5})(\d+)/, "($1) $2-$3");
60
75
  }
61
76
 
62
- export { __spreadValues, cn, formatCpfCnpj, formatPhoneBr, nvl };
63
- //# sourceMappingURL=chunk-NHHZBMJL.mjs.map
64
- //# sourceMappingURL=chunk-NHHZBMJL.mjs.map
77
+ export { __objRest, __spreadProps, __spreadValues, cn, formatCpfCnpj, formatPhoneBr, nvl };
78
+ //# sourceMappingURL=chunk-4DIPDYEU.mjs.map
79
+ //# sourceMappingURL=chunk-4DIPDYEU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/functions/cn/cn.ts","../src/functions/nvl/nvl.ts","../src/core/remove-digits.ts","../src/functions/format-cpf-cnpj/format-cpf-cnpj.ts","../src/functions/format-phone-br/format-phone-br.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIO,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACIO,SAAS,GAAA,CAAO,OAA6B,YAAA,EAAoB;AACtE,EAAA,OAAO,KAAA,IAAA,IAAA,GAAA,KAAA,GAAS,YAAA;AAClB;;;ACXO,SAAS,aAAa,KAAA,EAAuB;AAClD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAChC;;;ACOO,SAAS,cAAc,IAAA,EAAuB;AACnD,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAClB,EAAA,MAAM,KAAA,GAAQ,aAAa,IAAI,CAAA;AAE/B,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,IAAI,KAAA,CAAM,UAAU,EAAA,EAAI;AACtB,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC7B,IAAA,OAAO,GAAA,CACJ,OAAA,CAAQ,aAAA,EAAe,OAAO,CAAA,CAC9B,OAAA,CAAQ,aAAA,EAAe,OAAO,CAAA,CAC9B,OAAA,CAAQ,mBAAA,EAAqB,OAAO,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC9B,EAAA,OAAO,IAAA,CACJ,OAAA,CAAQ,cAAA,EAAgB,OAAO,EAC/B,OAAA,CAAQ,uBAAA,EAAyB,UAAU,CAAA,CAC3C,QAAQ,eAAA,EAAiB,QAAQ,CAAA,CACjC,OAAA,CAAQ,eAAe,OAAO,CAAA;AACnC;;;ACnBO,SAAS,cAAc,KAAA,EAAwB;AACpD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,MAAM,SAAS,YAAA,CAAa,KAAK,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAE9C,EAAA,IAAI,CAAC,QAAQ,OAAO,EAAA;AACpB,EAAA,IAAI,MAAA,CAAO,MAAA,IAAU,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACtB,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,SAAS,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,MAAA,CAAO,UAAU,EAAA,EAAI;AACvB,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,qBAAA,EAAuB,YAAY,CAAA;AAAA,EAC3D;AACA,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,qBAAA,EAAuB,YAAY,CAAA;AAC3D","file":"chunk-4DIPDYEU.mjs","sourcesContent":["import { twMerge } from \"tailwind-merge\";\r\nimport { clsx } from \"clsx\";\r\nimport type { ClassValue } from \"./utils/interfaces\";\r\n\r\nexport function cn(...values: ClassValue[]): string {\r\n return twMerge(clsx(values));\r\n}\r\n","/**\r\n * Função NVL (Null Value Logic) - retorna valor padrão se o valor for null/undefined\r\n * @param {T | null | undefined} value - Valor a ser verificado\r\n * @param {T} defaultValue - Valor padrão a ser retornado se value for null/undefined\r\n * @returns {T} Value se não for null/undefined, senão defaultValue\r\n * @template T - Tipo do valor\r\n * @example\r\n * nvl(null, 'padrão') // Retorna: 'padrão'\r\n * nvl('valor', 'padrão') // Retorna: 'valor'\r\n */\r\nexport function nvl<T>(value: T | null | undefined, defaultValue: T): T {\r\n return value ?? defaultValue;\r\n}\r\n","/** Remove tudo que não for dígito. */\r\nexport function removeDigits(value: string): string {\r\n return value.replace(/\\D/g, \"\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata CPF (até 11 dígitos) ou CNPJ (12–14 dígitos) conforme o tamanho.\r\n * @param data - Valor com ou sem formatação\r\n * @returns CPF `000.000.000-00` ou CNPJ `00.000.000/0000-00`; string vazia se ausente\r\n * @example\r\n * formatCpfCnpj(\"12345678901\") // \"123.456.789-01\"\r\n * formatCpfCnpj(\"12345678000199\") // \"12.345.678/0001-99\"\r\n */\r\nexport function formatCpfCnpj(data?: string): string {\r\n if (!data) return \"\";\r\n const value = removeDigits(data);\r\n\r\n if (!value) return \"\";\r\n if (value.length <= 11) {\r\n const cpf = value.slice(0, 11);\r\n return cpf\r\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{3})(\\d{1,2})$/, \"$1-$2\");\r\n }\r\n\r\n const cnpj = value.slice(0, 14);\r\n return cnpj\r\n .replace(/^(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/^(\\d{2})\\.(\\d{3})(\\d)/, \"$1.$2.$3\")\r\n .replace(/\\.(\\d{3})(\\d)/, \".$1/$2\")\r\n .replace(/(\\d{4})(\\d)/, \"$1-$2\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata telefone brasileiro (até 11 dígitos): fixo `(00) 0000-0000` ou celular `(00) 00000-0000`.\r\n * @param phone - Valor com ou sem formatação\r\n * @returns Telefone formatado ou string vazia se ausente\r\n * @example\r\n * formatPhoneBr(\"11987654321\") // \"(11) 98765-4321\"\r\n * formatPhoneBr(\"1133334444\") // \"(11) 3333-4444\"\r\n */\r\nexport function formatPhoneBr(phone?: string): string {\r\n if (!phone) return \"\";\r\n const digits = removeDigits(phone).slice(0, 11);\r\n\r\n if (!digits) return \"\";\r\n if (digits.length <= 2) return digits;\r\n if (digits.length <= 6) {\r\n return digits.replace(/(\\d{2})(\\d+)/, \"($1) $2\");\r\n }\r\n if (digits.length <= 10) {\r\n return digits.replace(/(\\d{2})(\\d{4})(\\d+)/, \"($1) $2-$3\");\r\n }\r\n return digits.replace(/(\\d{2})(\\d{5})(\\d+)/, \"($1) $2-$3\");\r\n}\r\n"]}