@yuno-payments/dashboard-design-system 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.
Files changed (71) hide show
  1. package/.storybook/main.ts +20 -0
  2. package/.storybook/preview.ts +18 -0
  3. package/.storybook/vitest.setup.ts +7 -0
  4. package/README.md +69 -0
  5. package/components.json +21 -0
  6. package/eslint.config.js +26 -0
  7. package/index.html +13 -0
  8. package/package.json +57 -0
  9. package/public/vite.svg +1 -0
  10. package/src/App.css +42 -0
  11. package/src/App.tsx +11 -0
  12. package/src/assets/react.svg +1 -0
  13. package/src/components/atoms/button/button.stories.tsx +222 -0
  14. package/src/components/atoms/button/button.test.tsx +78 -0
  15. package/src/components/atoms/button/index.tsx +80 -0
  16. package/src/components/atoms/checkbox/checkbox.stories.tsx +314 -0
  17. package/src/components/atoms/checkbox/checkbox.test.tsx +278 -0
  18. package/src/components/atoms/checkbox/index.tsx +103 -0
  19. package/src/components/atoms/chip/chip.stories.tsx +317 -0
  20. package/src/components/atoms/chip/chip.test.tsx +300 -0
  21. package/src/components/atoms/chip/index.tsx +114 -0
  22. package/src/components/atoms/input/index.tsx +27 -0
  23. package/src/components/atoms/link/index.tsx +79 -0
  24. package/src/components/atoms/link/link.stories.tsx +159 -0
  25. package/src/components/atoms/link/link.test.tsx +176 -0
  26. package/src/components/atoms/radiobutton/index.tsx +103 -0
  27. package/src/components/atoms/radiobutton/radiobutton.stories.tsx +314 -0
  28. package/src/components/atoms/radiobutton/radiobutton.test.tsx +245 -0
  29. package/src/components/atoms/tag/index.tsx +196 -0
  30. package/src/components/atoms/tag/tag.stories.tsx +281 -0
  31. package/src/components/atoms/tag/tag.test.tsx +282 -0
  32. package/src/components/atoms/typography/index.tsx +62 -0
  33. package/src/components/atoms/typography/typography.stories.tsx +214 -0
  34. package/src/components/atoms/typography/typography.test.tsx +187 -0
  35. package/src/components/index.tsx +17 -0
  36. package/src/components/molecules/announcement/announcement.stories.tsx +277 -0
  37. package/src/components/molecules/announcement/announcement.test.tsx +354 -0
  38. package/src/components/molecules/announcement/index.tsx +200 -0
  39. package/src/components/molecules/notification-alert/index.tsx +293 -0
  40. package/src/components/molecules/notification-alert/notification-alert.stories.tsx +418 -0
  41. package/src/components/molecules/notification-alert/notification-alert.test.tsx +454 -0
  42. package/src/components/molecules/popover/index.tsx +175 -0
  43. package/src/components/molecules/popover/popover.stories.tsx +241 -0
  44. package/src/components/molecules/popover/popover.test.tsx +191 -0
  45. package/src/components/molecules/textfield/index.tsx +154 -0
  46. package/src/components/molecules/textfield/textfield.stories.tsx +168 -0
  47. package/src/components/molecules/textfield/textfield.test.tsx +157 -0
  48. package/src/components/molecules/tooltip/index.tsx +263 -0
  49. package/src/components/molecules/tooltip/tooltip.stories.tsx +363 -0
  50. package/src/components/molecules/tooltip/tooltip.test.tsx +468 -0
  51. package/src/components/organisms/dialog/dialog.stories.tsx +522 -0
  52. package/src/components/organisms/dialog/dialog.test.tsx +525 -0
  53. package/src/components/organisms/dialog/index.tsx +233 -0
  54. package/src/components/organisms/dropdown/dropdown.stories.tsx +529 -0
  55. package/src/components/organisms/dropdown/dropdown.test.tsx +390 -0
  56. package/src/components/organisms/dropdown/index.tsx +624 -0
  57. package/src/index.css +184 -0
  58. package/src/lib/color-utils.ts +94 -0
  59. package/src/lib/utils.ts +6 -0
  60. package/src/main.tsx +10 -0
  61. package/src/stories/Colors.stories.tsx +107 -0
  62. package/src/stories/Shadows.stories.tsx +110 -0
  63. package/src/stories/Spacing.stories.tsx +121 -0
  64. package/src/stories/Typography.stories.tsx +197 -0
  65. package/src/vite-env.d.ts +1 -0
  66. package/tsconfig.app.json +33 -0
  67. package/tsconfig.json +13 -0
  68. package/tsconfig.node.json +25 -0
  69. package/vite.config.ts +43 -0
  70. package/vitest.config.ts +15 -0
  71. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,529 @@
