@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,233 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { X, ArrowLeft } from "lucide-react"
4
+ import { cn } from "../../../lib/utils"
5
+ import { Button } from "../../atoms/button"
6
+
7
+ const dialogVariants = cva(
8
+ "fixed inset-0 z-50 flex items-center justify-center p-4",
9
+ {
10
+ variants: {
11
+ verticalAlign: {
12
+ start: "items-start pt-20",
13
+ center: "items-center",
14
+ end: "items-end pb-20",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ verticalAlign: "center",
19
+ },
20
+ }
21
+ )
22
+
23
+ const dialogContentVariants = cva(
24
+ "relative bg-background rounded-lg shadow-lg border max-h-[90vh] overflow-hidden flex flex-col",
25
+ {
26
+ variants: {
27
+ size: {
28
+ default: "w-full max-w-md",
29
+ sm: "w-full max-w-sm",
30
+ lg: "w-full max-w-lg",
31
+ xl: "w-full max-w-xl",
32
+ fullscreen: "w-full h-full max-w-none max-h-none rounded-none",
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ size: "default",
37
+ },
38
+ }
39
+ )
40
+
41
+ export type VerticalAlign = 'start' | 'center' | 'end'
42
+ export type VariantButtonType = 'primary' | 'secondary' | 'tertiary' | 'text' | 'outlined' | 'contained'
43
+ export type SizeButtonType = 'small' | 'large' | 'medium'
44
+
45
+ export interface IDialogButton {
46
+ key?: string
47
+ variant?: VariantButtonType
48
+ label: string | React.ReactElement
49
+ event: () => void
50
+ size?: SizeButtonType
51
+ loading?: boolean
52
+ disabled?: boolean
53
+ testId?: string
54
+ type?: 'button' | 'reset' | 'submit'
55
+ }
56
+
57
+ export interface DialogProps
58
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'>,
59
+ VariantProps<typeof dialogVariants> {
60
+ title?: React.ReactElement | string
61
+ open: boolean
62
+ closeIcon: () => void
63
+ buttons?: IDialogButton[]
64
+ widthContainer?: number | string
65
+ heightContainer?: number | string
66
+ backButtonAction?: () => void
67
+ showActions?: boolean
68
+ otherActions?: React.ReactNode
69
+ withHeader?: boolean
70
+ children: React.ReactNode
71
+ }
72
+
73
+ const Dialog = React.forwardRef<HTMLDivElement, DialogProps>(
74
+ (
75
+ {
76
+ className,
77
+ verticalAlign,
78
+ title,
79
+ open,
80
+ closeIcon,
81
+ buttons = [],
82
+ widthContainer,
83
+ heightContainer,
84
+ backButtonAction,
85
+ showActions = true,
86
+ otherActions,
87
+ withHeader = true,
88
+ children,
89
+ ...props
90
+ },
91
+ ref
92
+ ) => {
93
+ const [isMobile, setIsMobile] = React.useState(false)
94
+
95
+ React.useEffect(() => {
96
+ const checkMobile = () => {
97
+ setIsMobile(window.innerWidth <= 599)
98
+ }
99
+
100
+ checkMobile()
101
+ window.addEventListener('resize', checkMobile)
102
+ return () => window.removeEventListener('resize', checkMobile)
103
+ }, [])
104
+
105
+ React.useEffect(() => {
106
+ if (open) {
107
+ document.body.style.overflow = 'hidden'
108
+ } else {
109
+ document.body.style.overflow = 'unset'
110
+ }
111
+
112
+ return () => {
113
+ document.body.style.overflow = 'unset'
114
+ }
115
+ }, [open])
116
+
117
+ const getButtonVariant = (variant?: VariantButtonType) => {
118
+ switch (variant) {
119
+ case 'primary':
120
+ return 'default'
121
+ case 'secondary':
122
+ return 'outline'
123
+ case 'tertiary':
124
+ return 'ghost'
125
+ default:
126
+ return variant as 'default' | 'outline' | 'ghost' | 'destructive' | 'secondary' | 'link'
127
+ }
128
+ }
129
+
130
+ const getButtonSize = (size?: SizeButtonType) => {
131
+ switch (size) {
132
+ case 'small':
133
+ return 'sm'
134
+ case 'large':
135
+ return 'lg'
136
+ case 'medium':
137
+ default:
138
+ return 'default'
139
+ }
140
+ }
141
+
142
+ if (!open) return null
143
+
144
+ const dialogStyle = {
145
+ width: widthContainer && !isMobile ? widthContainer : undefined,
146
+ height: heightContainer && !isMobile ? heightContainer : undefined,
147
+ }
148
+
149
+ return (
150
+ <>
151
+ <div
152
+ className="fixed inset-0 z-40 bg-black/25"
153
+ onClick={closeIcon}
154
+ aria-hidden="true"
155
+ />
156
+
157
+ <div className={cn(dialogVariants({ verticalAlign }))}>
158
+ <div
159
+ ref={ref}
160
+ className={cn(
161
+ dialogContentVariants({
162
+ size: isMobile ? "fullscreen" : "default"
163
+ }),
164
+ className
165
+ )}
166
+ style={dialogStyle}
167
+ role="dialog"
168
+ aria-modal="true"
169
+ {...props}
170
+ >
171
+ {withHeader && (
172
+ <div className="flex items-center justify-between p-6 border-b">
173
+ <div className="flex items-center gap-4 flex-1">
174
+ {backButtonAction && (
175
+ <button
176
+ onClick={backButtonAction}
177
+ className="inline-flex items-center justify-center size-6 rounded-sm opacity-70 hover:opacity-100 transition-opacity"
178
+ aria-label="Go back"
179
+ data-testid="back-button"
180
+ >
181
+ <ArrowLeft className="size-4" />
182
+ </button>
183
+ )}
184
+ <div className="text-lg font-semibold leading-none tracking-tight">
185
+ {title}
186
+ </div>
187
+ </div>
188
+
189
+ <div className="flex items-center gap-4">
190
+ {otherActions}
191
+ <button
192
+ onClick={closeIcon}
193
+ className="inline-flex items-center justify-center size-6 rounded-sm opacity-70 hover:opacity-100 transition-opacity"
194
+ aria-label="Close dialog"
195
+ data-testid="close-button"
196
+ >
197
+ <X className="size-4" />
198
+ </button>
199
+ </div>
200
+ </div>
201
+ )}
202
+
203
+ <div className="flex-1 overflow-auto p-6">
204
+ {children}
205
+ </div>
206
+
207
+ {buttons.length > 0 && showActions && (
208
+ <div className="flex items-center justify-end gap-3 p-6 border-t">
209
+ {buttons.map((button, index) => (
210
+ <Button
211
+ key={button.key || index}
212
+ variant={getButtonVariant(button.variant)}
213
+ size={getButtonSize(button.size)}
214
+ onClick={button.event}
215
+ disabled={button.disabled || button.loading}
216
+ data-testid={button.testId}
217
+ type={button.type}
218
+ >
219
+ {button.loading ? "Loading..." : button.label}
220
+ </Button>
221
+ ))}
222
+ </div>
223
+ )}
224
+ </div>
225
+ </div>
226
+ </>
227
+ )
228
+ }
229
+ )
230
+
231
+ Dialog.displayName = "Dialog"
232
+
233
+ export { Dialog }