dst-rg 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 (249) hide show
  1. package/.gitlab-ci.yml +43 -0
  2. package/.storybook/main.ts +15 -0
  3. package/.storybook/preview.ts +15 -0
  4. package/README.md +254 -0
  5. package/components.json +21 -0
  6. package/dist/Avatar.png +0 -0
  7. package/dist/assets/index-CCq7hmG3.js +186 -0
  8. package/dist/assets/index-Mg-hjQGu.css +1 -0
  9. package/dist/index.html +15 -0
  10. package/dist/test.png +0 -0
  11. package/dist/vite.svg +1 -0
  12. package/eslint.config.js +29 -0
  13. package/index.html +14 -0
  14. package/package.json +102 -0
  15. package/postcss.config.mjs +11 -0
  16. package/rollup.config.mjs +55 -0
  17. package/src/assets/react.svg +1 -0
  18. package/src/assets/style/animation.css +27 -0
  19. package/src/assets/style/box-shadow.css +25 -0
  20. package/src/assets/style/colors.css +402 -0
  21. package/src/assets/style/dark-theme.css +288 -0
  22. package/src/assets/style/font-size.css +14 -0
  23. package/src/assets/style/gradient.css +3 -0
  24. package/src/assets/style/index.css +12 -0
  25. package/src/assets/style/light-theme.css +148 -0
  26. package/src/assets/style/line-height.css +13 -0
  27. package/src/assets/style/max-width.css +5 -0
  28. package/src/assets/style/radius.css +13 -0
  29. package/src/assets/style/utility-colors.css +166 -0
  30. package/src/components/Accordion/_.stories.tsx +75 -0
  31. package/src/components/Accordion/_.test.tsx +77 -0
  32. package/src/components/Accordion/index.tsx +47 -0
  33. package/src/components/Accordion/type.ts +24 -0
  34. package/src/components/Avatar/_.stories.tsx +179 -0
  35. package/src/components/Avatar/_.style.ts +40 -0
  36. package/src/components/Avatar/_.test.tsx +150 -0
  37. package/src/components/Avatar/_.types.ts +66 -0
  38. package/src/components/Avatar/index.tsx +63 -0
  39. package/src/components/Badge/_.stories.tsx +75 -0
  40. package/src/components/Badge/_.style.ts +53 -0
  41. package/src/components/Badge/_.test.tsx +27 -0
  42. package/src/components/Badge/_.types.ts +11 -0
  43. package/src/components/Badge/index.tsx +42 -0
  44. package/src/components/Breadcrumbs/_.stories.tsx +95 -0
  45. package/src/components/Breadcrumbs/_.test.tsx +29 -0
  46. package/src/components/Breadcrumbs/_.type.ts +15 -0
  47. package/src/components/Breadcrumbs/index.tsx +103 -0
  48. package/src/components/Button/_.stories.tsx +85 -0
  49. package/src/components/Button/_.style.ts +56 -0
  50. package/src/components/Button/_.test.tsx +103 -0
  51. package/src/components/Button/_.types.ts +14 -0
  52. package/src/components/Button/index.tsx +70 -0
  53. package/src/components/Checkbox/_.stories.tsx +96 -0
  54. package/src/components/Checkbox/_.style.ts +24 -0
  55. package/src/components/Checkbox/_.test.tsx +85 -0
  56. package/src/components/Checkbox/_.types.ts +23 -0
  57. package/src/components/Checkbox/index.tsx +93 -0
  58. package/src/components/CheckboxGroup/PaymentCard/_.stories.tsx +104 -0
  59. package/src/components/CheckboxGroup/PaymentCard/_.style.ts +28 -0
  60. package/src/components/CheckboxGroup/PaymentCard/_.test.tsx +58 -0
  61. package/src/components/CheckboxGroup/PaymentCard/_.types.ts +28 -0
  62. package/src/components/CheckboxGroup/PaymentCard/index.tsx +71 -0
  63. package/src/components/CheckboxGroup/PlanCard/_.stories.tsx +165 -0
  64. package/src/components/CheckboxGroup/PlanCard/_.style.ts +32 -0
  65. package/src/components/CheckboxGroup/PlanCard/_.test.tsx +54 -0
  66. package/src/components/CheckboxGroup/PlanCard/_.types.ts +35 -0
  67. package/src/components/CheckboxGroup/PlanCard/index.tsx +53 -0
  68. package/src/components/CheckboxGroup/UserCard/_.stories.tsx +89 -0
  69. package/src/components/CheckboxGroup/UserCard/_.style.ts +42 -0
  70. package/src/components/CheckboxGroup/UserCard/_.test.tsx +66 -0
  71. package/src/components/CheckboxGroup/UserCard/_.types.ts +26 -0
  72. package/src/components/CheckboxGroup/UserCard/index.tsx +75 -0
  73. package/src/components/Dropdown/_.stories.tsx +180 -0
  74. package/src/components/Dropdown/_.style.ts +108 -0
  75. package/src/components/Dropdown/_.test.tsx +334 -0
  76. package/src/components/Dropdown/_.types.ts +12 -0
  77. package/src/components/Dropdown/index.tsx +130 -0
  78. package/src/components/FileUpload/_.stories.tsx +74 -0
  79. package/src/components/FileUpload/_.style.ts +0 -0
  80. package/src/components/FileUpload/_.test.tsx +222 -0
  81. package/src/components/FileUpload/_.types.ts +53 -0
  82. package/src/components/FileUpload/index.tsx +44 -0
  83. package/src/components/ImageMagnify/_.stories.tsx +226 -0
  84. package/src/components/ImageMagnify/_.style.ts +109 -0
  85. package/src/components/ImageMagnify/_.types.ts +44 -0
  86. package/src/components/ImageMagnify/index.tsx +204 -0
  87. package/src/components/Input/_.stories.tsx +177 -0
  88. package/src/components/Input/_.style.ts +79 -0
  89. package/src/components/Input/_.test.tsx +146 -0
  90. package/src/components/Input/_.types.ts +66 -0
  91. package/src/components/Input/index.tsx +231 -0
  92. package/src/components/InputTags/_.stories.tsx +51 -0
  93. package/src/components/InputTags/_.style.ts +28 -0
  94. package/src/components/InputTags/_.test.tsx +123 -0
  95. package/src/components/InputTags/_.types.ts +26 -0
  96. package/src/components/InputTags/index.tsx +140 -0
  97. package/src/components/Message/_.stories.tsx +79 -0
  98. package/src/components/Message/_.style.ts +87 -0
  99. package/src/components/Message/_.test.tsx +73 -0
  100. package/src/components/Message/_.types.ts +13 -0
  101. package/src/components/Message/index.tsx +57 -0
  102. package/src/components/Metric/_.stories.tsx +142 -0
  103. package/src/components/Metric/_.style.ts +14 -0
  104. package/src/components/Metric/_.test.tsx +166 -0
  105. package/src/components/Metric/_.types.ts +18 -0
  106. package/src/components/Metric/index.tsx +100 -0
  107. package/src/components/Modal/_.stories.tsx +93 -0
  108. package/src/components/Modal/_.style.ts +31 -0
  109. package/src/components/Modal/_.test.tsx +90 -0
  110. package/src/components/Modal/_.types.ts +14 -0
  111. package/src/components/Modal/index.tsx +82 -0
  112. package/src/components/Pagination/_.stories.tsx +118 -0
  113. package/src/components/Pagination/_.test.tsx +51 -0
  114. package/src/components/Pagination/index.tsx +256 -0
  115. package/src/components/Pagination/type.ts +48 -0
  116. package/src/components/PriceSlider/_.stories.tsx +107 -0
  117. package/src/components/PriceSlider/_.test.tsx +63 -0
  118. package/src/components/PriceSlider/_.type.tsx +19 -0
  119. package/src/components/PriceSlider/index.tsx +86 -0
  120. package/src/components/Progress/_.stories.tsx +93 -0
  121. package/src/components/Progress/_.style.ts +15 -0
  122. package/src/components/Progress/_.test.tsx +34 -0
  123. package/src/components/Progress/_.types.ts +17 -0
  124. package/src/components/Progress/index.tsx +173 -0
  125. package/src/components/Radio/_.stories.tsx +391 -0
  126. package/src/components/Radio/_.style.ts +33 -0
  127. package/src/components/Radio/_.test.tsx +77 -0
  128. package/src/components/Radio/_.types.ts +14 -0
  129. package/src/components/Radio/index.tsx +59 -0
  130. package/src/components/Select/_.stories.tsx +308 -0
  131. package/src/components/Select/_.style.ts +5 -0
  132. package/src/components/Select/_.types.ts +24 -0
  133. package/src/components/Select/index.tsx +172 -0
  134. package/src/components/Switch/_.stories.tsx +61 -0
  135. package/src/components/Switch/_.test.tsx +69 -0
  136. package/src/components/Switch/_.type.ts +12 -0
  137. package/src/components/Switch/index.tsx +70 -0
  138. package/src/components/Tabs/_.stories.tsx +508 -0
  139. package/src/components/Tabs/_.style.ts +63 -0
  140. package/src/components/Tabs/_.test.tsx +174 -0
  141. package/src/components/Tabs/_.type.ts +19 -0
  142. package/src/components/Tabs/index.tsx +35 -0
  143. package/src/components/Tag/_.stories.tsx +78 -0
  144. package/src/components/Tag/_.style.ts +71 -0
  145. package/src/components/Tag/_.test.tsx +44 -0
  146. package/src/components/Tag/_.types.ts +27 -0
  147. package/src/components/Tag/index.tsx +46 -0
  148. package/src/components/TextArea/_.stories.tsx +62 -0
  149. package/src/components/TextArea/_.style.ts +11 -0
  150. package/src/components/TextArea/_.test.tsx +43 -0
  151. package/src/components/TextArea/_.types.ts +29 -0
  152. package/src/components/TextArea/index.tsx +83 -0
  153. package/src/components/Toast/_.style.tsx +27 -0
  154. package/src/components/Toast/_.type.ts +30 -0
  155. package/src/components/Toast/_.utils.ts +23 -0
  156. package/src/components/Toast/container.tsx +171 -0
  157. package/src/components/Toast/index.tsx +29 -0
  158. package/src/components/Tooltip/_.stories.tsx +106 -0
  159. package/src/components/Tooltip/_.style.ts +27 -0
  160. package/src/components/Tooltip/_.test.tsx +54 -0
  161. package/src/components/Tooltip/_.types.ts +31 -0
  162. package/src/components/Tooltip/index.tsx +80 -0
  163. package/src/components/developers/AmirHossein.tsx +149 -0
  164. package/src/components/developers/Fardin.tsx +130 -0
  165. package/src/components/developers/Maryam.tsx +260 -0
  166. package/src/components/developers/Milad.tsx +431 -0
  167. package/src/components/developers/Rasoul.tsx +198 -0
  168. package/src/components/index.ts +28 -0
  169. package/src/components/ui/accordion.tsx +162 -0
  170. package/src/components/ui/avatars-component/avatar-description.tsx +30 -0
  171. package/src/components/ui/avatars-component/avatar-groups.tsx +68 -0
  172. package/src/components/ui/avatars-component/avatar-single.tsx +50 -0
  173. package/src/components/ui/card.tsx +92 -0
  174. package/src/components/ui/checkbox-group/plan-card/basic/_.test.tsx +66 -0
  175. package/src/components/ui/checkbox-group/plan-card/basic/index.tsx +70 -0
  176. package/src/components/ui/checkbox-group/plan-card/with-header/_.test.tsx +110 -0
  177. package/src/components/ui/checkbox-group/plan-card/with-header/header.test.tsx +96 -0
  178. package/src/components/ui/checkbox-group/plan-card/with-header/header.tsx +74 -0
  179. package/src/components/ui/checkbox-group/plan-card/with-header/index.tsx +65 -0
  180. package/src/components/ui/file-content/File-content.tsx +43 -0
  181. package/src/components/ui/file-uploader-components/file-uploader-box.tsx +76 -0
  182. package/src/components/ui/file-uploader-components/file-uploader-item.tsx +64 -0
  183. package/src/components/ui/icon-wrapper/_.test.tsx +60 -0
  184. package/src/components/ui/icon-wrapper/index.tsx +19 -0
  185. package/src/components/ui/input-component/input-label.tsx +11 -0
  186. package/src/components/ui/number.tsx +18 -0
  187. package/src/components/ui/pagination/card-minimal-center-align.tsx +96 -0
  188. package/src/components/ui/pagination/card-minimal-right-aligne.tsx +90 -0
  189. package/src/components/ui/pagination/default-pagination.tsx +128 -0
  190. package/src/components/ui/pagination/get-pagination-item.tsx +36 -0
  191. package/src/components/ui/pagination/pagination-card-button-group-aligned.tsx +94 -0
  192. package/src/components/ui/pagination/pagination-card-minimal-left-aligned.tsx +90 -0
  193. package/src/components/ui/pagination/pagination-content.tsx +15 -0
  194. package/src/components/ui/pagination/pagination-item.tsx +11 -0
  195. package/src/components/ui/pagination/pagination-link.tsx +42 -0
  196. package/src/components/ui/tab-components/tabs-content.tsx +15 -0
  197. package/src/components/ui/tab-components/tabs-list.tsx +27 -0
  198. package/src/components/ui/tab-components/tabs-trigger.tsx +25 -0
  199. package/src/components/ui/text-content-wrapper.tsx +36 -0
  200. package/src/hooks/useClickOutside.ts +23 -0
  201. package/src/icons/general/ArrowLeft.tsx +31 -0
  202. package/src/icons/general/ArrowRight.tsx +31 -0
  203. package/src/icons/general/activity-heart.tsx +31 -0
  204. package/src/icons/general/activity.tsx +31 -0
  205. package/src/icons/general/anchor.tsx +31 -0
  206. package/src/icons/general/archive.tsx +31 -0
  207. package/src/icons/general/arrow-left.tsx +25 -0
  208. package/src/icons/general/arrow-right.tsx +25 -0
  209. package/src/icons/general/asterisk-01.tsx +31 -0
  210. package/src/icons/general/asterisk-02.tsx +31 -0
  211. package/src/icons/general/at-sign.tsx +31 -0
  212. package/src/icons/general/attention-mark.tsx +43 -0
  213. package/src/icons/general/bookmark-add.tsx +31 -0
  214. package/src/icons/general/bookmark.tsx +31 -0
  215. package/src/icons/general/chevron-left.tsx +25 -0
  216. package/src/icons/general/chevron-right.tsx +25 -0
  217. package/src/icons/general/circle-minues.tsx +25 -0
  218. package/src/icons/general/circle-plus.tsx +25 -0
  219. package/src/icons/general/circle-question-mark.tsx +32 -0
  220. package/src/icons/general/circle.tsx +32 -0
  221. package/src/icons/general/copy.tsx +43 -0
  222. package/src/icons/general/email.tsx +32 -0
  223. package/src/icons/general/home.tsx +25 -0
  224. package/src/icons/general/layer.tsx +36 -0
  225. package/src/icons/general/leading.tsx +19 -0
  226. package/src/icons/general/master-card.tsx +37 -0
  227. package/src/icons/general/minus.tsx +36 -0
  228. package/src/icons/general/plus.tsx +19 -0
  229. package/src/icons/general/remove.tsx +32 -0
  230. package/src/icons/general/slash-divider.tsx +26 -0
  231. package/src/icons/general/tick-box.tsx +37 -0
  232. package/src/icons/general/trailing.tsx +19 -0
  233. package/src/icons/general/unkown-format.tsx +25 -0
  234. package/src/icons/general/visa-card.tsx +38 -0
  235. package/src/icons/general/x-close.tsx +35 -0
  236. package/src/icons/icons.type.ts +7 -0
  237. package/src/index.css +21 -0
  238. package/src/index.ts +3 -0
  239. package/src/lib/utils.ts +6 -0
  240. package/src/lib/zIndexUtils.ts +2 -0
  241. package/src/main.tsx +50 -0
  242. package/src/vite-env.d.ts +1 -0
  243. package/tests/setup.ts +8 -0
  244. package/tsconfig.app.json +31 -0
  245. package/tsconfig.json +7 -0
  246. package/tsconfig.node.json +24 -0
  247. package/tsconfig.rollup.json +12 -0
  248. package/vite.config.ts +20 -0
  249. package/vitest.config.ts +47 -0