1
+ import * as React from 'react'
2
+ import type { Meta, StoryObj } from '@storybook/react-vite'
3
+ import { Dropdown } from './index'
4
+
5
+ const mockNone = [
6
+ {
7
+ header: 'Options',
8
+ options: [
9
+ { label: 'Juan', value: 'JuanValue' },
10
+ { label: 'Rodrigo', value: 'Rodrigo' },
11
+ { label: 'Pepe', value: 'Pepe' },
12
+ { label: 'Martin', value: 'Martin' },
13
+ { label: 'Bruno', value: 'Bruno' },
14
+ { label: 'Federico', value: 'Federico' },
15
+ { label: 'Miriam', value: 'MiriamValue' },
16
+ { label: 'Mariano', value: 'Mariano', disabled: true },
17
+ { label: 'Matias', value: 'Matias' },
18
+ { label: 'Marcelo', value: 'Marcelo' },
19
+ { label: 'Ronaldo', value: 'Ronaldo' },
20
+ ],
21
+ },
22
+ ]
23
+
24
+ const mockCheckbox = [
25
+ {
26
+ header: 'Checkbox Options',
27
+ type: 'checkbox' as const,
28
+ options: [
29
+ { label: 'Juan', value: 'JuanValue' },
30
+ { label: 'Rodrigo', value: 'Rodrigo' },
31
+ { label: 'Federico', value: 'Federico', disabled: true },
32
+ { label: 'Nahuel', value: 'Nahuel' },
33
+ { label: 'Matias', value: 'Matias' },
34
+ { label: 'Pepe', value: 'Pepe', disabled: true },
35
+ { label: 'Klaus', value: 'Klaus' },
36
+ { label: 'Miriam', value: 'MiriamValue' },
37
+ ],
38
+ },
39
+ ]
40
+
41
+ const mockRadioButton = [
42
+ {
43
+ header: 'Radio Options',
44
+ type: 'radiobutton' as const,
45
+ options: [
46
+ { label: 'Juan', value: 'Juan' },
47
+ { label: 'Rodrigo', value: 'Rodrigo' },
48
+ { label: 'Federico', value: 'Federico', disabled: true },
49
+ { label: 'Nahuel', value: 'Nahuel' },
50
+ ],
51
+ },
52
+ ]
53
+
54
+ const mockCheckboxOneLevel = [
55
+ {
56
+ header: 'Nested Options',
57
+ options: [
58
+ {
59
+ label: 'Cuentas test',
60
+ value: 'cuentas-test',
61
+ options: [
62
+ { label: 'Juan', value: 'Juan' },
63
+ { label: 'Rodrigo', value: 'Rodrigo' },
64
+ ],
65
+ },
66
+ {
67
+ label: 'Cuentas Yuno',
68
+ value: 'cuentas-yuno',
69
+ options: [
70
+ { label: 'Omelia', value: 'Omelia' },
71
+ { label: 'Federico', value: 'Federico', disabled: true },
72
+ ],
73
+ },
74
+ {
75
+ label: 'Cuentas Avianca',
76
+ value: 'cuentas-avianca',
77
+ options: [
78
+ { label: 'Tom', value: 'Tom' },
79
+ { label: 'Zac', value: 'Zac' },
80
+ ],
81
+ },
82
+ ],
83
+ },
84
+ ]
85
+
86
+ const mockCheckboxTwoLevels = [
87
+ {
88
+ header: 'Two Level Nested',
89
+ options: [
90
+ {
91
+ label: 'Cuentas test',
92
+ value: 'cuentas-test',
93
+ options: [
94
+ {
95
+ label: 'Cuentas Yuno',
96
+ value: 'cuentas-yuno',
97
+ options: [
98
+ { label: 'Omelia', value: 'Omelia' },
99
+ { label: 'Federico', value: 'Federico' },
100
+ ],
101
+ },
102
+ {
103
+ label: 'Cuentas Avianca',
104
+ value: 'cuentas-avianca',
105
+ options: [
106
+ { label: 'Tom', value: 'Tom' },
107
+ { label: 'Bruno', value: 'Bruno', disabled: true },
108
+ { label: 'Zac', value: 'Zac' },
109
+ ],
110
+ },
111
+ ],
112
+ },
113
+ ],
114
+ },
115
+ ]
116
+
117
+ const mockRadioButtonOneLevel = [
118
+ {
119
+ header: 'Options',
120
+ options: [
121
+ {
122
+ label: 'Select team',
123
+ value: 'select-team',
124
+ options: [
125
+ { label: 'Dashboard', value: 'Dashboard' },
126
+ { label: 'Core', value: 'Core' },
127
+ { label: 'Secops', value: 'Secops', disabled: true },
128
+ { label: 'Integrations', value: 'Integrations' },
129
+ ],
130
+ },
131
+ {
132
+ label: 'Select genre',
133
+ value: 'select-genre',
134
+ options: [
135
+ { label: 'Male', value: 'Male' },
136
+ { label: 'Female', value: 'Female' },
137
+ ],
138
+ },
139
+ {
140
+ label: 'Select rol',
141
+ value: 'select-rol',
142
+ options: [
143
+ { label: 'QA', value: 'QA' },
144
+ { label: 'Frontend', value: 'Frontend' },
145
+ { label: 'Backend', value: 'Backend' },
146
+ ],
147
+ },
148
+ ],
149
+ },
150
+ ]
151
+
152
+ const mockNoneOneLevel = [
153
+ {
154
+ header: 'Simple Nested',
155
+ options: [
156
+ {
157
+ label: 'Cuentas test',
158
+ value: 'cuentas-test',
159
+ options: [
160
+ { label: 'Juan', value: 'Juan' },
161
+ { label: 'Rodrigo', value: 'Rodrigo' },
162
+ ],
163
+ },
164
+ {
165
+ label: 'Cuentas Yuno',
166
+ value: 'cuentas-yuno',
167
+ options: [
168
+ { label: 'Omelia', value: 'Omelia' },
169
+ { label: 'Federico', value: 'Federico', disabled: true },
170
+ ],
171
+ },
172
+ {
173
+ label: 'Cuentas Avianca',
174
+ value: 'cuentas-avianca',
175
+ options: [
176
+ { label: 'Tom', value: 'Tom' },
177
+ { label: 'Zac', value: 'Zac' },
178
+ ],
179
+ },
180
+ ],
181
+ },
182
+ ]
183
+
184
+ const meta: Meta<typeof Dropdown> = {
185
+ title: 'Organisms/Dropdown',
186
+ component: Dropdown,
187
+ parameters: {
188
+ layout: 'centered',
189
+ },
190
+ tags: ['autodocs'],
191
+ argTypes: {
192
+ variant: {
193
+ control: 'select',
194
+ options: ['default'],
195
+ description: 'The visual variant of the dropdown',
196
+ },
197
+ size: {
198
+ control: 'select',
199
+ options: ['default', 'sm', 'lg'],
200
+ description: 'The size of the dropdown',
201
+ },
202
+ onlyOneValue: {
203
+ control: 'boolean',
204
+ description: 'Whether to allow only single selection',
205
+ },
206
+ showSearchBar: {
207
+ control: 'boolean',
208
+ description: 'Whether to show the search bar',
209
+ },
210
+ showLabelOrValue: {
211
+ control: 'select',
212
+ options: ['label', 'value'],
213
+ description: 'Whether to show label or value in display',
214
+ },
215
+ disabled: {
216
+ control: 'boolean',
217
+ description: 'Whether the dropdown is disabled',
218
+ },
219
+ placeholder: {
220
+ control: 'text',
221
+ description: 'Placeholder text when no option is selected',
222
+ },
223
+ label: {
224
+ control: 'text',
225
+ description: 'Label for the dropdown',
226
+ },
227
+ helperText: {
228
+ control: 'text',
229
+ description: 'Helper text below the dropdown',
230
+ },
231
+ width: {
232
+ control: 'number',
233
+ description: 'Fixed width for the dropdown',
234
+ },
235
+ },
236
+ }
237
+
238
+ export default meta
239
+ type Story = StoryObj<typeof meta>
240
+
241
+ export const Primary: Story = {
242
+ args: {
243
+ initialData: mockNone,
244
+ showSearchBar: true,
245
+ width: 400,
246
+ showLabelOrValue: 'value',
247
+ placeholder: 'Select an option',
248
+ },
249
+ }
250
+
251
+ export const Checkbox: Story = {
252
+ args: {
253
+ initialData: mockCheckbox,
254
+ initialDataSelected: ['JuanValue'],
255
+ width: 400,
256
+ onlyOneValue: false,
257
+ showSearchBar: true,
258
+ showLabelOrValue: 'value',
259
+ placeholder: 'Select options',
260
+ },
261
+ }
262
+
263
+ export const Checkbox1Level: Story = {
264
+ args: {
265
+ initialData: mockCheckboxOneLevel,
266
+ width: 400,
267
+ onlyOneValue: false,
268
+ showSearchBar: true,
269
+ placeholder: 'Select options',
270
+ },
271
+ }
272
+
273
+ export const Checkbox2Levels: Story = {
274
+ args: {
275
+ initialData: mockCheckboxTwoLevels,
276
+ width: 400,
277
+ onlyOneValue: false,
278
+ placeholder: 'Select options',
279
+ },
280
+ }
281
+
282
+ export const RadioButton: Story = {
283
+ args: {
284
+ initialData: mockRadioButton,
285
+ width: 400,
286
+ placeholder: 'Select an option',
287
+ },
288
+ }
289
+
290
+ export const RadioButton1Level: Story = {
291
+ args: {
292
+ initialData: mockRadioButtonOneLevel,
293
+ width: 400,
294
+ onlyOneValue: false,
295
+ placeholder: 'Select an option',
296
+ },
297
+ }
298
+
299
+ export const SimpleOneLevel: Story = {
300
+ args: {
301
+ initialData: mockNoneOneLevel,
302
+ width: 400,
303
+ placeholder: 'Select an option',
304
+ },
305
+ }
306
+
307
+ export const WithSearch: Story = {
308
+ args: {
309
+ initialData: mockNone,
310
+ showSearchBar: true,
311
+ searchPlaceholder: 'Search options...',
312
+ width: 400,
313
+ placeholder: 'Select an option',
314
+ },
315
+ }
316
+
317
+ export const WithLabel: Story = {
318
+ args: {
319
+ initialData: mockNone,
320
+ label: 'Choose an option',
321
+ helperText: 'This is a helper text',
322
+ width: 400,
323
+ placeholder: 'Select an option',
324
+ },
325
+ }
326
+
327
+ export const Disabled: Story = {
328
+ args: {
329
+ initialData: mockNone,
330
+ disabled: true,
331
+ width: 400,
332
+ placeholder: 'Select an option',
333
+ },
334
+ }
335
+
336
+ export const Sizes: Story = {
337
+ render: () => (
338
+ <div className="space-y-4">
339
+ <div>
340
+ <h3 className="text-sm font-medium mb-2">Small</h3>
341
+ <Dropdown
342
+ size="sm"
343
+ initialData={mockNone}
344
+ width={300}
345
+ placeholder="Small dropdown"
346
+ />
347
+ </div>
348
+ <div>
349
+ <h3 className="text-sm font-medium mb-2">Default</h3>
350
+ <Dropdown
351
+ size="default"
352
+ initialData={mockNone}
353
+ width={300}
354
+ placeholder="Default dropdown"
355
+ />
356
+ </div>
357
+ <div>
358
+ <h3 className="text-sm font-medium mb-2">Large</h3>
359
+ <Dropdown
360
+ size="lg"
361
+ initialData={mockNone}
362
+ width={300}
363
+ placeholder="Large dropdown"
364
+ />
365
+ </div>
366
+ </div>
367
+ ),
368
+ }
369
+
370
+ export const Interactive: Story = {
371
+ render: () => {
372
+ const [selectedValues, setSelectedValues] = React.useState<string[]>([])
373
+
374
+ return (
375
+ <div className="space-y-4">
376
+ <Dropdown
377
+ initialData={mockCheckbox}
378
+ onlyOneValue={false}
379
+ showSearchBar={true}
380
+ width={400}
381
+ placeholder="Select multiple options"
382
+ onChangeSelected={setSelectedValues}
383
+ label="Interactive Dropdown"
384
+ helperText="Try selecting multiple options and searching"
385
+ />
386
+ <div className="text-sm text-muted-foreground">
387
+ Selected: {selectedValues.length > 0 ? selectedValues.join(', ') : 'None'}
388
+ </div>
389
+ </div>
390
+ )
391
+ },
392
+ }
393
+
394
+ export const Docs: Story = {
395
+ render: () => (
396
+ <div className="max-w-4xl mx-auto p-6 space-y-8">
397
+ <div>
398
+ <h1 className="text-3xl font-bold mb-4">Dropdown Component</h1>
399
+ <p className="text-lg text-muted-foreground mb-6">
400
+ A flexible dropdown component that supports single and multiple selection,
401
+ nested options, search functionality, and different item types (checkbox, radiobutton, none).
402
+ </p>
403
+ </div>
404
+
405
+ <div className="space-y-6">
406
+ <div>
407
+ <h2 className="text-xl font-semibold mb-3">Basic Usage</h2>
408
+ <div className="space-y-4">
409
+ <Dropdown
410
+ initialData={mockNone}
411
+ width={400}
412
+ placeholder="Select an option"
413
+ label="Basic Dropdown"
414
+ />
415
+ </div>
416
+ </div>
417
+
418
+ <div>
419
+ <h2 className="text-xl font-semibold mb-3">Multiple Selection</h2>
420
+ <div className="space-y-4">
421
+ <Dropdown
422
+ initialData={mockCheckbox}
423
+ onlyOneValue={false}
424
+ width={400}
425
+ placeholder="Select multiple options"
426
+ label="Multiple Selection"
427
+ />
428
+ </div>
429
+ </div>
430
+
431
+ <div>
432
+ <h2 className="text-xl font-semibold mb-3">With Search</h2>
433
+ <div className="space-y-4">
434
+ <Dropdown
435
+ initialData={mockNone}
436
+ showSearchBar={true}
437
+ width={400}
438
+ placeholder="Select an option"
439
+ label="Searchable Dropdown"
440
+ />
441
+ </div>
442
+ </div>
443
+
444
+ <div>
445
+ <h2 className="text-xl font-semibold mb-3">Nested Options</h2>
446
+ <div className="space-y-4">
447
+ <Dropdown
448
+ initialData={mockCheckboxOneLevel}
449
+ onlyOneValue={false}
450
+ width={400}
451
+ placeholder="Select options"
452
+ label="Nested Options"
453
+ />
454
+ </div>
455
+ </div>
456
+
457
+ <div>
458
+ <h2 className="text-xl font-semibold mb-3">Radio Button Type</h2>
459
+ <div className="space-y-4">
460
+ <Dropdown
461
+ initialData={mockRadioButton}
462
+ width={400}
463
+ placeholder="Select an option"
464
+ label="Radio Button Selection"
465
+ />
466
+ </div>
467
+ </div>
468
+ </div>
469
+
470
+ <div className="border-t pt-8">
471
+ <h2 className="text-xl font-semibold mb-4">Usage Guidelines</h2>
472
+ <div className="grid md:grid-cols-2 gap-6">
473
+ <div>
474
+ <h3 className="text-base font-medium mb-2">When to Use</h3>
475
+ <div className="space-y-2">
476
+ <p className="text-sm text-muted-foreground">
477
+ • Use for selecting from a list of options when space is limited
478
+ </p>
479
+ <p className="text-sm text-muted-foreground">
480
+ • Use multiple selection for filtering or categorization
481
+ </p>
482
+ <p className="text-sm text-muted-foreground">
483
+ • Use nested options for hierarchical data structures
484
+ </p>
485
+ <p className="text-sm text-muted-foreground">
486
+ • Use search functionality for large lists of options
487
+ </p>
488
+ </div>
489
+ </div>
490
+ <div>
491
+ <h3 className="text-base font-medium mb-2">Best Practices</h3>
492
+ <div className="space-y-2">
493
+ <p className="text-sm text-muted-foreground">
494
+ • Keep option labels clear and concise
495
+ </p>
496
+ <p className="text-sm text-muted-foreground">
497
+ • Use appropriate selection type (single vs multiple)
498
+ </p>
499
+ <p className="text-sm text-muted-foreground">
500
+ • Provide helpful placeholder text
501
+ </p>
502
+ <p className="text-sm text-muted-foreground">
503
+ • Consider using search for lists with more than 10 options
504
+ </p>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ </div>
509
+
510
+ <div className="border-t pt-8">
511
+ <h2 className="text-xl font-semibold mb-4">Accessibility</h2>
512
+ <div className="space-y-2">
513
+ <p className="text-sm text-muted-foreground">
514
+ • Supports keyboard navigation with arrow keys and Enter/Space
515
+ </p>
516
+ <p className="text-sm text-muted-foreground">
517
+ • Proper ARIA attributes for screen readers
518
+ </p>
519
+ <p className="text-sm text-muted-foreground">
520
+ • Focus management and escape key handling
521
+ </p>
522
+ <p className="text-sm text-muted-foreground">
523
+ • Clear visual indicators for selected and disabled states
524
+ </p>
525
+ </div>
526
+ </div>
527
+ </div>
528
+ ),
529
+ }