@gob-ds/gob-ds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.editorconfig +17 -0
  2. package/.storybook/main.ts +19 -0
  3. package/.storybook/preview.ts +18 -0
  4. package/.storybook/tsconfig.doc.json +10 -0
  5. package/.storybook/tsconfig.json +11 -0
  6. package/.storybook/typings.d.ts +4 -0
  7. package/.vscode/extensions.json +4 -0
  8. package/.vscode/launch.json +20 -0
  9. package/.vscode/mcp.json +9 -0
  10. package/.vscode/tasks.json +42 -0
  11. package/README.md +0 -0
  12. package/angular.json +113 -0
  13. package/documentation.json +1472 -0
  14. package/package.json +65 -0
  15. package/public/favicon.ico +0 -0
  16. package/src/app/app.config.server.ts +12 -0
  17. package/src/app/app.config.ts +12 -0
  18. package/src/app/app.html +342 -0
  19. package/src/app/app.routes.server.ts +8 -0
  20. package/src/app/app.routes.ts +3 -0
  21. package/src/app/app.scss +0 -0
  22. package/src/app/app.spec.ts +23 -0
  23. package/src/app/app.ts +12 -0
  24. package/src/app/lib/alert-dialog/alert-dialog.component.html +35 -0
  25. package/src/app/lib/alert-dialog/alert-dialog.component.scss +94 -0
  26. package/src/app/lib/alert-dialog/alert-dialog.component.ts +144 -0
  27. package/src/app/lib/badge/badge.component.ts +25 -0
  28. package/src/app/lib/badge/badge.scss +50 -0
  29. package/src/app/lib/button/button.component.html +35 -0
  30. package/src/app/lib/button/button.component.scss +226 -0
  31. package/src/app/lib/button/button.component.ts +70 -0
  32. package/src/app/lib/checkbox/checkbox.component.html +34 -0
  33. package/src/app/lib/checkbox/checkbox.component.scss +80 -0
  34. package/src/app/lib/checkbox/checkbox.component.ts +84 -0
  35. package/src/app/lib/input/input.component.html +43 -0
  36. package/src/app/lib/input/input.component.scss +181 -0
  37. package/src/app/lib/input/input.component.ts +87 -0
  38. package/src/app/lib/search/search.component.html +30 -0
  39. package/src/app/lib/search/search.component.scss +102 -0
  40. package/src/app/lib/search/search.component.ts +73 -0
  41. package/src/index.html +13 -0
  42. package/src/main.server.ts +8 -0
  43. package/src/main.ts +6 -0
  44. package/src/server.ts +68 -0
  45. package/src/stories/Configure.mdx +364 -0
  46. package/src/stories/assets/accessibility.png +0 -0
  47. package/src/stories/assets/accessibility.svg +1 -0
  48. package/src/stories/assets/addon-library.png +0 -0
  49. package/src/stories/assets/assets.png +0 -0
  50. package/src/stories/assets/avif-test-image.avif +0 -0
  51. package/src/stories/assets/context.png +0 -0
  52. package/src/stories/assets/discord.svg +1 -0
  53. package/src/stories/assets/docs.png +0 -0
  54. package/src/stories/assets/figma-plugin.png +0 -0
  55. package/src/stories/assets/github.svg +1 -0
  56. package/src/stories/assets/share.png +0 -0
  57. package/src/stories/assets/styling.png +0 -0
  58. package/src/stories/assets/testing.png +0 -0
  59. package/src/stories/assets/theming.png +0 -0
  60. package/src/stories/assets/tutorials.svg +1 -0
  61. package/src/stories/assets/youtube.svg +1 -0
  62. package/src/stories/components/alert-dialog.stories.ts +60 -0
  63. package/src/stories/components/badge.stories.ts +111 -0
  64. package/src/stories/components/button.stories.ts +329 -0
  65. package/src/stories/components/checkbox.stories.ts +102 -0
  66. package/src/stories/components/input.stories.ts +100 -0
  67. package/src/stories/components/search.stories.ts +81 -0
  68. package/src/stories/user.ts +3 -0
  69. package/src/styles.scss +14 -0
  70. package/src/tokens/stories/borders.stories.ts +118 -0
  71. package/src/tokens/stories/colors.stories.ts +90 -0
  72. package/src/tokens/stories/shadows.stories.ts +93 -0
  73. package/src/tokens/stories/spacing.stories.ts +55 -0
  74. package/src/tokens/stories/typography.stories.ts +76 -0
  75. package/src/tokens/styles/_borders.scss +16 -0
  76. package/src/tokens/styles/_colors.scss +76 -0
  77. package/src/tokens/styles/_shadows.scss +9 -0
  78. package/src/tokens/styles/_spacing.scss +17 -0
  79. package/src/tokens/styles/_typography.scss +34 -0
  80. package/src/tokens/styles/tokens.scss +5 -0
  81. package/src/tokens/tokens.ts +42 -0
  82. package/tsconfig.app.json +17 -0
  83. package/tsconfig.json +33 -0
  84. package/tsconfig.spec.json +15 -0