@@ -0,0 +1,162 @@
1
+
2
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
3
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
4
+ import { cn } from "@/lib/utils";
5
+ import React, { useState } from "react";
6
+ import { AccordionProps } from "../Accordion/type";
7
+
8
+ function Accordion({
9
+ type = "single",
10
+ collapsible = false,
11
+ className,
12
+ children,
13
+ ...props
14
+ }: Readonly<AccordionProps>) {
15
+ const [openValue, setOpenValue] = useState<string | string[]>(
16
+ type === "multiple" ? [] : ""
17
+ );
18
+
19
+ if (type === "multiple") {
20
+ return (
21
+ <AccordionPrimitive.Root
22
+ type="multiple"
23
+ className={className}
24
+ value={openValue as string[]}
25
+ onValueChange={(val: string[] | string) => setOpenValue(val)}
26
+ data-slot="accordion"
27
+ {...props}
28
+ >
29
+ {React.Children.map(children, (child) =>
30
+ React.isValidElement(child)
31
+ ? React.cloneElement(child as React.ReactElement<{ openValue?: string | string[] }>, {
32
+ openValue,
33
+ })
34
+ : child
35
+ )}
36
+ </AccordionPrimitive.Root>
37
+ );
38
+ }
39
+
40
+ return (
41
+ <AccordionPrimitive.Root
42
+ type="single"
43
+ collapsible={collapsible}
44
+ className={className}
45
+ value={openValue as string}
46
+ onValueChange={(val: string | string[]) => setOpenValue(val)}
47
+ data-slot="accordion"
48
+ {...props}
49
+ >
50
+ {React.Children.map(children, (child) =>
51
+ React.isValidElement(child)
52
+ ? React.cloneElement(child as React.ReactElement<{ openValue?: string | string[] }>, {
53
+ ...(child.props ?? {}),
54
+ openValue,
55
+ })
56
+ : child
57
+ )}
58
+ </AccordionPrimitive.Root>
59
+ );
60
+ }
61
+
62
+
63
+ type AccordionItemProps = {
64
+ className?: string;
65
+ children?: React.ReactNode;
66
+ value: string;
67
+ openValue?: string | string[];
68
+ };
69
+
70
+ function AccordionItem({
71
+ className,
72
+ openValue,
73
+ value,
74
+ children,
75
+ ...props
76
+ }: Readonly<AccordionItemProps>) {
77
+ return (
78
+ <AccordionPrimitive.Item
79
+ data-slot="accordion-item"
80
+ className={cn("border-b last:border-b-0", className)}
81
+ value={value}
82
+ {...props}
83
+ >
84
+ {React.Children.map(children, (child) =>
85
+ React.isValidElement(child)
86
+ ? React.cloneElement(child as React.ReactElement<{ itemValue?: string; openValue?: string | string[] }>, {
87
+ itemValue: value,
88
+ openValue,
89
+ })
90
+ : child
91
+ )}
92
+ </AccordionPrimitive.Item>
93
+ );
94
+ }
95
+
96
+ interface AccordionTriggerProps
97
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {
98
+ iconOpen?: React.ComponentType<React.SVGProps<SVGSVGElement>>;
99
+ iconClosed?: React.ComponentType<React.SVGProps<SVGSVGElement>>;
100
+ itemValue?: string;
101
+ openValue?: string | string[];
102
+ }
103
+
104
+ function AccordionTrigger({
105
+ className,
106
+ children,
107
+ iconOpen: IconOpen = ChevronUpIcon,
108
+ iconClosed: IconClosed = ChevronDownIcon,
109
+ itemValue,
110
+ openValue,
111
+ ...props
112
+ }: Readonly<AccordionTriggerProps>) {
113
+ const isOpen =
114
+ Array.isArray(openValue) && itemValue
115
+ ? openValue.includes(itemValue)
116
+ : openValue === itemValue;
117
+
118
+ return (
119
+ <AccordionPrimitive.Header className="flex w-full">
120
+ <AccordionPrimitive.Trigger
121
+ data-slot="accordion-trigger"
122
+ className={cn(
123
+ "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50",
124
+ className,
125
+ isOpen ? "rounded-t-md" : "rounded-md"
126
+ )}
127
+ {...props}
128
+ >
129
+ {children}
130
+ {isOpen ? (
131
+ <IconOpen className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
132
+ ) : (
133
+ <IconClosed className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
134
+ )}
135
+ </AccordionPrimitive.Trigger>
136
+ </AccordionPrimitive.Header>
137
+ );
138
+ }
139
+
140
+ interface AccordionContentProps
141
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {
142
+ className?: string;
143
+ children?: React.ReactNode;
144
+ }
145
+
146
+ function AccordionContent({
147
+ className,
148
+ children,
149
+ ...props
150
+ }: Readonly<AccordionContentProps>) {
151
+ return (
152
+ <AccordionPrimitive.Content
153
+ data-slot="accordion-content"
154
+ className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
155
+ {...props}
156
+ >
157
+ <div className={cn("pt-0 pb-4", className)}>{children}</div>
158
+ </AccordionPrimitive.Content>
159
+ );
160
+ }
161
+
162
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,30 @@
1
+ import { textSizeStyle } from "@/components/Avatar/_.style";
2
+ import { AvatarDescription as AvatarDescriptionType } from "@/components/Avatar/_.types";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ export const AvatarDescription = ({
6
+ title,
7
+ description,
8
+ size,
9
+ }: AvatarDescriptionType) => {
10
+ return (
11
+ <div className="flex flex-col">
12
+ <span
13
+ className={cn(
14
+ `text-rtext-secondary-700 font-semibold`,
15
+ textSizeStyle[size]
16
+ )}
17
+ >
18
+ {title}
19
+ </span>
20
+ <span
21
+ className={cn(
22
+ `font-normal text-rtext-tertiary-600`,
23
+ textSizeStyle[size]
24
+ )}
25
+ >
26
+ {description}
27
+ </span>
28
+ </div>
29
+ );
30
+ };
@@ -0,0 +1,68 @@
1
+ import { sizeStyles } from "@/components/Avatar/_.style";
2
+ import { AvatarGroupProps } from "@/components/Avatar/_.types";
3
+ import { TooltipWrapper } from "@/components/Tooltip";
4
+ import Plus from "@/icons/general/plus";
5
+ import { cn } from "@/lib/utils";
6
+ import React from "react";
7
+
8
+ export const AvatarGroup: React.FC<AvatarGroupProps> = ({
9
+ imgList,
10
+ size,
11
+ showAmount = 5,
12
+ showAddBtn = false,
13
+ tooltip,
14
+ addBtnAction,
15
+ }) => {
16
+ const visibleAvatars = imgList.slice(0, showAmount);
17
+ const extraCount = imgList.length - showAmount;
18
+ return (
19
+ <div className="flex -space-x-1 w-full">
20
+ {visibleAvatars.map((img, index) => (
21
+ <img
22
+ key={index}
23
+ alt=""
24
+ className={cn(
25
+ "inline-block rounded-full ring-2 ring-white",
26
+ sizeStyles[size]
27
+ )}
28
+ style={{ zIndex: index }}
29
+ {...img}
30
+ />
31
+ ))}
32
+ {extraCount > 0 && (
33
+ <div
34
+ className={cn(
35
+ "inline-flex items-center justify-center rounded-full bg-gray-100 border-2 border-white font-medium text-gray-700 shadow-2xs align-middle hover:bg-gray-200 focus:outline-hidden focus:bg-gray-300 text-sm dark:bg-neutral-700 dark:text-white dark:hover:bg-neutral-600 dark:focus:bg-neutral-600 dark:border-neutral-800",
36
+ sizeStyles[size]
37
+ )}
38
+ style={{ zIndex: showAmount }}
39
+ >
40
+ <span className="font-medium text-xs">+{extraCount}</span>
41
+ </div>
42
+ )}
43
+ {showAddBtn && tooltip ? (
44
+ <TooltipWrapper {...tooltip}>
45
+ <button
46
+ className={cn(
47
+ `mx-2 p-1 flex justify-center items-center cursor-pointer stroke-rfg-quinary-400 rounded-full bg-rbg-primary border border-dashed border-rborder-primary hover:bg-rbg-primary-hover disabled:bg-rbg-disabled-subtle disabled:cur`,
48
+ sizeStyles[size]
49
+ )}
50
+ onClick={addBtnAction}
51
+ >
52
+ <Plus />
53
+ </button>
54
+ </TooltipWrapper>
55
+ ) : (
56
+ <button
57
+ className={cn(
58
+ `mx-2 p-1 flex justify-center items-center cursor-pointer stroke-rfg-quinary-400 rounded-full bg-rbg-primary border border-dashed border-rborder-primary hover:bg-rbg-primary-hover disabled:bg-rbg-disabled-subtle disabled:cur`,
59
+ sizeStyles[size]
60
+ )}
61
+ onClick={addBtnAction}
62
+ >
63
+ <Plus />
64
+ </button>
65
+ )}
66
+ </div>
67
+ );
68
+ };
@@ -0,0 +1,50 @@
1
+ import {
2
+ dotSizeStyle,
3
+ iconSizeStyle,
4
+ sizeStyles,
5
+ } from "@/components/Avatar/_.style";
6
+ import { SingleAvatarProps } from "@/components/Avatar/_.types";
7
+ import { cn } from "@/lib/utils";
8
+ import React from "react";
9
+
10
+ export const AvatarSingle: React.FC<SingleAvatarProps> = ({
11
+ img,
12
+ size,
13
+ notifyColor = "",
14
+ notifyIcon = "",
15
+ iconBorder,
16
+ }) => {
17
+ return (
18
+ <div className={cn(`relative inline-block`, sizeStyles[size])}>
19
+ <img
20
+ alt=""
21
+ {...img}
22
+ className={cn(
23
+ `rounded-full object-cover ring-2 ring-white`,
24
+ sizeStyles[size]
25
+ )}
26
+ />
27
+ {notifyColor && (
28
+ <span
29
+ className={cn(
30
+ `absolute bottom-0 right-1 block rounded-full ${notifyColor} ring-2 ring-white`,
31
+ dotSizeStyle[size]
32
+ )}
33
+ />
34
+ )}
35
+ {notifyIcon && (
36
+ <span
37
+ className={cn(
38
+ `absolute bottom-0 right-1 block rounded-full`,
39
+ iconSizeStyle[size],
40
+ `has-[>svg]:${iconSizeStyle[size]} ${
41
+ iconBorder && "ring-2 ring-white"
42
+ }`
43
+ )}
44
+ >
45
+ {notifyIcon}
46
+ </span>
47
+ )}
48
+ </div>
49
+ );
50
+ };
@@ -0,0 +1,92 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="card"
9
+ className={cn(
10
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn("leading-none font-semibold", className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn("text-muted-foreground text-sm", className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57
+ className
58
+ )}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn("px-6", className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent,
92
+ }
@@ -0,0 +1,66 @@
1
+ import { render, screen, fireEvent } from "@testing-library/react";
2
+ import "@testing-library/jest-dom";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { PlanCardBasic } from ".";
5
+ import { iconSizeStyle } from "@/components/CheckboxGroup/PlanCard/_.style";
6
+
7
+ describe("PlanCardBasic", () => {
8
+ const baseProps = {
9
+ per: "month",
10
+ title: "Basic Plan",
11
+ description: "This is a test plan",
12
+ price: "$10",
13
+ id: "plan-1",
14
+ checkboxIndex: 0,
15
+ name: "plan",
16
+ value: "basic",
17
+ onChange: vi.fn(),
18
+ };
19
+
20
+ it("renders title, price, per, and description", () => {
21
+ render(<PlanCardBasic {...baseProps} />);
22
+
23
+ expect(screen.getByText("Basic Plan")).toBeInTheDocument();
24
+ expect(screen.getByText("$10/month")).toBeInTheDocument();
25
+ expect(screen.getByText("This is a test plan")).toBeInTheDocument();
26
+ });
27
+
28
+ it("renders IconWrapper and Layer with correct size", () => {
29
+ render(<PlanCardBasic {...baseProps} size="md" />);
30
+ const iconWrapper = screen.getByTestId("icon-wrapper");
31
+ expect(iconWrapper).toBeInTheDocument();
32
+ const svg = iconWrapper.querySelector("svg");
33
+ expect(svg).toHaveAttribute("width", iconSizeStyle["md"]);
34
+ expect(svg).toHaveAttribute("height", iconSizeStyle["md"]);
35
+ });
36
+
37
+ it("renders a radio input when type is 'radio'", () => {
38
+ render(<PlanCardBasic {...baseProps} type="radio" />);
39
+ const radio = screen.getByRole("radio");
40
+ expect(radio).toBeInTheDocument();
41
+ fireEvent.click(radio);
42
+ expect(baseProps.onChange).toHaveBeenCalled();
43
+ });
44
+
45
+ it("renders a checkbox input when type is not 'radio'", () => {
46
+ render(<PlanCardBasic {...baseProps} type="checkbox" />);
47
+ const checkbox = screen.getByRole("checkbox");
48
+ expect(checkbox).toBeInTheDocument();
49
+ fireEvent.click(checkbox);
50
+ expect(baseProps.onChange).toHaveBeenCalled();
51
+ });
52
+
53
+ it("renders disabled radio input correctly", () => {
54
+ render(<PlanCardBasic {...baseProps} type="radio" disabled checked />);
55
+ const radio = screen.getByRole("radio") as HTMLInputElement;
56
+ expect(radio).toBeDisabled();
57
+ expect(radio.checked).toBe(true);
58
+ });
59
+
60
+ it("renders disabled checkbox input correctly", () => {
61
+ render(<PlanCardBasic {...baseProps} type="checkbox" disabled checked />);
62
+ const checkbox = screen.getByRole("checkbox") as HTMLInputElement;
63
+ expect(checkbox).toBeDisabled();
64
+ expect(checkbox.checked).toBe(true);
65
+ });
66
+ });
@@ -0,0 +1,70 @@
1
+ import { Checkbox } from "@/components/Checkbox";
2
+ import { iconSizeStyle } from "@/components/CheckboxGroup/PlanCard/_.style";
3
+ import { PlanCardProps } from "@/components/CheckboxGroup/PlanCard/_.types";
4
+ import { Radio } from "@/components/Radio";
5
+ import Layer from "@/icons/general/layer";
6
+ import IconWrapper from "../../../icon-wrapper";
7
+
8
+ export function PlanCardBasic({
9
+ per,
10
+ size = "sm",
11
+ title = "",
12
+ description,
13
+ price,
14
+ id,
15
+ checkboxIndex,
16
+ checked,
17
+ name = "",
18
+ value = "",
19
+ inputProps,
20
+ onChange,
21
+ type,
22
+ onCardClick,
23
+ disabled,
24
+ }: Readonly<PlanCardProps>) {
25
+ return (
26
+ <>
27
+ <IconWrapper data-testid="icon-wrapper">
28
+ <Layer width={iconSizeStyle[size]} height={iconSizeStyle[size]} />
29
+ </IconWrapper>
30
+ <div onClick={onCardClick} className="flex flex-col grow justify-between">
31
+ <div className="flex">
32
+ <h3 className="font-medium text-foreground text-rtext-secondary-700">
33
+ {title}
34
+ </h3>
35
+ &nbsp;
36
+ <span>
37
+ {price}/{per}
38
+ </span>
39
+ </div>
40
+ <div className="text-muted-foreground">{description}</div>
41
+ </div>
42
+ <div className="flex items-start gap-2">
43
+ {type === "radio" ? (
44
+ <Radio
45
+ onChange={onChange}
46
+ checked={checked}
47
+ disabled={disabled}
48
+ value={value}
49
+ name={name}
50
+ size={size}
51
+ id={id}
52
+ {...inputProps}
53
+ />
54
+ ) : (
55
+ <Checkbox
56
+ {...inputProps}
57
+ disabled={disabled}
58
+ id={id}
59
+ name={name}
60
+ onChange={onChange}
61
+ size={size}
62
+ value={value}
63
+ checkboxIndex={checkboxIndex}
64
+ checked={checked}
65
+ />
66
+ )}
67
+ </div>
68
+ </>
69
+ );
70
+ }
@@ -0,0 +1,110 @@
1
+ import { render, screen, fireEvent } from "@testing-library/react";
2
+ import "@testing-library/jest-dom";
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { ReactNode } from "react";
5
+ import { PlanCardWithHeader } from ".";
6
+
7
+ // Mock the Header and Badge components to avoid actual component logic
8
+ vi.mock("./header", () => ({
9
+ Header: ({
10
+ title,
11
+ price,
12
+ onChange,
13
+ }: {
14
+ title: string;
15
+ price: string;
16
+ onChange?: () => void; // required
17
+ }) => (
18
+ <div
19
+ data-testid="header"
20
+ onClick={onChange} // Mock the onClick event to trigger onChange
21
+ >
22
+ {title} - {price}
23
+ </div>
24
+ ),
25
+ }));
26
+
27
+ vi.mock("@/components/Badge", () => ({
28
+ Badge: ({ children }: { children: ReactNode }) => (
29
+ <div data-testid="badge">{children}</div>
30
+ ),
31
+ }));
32
+
33
+ describe("PlanCardWithHeader", () => {
34
+ it("calls onChange when input is checked or unchecked", () => {
35
+ const onChange = vi.fn();
36
+
37
+ // Render PlanCardWithHeader with a mock onChange handler
38
+ render(
39
+ <PlanCardWithHeader
40
+ title="Basic Plan"
41
+ price="$99"
42
+ per="month"
43
+ description="Plan description"
44
+ onChange={onChange}
45
+ checked={false}
46
+ size={"sm"}
47
+ checkboxIndex={1}
48
+ id={"name"}
49
+ value={"name2"}
50
+ name={"group"}
51
+ />
52
+ );
53
+
54
+ // Find the header element that triggers the change
55
+ const header = screen.getByTestId("header");
56
+
57
+ // Trigger the click event on the header
58
+ fireEvent.click(header);
59
+
60
+ // Assert that onChange was called when the header is clicked
61
+ expect(onChange).toHaveBeenCalled();
62
+ });
63
+ it("renders Badge with the correct content and styles when badgeContent is provided", () => {
64
+ const badgeContent = "New!";
65
+
66
+ render(
67
+ <PlanCardWithHeader
68
+ title="Basic Plan"
69
+ price="$99"
70
+ per="month"
71
+ description="Plan description"
72
+ badgeContent={badgeContent}
73
+ checked={false}
74
+ size="sm"
75
+ checkboxIndex={1}
76
+ id="name"
77
+ value="name2"
78
+ name="group"
79
+ />
80
+ );
81
+
82
+ // Check if Badge is rendered
83
+ const badge = screen.getByText("New!");
84
+ expect(badge).toBeInTheDocument();
85
+
86
+ // Check if Badge contains the correct content (badgeContent)
87
+ expect(badge).toHaveTextContent(badgeContent);
88
+ });
89
+
90
+ it("does not render Badge when badgeContent is not provided", () => {
91
+ render(
92
+ <PlanCardWithHeader
93
+ title="Basic Plan"
94
+ price="$99"
95
+ per="month"
96
+ description="Plan description"
97
+ checked={false}
98
+ size="sm"
99
+ checkboxIndex={1}
100
+ id="name"
101
+ value="name2"
102
+ name="group"
103
+ />
104
+ );
105
+
106
+ // Check if Badge is not rendered when no badgeContent is passed
107
+ const badge = screen.queryByTestId("badge");
108
+ expect(badge).toBeNull();
109
+ });
110
+ });