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,177 @@
1
+ import { inputProps } from "@/components/Input/_.types";
2
+ import Email from "@/icons/general/email";
3
+ import type { Meta, StoryObj } from "@storybook/react-vite";
4
+ import { Input } from "./";
5
+
6
+ const meta: Meta<inputProps> = {
7
+ title: "Components/Input",
8
+ component: Input,
9
+ tags: ["autodocs"],
10
+ argTypes: {
11
+ disabled: {
12
+ control: { type: "radio" },
13
+ options: [true, false]
14
+ },
15
+ helpIcon: {
16
+ control: { type: "radio" },
17
+ options: [true, false]
18
+ },
19
+ size: {
20
+ control: { type: "radio" },
21
+ options: ["sm", "md"],
22
+ },
23
+ destructive: {
24
+ control: { type: "radio" },
25
+ options: [true, false]
26
+ },
27
+ inputType: {
28
+ control: { type: "select" },
29
+ options: ["default", "iconLeading", "leadingDropdown", "trailingDropdown", "leadingText", "trailingButton", "shaba"],
30
+ },
31
+ shabaLabelSize: {
32
+ control: { type: "select" },
33
+ options: ["sm", "md", "lg", "xl"],
34
+ },
35
+ },
36
+ parameters: {
37
+ layout: "centered",
38
+ },
39
+ args: {
40
+ disabled: false,
41
+ size: "sm",
42
+ type: "text",
43
+ label: "Email",
44
+ inputType: "default",
45
+ required: true,
46
+ hintText: "This is a hint text to help user.",
47
+ placeholder: "Enter your email",
48
+ destructive: false,
49
+ destructiveText: "error text",
50
+ className: "min-w-[400px] max-w-[400px]",
51
+ }
52
+ };
53
+
54
+ export default meta;
55
+
56
+ type Story = StoryObj<inputProps>;
57
+
58
+ export const Default: Story = {};
59
+
60
+ export const IconLeading: Story = {
61
+ args: {
62
+ inputType: "iconLeading",
63
+ icon: Email,
64
+ },
65
+ };
66
+
67
+ export const TrailingButton: Story = {
68
+ args: {
69
+ label: "Tracking Number",
70
+ inputType: "trailingButton",
71
+ trailingButtonText: "Copy",
72
+ value: "1234567890",
73
+ },
74
+ };
75
+
76
+ export const LeadingText: Story = {
77
+ args: {
78
+ label: "Address",
79
+ inputType: "leadingText",
80
+ placeholder: "Enter your site address",
81
+ leadingTextValue: "https",
82
+ },
83
+ };
84
+
85
+ export const TrailingDropdown: Story = {
86
+ args: {
87
+ size: "md",
88
+ type: "number",
89
+ label: "Price",
90
+ inputType: "trailingDropdown",
91
+ required: false,
92
+ placeholder: "Enter your product price",
93
+ helpIcon: true,
94
+ trailingDropdownDefault: { title: "usd", value: 1, icon: "$" },
95
+ trailingDropdownOptions: [
96
+ { title: "usd", value: 1, icon: "$" },
97
+ { title: "pound", value: 2, icon: "£" },
98
+ { title: "euro", value: 3, icon: "€" },
99
+ ],
100
+ tooltipProps: {
101
+ text: "This is a tooltip",
102
+ description: "Tooltips are used to describe or identify an element. In most scenarios",
103
+ position: "top",
104
+ dir: "ltr",
105
+ descriptionClassName: "max-w-[260px] w-full",
106
+ },
107
+ },
108
+ };
109
+
110
+ export const CustomLabel: Story = {
111
+ args: {
112
+ inputType: "iconLeading",
113
+ icon: Email,
114
+ label: "Email",
115
+ labelClass: "text-blue-600",
116
+ labelStarClass: "text-red-500",
117
+ },
118
+ };
119
+
120
+ export const Shaba: Story = {
121
+ args: {
122
+ label: "شماره شبا",
123
+ inputType: "shaba",
124
+ type: "text",
125
+ placeholder: "Enter شماره شبا",
126
+ shabaLabelSize: "lg",
127
+ },
128
+ };
129
+
130
+ export const ShabaSmall: Story = {
131
+ args: {
132
+ label: "شماره شبا (Small)",
133
+ inputType: "shaba",
134
+ type: "text",
135
+ placeholder: "Enter شماره شبا",
136
+ shabaLabelSize: "sm",
137
+ },
138
+ };
139
+
140
+ export const ShabaMedium: Story = {
141
+ args: {
142
+ label: "شماره شبا (Medium)",
143
+ inputType: "shaba",
144
+ type: "text",
145
+ placeholder: "Enter شماره شبا",
146
+ shabaLabelSize: "md",
147
+ },
148
+ };
149
+
150
+ export const ShabaLarge: Story = {
151
+ args: {
152
+ label: "شماره شبا (Large)",
153
+ inputType: "shaba",
154
+ type: "text",
155
+ placeholder: "Enter شماره شبا",
156
+ shabaLabelSize: "lg",
157
+ },
158
+ };
159
+
160
+ export const ShabaXLarge: Story = {
161
+ args: {
162
+ label: "شماره شبا (XLarge)",
163
+ inputType: "shaba",
164
+ type: "text",
165
+ placeholder: "Enter شماره شبا",
166
+ shabaLabelSize: "xl",
167
+ },
168
+ };
169
+
170
+ export const InputAutoFocus: Story = {
171
+ args: {
172
+ label: "ایمیل",
173
+ type: "email",
174
+ placeholder: "آدرس ایمیل را وارد کنید",
175
+ autoFocus: true
176
+ },
177
+ };
@@ -0,0 +1,79 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ const baseStyles =
4
+ "rounded-md px-2 shadow-xs w-fit bg-white border border-rborder-primary" +
5
+ " focus:outline-2 focus:outline-rborder-brand disabled:bg-rbg-disabled-subtle disabled:border-rborder-disabled";
6
+
7
+ const leadingTextValueStyles =
8
+ "h-full absolute text-sm text-rfg-tertiary-600 ltr:left-3 rtl:right-3 top-1/2 -translate-y-1/2 border-e pe-2" +
9
+ " w-15 truncate text-center";
10
+
11
+ const trailingButton =
12
+ "flex items-center gap-1 h-full absolute text-sm text-rbutton-secondary-fg cursor-pointer" +
13
+ " ltr:right-3 rtl:left-3 top-1/2 -translate-y-1/2 border-s ps-2";
14
+
15
+ const trailingShabaLabelBase =
16
+ "flex items-center h-full absolute text-rfg-tertiary-600" +
17
+ " ltr:right-0 rtl:left-0 top-1/2 -translate-y-1/2 border-s";
18
+
19
+ const trailingShabaLabelSizes = {
20
+ sm: "text-xs ps-2 pe-2",
21
+ md: "text-sm ps-5 pe-5",
22
+ lg: "text-base ps-8 pe-8",
23
+ xl: "text-base ps-11 pe-11",
24
+ };
25
+
26
+ const sizeStyle = {
27
+ sm: "h-9.5 py-2.5",
28
+ md: "h-10.5 pt-3 pb-3",
29
+ };
30
+
31
+ const destructiveStyles = "!border-2 !border-rborder-error focus:!outline-0";
32
+
33
+ const disableStyles = "bg-rbg-disabled-subtle border-rborder-disabled";
34
+
35
+ const iconStyles = "ltr:right-2 rtl:left-2";
36
+
37
+ const iconTrailingButtonStyles = "ltr:right-20 rtl:left-20";
38
+
39
+ const iconTrailingDropdownStyles = "ltr:right-20 rtl:left-20";
40
+
41
+ const iconShabaStyles = "ltr:right-12 rtl:left-12";
42
+
43
+ const typeStyle = {
44
+ default: "pe-8",
45
+ iconLeading: "ps-10",
46
+ leadingDropdown: "pe-8",
47
+ trailingDropdown: "pe-8 ps-6",
48
+ leadingText: "pe-8 ps-20",
49
+ trailingButton: "pe-8",
50
+ shaba: "pe-12",
51
+ };
52
+
53
+ const inputVariants = cva(baseStyles, {
54
+ variants: {
55
+ size: sizeStyle,
56
+ inputType: typeStyle,
57
+ },
58
+ defaultVariants: {
59
+ size: "sm",
60
+ inputType: "default",
61
+ },
62
+ });
63
+
64
+ export {
65
+ baseStyles,
66
+ destructiveStyles,
67
+ disableStyles,
68
+ iconStyles,
69
+ iconTrailingButtonStyles,
70
+ iconTrailingDropdownStyles,
71
+ iconShabaStyles,
72
+ inputVariants,
73
+ leadingTextValueStyles,
74
+ sizeStyle,
75
+ trailingButton,
76
+ trailingShabaLabelBase,
77
+ trailingShabaLabelSizes,
78
+ typeStyle,
79
+ };
@@ -0,0 +1,146 @@
1
+ import "@testing-library/jest-dom";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { Input } from ".";
5
+ import type { inputProps } from "./_.types";
6
+
7
+ // Mocking clipboard API globally
8
+ Object.assign(navigator, {
9
+ clipboard: {
10
+ writeText: vi.fn().mockResolvedValue(undefined),
11
+ },
12
+ });
13
+
14
+ const DummyIcon = () => <svg data-testid="dummy-icon" />;
15
+
16
+ const createInputProps = (overrides: Partial<inputProps> = {}): inputProps => ({
17
+ label: "Email",
18
+ id: "email-input",
19
+ size: "sm",
20
+ type: "text",
21
+ inputType: "trailingButton",
22
+ destructive: false,
23
+ required: true,
24
+ hintText: "This is a hint text to help user.",
25
+ placeholder: "Enter your email",
26
+ helpIcon: true,
27
+ onChange: vi.fn(),
28
+ value: "test@example.com",
29
+ trailingDropdownOptions: [{ title: "Option 1", value: 1, icon: "icon-1" }],
30
+ trailingDropdownDefault: { title: "Select", value: -1, icon: "" },
31
+ tooltipProps: {
32
+ text: "This is a tooltip",
33
+ description: "Tooltips are used to describe or identify an element. In most scenarios",
34
+ position: "top",
35
+ dir: "ltr",
36
+ descriptionClassName: "max-w-[260px] w-full",
37
+ },
38
+ ...overrides,
39
+ });
40
+
41
+ describe("Input Component", () => {
42
+ beforeEach(() => {
43
+ vi.useFakeTimers();
44
+ });
45
+
46
+ afterEach(() => {
47
+ vi.runOnlyPendingTimers();
48
+ vi.useRealTimers();
49
+ vi.resetAllMocks();
50
+ });
51
+
52
+ it("renders the input with label and placeholder", () => {
53
+ render(<Input {...createInputProps()} />);
54
+ const input = screen.getByRole("textbox");
55
+ expect(input).toBeInTheDocument();
56
+ expect(screen.getByText("Email")).toBeInTheDocument();
57
+ });
58
+
59
+ it("calls onChange when value changes", () => {
60
+ const onChange = vi.fn();
61
+ render(<Input {...createInputProps({ onChange })} />);
62
+ const input = screen.getByRole("textbox") as HTMLInputElement;
63
+ fireEvent.change(input, { target: { value: "changed@example.com" } });
64
+ expect(onChange).toHaveBeenCalledTimes(1);
65
+ });
66
+
67
+ it("renders as disabled when 'disabled' prop is true", () => {
68
+ render(<Input {...createInputProps({ disabled: true })} />);
69
+ const input = screen.getByRole("textbox");
70
+ expect(input).toBeDisabled();
71
+ });
72
+
73
+ it("renders trailing button when inputType is 'trailingButton'", () => {
74
+ render(<Input {...createInputProps({ inputType: "trailingButton" })} />);
75
+ const trailingButton = screen.getByLabelText("copyButton");
76
+ expect(trailingButton).toBeInTheDocument();
77
+ });
78
+
79
+ it("copies text to clipboard when trailing button is clicked", async () => {
80
+ render(<Input {...createInputProps({ inputType: "trailingButton" })} />);
81
+ const copyButton = screen.getByLabelText("copyButton");
82
+ fireEvent.click(copyButton);
83
+
84
+ expect(navigator.clipboard.writeText).toHaveBeenCalledTimes(1);
85
+ expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.any(String));
86
+ });
87
+
88
+ // it("handles trailing dropdown selection", () => {
89
+ // render(<Input {...createInputProps({ inputType: "trailingDropdown" })} />);
90
+ // const selectButton = screen.getByRole("combobox");
91
+ // fireEvent.click(selectButton);
92
+ // const option = screen.getByText("Option 1");
93
+ // fireEvent.click(option);
94
+ // expect(screen.getByText("Option 1")).toBeInTheDocument();
95
+ // });
96
+
97
+ it("renders destructive state with destructive text", () => {
98
+ render(<Input {...createInputProps({ destructive: true, destructiveText: "Destructive action" })} />);
99
+ const destructiveText = screen.getByText("Destructive action");
100
+ expect(destructiveText).toBeInTheDocument();
101
+ });
102
+
103
+ it("does not render destructive text when destructive is false", () => {
104
+ render(<Input {...createInputProps({ destructive: false })} />);
105
+ const destructiveText = screen.queryByText("Destructive action");
106
+ expect(destructiveText).not.toBeInTheDocument();
107
+ });
108
+
109
+ it("renders correct styles when destructive state is true", () => {
110
+ render(<Input {...createInputProps({ destructive: true, inputType: "default" })} />); // Ensure inputType is not "tags"
111
+ const input = screen.getByRole("textbox");
112
+ expect(input).toHaveClass("bg-rbg-disabled-subtle");
113
+ });
114
+
115
+ it("renders correct icon in leadingText state", () => {
116
+ render(<Input {...createInputProps({ inputType: "leadingText", leadingTextValue: "Text" })} />);
117
+ const leadingText = screen.getByText("Text");
118
+ expect(leadingText).toBeInTheDocument();
119
+ });
120
+
121
+ it("renders icon when inputType is 'iconLeading' and icon is provided", () => {
122
+ render(<Input {...createInputProps({ inputType: "iconLeading", icon: DummyIcon })} />);
123
+ const iconWrapper = screen.getByLabelText("iconLeading");
124
+ const icon = screen.getByTestId("dummy-icon");
125
+ expect(iconWrapper).toBeInTheDocument();
126
+ expect(icon).toBeInTheDocument();
127
+ });
128
+
129
+ it("renders leading text value with appropriate styles for non-destructive input", () => {
130
+ render(<Input {...createInputProps({ inputType: "leadingText", leadingTextValue: "USD", destructive: false })} />);
131
+ const leadingText = screen.getByLabelText("leadingText");
132
+
133
+ expect(leadingText).toBeInTheDocument();
134
+ expect(leadingText).toHaveClass("border-rborder-primary");
135
+ expect(leadingText).toHaveClass("pt-2"); // size = sm
136
+ });
137
+
138
+ it("renders leading text value with error style when destructive is true", () => {
139
+ render(<Input {...createInputProps({ inputType: "leadingText", leadingTextValue: "USD", destructive: true })} />);
140
+ const leadingText = screen.getByLabelText("leadingText");
141
+
142
+ expect(leadingText).toBeInTheDocument();
143
+ expect(leadingText).toHaveClass("border-rborder-error");
144
+ });
145
+
146
+ });
@@ -0,0 +1,66 @@
1
+ import { IconPropsType } from "@/icons/icons.type";
2
+ import React, { ComponentType } from "react";
3
+ import { Position } from "../Tooltip/_.types";
4
+
5
+ export type optionType = { title: string; value: number };
6
+ export type customOptionType = { title: string; value: number; icon: string };
7
+
8
+ export type inputProps = {
9
+ className?: string;
10
+ tooltipProps?: {
11
+ text: string;
12
+ description?: string;
13
+ position?: Position;
14
+ dir?: "rtl" | "ltr" | undefined;
15
+ descriptionClassName?: string;
16
+ };
17
+ size?: "sm" | "md";
18
+ type?: "text" | "number" | "password" | "email" | "url" | "tel";
19
+ inputType?:
20
+ | "default"
21
+ | "iconLeading"
22
+ | "leadingDropdown"
23
+ | "trailingDropdown"
24
+ | "leadingText"
25
+ | "trailingButton"
26
+ | "shaba";
27
+ icon?: ComponentType<IconPropsType>;
28
+ leadingTextValue?: string;
29
+ destructive?: boolean;
30
+ destructiveText?: string;
31
+ dir?: "ltr" | "rtl";
32
+ label?: string;
33
+ required?: boolean;
34
+ hintText?: string;
35
+ helpIcon?: boolean;
36
+ iconSwap?: boolean;
37
+ disabled?: boolean;
38
+ id?: string;
39
+ placeholder?: string;
40
+ trailingButtonText?: string;
41
+ name?: string;
42
+ trailingDropdownOptions?: customOptionType[];
43
+ trailingDropdownDefault?: customOptionType;
44
+ tagOnChange?: ((tags: string[]) => void) | (() => void);
45
+ onChange?: ((e: React.ChangeEvent<HTMLInputElement>) => void) | (() => void);
46
+ value?: string;
47
+ copyHandler?: () => void;
48
+ labelClass?: string;
49
+ labelStarClass?: string;
50
+ shabaLabelSize?: "sm" | "md" | "lg" | "xl";
51
+ autoFocus?: boolean
52
+ };
53
+
54
+ export type inputLabelProps = {
55
+ id?: string;
56
+ label?: string;
57
+ required?: boolean;
58
+ labelClass?: string;
59
+ labelStarClass?: string;
60
+ };
61
+
62
+ export type inputSelectProps = {
63
+ handleSelectChange?: (value: string) => void;
64
+ trailingDropdownOptions?: customOptionType[];
65
+ trailingDropdownDefault?: customOptionType;
66
+ };
@@ -0,0 +1,231 @@
1
+ import {
2
+ destructiveStyles,
3
+ disableStyles,
4
+ iconShabaStyles,
5
+ iconStyles,
6
+ iconTrailingButtonStyles,
7
+ iconTrailingDropdownStyles,
8
+ inputVariants,
9
+ leadingTextValueStyles,
10
+ trailingButton,
11
+ trailingShabaLabelBase,
12
+ trailingShabaLabelSizes,
13
+ } from "@/components/Input/_.style";
14
+ import { customOptionType, inputProps } from "@/components/Input/_.types";
15
+ import { InputLabel } from "@/components/ui/input-component/input-label";
16
+ import CircleQuestionMark from "@/icons/general/circle-question-mark";
17
+ import { IconPropsType } from "@/icons/icons.type";
18
+ import { cn } from "@/lib/utils";
19
+ import { Copy, Eye, EyeOff } from "lucide-react";
20
+ import React, { useState } from "react";
21
+ import { Button } from "../Button";
22
+ import { Select } from "../Select";
23
+ import { TooltipWrapper } from "../Tooltip";
24
+
25
+ export const Input = ({
26
+ size = "sm",
27
+ type = "text",
28
+ inputType = "default",
29
+ disabled = false,
30
+ id,
31
+ label,
32
+ required = false,
33
+ destructive = false,
34
+ destructiveText,
35
+ hintText,
36
+ placeholder,
37
+ helpIcon = false,
38
+ icon,
39
+ leadingTextValue,
40
+ className,
41
+ trailingDropdownOptions,
42
+ trailingDropdownDefault,
43
+ onChange,
44
+ value,
45
+ tooltipProps,
46
+ trailingButtonText,
47
+ name,
48
+ labelClass,
49
+ labelStarClass,
50
+ shabaLabelSize = "lg",
51
+ autoFocus = false,
52
+ ...props
53
+ }: Readonly<inputProps>) => {
54
+ const Icon: React.ComponentType<IconPropsType> | undefined = icon;
55
+
56
+ const [selectedItem, setSelectedItem] = useState<customOptionType>();
57
+ const [showPassword, setShowPassword] = useState(false);
58
+
59
+ const handleSelectChange = (info: customOptionType) => {
60
+ const item = trailingDropdownOptions?.find(
61
+ (elem) => elem?.value === info?.value
62
+ );
63
+ setSelectedItem(item ?? info);
64
+ };
65
+
66
+ const copyHandler = (text: string) => {
67
+ navigator.clipboard.writeText(text);
68
+ };
69
+
70
+ return (
71
+ <div className="flex flex-col gap-1 items-start">
72
+ <InputLabel
73
+ id={id}
74
+ label={label}
75
+ required={required}
76
+ labelClass={labelClass}
77
+ labelStarClass={labelStarClass}
78
+ />
79
+ <div className="relative w-full">
80
+ {Icon && inputType == "iconLeading" && (
81
+ <div
82
+ aria-label="iconLeading"
83
+ className="absolute ltr:left-3 rtl:right-3 top-1/2 -translate-y-1/2"
84
+ >
85
+ <Icon />
86
+ </div>
87
+ )}
88
+ {leadingTextValue && inputType == "leadingText" && (
89
+ <div
90
+ aria-label="leadingText"
91
+ className={`${leadingTextValueStyles} ${size === "sm" ? "pt-2" : "pt-2.5"
92
+ }
93
+ ${destructive === true
94
+ ? "border-rborder-error"
95
+ : "border-rborder-primary"
96
+ }`}
97
+ >
98
+ {leadingTextValue}
99
+ </div>
100
+ )}
101
+ {inputType == "trailingDropdown" && (
102
+ <p className="absolute ltr:left-2 rtl:right-2 top-1/2 -translate-y-1/2">
103
+ {selectedItem ? selectedItem?.icon : trailingDropdownDefault?.icon}
104
+ </p>
105
+ )}
106
+ <input
107
+ value={value}
108
+ name={name}
109
+ onChange={onChange}
110
+ placeholder={placeholder}
111
+ autoFocus={autoFocus}
112
+ className={cn(
113
+ inputVariants({ size, inputType }),
114
+ className,
115
+ destructive && "bg-rbg-disabled-subtle",
116
+ destructive && destructiveStyles,
117
+ disabled && disableStyles
118
+ )}
119
+ type={type === "password" && showPassword ? "text" : type}
120
+ id={id}
121
+ disabled={disabled}
122
+ {...props}
123
+ />
124
+
125
+ {type === "password" && (
126
+ <div
127
+ className={
128
+ "absolute top-1/2 -translate-y-1/2 ltr:right-2 rtl:left-2 w-fit h-5 flex items-center justify-center"
129
+ }
130
+ >
131
+ <Button
132
+ type="button"
133
+ variant="linkGray"
134
+ onClick={() => setShowPassword(!showPassword)}
135
+ >
136
+ {showPassword ? (
137
+ <EyeOff size={18} className="text-rbutton-tertiary-fg" />
138
+ ) : (
139
+ <Eye size={18} className="text-rbutton-tertiary-fg" />
140
+ )}
141
+ </Button>
142
+ </div>
143
+ )}
144
+
145
+ {helpIcon && tooltipProps && destructive === false && (
146
+ <TooltipWrapper
147
+ content={tooltipProps?.text}
148
+ description={tooltipProps?.description}
149
+ position={tooltipProps?.position}
150
+ dir={tooltipProps?.dir}
151
+ descriptionClassName={tooltipProps?.descriptionClassName}
152
+ >
153
+ <div
154
+ data-testid="tooltip-button"
155
+ className={`w-fit absolute top-1/2 -translate-y-1/2
156
+ ${inputType == "trailingButton"
157
+ ? iconTrailingButtonStyles
158
+ : inputType == "trailingDropdown"
159
+ ? iconTrailingDropdownStyles
160
+ : inputType == "shaba"
161
+ ? iconShabaStyles
162
+ : iconStyles
163
+ }`}
164
+ >
165
+ <CircleQuestionMark />
166
+ </div>
167
+ </TooltipWrapper>
168
+ )}
169
+ {/* {destructive && type !== "password" && (
170
+ <div
171
+ className={`w-fit absolute top-1/2 -translate-y-1/2
172
+ ${inputType == "trailingButton"
173
+ ? iconTrailingButtonStyles
174
+ : inputType == "trailingDropdown"
175
+ ? iconTrailingDropdownStyles
176
+ : iconStyles
177
+ }`}
178
+ >
179
+ <AttentionMark />
180
+ </div>
181
+ )} */}
182
+ {inputType == "trailingButton" && (
183
+ <button
184
+ aria-label="copyButton"
185
+ onClick={() => copyHandler(String(value))}
186
+ className={`${trailingButton} ${destructive === true
187
+ ? "border-rborder-error"
188
+ : "border-rborder-primary"
189
+ }`}
190
+ >
191
+ <Copy size={20} /> {trailingButtonText}
192
+ </button>
193
+ )}
194
+ {inputType == "trailingDropdown" && (
195
+ <Select
196
+ onChange={handleSelectChange}
197
+ options={trailingDropdownOptions ?? []}
198
+ selectedValueLabel={trailingDropdownDefault?.title ?? "-"}
199
+ config={{
200
+ canSelectZero: true,
201
+ name: "trailingDropdown",
202
+ }}
203
+ className="w-fit absolute rtl:left-0 ltr:right-0 top-0"
204
+ />
205
+ )}
206
+ {inputType == "shaba" && (
207
+ <div
208
+ aria-label="shabaLabel"
209
+ className={cn(
210
+ trailingShabaLabelBase,
211
+ trailingShabaLabelSizes[shabaLabelSize],
212
+ destructive === true
213
+ ? "border-rborder-error"
214
+ : "border-rborder-primary"
215
+ )}
216
+ >
217
+ IR
218
+ </div>
219
+ )}
220
+ </div>
221
+ {destructive === false && hintText && (
222
+ <p className="text-sm text-rtext-tertiary-600">{hintText}</p>
223
+ )}
224
+ {destructive && destructiveText && (
225
+ <p className="text-sm text-rtext-error-primary-600">
226
+ {destructiveText}
227
+ </p>
228
+ )}
229
+ </div>
230
+ );
231
+ };