@@ -0,0 +1,329 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { ArrowRight, Trash2, Plus, GitBranch } from 'lucide-angular';
3
+ import { ButtonComponent } from '../../app/lib/button/button.component';
4
+
5
+ const meta: Meta<ButtonComponent> = {
6
+ title: 'Components/Button',
7
+ component: ButtonComponent,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ layout: 'centered',
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ Componente base de acción del design system.
15
+
16
+ | Prop | Tipo | Valores |
17
+ |------|------|---------|
18
+ | \`variant\` | enum | \`primary\` \`secondary\` \`outline\` \`ghost\` \`destructive\` \`link\` |
19
+ | \`size\` | enum | \`sm\` \`md\` \`lg\` |
20
+ | \`disabled\` | boolean | — |
21
+ | \`loading\` | boolean | — |
22
+ | \`fullWidth\` | boolean | — |
23
+ | \`iconPosition\` | enum | \`left\` \`right\` \`only\` |
24
+ | \`asTag\` | element | \`button\` \`a\` |
25
+ `,
26
+ },
27
+ },
28
+ },
29
+ argTypes: {
30
+ variant: {
31
+ control: 'select',
32
+ options: ['primary', 'secondary', 'outline', 'ghost', 'destructive', 'link'],
33
+ },
34
+ size: {
35
+ control: 'radio',
36
+ options: ['sm', 'md', 'lg'],
37
+ },
38
+ iconPosition: {
39
+ control: 'radio',
40
+ options: [null, 'left', 'right', 'only'],
41
+ },
42
+ asTag: {
43
+ control: 'radio',
44
+ options: ['button', 'a'],
45
+ },
46
+ disabled: { control: 'boolean' },
47
+ loading: { control: 'boolean' },
48
+ fullWidth: { control: 'boolean' },
49
+ },
50
+ };
51
+
52
+ export default meta;
53
+ type Story = StoryObj<ButtonComponent>;
54
+
55
+ // ── Playground ─────────────────────────────────────────────────
56
+ export const Playground: Story = {
57
+ args: { variant: 'primary', size: 'md', disabled: false, loading: false },
58
+ render: (args) => ({
59
+ props: args,
60
+ template: `<ds-button [variant]="variant" [size]="size" [disabled]="disabled" [loading]="loading">Guardar cambios</ds-button>`,
61
+ }),
62
+ };
63
+
64
+ // ── Variants ───────────────────────────────────────────────────
65
+ export const Variants: Story = {
66
+ render: () => ({
67
+ template: `
68
+ <div style="display:flex; flex-wrap:wrap; align-items:center; gap:12px;">
69
+ <ds-button variant="primary">Primary</ds-button>
70
+ <ds-button variant="secondary">Secondary</ds-button>
71
+ <ds-button variant="outline">Outline</ds-button>
72
+ <ds-button variant="ghost">Ghost</ds-button>
73
+ <ds-button variant="destructive">Destructive</ds-button>
74
+ <ds-button variant="link">Link</ds-button>
75
+ </div>
76
+ `,
77
+ }),
78
+ };
79
+
80
+ // ── Sizes ──────────────────────────────────────────────────────
81
+ export const Sizes: Story = {
82
+ render: () => ({
83
+ template: `
84
+ <div style="display:flex; align-items:center; gap:12px;">
85
+ <ds-button size="sm">Small</ds-button>
86
+ <ds-button size="md">Default</ds-button>
87
+ <ds-button size="lg">Large</ds-button>
88
+ </div>
89
+ `,
90
+ }),
91
+ };
92
+
93
+ // ── With Icons ───────────────────────────────────────────────
94
+ export const WithIcons: Story = {
95
+ render: () => ({
96
+ props: { ArrowRight, Plus, Trash2, GitBranch },
97
+ template: `
98
+ <div style="display:flex; flex-wrap:wrap; align-items:center; gap:12px;">
99
+ <ds-button variant="primary" [icon]="Plus" iconPosition="left">Nuevo</ds-button>
100
+ <ds-button variant="outline" [icon]="ArrowRight" iconPosition="right">Continuar</ds-button>
101
+ <ds-button variant="destructive" [icon]="Trash2" iconPosition="left">Eliminar</ds-button>
102
+ <ds-button variant="secondary" [icon]="GitBranch" iconPosition="left">New Branch</ds-button>
103
+ </div>
104
+ `,
105
+ }),
106
+ };
107
+
108
+ // ── Icon only ──────────────────────────────────────────────────
109
+ export const IconOnly: Story = {
110
+ render: () => ({
111
+ props: { Plus, Trash2, ArrowRight },
112
+ template: `
113
+ <div style="display:flex; align-items:center; gap:12px;">
114
+ <ds-button variant="primary" [icon]="Plus" iconPosition="only" size="sm" />
115
+ <ds-button variant="outline" [icon]="ArrowRight" iconPosition="only" size="md" />
116
+ <ds-button variant="destructive" [icon]="Trash2" iconPosition="only" size="lg" />
117
+ </div>
118
+ `,
119
+ }),
120
+ };
121
+
122
+ export const Status: Story = {
123
+ parameters: { layout: 'padded' },
124
+ render: () => ({
125
+ props: { Plus, ArrowRight, Trash2 },
126
+ template: `
127
+ <div style="display:grid; gap:18px; min-width: 760px;">
128
+
129
+ <!-- Default / Disabled / Loading (Primary) -->
130
+ <div>
131
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
132
+ Primary states
133
+ </div>
134
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
135
+ <ds-button variant="primary">Default</ds-button>
136
+ <ds-button variant="primary" [disabled]="true">Disabled</ds-button>
137
+ <ds-button variant="primary" [loading]="true">Loading</ds-button>
138
+ <ds-button variant="primary" [icon]="Plus" iconPosition="left">With icon</ds-button>
139
+ <ds-button variant="primary" [icon]="Plus" iconPosition="left" [loading]="true">Loading + icon</ds-button>
140
+ </div>
141
+ </div>
142
+
143
+ <!-- Outline / Ghost / Secondary disabled + loading -->
144
+ <div>
145
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
146
+ Other variants states
147
+ </div>
148
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
149
+ <ds-button variant="secondary">Secondary</ds-button>
150
+ <ds-button variant="secondary" [disabled]="true">Secondary disabled</ds-button>
151
+ <ds-button variant="secondary" [loading]="true">Secondary loading</ds-button>
152
+
153
+ <ds-button variant="outline">Outline</ds-button>
154
+ <ds-button variant="outline" [disabled]="true">Outline disabled</ds-button>
155
+ <ds-button variant="outline" [loading]="true">Outline loading</ds-button>
156
+
157
+ <ds-button variant="ghost">Ghost</ds-button>
158
+ <ds-button variant="ghost" [disabled]="true">Ghost disabled</ds-button>
159
+ <ds-button variant="ghost" [loading]="true">Ghost loading</ds-button>
160
+ </div>
161
+ </div>
162
+
163
+ <!-- Destructive -->
164
+ <div>
165
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
166
+ Destructive states
167
+ </div>
168
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
169
+ <ds-button variant="destructive">Delete</ds-button>
170
+ <ds-button variant="destructive" [disabled]="true">Disabled</ds-button>
171
+ <ds-button variant="destructive" [loading]="true">Deleting...</ds-button>
172
+ <ds-button variant="destructive" [icon]="Trash2" iconPosition="left">With icon</ds-button>
173
+ <ds-button variant="destructive" [icon]="Trash2" iconPosition="left" [loading]="true">Loading + icon</ds-button>
174
+ </div>
175
+ </div>
176
+
177
+ <!-- Link (special case) -->
178
+ <div>
179
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
180
+ Link states (special)
181
+ </div>
182
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
183
+ <ds-button variant="link">Link</ds-button>
184
+ <ds-button variant="link" [disabled]="true">Link disabled</ds-button>
185
+ <ds-button variant="link" [loading]="true">Link loading</ds-button>
186
+ <ds-button variant="link" [icon]="ArrowRight" iconPosition="right">Link + icon</ds-button>
187
+ </div>
188
+ </div>
189
+
190
+ <!-- Icon-only edge cases -->
191
+ <div>
192
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
193
+ Icon-only edge cases
194
+ </div>
195
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
196
+ <ds-button variant="primary" [icon]="Plus" iconPosition="only" size="sm" />
197
+ <ds-button variant="primary" [icon]="Plus" iconPosition="only" size="sm" [disabled]="true" />
198
+ <ds-button variant="primary" [icon]="Plus" iconPosition="only" size="sm" [loading]="true" />
199
+
200
+ <ds-button variant="outline" [icon]="ArrowRight" iconPosition="only" size="md" />
201
+ <ds-button variant="outline" [icon]="ArrowRight" iconPosition="only" size="md" [disabled]="true" />
202
+ <ds-button variant="outline" [icon]="ArrowRight" iconPosition="only" size="md" [loading]="true" />
203
+ </div>
204
+ </div>
205
+
206
+ <!-- Full width states -->
207
+ <div style="max-width: 320px;">
208
+ <div style="margin-bottom:8px; font-size:13px; color: var(--color-text-secondary); font-weight: 500;">
209
+ Full width states
210
+ </div>
211
+ <div style="display:flex; flex-direction:column; gap:10px;">
212
+ <ds-button variant="primary" [fullWidth]="true" size="lg">Continue</ds-button>
213
+ <ds-button variant="primary" [fullWidth]="true" size="lg" [loading]="true">Continue</ds-button>
214
+ <ds-button variant="outline" [fullWidth]="true" size="lg" [disabled]="true">Cancel</ds-button>
215
+ </div>
216
+ </div>
217
+
218
+ </div>
219
+ `,
220
+ }),
221
+ };
222
+
223
+ // ── Full Width ─────────────────────────────────────────────────
224
+ export const FullWidth: Story = {
225
+ parameters: { layout: 'padded' },
226
+ render: () => ({
227
+ template: `
228
+ <div style="display:flex; flex-direction:column; gap:10px; width:320px;">
229
+ <ds-button variant="primary" [fullWidth]="true">Iniciar sesión</ds-button>
230
+ <ds-button variant="outline" [fullWidth]="true">Crear cuenta</ds-button>
231
+ </div>
232
+ `,
233
+ }),
234
+ };
235
+
236
+ // ── Toolbar ────────────────────────────────────────────────────
237
+ export const Toolbar: Story = {
238
+ render: () => ({
239
+ template: `
240
+ <div style="display:flex; gap:0;">
241
+ <ds-button variant="outline" size="sm"
242
+ style="border-radius: 6px 0 0 6px; border-right: none;">Archive</ds-button>
243
+ <ds-button variant="outline" size="sm"
244
+ style="border-radius: 0; border-right: none;">Report</ds-button>
245
+ <ds-button variant="outline" size="sm"
246
+ style="border-radius: 0; border-right: none;">Snooze</ds-button>
247
+ <ds-button variant="outline" size="sm"
248
+ style="border-radius: 0 6px 6px 0;">···</ds-button>
249
+ </div>
250
+ `,
251
+ }),
252
+ };
253
+
254
+ export const StateMatrix: Story = {
255
+ parameters: { layout: 'padded' },
256
+ render: () => ({
257
+ template: `
258
+ <div style="display:grid; gap:12px;">
259
+ <div style="display:grid; grid-template-columns: 140px repeat(5, 160px); gap:12px; align-items:center; font-size: 13px;">
260
+ <div></div>
261
+ <div style="color: var(--color-text-secondary); font-weight: 500;">Default</div>
262
+ <div style="color: var(--color-text-secondary); font-weight: 500;">Hover</div>
263
+ <div style="color: var(--color-text-secondary); font-weight: 500;">Active</div>
264
+ <div style="color: var(--color-text-secondary); font-weight: 500;">Focus</div>
265
+ <div style="color: var(--color-text-secondary); font-weight: 500;">Disabled</div>
266
+ </div>
267
+
268
+ ${['primary','secondary','outline','ghost','destructive','link'].map((variant) => `
269
+ <div style="display:grid; grid-template-columns: 140px repeat(5, 160px); gap:12px; align-items:center;">
270
+ <div style="color: var(--color-text-secondary); font-size: 13px;">${variant}</div>
271
+
272
+ <ds-button variant="${variant}">Label</ds-button>
273
+ <ds-button variant="${variant}" class="is-hover">Label</ds-button>
274
+ <ds-button variant="${variant}" class="is-active">Label</ds-button>
275
+ <ds-button variant="${variant}" class="is-focus">Label</ds-button>
276
+ <ds-button variant="${variant}" disabled>Label</ds-button>
277
+ </div>
278
+ `).join('')}
279
+ </div>
280
+ `,
281
+ }),
282
+ };
283
+
284
+ export const LoadingMatrix: Story = {
285
+ parameters: { layout: 'padded' },
286
+ render: () => ({
287
+ template: `
288
+ <div style="display:grid; gap:12px;">
289
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
290
+ <ds-button variant="primary" [loading]="true">Primary</ds-button>
291
+ <ds-button variant="secondary" [loading]="true">Secondary</ds-button>
292
+ <ds-button variant="outline" [loading]="true">Outline</ds-button>
293
+ <ds-button variant="ghost" [loading]="true">Ghost</ds-button>
294
+ <ds-button variant="destructive" [loading]="true">Destructive</ds-button>
295
+ <ds-button variant="link" [loading]="true">Link</ds-button>
296
+ </div>
297
+ </div>
298
+ `,
299
+ }),
300
+ };
301
+
302
+ // ── Disabled ───────────────────────────────────────────────────
303
+ export const DisabledPerVariant: Story = {
304
+ render: () => ({
305
+ template: `
306
+ <div style="display:flex; flex-wrap:wrap; gap:12px;">
307
+ <ds-button variant="primary" [disabled]="true">Primary</ds-button>
308
+ <ds-button variant="secondary" [disabled]="true">Secondary</ds-button>
309
+ <ds-button variant="outline" [disabled]="true">Outline</ds-button>
310
+ <ds-button variant="ghost" [disabled]="true">Ghost</ds-button>
311
+ <ds-button variant="destructive" [disabled]="true">Destructive</ds-button>
312
+ <ds-button variant="link" [disabled]="true">Link</ds-button>
313
+ </div>
314
+ `,
315
+ }),
316
+ };
317
+
318
+ // ── As Link ───────────────────────────────────────────────────
319
+ export const AsLink: Story = {
320
+ render: () => ({
321
+ template: `
322
+ <div style="display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
323
+ <ds-button asTag="a" variant="primary">Anchor Primary</ds-button>
324
+ <ds-button asTag="a" variant="outline">Anchor Outline</ds-button>
325
+ <ds-button asTag="a" variant="link">Anchor Link</ds-button>
326
+ </div>
327
+ `,
328
+ }),
329
+ };
@@ -0,0 +1,102 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { CheckboxComponent } from '../../app/lib/checkbox/checkbox.component';
3
+
4
+ const meta: Meta<CheckboxComponent> = {
5
+ title: 'Components/Checkbox',
6
+ component: CheckboxComponent,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: 'Checkbox accesible con soporte para estado indeterminado y ReactiveForms.',
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ disabled: { control: 'boolean' },
18
+ indeterminate: { control: 'boolean' },
19
+ label: { control: 'text' },
20
+ hint: { control: 'text' },
21
+ },
22
+ };
23
+
24
+ export default meta;
25
+ type Story = StoryObj<CheckboxComponent>;
26
+
27
+ // ── Playground ─────────────────────────────────────────────────
28
+ export const Playground: Story = {
29
+ args: { label: 'Mantener sesión iniciada' },
30
+ render: (args) => ({
31
+ props: args,
32
+ template: `
33
+ <ds-checkbox
34
+ [label]="label"
35
+ [hint]="hint"
36
+ [disabled]="disabled"
37
+ [indeterminate]="indeterminate"
38
+ />
39
+ `,
40
+ }),
41
+ };
42
+
43
+ // ── Estados ────────────────────────────────────────────────────
44
+ export const Estados: Story = {
45
+ render: () => ({
46
+ template: `
47
+ <div style="display:flex; flex-direction:column; gap:16px;">
48
+ <ds-checkbox label="Sin marcar" />
49
+ <ds-checkbox label="Marcado" [checked]="true" />
50
+ <ds-checkbox label="Indeterminado" [indeterminate]="true" />
51
+ <ds-checkbox label="Deshabilitado sin marcar" [disabled]="true" />
52
+ <ds-checkbox label="Deshabilitado marcado" [disabled]="true" [checked]="true" />
53
+ </div>
54
+ `,
55
+ }),
56
+ };
57
+
58
+ // ── Con hint ───────────────────────────────────────────────────
59
+ export const ConHint: Story = {
60
+ render: () => ({
61
+ template: `
62
+ <div style="display:flex; flex-direction:column; gap:16px; max-width:280px;">
63
+ <ds-checkbox
64
+ label="Mantener sesión iniciada"
65
+ hint="Tu sesión no cerrará al salir del navegador."
66
+ />
67
+ <ds-checkbox
68
+ label="Recibir notificaciones"
69
+ hint="Te avisaremos sobre cambios importantes en tu cuenta."
70
+ [checked]="true"
71
+ />
72
+ </div>
73
+ `,
74
+ }),
75
+ };
76
+
77
+ // ── Grupo (lista de opciones) ──────────────────────────────────
78
+ export const Grupo: Story = {
79
+ parameters: { layout: 'padded' },
80
+ render: () => ({
81
+ template: `
82
+ <fieldset style="border:1px solid var(--color-border); border-radius:8px; padding:20px; display:flex; flex-direction:column; gap:14px; min-width:280px;">
83
+ <legend style="font-size:13px; font-weight:600; color:var(--color-text-secondary); padding:0 6px;">
84
+ Permisos de acceso
85
+ </legend>
86
+ <ds-checkbox label="Ver reportes" hint="Acceso de solo lectura a todos los reportes." [checked]="true" />
87
+ <ds-checkbox label="Editar registros" hint="Puede modificar datos existentes." />
88
+ <ds-checkbox label="Eliminar registros" hint="Acción irreversible." [disabled]="true" />
89
+ <ds-checkbox label="Administrar usuarios" hint="Requiere aprobación del administrador." [indeterminate]="true" />
90
+ </fieldset>
91
+ `,
92
+ }),
93
+ };
94
+
95
+ // ── En contexto (como en tu imagen de login) ───────────────────
96
+ export const EnLogin: Story = {
97
+ render: () => ({
98
+ template: `
99
+ <ds-checkbox label="Mantener sesión iniciada" [checked]="true" />
100
+ `,
101
+ }),
102
+ };
@@ -0,0 +1,100 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { Search, Mail } from 'lucide-angular';
3
+ import { InputComponent } from '../../app/lib/input/input.component';
4
+
5
+ const meta: Meta<InputComponent> = {
6
+ title: 'Components/Input',
7
+ component: InputComponent,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ layout: 'centered',
11
+ docs: {
12
+ description: {
13
+ component: 'Campo de texto base del design system. Compatible con ReactiveForms y ngModel.',
14
+ },
15
+ },
16
+ },
17
+ argTypes: {
18
+ type: { control: 'select', options: ['text', 'password', 'email', 'number'] },
19
+ disabled: { control: 'boolean' },
20
+ label: { control: 'text' },
21
+ placeholder: { control: 'text' },
22
+ hint: { control: 'text' },
23
+ error: { control: 'text' },
24
+ required: { control: 'boolean' },
25
+ },
26
+ };
27
+
28
+ export default meta;
29
+ type Story = StoryObj<InputComponent>;
30
+
31
+ // ── Playground ─────────────────────────────────────────────────
32
+ export const Playground: Story = {
33
+ args: {
34
+ label: 'RFC',
35
+ placeholder: 'VECJ880326XXX',
36
+ required: true,
37
+ },
38
+ render: (args) => ({
39
+ props: args,
40
+ template: `
41
+ <div style="width: 320px;">
42
+ <ds-input
43
+ [label]="label"
44
+ [placeholder]="placeholder"
45
+ [hint]="hint"
46
+ [error]="error"
47
+ [disabled]="disabled"
48
+ [type]="type"
49
+ [required]="required"
50
+ />
51
+ </div>
52
+ `,
53
+ }),
54
+ };
55
+
56
+ // ── Login form (como en la imagen) ────────────────────────────
57
+ export const LoginForm: Story = {
58
+ render: () => ({
59
+ template: `
60
+ <div style="width: 360px; display: flex; flex-direction: column; gap: 16px;">
61
+ <ds-input label="RFC" placeholder="VECJ880326XXX" />
62
+ <ds-input label="Contraseña" type="password" placeholder="" />
63
+ </div>
64
+ `,
65
+ }),
66
+ parameters: { layout: 'centered' },
67
+ };
68
+
69
+ // ── Estados ────────────────────────────────────────────────────
70
+ export const Estados: Story = {
71
+ render: () => ({
72
+ template: `
73
+ <div style="width: 320px; display: flex; flex-direction: column; gap: 16px;">
74
+ <ds-input label="Default" placeholder="Escribe algo..." />
75
+ <ds-input label="Con hint" placeholder="usuario@empresa.com"
76
+ hint="Usaremos este correo para notificaciones." />
77
+ <ds-input label="Con error" placeholder="RFC"
78
+ error="El RFC ingresado no es válido." />
79
+ <ds-input label="Disabled" placeholder="No editable" [disabled]="true" />
80
+ </div>
81
+ `,
82
+ }),
83
+ parameters: { layout: 'padded' },
84
+ };
85
+
86
+ // ── Con íconos ─────────────────────────────────────────────────
87
+ export const ConIconos: Story = {
88
+ render: () => ({
89
+ props: { Search, Mail },
90
+ template: `
91
+ <div style="width: 320px; display: flex; flex-direction: column; gap: 16px;">
92
+ <ds-input label="Buscar" placeholder="Buscar..." [prefixIcon]="Search" />
93
+ <ds-input label="Correo" placeholder="usuario@empresa.com" [prefixIcon]="Mail" />
94
+ <ds-input label="Contraseña" type="password" />
95
+ </div>
96
+ `,
97
+ }),
98
+ parameters: { layout: 'padded' },
99
+ };
100
+
@@ -0,0 +1,81 @@
1
+ import type { Meta, StoryObj } from '@storybook/angular';
2
+ import { SearchComponent } from '../../app/lib/search/search.component';
3
+
4
+ const meta: Meta<SearchComponent> = {
5
+ title: 'Components/Search',
6
+ component: SearchComponent,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: 'Input de búsqueda con ícono prefix, botón de limpiar y eventos `search` y `cleared`.',
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ disabled: { control: 'boolean' },
18
+ placeholder: { control: 'text' },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+ type Story = StoryObj<SearchComponent>;
24
+
25
+ // ── Playground ─────────────────────────────────────────────────
26
+ export const Playground: Story = {
27
+ args: {
28
+ placeholder: 'Buscar por nombre o RFC...',
29
+ },
30
+ render: (args) => ({
31
+ props: args,
32
+ template: `
33
+ <div style="width: 340px;">
34
+ <ds-search
35
+ [placeholder]="placeholder"
36
+ [disabled]="disabled"
37
+ />
38
+ </div>
39
+ `,
40
+ }),
41
+ };
42
+
43
+ // ── Estados ────────────────────────────────────────────────────
44
+ export const Estados: Story = {
45
+ render: () => ({
46
+ template: `
47
+ <div style="width:320px; display:flex; flex-direction:column; gap:12px;">
48
+ <ds-search placeholder="Sin texto (default)" />
49
+ <ds-search placeholder="Disabled" [disabled]="true" />
50
+ </div>
51
+ `,
52
+ }),
53
+ parameters: { layout: 'padded' },
54
+ };
55
+
56
+ // ── En contexto (toolbar de tabla) ────────────────────────────
57
+ export const EnToolbar: Story = {
58
+ parameters: { layout: 'padded' },
59
+ render: () => ({
60
+ template: `
61
+ <div style="
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ padding: 16px;
66
+ border: 1px solid var(--color-border);
67
+ border-radius: 12px;
68
+ background: var(--color-bg-default);
69
+ gap: 12px;
70
+ min-width: 560px;
71
+ ">
72
+ <div style="flex:1; max-width:320px;">
73
+ <ds-search placeholder="Buscar por nombre o RFC..." />
74
+ </div>
75
+ <span style="font-size:13px; color:var(--color-text-tertiary);">
76
+ 52 resultados
77
+ </span>
78
+ </div>
79
+ `,
80
+ }),
81
+ };
@@ -0,0 +1,3 @@
1
+ export interface User {
2
+ name: string;
3
+ }
@@ -0,0 +1,14 @@
1
+ @use 'tokens/styles/tokens';
2
+
3
+ *, *::before, *::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ margin: 0;
9
+ font-family: var(--font-family-sans);
10
+ font-size: var(--font-size-md);
11
+ color: var(--color-text-primary);
12
+ background: var(--color-bg-default);
13
+ line-height: var(--line-height-normal);
14
+ }