ngx-opalbytes-components 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli/cao-comp.cjs CHANGED
@@ -5,9 +5,11 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
 
7
7
  const USAGE = `cao-comp — Copia um componente da lib ngx-opalbytes-components para qualquer projeto
8
+ e gera o setup de Storybook para visualizar os componentes
8
9
 
9
10
  Uso:
10
11
  cao-comp <componente> <destino> [opcoes]
12
+ cao-comp storybook <destino> [opcoes]
11
13
 
12
14
  Argumentos:
13
15
  <componente> Nome da pasta do componente em shared/components (ex: base-button)
@@ -19,10 +21,214 @@ Opcoes:
19
21
  -f, --force Sobrescreve arquivos existentes no destino
20
22
  -v, --version Exibe a versao
21
23
 
24
+ Subcomando storybook:
25
+ Gera o setup minimo do Storybook (.storybook/, exemplo de story e STORYBOOK-SETUP.md)
26
+ em <destino>, pronto para visualizar os componentes copiados.
27
+
22
28
  Exemplos:
23
29
  cao-comp base-button ./src/app/components
24
30
  cao-comp stepper ./src/app/components --force
25
31
  cao-comp --list
32
+ cao-comp storybook ./meu-projeto
33
+ cao-comp base-button ./meu-projeto/src/app/components && cao-comp storybook ./meu-projeto
34
+ `;
35
+
36
+ const STORYBOOK_FILES = {
37
+ '.storybook/main.ts': `import type { StorybookConfig } from '@storybook/angular-vite';
38
+
39
+ const config: StorybookConfig = {
40
+ "stories": [
41
+ "../src/**/*.mdx",
42
+ "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
43
+ ],
44
+ "addons": [
45
+ "@storybook/addon-essentials",
46
+ "@storybook/addon-a11y",
47
+ "@storybook/addon-docs",
48
+ "@storybook/addon-onboarding"
49
+ ],
50
+ "framework": {
51
+ "name": "@storybook/angular-vite",
52
+ "options": {
53
+ "compodoc": false,
54
+ "compodocArgs": [
55
+ "-e",
56
+ "json",
57
+ "-d",
58
+ "."
59
+ ]
60
+ }
61
+ }
62
+ };
63
+ export default config;
64
+ `,
65
+ '.storybook/preview.ts': `import type { Preview } from '@storybook/angular-vite';
66
+
67
+ // Para habilitar as docs automaticas (argTypes) com Compodoc:
68
+ // 1. Gere o documentation.json: npx @compodoc/compodoc -p tsconfig.json -e json -d .
69
+ // 2. Coloque "compodoc": true no framework options do .storybook/main.ts
70
+ // 3. Descomente as linhas abaixo:
71
+ // import { setCompodocJson } from '@storybook/addon-docs/angular';
72
+ // import docJson from '../documentation.json';
73
+ // setCompodocJson(docJson);
74
+
75
+ const preview: Preview = {
76
+ parameters: {
77
+ controls: {
78
+ matchers: {
79
+ color: /(background|color)$/i,
80
+ date: /Date$/i,
81
+ },
82
+ },
83
+ },
84
+ };
85
+
86
+ export default preview;
87
+ `,
88
+ '.storybook/tsconfig.json': `{
89
+ "extends": "../tsconfig.json",
90
+ "compilerOptions": {
91
+ "allowSyntheticDefaultImports": true,
92
+ "esModuleInterop": true,
93
+ "resolveJsonModule": true,
94
+ "skipLibCheck": true,
95
+ "types": ["node"]
96
+ },
97
+ "include": ["../src/**/*.stories.*", "./preview.ts", "./main.ts", "./typings.d.ts"]
98
+ }
99
+ `,
100
+ '.storybook/typings.d.ts': `declare module '*.md';
101
+ `,
102
+ };
103
+
104
+ const EXAMPLE_STORY_LINES = [
105
+ `import { Component, EventEmitter, Input, Output } from '@angular/core';`,
106
+ `import type { Meta, StoryObj } from '@storybook/angular-vite';`,
107
+ `import { fn } from 'storybook/test';`,
108
+ ``,
109
+ `@Component({`,
110
+ ` standalone: true,`,
111
+ ` selector: 'storybook-example-button',`,
112
+ ` template: \``,
113
+ ` <button`,
114
+ ` type="button"`,
115
+ ` (click)="onClick.emit()"`,
116
+ ` [disabled]="isDisabled"`,
117
+ ` style="padding:10px 18px;font-size:14px;cursor:pointer;border-radius:6px;border:1px solid #4f46e5;background:#4f46e5;color:#fff;">`,
118
+ ` {{ label }}`,
119
+ ` </button>`,
120
+ ` \`,`,
121
+ `})`,
122
+ `export class StorybookExampleButtonComponent {`,
123
+ ` @Input() label = 'Clique!';`,
124
+ ` @Input() isDisabled = false;`,
125
+ ` @Output() readonly onClick = new EventEmitter<void>();`,
126
+ `}`,
127
+ ``,
128
+ `const meta: Meta<StorybookExampleButtonComponent> = {`,
129
+ ` title: 'Exemplo/Cao Button',`,
130
+ ` component: StorybookExampleButtonComponent,`,
131
+ ` tags: ['autodocs'],`,
132
+ ` args: { onClick: fn() },`,
133
+ `};`,
134
+ ``,
135
+ `export default meta;`,
136
+ `type Story = StoryObj<StorybookExampleButtonComponent>;`,
137
+ ``,
138
+ `export const Default: Story = {`,
139
+ ` args: { label: 'Clique!' },`,
140
+ `};`,
141
+ ``,
142
+ `export const ComIconeTexto: Story = {`,
143
+ ` args: { label: 'Salvar' },`,
144
+ `};`,
145
+ ``,
146
+ `export const Desabilitado: Story = {`,
147
+ ` args: { label: 'Bloqueado', isDisabled: true },`,
148
+ `};`,
149
+ ``,
150
+ ];
151
+
152
+ const STORYBOOK_SETUP_DOC = `# Storybook — Setup gerado pelo cao-comp
153
+
154
+ Este diretorio contem o setup minimo do Storybook para visualizar os
155
+ componentes da lib ngx-opalbytes-components em um projeto externo.
156
+
157
+ ## 1. Instalar as dependencias (no destino)
158
+
159
+ Adicione as dependencias de desenvolvimento:
160
+
161
+ \`\`\`bash
162
+ npm i -D storybook @storybook/angular-vite @storybook/addon-essentials @storybook/addon-a11y @storybook/addon-docs @storybook/addon-onboarding @compodoc/compodoc
163
+ \`\`\`
164
+
165
+ Certifique-se de que as peer dependencies dos componentes estao instaladas:
166
+ \`@angular/core\`, \`@angular/common\`, \`@angular/material\`, \`@angular/cdk\`,
167
+ \`@lucide/angular\` e \`ngx-mask\`.
168
+
169
+ ## 2. Copiar os componentes que deseja visualizar
170
+
171
+ \`\`\`bash
172
+ cao-comp base-button ./src/app/components
173
+ cao-comp base-input ./src/app/components
174
+ cao-comp --list # lista todos os componentes disponiveis
175
+ \`\`\`
176
+
177
+ ## 3. Criar stories para os componentes copiados
178
+
179
+ Abra \`src/stories/CaoButton.stories.ts\` (exemplo gerado) ou crie arquivos
180
+ \`*.stories.ts\` junto dos componentes. Exemplo:
181
+
182
+ \`\`\`ts
183
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
184
+ import { fn } from 'storybook/test';
185
+ import { CaoBaseButtonComponent } from '../../app/components/base-button/base-button.component';
186
+
187
+ const meta: Meta<CaoBaseButtonComponent> = {
188
+ title: 'Components/Base Button',
189
+ component: CaoBaseButtonComponent,
190
+ tags: ['autodocs'],
191
+ args: { buttonClick: fn() },
192
+ };
193
+
194
+ export default meta;
195
+ type Story = StoryObj<CaoBaseButtonComponent>;
196
+
197
+ export const Default: Story = { args: { buttonText: 'Clique!' } };
198
+ export const ComIcone: Story = { args: { buttonText: 'Salvar', leadingIcon: 'Save', isLucideIcon: true } };
199
+ \`\`\`
200
+
201
+ ## 4. Rodar
202
+
203
+ \`\`\`bash
204
+ # Servidor de desenvolvimento (porta 6006)
205
+ npx storybook dev -c .storybook -p 6006
206
+
207
+ # Build estatico
208
+ npx storybook build -c .storybook -o storybook-static
209
+ \`\`\`
210
+
211
+ Dica: adicione ao package.json do projeto de destino:
212
+
213
+ \`\`\`json
214
+ {
215
+ "scripts": {
216
+ "storybook": "storybook dev -c .storybook -p 6006",
217
+ "build-storybook": "storybook build -c .storybook -o storybook-static"
218
+ }
219
+ }
220
+ \`\`\`
221
+
222
+ ## Opcional: Compodoc (docs automaticas)
223
+
224
+ 1. Gere o JSON de documentacao na raiz do destino:
225
+ \`\`\`bash
226
+ npx @compodoc/compodoc -p tsconfig.json -e json -d .
227
+ \`\`\`
228
+ 2. No \`.storybook/main.ts\`, altere \`"compodoc": false\` para \`"compodoc": true\`.
229
+ 3. No \`.storybook/preview.ts\`, descomente o bloco do Compodoc.
230
+
231
+ > O \`--force\` sobrescreve os arquivos gerados pelo cao-comp no destino.
26
232
  `;
