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,179 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Avatar } from ".";
3
+ import { VerifiedIcon } from "lucide-react";
4
+
5
+ const meta: Meta<typeof Avatar> = {
6
+ title: "Components/Avatar",
7
+ component: Avatar,
8
+ tags: ["autodocs"],
9
+ argTypes: {
10
+ type: {
11
+ control: "radio",
12
+ options: ["single", "group", "labled"],
13
+ },
14
+ size: {
15
+ control: "select",
16
+ options: ["xs", "sm", "md", "lg", "xl", "2xl"],
17
+ },
18
+ showAmount: {
19
+ control: "number",
20
+ min: 1,
21
+ max: 10,
22
+ step: 1,
23
+ },
24
+ },
25
+ };
26
+
27
+ export default meta;
28
+
29
+ type Story = StoryObj<typeof Avatar>;
30
+
31
+ const sampleImage = {
32
+ src: "https://randomuser.me/api/portraits/women/44.jpg",
33
+ alt: "Jane Doe",
34
+ label: "Jane",
35
+ };
36
+
37
+ const sampleImageList = [
38
+ {
39
+ src: "https://randomuser.me/api/portraits/men/1.jpg",
40
+ alt: "User 1",
41
+ },
42
+ {
43
+ src: "https://randomuser.me/api/portraits/women/2.jpg",
44
+ alt: "User 2",
45
+ },
46
+ {
47
+ src: "https://randomuser.me/api/portraits/men/3.jpg",
48
+ alt: "User 3",
49
+ },
50
+ {
51
+ src: "https://randomuser.me/api/portraits/women/4.jpg",
52
+ alt: "User 4",
53
+ },
54
+ {
55
+ src: "https://randomuser.me/api/portraits/men/5.jpg",
56
+ alt: "User 5",
57
+ },
58
+ {
59
+ src: "https://randomuser.me/api/portraits/women/6.jpg",
60
+ alt: "User 6",
61
+ },
62
+ ];
63
+
64
+ export const SingleWithDot: Story = {
65
+ args: {
66
+ type: "single",
67
+ img: sampleImage,
68
+ size: "md",
69
+ notifyColor: "bg-red-500",
70
+ },
71
+ };
72
+ export const SingleWithIcon: Story = {
73
+ args: {
74
+ type: "single",
75
+ img: sampleImage,
76
+ size: "lg",
77
+ notifyIcon: <VerifiedIcon />,
78
+ iconBorder:false
79
+ },
80
+ };
81
+
82
+ export const Group: Story = {
83
+ args: {
84
+ type: "group",
85
+ imgList: sampleImageList,
86
+ showAmount: 3,
87
+ showAddBtn: true,
88
+ tooltip: {
89
+ content: "Add user",
90
+ description: "Click to add a new team member.",
91
+ dir: "ltr",
92
+ position: "top",
93
+ },
94
+ size: "md",
95
+ addBtnAction: () => alert("Add button clicked"),
96
+ },
97
+ };
98
+
99
+ export const GroupWithMoreAvatars: Story = {
100
+ args: {
101
+ type: "group",
102
+ imgList: sampleImageList,
103
+ showAmount: 3,
104
+ showAddBtn: true,
105
+ tooltip: {
106
+ content: "Add user",
107
+ description: "Click to add a new team member.",
108
+ dir: "ltr",
109
+ position: "top",
110
+ },
111
+ size: "md",
112
+ addBtnAction: () => alert("Add button clicked"),
113
+ },
114
+ };
115
+
116
+ export const Labled: Story = {
117
+ args: {
118
+ type: "labled",
119
+ img: sampleImage,
120
+ title: "Jane Doe",
121
+ description: "UX Designer",
122
+ size: "md",
123
+ // notifyIcon: <div className=" rounded-full bg-red-500" />,
124
+ notifyColor: "bg-red-500",
125
+ },
126
+ };
127
+
128
+ export const LabledWithTooltip: Story = {
129
+ args: {
130
+ type: "labled",
131
+ img: sampleImage,
132
+ title: "Jane Doe",
133
+ description: "UX Designer",
134
+ size: "md",
135
+
136
+
137
+ notifyColor: "bg-red-500",
138
+ tooltip: {
139
+ content: "More information",
140
+ description: "This user is an experienced UX designer.",
141
+ dir: "ltr",
142
+ position: "right",
143
+ },
144
+ },
145
+ };
146
+
147
+ export const GroupWithLessAvatarsAndShowAddBtn: Story = {
148
+ args: {
149
+ type: "group",
150
+ imgList: sampleImageList,
151
+ showAmount: 2,
152
+ showAddBtn: true,
153
+ tooltip: {
154
+ content: "Add user",
155
+ description: "Click to add a new team member.",
156
+ dir: "ltr",
157
+ position: "top",
158
+ },
159
+ size: "md",
160
+ addBtnAction: () => alert("Add button clicked"),
161
+ },
162
+ };
163
+
164
+ export const GroupWithNotifications: Story = {
165
+ args: {
166
+ type: "group",
167
+ imgList: sampleImageList,
168
+ showAmount: 3,
169
+ showAddBtn: true,
170
+ tooltip: {
171
+ content: "Add user",
172
+ description: "Click to add a new team member.",
173
+ dir: "ltr",
174
+ position: "top",
175
+ },
176
+ size: "md",
177
+ addBtnAction: () => alert("Add button clicked"),
178
+ },
179
+ };
@@ -0,0 +1,40 @@
1
+ export const sizeStyles = {
2
+ xs: "w-6 h-6",
3
+ sm: "w-8 h-8 ",
4
+ md: "w-10 h-10 ",
5
+ lg: "w-12 h-12 ",
6
+ xl: "w-14 h-14 ",
7
+ "2xl": "w-16 h-16 ",
8
+ };
9
+ export const dotSizeStyle = {
10
+ xs: "w-1.5 h-1.5",
11
+ sm: "w-2 h-2 ",
12
+ md: "w-2.5 h-2.5 ",
13
+ lg: "w-3 h-3 ",
14
+ xl: "w-3.5 h-3.5 ",
15
+ "2xl": "w-4 h-4 ",
16
+ };
17
+ export const iconSizeStyle = {
18
+ xs: "w-2.5 h-2.5",
19
+ sm: "w-3 h-3",
20
+ md: "w-3.5 h-3.5",
21
+ lg: "w-4 h-4",
22
+ xl: "w-4.5 h-4.5 ",
23
+ "2xl": "w-5 h-5 ",
24
+ };
25
+ export const wrapperSizeStyle = {
26
+ xs: "gap-2",
27
+ sm: "gap-2.5",
28
+ md: "gap-3",
29
+ lg: "gap-3.5",
30
+ xl: "gap-4",
31
+ "2xl": "gap-4.5",
32
+ };
33
+ export const textSizeStyle = {
34
+ xs: "text-sm",
35
+ sm: "text-sm",
36
+ md: "text-sm",
37
+ lg: "text-md",
38
+ xl: "text-lg",
39
+ "2xl": "text-lg",
40
+ };
@@ -0,0 +1,150 @@
1
+ // Avatar.test.tsx
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { Avatar } from ".";
5
+ const MockNotifyIcon = () => <svg data-testid="notify-icon" />;
6
+ // Sample data for testing
7
+ const sampleImage = {
8
+ src: "https://randomuser.me/api/portraits/women/44.jpg",
9
+ alt: "Jane Doe",
10
+ label: "Jane",
11
+ };
12
+
13
+ const sampleImageList = [
14
+ { src: "https://randomuser.me/api/portraits/men/1.jpg", alt: "User 1" },
15
+ { src: "https://randomuser.me/api/portraits/women/2.jpg", alt: "User 2" },
16
+ { src: "https://randomuser.me/api/portraits/men/3.jpg", alt: "User 3" },
17
+ ];
18
+
19
+ describe("Avatar Component", () => {
20
+ it("renders single avatar when type is single", () => {
21
+ render(
22
+ <Avatar
23
+ type="single"
24
+ img={sampleImage}
25
+ size="md"
26
+ addBtnAction={() => {}}
27
+ />
28
+ );
29
+ // Check if image with alt text is rendered
30
+ const imgEl = screen.getByAltText(/Jane Doe/i);
31
+ expect(imgEl).toBeInTheDocument();
32
+ });
33
+
34
+ it("renders avatar group when type is group", () => {
35
+ render(
36
+ <Avatar
37
+ type="group"
38
+ imgList={sampleImageList}
39
+ size="sm"
40
+ showAmount={2}
41
+ showAddBtn={false}
42
+ addBtnAction={() => {}}
43
+ />
44
+ );
45
+ // Check if two avatars appear and then a + indicator for extra avatars if applicable.
46
+ const avatarImages = screen.getAllByRole("img");
47
+ // Since we limit to 2 avatars using showAmount
48
+ expect(avatarImages).toHaveLength(2);
49
+ // Optionally, test the extra count element if one exists (if sampleImageList.length > 2)
50
+ });
51
+
52
+ it("renders labled avatar with description when type is labled", () => {
53
+ render(
54
+ <Avatar
55
+ type="labled"
56
+ img={sampleImage}
57
+ size="md"
58
+ title="Jane Doe"
59
+ description="UX Designer"
60
+ addBtnAction={() => {}}
61
+ />
62
+ );
63
+ // Check if title and description text appear
64
+ expect(screen.getByText(/Jane Doe/i)).toBeInTheDocument();
65
+ expect(screen.getByText(/UX Designer/i)).toBeInTheDocument();
66
+ });
67
+
68
+ it("calls addBtnAction when add button is clicked in group type", () => {
69
+ const addBtnAction = vi.fn();
70
+ render(
71
+ <Avatar
72
+ type="group"
73
+ imgList={sampleImageList}
74
+ size="sm"
75
+ showAmount={2}
76
+ showAddBtn={true}
77
+ tooltip={{
78
+ content: "Add user",
79
+ description: "Click to add a new team member.",
80
+ dir: "ltr",
81
+ }}
82
+ addBtnAction={addBtnAction}
83
+ />
84
+ );
85
+ // Find the add button (assuming the button is rendered with the Plus icon or text)
86
+ const addBtn = screen.getByRole("button");
87
+ fireEvent.click(addBtn);
88
+ expect(addBtnAction).toHaveBeenCalled();
89
+ });
90
+ it("renders notification dot when notifyColor is provided", () => {
91
+ const { container } = render(
92
+ <Avatar
93
+ type="single"
94
+ img={sampleImage}
95
+ notifyColor="bg-green-500"
96
+ size="md"
97
+ />
98
+ );
99
+
100
+ const dot = container.querySelector("span.bg-green-500");
101
+ expect(dot).toBeInTheDocument();
102
+ expect(dot?.className).toContain("ring-2");
103
+ });
104
+ it("renders notification icon when notifyIcon is provided", () => {
105
+ render(
106
+ <Avatar
107
+ type="single"
108
+ img={sampleImage}
109
+ notifyIcon={<MockNotifyIcon />}
110
+ size="md"
111
+ />
112
+ );
113
+
114
+ const icon = screen.getByTestId("notify-icon");
115
+ expect(icon).toBeInTheDocument();
116
+ expect(icon.parentElement?.className).toContain("absolute");
117
+ expect(icon.parentElement?.className).toContain("rounded-full");
118
+ });
119
+ it("adds ring to notify icon when iconBorder is true", () => {
120
+ render(
121
+ <Avatar
122
+ type="single"
123
+ img={sampleImage}
124
+ notifyIcon={<MockNotifyIcon />}
125
+ iconBorder={true}
126
+ size="md"
127
+ />
128
+ );
129
+
130
+ const icon = screen.getByTestId("notify-icon");
131
+ expect(icon.parentElement?.className).toContain("ring-2");
132
+ expect(icon.parentElement?.className).toContain("ring-white");
133
+ });
134
+ it("does not add ring when iconBorder is false", () => {
135
+ const NotifyIcon = () => <svg data-testid="notify-icon" />;
136
+
137
+ render(
138
+ <Avatar
139
+ type="single"
140
+ img={sampleImage}
141
+ size="md"
142
+ notifyIcon={<NotifyIcon />}
143
+ iconBorder={false}
144
+ />
145
+ );
146
+
147
+ const wrapper = screen.getByTestId("notify-icon").parentElement!;
148
+ expect(wrapper.className).not.toContain("ring-2");
149
+ });
150
+ });
@@ -0,0 +1,66 @@
1
+ import { Position } from "../Tooltip/_.types";
2
+
3
+ type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
4
+ type AvatarType = "single" | "group" | "labled";
5
+ type TooltipDirection = "rtl" | "ltr";
6
+
7
+ export interface AvatarProps {
8
+ type?: AvatarType;
9
+ size?: AvatarSize;
10
+ imgList?: Image[];
11
+ img?: Image;
12
+ showAmount?: number;
13
+ showAddBtn?: boolean;
14
+ addBtnAction?: () => void;
15
+ notifyIcon?: React.ReactNode;
16
+ notifyColor?: string;
17
+ title?: string;
18
+ description?: string;
19
+ iconBorder?: boolean;
20
+ tooltip?: {
21
+ content: string;
22
+ description?: string;
23
+ className?: string;
24
+ contentClassName?: string;
25
+ descriptionClassName?: string;
26
+ sideOffset?: number;
27
+ position?: Position;
28
+ dir?: TooltipDirection;
29
+ };
30
+ }export interface Image {
31
+ src?: string;
32
+ icon?: React.ReactNode;
33
+ label?: string;
34
+ backUpSrc?: string;
35
+ description?: string;
36
+ alt?: string;
37
+ }
38
+ export interface AvatarGroupProps {
39
+ imgList: Image[];
40
+ showAmount: number;
41
+ size: AvatarSize;
42
+ showAddBtn: boolean;
43
+ tooltip?: {
44
+ content: string;
45
+ description?: string;
46
+ className?: string;
47
+ contentClassName?: string;
48
+ descriptionClassName?: string;
49
+ sideOffset?: number;
50
+ position?: Position;
51
+ dir?: TooltipDirection;
52
+ };
53
+ addBtnAction: () => void;
54
+ }export interface SingleAvatarProps {
55
+ img: Image;
56
+ size: AvatarSize;
57
+ notifyIcon?: React.ReactNode;
58
+ notifyColor?: string;
59
+ iconBorder: boolean;
60
+ }
61
+
62
+ export interface AvatarDescription {
63
+ title: string;
64
+ description: string;
65
+ size: AvatarSize;
66
+ }
@@ -0,0 +1,63 @@
1
+ import { cn } from "@/lib/utils";
2
+ import { AvatarDescription } from "../ui/avatars-component/avatar-description";
3
+ import { AvatarGroup } from "../ui/avatars-component/avatar-groups";
4
+ import { AvatarSingle } from "../ui/avatars-component/avatar-single";
5
+ import { wrapperSizeStyle } from "./_.style";
6
+ import { AvatarProps } from "./_.types";
7
+
8
+ export const Avatar = ({
9
+ type,
10
+ size = "md",
11
+ imgList = [],
12
+ img = {},
13
+ showAmount = 1,
14
+ showAddBtn = false,
15
+ notifyColor = "",
16
+ notifyIcon = "",
17
+ title = "",
18
+ description = "",
19
+ iconBorder = true,
20
+ tooltip,
21
+ addBtnAction = () => {},
22
+ }: AvatarProps) => {
23
+ return (
24
+ <>
25
+ {type == "single" && (
26
+ <AvatarSingle
27
+ img={img}
28
+ size={size}
29
+ notifyColor={notifyColor}
30
+ notifyIcon={notifyIcon}
31
+ iconBorder={iconBorder}
32
+ />
33
+ )}
34
+ {type == "group" && (
35
+ <AvatarGroup
36
+ imgList={imgList}
37
+ size={size}
38
+ showAmount={showAmount}
39
+ showAddBtn={showAddBtn}
40
+ tooltip={tooltip}
41
+ addBtnAction={addBtnAction}
42
+ />
43
+ )}
44
+
45
+ {type == "labled" && (
46
+ <div className={cn(`inline-flex items-center`, wrapperSizeStyle[size])}>
47
+ <AvatarSingle
48
+ img={img}
49
+ size={size}
50
+ notifyColor={notifyColor}
51
+ notifyIcon={notifyIcon}
52
+ iconBorder={iconBorder}
53
+ />
54
+ <AvatarDescription
55
+ size={size}
56
+ title={title}
57
+ description={description}
58
+ />
59
+ </div>
60
+ )}
61
+ </>
62
+ );
63
+ };
@@ -0,0 +1,75 @@
1
+ import Plus from "@/icons/general/plus";
2
+ import type { StoryObj } from "@storybook/react-vite";
3
+ import { Meta } from "@storybook/react-vite";
4
+ import { Badge } from ".";
5
+ import { BadgeProps } from "./_.types";
6
+
7
+ export default {
8
+ title: "Components/Badge",
9
+ component: Badge,
10
+ tags: ["autodocs"],
11
+ argTypes: {
12
+ type: {
13
+ control: { type: "radio" }, // Enables a dropdown in Storybook UI
14
+ options: ["pillColor", "pillOutline", "badgeColor", "badgeModern"],
15
+ },
16
+ size: {
17
+ control: { type: "radio" },
18
+ options: ["sm", "md", "lg"],
19
+ },
20
+ color: {
21
+ control: { type: "select" },
22
+ options: ["gray", "brand", "error", "success", "grayBlue", "blueLight", "blue", "indigo", "purple", "pink", "orange"],
23
+ },
24
+ dir: {
25
+ control: { type: "radio" },
26
+ options: ["ltr", "rtl"],
27
+ },
28
+ closable: {
29
+ control: { type: "boolean" },
30
+ },
31
+ onClose: {
32
+ control: { action: "close" },
33
+ }
34
+ },
35
+ args: {
36
+ size: "sm",
37
+ type: "pillColor",
38
+ dir: "rtl",
39
+ color: "blue",
40
+ children: "Badge Label",
41
+ },
42
+ } as Meta<typeof Badge>;
43
+
44
+ type Story = StoryObj<BadgeProps>;
45
+
46
+ export const Default: Story = {};
47
+ export const WithAvatar: Story = {
48
+ args: {
49
+ icon: <img src="https://i.pravatar.cc/40?img=3" className="w-5 h-5 rounded-full" alt="avatar" />,
50
+ children: "Badge Label",
51
+ size: "md",
52
+ },
53
+ };
54
+ export const WithClose = {
55
+ args: {
56
+ type: "badgeModern",
57
+ color: "blue",
58
+ children: "Badge Label",
59
+ closable: true,
60
+ },
61
+ };
62
+
63
+ export const WithIcon = {
64
+ args: {
65
+ icon: "only",
66
+ children: <Plus stroke="red" />,
67
+ },
68
+ }
69
+
70
+ export const WithDot = {
71
+ args: {
72
+ icon: <span className="w-2 h-2 rounded-full bg-current"/>,
73
+ children: "With Dot",
74
+ },
75
+ }
@@ -0,0 +1,53 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ const baseStyles =
4
+ "flex items-center font-medium";
5
+
6
+ const colorStyle = {
7
+ gray: "bg-utility-gray-50 text-utility-gray-700 border-utility-gray-200 has-[>svg]:stroke-utility-gray-light-400",
8
+ brand: "bg-utility-brand-50 text-utility-brand-700 border-utility-brand-200 has-[>svg]:stroke-utility-brand-400",
9
+ error: "bg-utility-error-50 text-utility-error-700 border-utility-error-200 has-[>svg]:stroke-utility-error-400",
10
+ success: "bg-utility-success-50 text-utility-success-700 border-utility-success-200 has-[>svg]:stroke-utility-success-400",
11
+ grayBlue: "bg-utility-gray-blue-50 text-utility-gray-blue-700 border-utility-gray-blue-200 has-[>svg]:stroke-utility-gray-blue-400",
12
+ blueLight: "bg-utility-blue-light-50 text-utility-blue-light-700 border-utility-blue-light-200 has-[>svg]:stroke-utility-blue-light-400",
13
+ blue: "bg-utility-blue-50 text-utility-blue-700 border-utility-blue-200 has-[>svg]:stroke-utility-blue-400",
14
+ indigo: "bg-utility-indigo-50 text-utility-indigo-700 border-utility-indigo-200 has-[>svg]:stroke-utility-indigo-400",
15
+ purple: "bg-utility-purple-50 text-utility-purple-700 border-utility-purple-200 has-[>svg]:stroke-utility-purple-400",
16
+ pink: "bg-utility-pink-50 text-utility-pink-700 border-utility-pink-200 has-[>svg]:stroke-utility-pink-400",
17
+ orange: "bg-utility-orange-50 text-utility-orange-700 border-utility-orange-200 has-[>svg]:stroke-utility-orange-400 fill-red-500",
18
+ }
19
+
20
+ const sizeStyle = {
21
+ sm: "px-2 py-0.5 gap-1 has-[>svg]:text-sm text-xs",
22
+ md: "px-2.5 py-0.5 gap-1.5 has-[>svg]:text-md text-sm",
23
+ lg: "px-3 py-1 gap-2 has-[>svg]:text-lg text-sm",
24
+ }
25
+
26
+ const typeStyle = {
27
+ pillColor: "rounded-full border",
28
+ pillOutline: "rounded-full border-[1.5px]",
29
+ badgeColor: "rounded-sm border",
30
+ badgeModern: "rounded-md shadow-sm border has-[>svg]:stroke-current",
31
+ }
32
+
33
+ export const badgeVariants = cva(
34
+ baseStyles,
35
+ {
36
+ variants: {
37
+ size: sizeStyle,
38
+ type: typeStyle,
39
+ dir: {
40
+ ltr: "flex-row",
41
+ rtl: "flex-row-reverse",
42
+ },
43
+ color: colorStyle,
44
+ },
45
+ defaultVariants: {
46
+ size: "sm",
47
+ type: "pillColor",
48
+ dir: "ltr",
49
+ color: "blue",
50
+ }
51
+ }
52
+ )
53
+
@@ -0,0 +1,27 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+ import { Badge } from ".";
4
+
5
+ describe("Button Component", () => {
6
+ it("renders button with label", () => {
7
+ render(<Badge>Click Me</Badge>);
8
+ expect(screen.getByText("Click Me")).toBeDefined();
9
+ });
10
+ it("renders button with avatar", () => {
11
+ const Avatar = "https://i.pravatar.cc/40?img=3";
12
+ render(<Badge icon={<img src={Avatar} alt="avatar" className="rounded-full w-5 h-5" />} >Username</Badge>);
13
+ const img = screen.getByAltText("avatar") as HTMLImageElement;
14
+ expect(img).toBeInTheDocument();
15
+ expect(img.src).toContain(Avatar);
16
+ });
17
+ it("render badge modern type class", () => {
18
+ render(<Badge type="badgeModern">Click Me</Badge>);
19
+ const badge = screen.getByText("Click Me");
20
+ expect(badge).toHaveClass("bg-transparent border-primary text-secondary");
21
+ });
22
+ it("render closable icon", () => {
23
+ render(<Badge closable>Click Me</Badge>);
24
+ const closeIcon = screen.getByRole("button");
25
+ expect(closeIcon).toBeInTheDocument();
26
+ });
27
+ });
@@ -0,0 +1,11 @@
1
+ export type BadgeProps = {
2
+ className?: string;
3
+ size?: "sm" | "md" | "lg";
4
+ type?: "pillColor" | "pillOutline" | "badgeColor" | "badgeModern";
5
+ color?: "gray" | "brand" | "error" | "success" | "grayBlue" | "blueLight" | "blue" | "indigo" | "purple" | "pink" | "orange";
6
+ dir?: "ltr" | "rtl";
7
+ children: React.ReactNode;
8
+ icon?: React.ReactNode;
9
+ closable?: boolean;
10
+ onClose?: () => void;
11
+ }