27
233
 
28
234
  function resolveTemplatesDir() {
@@ -86,6 +292,57 @@ function copyRecursive(src, dest, force, conflicts) {
86
292
  }
87
293
  }
88
294
 
295
+ function writeFileIfAllowed(filePath, content, force, conflicts) {
296
+ if (fs.existsSync(filePath) && !force) {
297
+ conflicts.push(filePath);
298
+ return false;
299
+ }
300
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
301
+ fs.writeFileSync(filePath, content);
302
+ return true;
303
+ }
304
+
305
+ function setupStorybook(destination, force) {
306
+ const root = path.resolve(destination);
307
+ const conflicts = [];
308
+ const created = [];
309
+
310
+ for (const [rel, content] of Object.entries(STORYBOOK_FILES)) {
311
+ const file = path.join(root, rel);
312
+ if (writeFileIfAllowed(file, content, force, conflicts)) {
313
+ created.push(path.relative(root, file));
314
+ }
315
+ }
316
+
317
+ const storyFile = path.join(root, 'src', 'stories', 'CaoButton.stories.ts');
318
+ if (writeFileIfAllowed(storyFile, EXAMPLE_STORY_LINES.join('\n'), force, conflicts)) {
319
+ created.push(path.relative(root, storyFile));
320
+ }
321
+
322
+ const docFile = path.join(root, 'STORYBOOK-SETUP.md');
323
+ if (writeFileIfAllowed(docFile, STORYBOOK_SETUP_DOC, force, conflicts)) {
324
+ created.push(path.relative(root, docFile));
325
+ }
326
+
327
+ if (conflicts.length) {
328
+ process.stderr.write(
329
+ `Erro: os seguintes arquivos ja existem no destino (use --force para sobrescrever):\n` +
330
+ conflicts.map((c) => ` - ${c}`).join('\n') +
331
+ '\n'
332
+ );
333
+ return 1;
334
+ }
335
+
336
+ process.stdout.write(
337
+ `Setup de Storybook gerado em "${root}".\n` +
338
+ `Arquivos criados:\n` +
339
+ created.map((c) => ` - ${c}`).join('\n') +
340
+ '\n' +
341
+ `Leia ${path.join(root, 'STORYBOOK-SETUP.md')} para instalar as dependencias e rodar.\n`
342
+ );
343
+ return 0;
344
+ }
345
+
89
346
  function parseArgs(argv) {
90
347
  const positionals = [];
91
348
  const flags = { help: false, list: false, force: false, version: false };
@@ -146,7 +403,20 @@ function main() {
146
403
  return 0;
147
404
  }
148
405
 
149
- const [component, destination] = positionals;
406
+ const [first, second] = positionals;
407
+
408
+ if (first === 'storybook') {
409
+ if (!second) {
410
+ process.stderr.write(
411
+ 'Erro: informe o destino do Storybook.\n\n' + USAGE + '\n'
412
+ );
413
+ return 1;
414
+ }
415
+ return setupStorybook(second, flags.force);
416
+ }
417
+
418
+ const component = first;
419
+ const destination = second;
150
420
  if (!component || !destination) {
151
421
  process.stderr.write(
152
422
  'Erro: informe o componente e o destino.\n\n' + USAGE + '\n'
@@ -183,4 +453,4 @@ function main() {
183
453
  return 0;
184
454
  }
185
455
 
186
- process.exit(main());
456
+ process.exit(main());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-opalbytes-components",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -0,0 +1,133 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
2
+ import { fn } from 'storybook/test';
3
+
4
+ import { CaoAutocompleteComponent, ICaoAutoCompleteOption } from './autocomplete.component';
5
+
6
+ const defaultOptions: ICaoAutoCompleteOption[] = [
7
+ { id: 1, nome: 'João Silva' },
8
+ { id: 2, nome: 'Maria Souza' },
9
+ { id: 3, nome: 'Pedro Santos' },
10
+ { id: 4, nome: 'Ana Oliveira' },
11
+ ];
12
+
13
+ const optionsWithIcons: ICaoAutoCompleteOption[] = [
14
+ { id: 1, nome: 'João Silva', icon: 'User' },
15
+ { id: 2, nome: 'Maria Souza', icon: 'User' },
16
+ { id: 3, nome: 'Pedro Santos', icon: 'User' },
17
+ { id: 4, nome: 'Ana Oliveira', icon: 'User' },
18
+ ];
19
+
20
+ const meta: Meta<CaoAutocompleteComponent> = {
21
+ title: 'Componentes/Autocomplete',
22
+ component: CaoAutocompleteComponent,
23
+ tags: ['autodocs'],
24
+ argTypes: {
25
+ label: { control: 'text' },
26
+ placeholder: { control: 'text' },
27
+ options: { control: 'object' },
28
+ dataCy: { control: 'text' },
29
+ controlName: { control: 'text' },
30
+ isLucideIcon: { control: 'boolean' },
31
+ iconColor: { control: 'color' },
32
+ optionIcon: { control: 'text' },
33
+ optionIConColor: { control: 'color' },
34
+ isLucideOptionIcon: { control: 'boolean' },
35
+ autocompleteBgColor: { control: 'color' },
36
+ strokeWidthIcon: { control: { type: 'number', min: 0.5, max: 3, step: 0.1 } },
37
+ isDisabled: { control: 'boolean' },
38
+ inputHeigth: { control: 'text' },
39
+ iconSize: { control: { type: 'number', min: 8, max: 48 } },
40
+ showCheckIcon: { control: 'boolean' },
41
+ isLucideCheckIcon: { control: 'boolean' },
42
+ },
43
+ args: {
44
+ itemSelected: fn(),
45
+ blurEvent: fn(),
46
+ focusEvent: fn(),
47
+ leadingIconClick: fn(),
48
+ trailingIconClick: fn(),
49
+ label: 'Selecione um usuário',
50
+ placeholder: 'Buscar usuário...',
51
+ options: defaultOptions,
52
+ },
53
+ };
54
+
55
+ export default meta;
56
+ type Story = StoryObj<CaoAutocompleteComponent>;
57
+
58
+ export const Padrao: Story = {
59
+ args: {
60
+ label: 'Usuários',
61
+ placeholder: 'Buscar usuário...',
62
+ options: defaultOptions,
63
+ },
64
+ };
65
+
66
+ export const ComLeadingIcon: Story = {
67
+ args: {
68
+ label: 'Usuários',
69
+ placeholder: 'Buscar usuário...',
70
+ options: defaultOptions,
71
+ _leadingIcon: 'Search',
72
+ isLucideIcon: true,
73
+ iconColor: '#6b7280',
74
+ },
75
+ };
76
+
77
+ export const ComLeadingETrailingIcons: Story = {
78
+ args: {
79
+ label: 'Usuários',
80
+ placeholder: 'Buscar usuário...',
81
+ options: defaultOptions,
82
+ _leadingIcon: 'Search',
83
+ _trailingIcon: 'ChevronsUpDown',
84
+ isLucideIcon: true,
85
+ },
86
+ };
87
+
88
+ export const ComIconesNasOpcoes: Story = {
89
+ args: {
90
+ label: 'Usuários',
91
+ placeholder: 'Buscar usuário...',
92
+ options: optionsWithIcons,
93
+ optionIcon: 'User',
94
+ isLucideOptionIcon: true,
95
+ optionIConColor: '#f97316',
96
+ },
97
+ };
98
+
99
+ export const Desabilitado: Story = {
100
+ args: {
101
+ label: 'Usuários',
102
+ placeholder: 'Buscar usuário...',
103
+ options: defaultOptions,
104
+ isDisabled: true,
105
+ },
106
+ };
107
+
108
+ export const AlturaPersonalizada: Story = {
109
+ args: {
110
+ label: 'Usuários',
111
+ placeholder: 'Buscar usuário...',
112
+ options: defaultOptions,
113
+ inputHeigth: '70px',
114
+ },
115
+ };
116
+
117
+ export const IconeCheckOculto: Story = {
118
+ args: {
119
+ label: 'Usuários',
120
+ placeholder: 'Buscar usuário...',
121
+ options: defaultOptions,
122
+ showCheckIcon: false,
123
+ },
124
+ };
125
+
126
+ export const FundoPersonalizado: Story = {
127
+ args: {
128
+ label: 'Usuários',
129
+ placeholder: 'Buscar usuário...',
130
+ options: defaultOptions,
131
+ autocompleteBgColor: '#f3f4f6',
132
+ },
133
+ };
@@ -0,0 +1,102 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
2
+ import { fn } from 'storybook/test';
3
+
4
+ import { CaoBaseButtonComponent } from './base-button.component';
5
+
6
+ const meta: Meta<CaoBaseButtonComponent> = {
7
+ title: 'Componentes/Base Button',
8
+ component: CaoBaseButtonComponent,
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ buttonText: { control: 'text' },
12
+ btnClass: { control: 'text' },
13
+ tooltip: { control: 'text' },
14
+ leadingIcon: { control: 'text' },
15
+ trailingIcon: { control: 'text' },
16
+ isLucideIcon: { control: 'boolean' },
17
+ iconColor: { control: 'color' },
18
+ isDarkMode: { control: 'boolean' },
19
+ isDisabled: { control: 'boolean' },
20
+ isLoading: { control: 'boolean' },
21
+ strokeWidthIcon: { control: { type: 'number', min: 0.5, max: 3, step: 0.1 } },
22
+ minTextToTooltip: { control: { type: 'number', min: 1, max: 100 } },
23
+ iconSize: { control: { type: 'number', min: 8, max: 64 } },
24
+ dataCy: { control: 'text' },
25
+ },
26
+ args: {
27
+ buttonClick: fn(),
28
+ buttonText: 'Clique!',
29
+ },
30
+ };
31
+
32
+ export default meta;
33
+ type Story = StoryObj<CaoBaseButtonComponent>;
34
+
35
+ export const Padrao: Story = {
36
+ args: {
37
+ buttonText: 'Clique!',
38
+ },
39
+ };
40
+
41
+ export const Principal: Story = {
42
+ args: {
43
+ buttonText: 'Salvar',
44
+ btnClass: 'btn-primary',
45
+ },
46
+ };
47
+
48
+ export const ComLeadingIcon: Story = {
49
+ args: {
50
+ buttonText: 'Salvar',
51
+ leadingIcon: 'Save',
52
+ isLucideIcon: true,
53
+ },
54
+ };
55
+
56
+ export const ComTrailingIcon: Story = {
57
+ args: {
58
+ buttonText: 'Próximo',
59
+ trailingIcon: 'ArrowRight',
60
+ isLucideIcon: true,
61
+ },
62
+ };
63
+
64
+ export const ComAmbosIcones: Story = {
65
+ args: {
66
+ buttonText: 'Enviar',
67
+ leadingIcon: 'Send',
68
+ trailingIcon: 'ArrowRight',
69
+ isLucideIcon: true,
70
+ iconColor: '#f97316',
71
+ },
72
+ };
73
+
74
+ export const Desabilitado: Story = {
75
+ args: {
76
+ buttonText: 'Desabilitado',
77
+ isDisabled: true,
78
+ },
79
+ };
80
+
81
+ export const Carregando: Story = {
82
+ args: {
83
+ buttonText: 'Carregando...',
84
+ isLoading: true,
85
+ },
86
+ };
87
+
88
+ export const ModoEscuro: Story = {
89
+ args: {
90
+ buttonText: 'Tema Escuro',
91
+ isDarkMode: true,
92
+ },
93
+ };
94
+
95
+ export const DesabilitadoComIcone: Story = {
96
+ args: {
97
+ buttonText: 'Bloqueado',
98
+ leadingIcon: 'Lock',
99
+ isLucideIcon: true,
100
+ isDisabled: true,
101
+ },
102
+ };
@@ -0,0 +1,56 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular-vite';
2
+
3
+ import { CaoBaseIcon } from './base-icon';
4
+
5
+ const meta: Meta<CaoBaseIcon> = {
6
+ title: 'Componentes/Base Icon',
7
+ component: CaoBaseIcon,
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ imgSource: { control: 'text' },
11
+ isLucideIcon: { control: 'boolean' },
12
+ strokeWidthIcon: { control: { type: 'number', min: 0.5, max: 3, step: 0.1 } },
13
+ iconColor: { control: 'color' },
14
+ size: { control: { type: 'number', min: 8, max: 96 } },
15
+ },
16
+ args: {
17
+ imgSource: 'Home',
18
+ isLucideIcon: true,
19
+ size: 32,
20
+ },
21
+ };
22
+
23
+ export default meta;
24
+ type Story = StoryObj<CaoBaseIcon>;
25
+
26
+ export const IconeLucide: Story = {
27
+ args: {
28
+ imgSource: 'Home',
29
+ isLucideIcon: true,
30
+ },
31
+ };
32
+
33
+ export const IconeLucideComCor: Story = {
34
+ args: {
35
+ imgSource: 'Settings',
36
+ isLucideIcon: true,
37
+ iconColor: '#3b82f6',
38
+ },
39
+ };
40
+
41
+ export const TamanhoPersonalizado: Story = {
42
+ args: {
43
+ imgSource: 'Bell',
44
+ isLucideIcon: true,
45
+ size: 48,
46
+ strokeWidthIcon: 2,
47
+ },
48
+ };
49
+
50
+ export const IconeSVG: Story = {
51
+ args: {
52
+ imgSource: 'https://lucide.dev/icons/home.svg',
53
+ isLucideIcon: false,
54
+ size: 32,
55
+ },
56
+ };