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.
- package/.gitlab-ci.yml +43 -0
- package/.storybook/main.ts +15 -0
- package/.storybook/preview.ts +15 -0
- package/README.md +254 -0
- package/components.json +21 -0
- package/dist/Avatar.png +0 -0
- package/dist/assets/index-CCq7hmG3.js +186 -0
- package/dist/assets/index-Mg-hjQGu.css +1 -0
- package/dist/index.html +15 -0
- package/dist/test.png +0 -0
- package/dist/vite.svg +1 -0
- package/eslint.config.js +29 -0
- package/index.html +14 -0
- package/package.json +102 -0
- package/postcss.config.mjs +11 -0
- package/rollup.config.mjs +55 -0
- package/src/assets/react.svg +1 -0
- package/src/assets/style/animation.css +27 -0
- package/src/assets/style/box-shadow.css +25 -0
- package/src/assets/style/colors.css +402 -0
- package/src/assets/style/dark-theme.css +288 -0
- package/src/assets/style/font-size.css +14 -0
- package/src/assets/style/gradient.css +3 -0
- package/src/assets/style/index.css +12 -0
- package/src/assets/style/light-theme.css +148 -0
- package/src/assets/style/line-height.css +13 -0
- package/src/assets/style/max-width.css +5 -0
- package/src/assets/style/radius.css +13 -0
- package/src/assets/style/utility-colors.css +166 -0
- package/src/components/Accordion/_.stories.tsx +75 -0
- package/src/components/Accordion/_.test.tsx +77 -0
- package/src/components/Accordion/index.tsx +47 -0
- package/src/components/Accordion/type.ts +24 -0
- package/src/components/Avatar/_.stories.tsx +179 -0
- package/src/components/Avatar/_.style.ts +40 -0
- package/src/components/Avatar/_.test.tsx +150 -0
- package/src/components/Avatar/_.types.ts +66 -0
- package/src/components/Avatar/index.tsx +63 -0
- package/src/components/Badge/_.stories.tsx +75 -0
- package/src/components/Badge/_.style.ts +53 -0
- package/src/components/Badge/_.test.tsx +27 -0
- package/src/components/Badge/_.types.ts +11 -0
- package/src/components/Badge/index.tsx +42 -0
- package/src/components/Breadcrumbs/_.stories.tsx +95 -0
- package/src/components/Breadcrumbs/_.test.tsx +29 -0
- package/src/components/Breadcrumbs/_.type.ts +15 -0
- package/src/components/Breadcrumbs/index.tsx +103 -0
- package/src/components/Button/_.stories.tsx +85 -0
- package/src/components/Button/_.style.ts +56 -0
- package/src/components/Button/_.test.tsx +103 -0
- package/src/components/Button/_.types.ts +14 -0
- package/src/components/Button/index.tsx +70 -0
- package/src/components/Checkbox/_.stories.tsx +96 -0
- package/src/components/Checkbox/_.style.ts +24 -0
- package/src/components/Checkbox/_.test.tsx +85 -0
- package/src/components/Checkbox/_.types.ts +23 -0
- package/src/components/Checkbox/index.tsx +93 -0
- package/src/components/CheckboxGroup/PaymentCard/_.stories.tsx +104 -0
- package/src/components/CheckboxGroup/PaymentCard/_.style.ts +28 -0
- package/src/components/CheckboxGroup/PaymentCard/_.test.tsx +58 -0
- package/src/components/CheckboxGroup/PaymentCard/_.types.ts +28 -0
- package/src/components/CheckboxGroup/PaymentCard/index.tsx +71 -0
- package/src/components/CheckboxGroup/PlanCard/_.stories.tsx +165 -0
- package/src/components/CheckboxGroup/PlanCard/_.style.ts +32 -0
- package/src/components/CheckboxGroup/PlanCard/_.test.tsx +54 -0
- package/src/components/CheckboxGroup/PlanCard/_.types.ts +35 -0
- package/src/components/CheckboxGroup/PlanCard/index.tsx +53 -0
- package/src/components/CheckboxGroup/UserCard/_.stories.tsx +89 -0
- package/src/components/CheckboxGroup/UserCard/_.style.ts +42 -0
- package/src/components/CheckboxGroup/UserCard/_.test.tsx +66 -0
- package/src/components/CheckboxGroup/UserCard/_.types.ts +26 -0
- package/src/components/CheckboxGroup/UserCard/index.tsx +75 -0
- package/src/components/Dropdown/_.stories.tsx +180 -0
- package/src/components/Dropdown/_.style.ts +108 -0
- package/src/components/Dropdown/_.test.tsx +334 -0
- package/src/components/Dropdown/_.types.ts +12 -0
- package/src/components/Dropdown/index.tsx +130 -0
- package/src/components/FileUpload/_.stories.tsx +74 -0
- package/src/components/FileUpload/_.style.ts +0 -0
- package/src/components/FileUpload/_.test.tsx +222 -0
- package/src/components/FileUpload/_.types.ts +53 -0
- package/src/components/FileUpload/index.tsx +44 -0
- package/src/components/ImageMagnify/_.stories.tsx +226 -0
- package/src/components/ImageMagnify/_.style.ts +109 -0
- package/src/components/ImageMagnify/_.types.ts +44 -0
- package/src/components/ImageMagnify/index.tsx +204 -0
- package/src/components/Input/_.stories.tsx +177 -0
- package/src/components/Input/_.style.ts +79 -0
- package/src/components/Input/_.test.tsx +146 -0
- package/src/components/Input/_.types.ts +66 -0
- package/src/components/Input/index.tsx +231 -0
- package/src/components/InputTags/_.stories.tsx +51 -0
- package/src/components/InputTags/_.style.ts +28 -0
- package/src/components/InputTags/_.test.tsx +123 -0
- package/src/components/InputTags/_.types.ts +26 -0
- package/src/components/InputTags/index.tsx +140 -0
- package/src/components/Message/_.stories.tsx +79 -0
- package/src/components/Message/_.style.ts +87 -0
- package/src/components/Message/_.test.tsx +73 -0
- package/src/components/Message/_.types.ts +13 -0
- package/src/components/Message/index.tsx +57 -0
- package/src/components/Metric/_.stories.tsx +142 -0
- package/src/components/Metric/_.style.ts +14 -0
- package/src/components/Metric/_.test.tsx +166 -0
- package/src/components/Metric/_.types.ts +18 -0
- package/src/components/Metric/index.tsx +100 -0
- package/src/components/Modal/_.stories.tsx +93 -0
- package/src/components/Modal/_.style.ts +31 -0
- package/src/components/Modal/_.test.tsx +90 -0
- package/src/components/Modal/_.types.ts +14 -0
- package/src/components/Modal/index.tsx +82 -0
- package/src/components/Pagination/_.stories.tsx +118 -0
- package/src/components/Pagination/_.test.tsx +51 -0
- package/src/components/Pagination/index.tsx +256 -0
- package/src/components/Pagination/type.ts +48 -0
- package/src/components/PriceSlider/_.stories.tsx +107 -0
- package/src/components/PriceSlider/_.test.tsx +63 -0
- package/src/components/PriceSlider/_.type.tsx +19 -0
- package/src/components/PriceSlider/index.tsx +86 -0
- package/src/components/Progress/_.stories.tsx +93 -0
- package/src/components/Progress/_.style.ts +15 -0
- package/src/components/Progress/_.test.tsx +34 -0
- package/src/components/Progress/_.types.ts +17 -0
- package/src/components/Progress/index.tsx +173 -0
- package/src/components/Radio/_.stories.tsx +391 -0
- package/src/components/Radio/_.style.ts +33 -0
- package/src/components/Radio/_.test.tsx +77 -0
- package/src/components/Radio/_.types.ts +14 -0
- package/src/components/Radio/index.tsx +59 -0
- package/src/components/Select/_.stories.tsx +308 -0
- package/src/components/Select/_.style.ts +5 -0
- package/src/components/Select/_.types.ts +24 -0
- package/src/components/Select/index.tsx +172 -0
- package/src/components/Switch/_.stories.tsx +61 -0
- package/src/components/Switch/_.test.tsx +69 -0
- package/src/components/Switch/_.type.ts +12 -0
- package/src/components/Switch/index.tsx +70 -0
- package/src/components/Tabs/_.stories.tsx +508 -0
- package/src/components/Tabs/_.style.ts +63 -0
- package/src/components/Tabs/_.test.tsx +174 -0
- package/src/components/Tabs/_.type.ts +19 -0
- package/src/components/Tabs/index.tsx +35 -0
- package/src/components/Tag/_.stories.tsx +78 -0
- package/src/components/Tag/_.style.ts +71 -0
- package/src/components/Tag/_.test.tsx +44 -0
- package/src/components/Tag/_.types.ts +27 -0
- package/src/components/Tag/index.tsx +46 -0
- package/src/components/TextArea/_.stories.tsx +62 -0
- package/src/components/TextArea/_.style.ts +11 -0
- package/src/components/TextArea/_.test.tsx +43 -0
- package/src/components/TextArea/_.types.ts +29 -0
- package/src/components/TextArea/index.tsx +83 -0
- package/src/components/Toast/_.style.tsx +27 -0
- package/src/components/Toast/_.type.ts +30 -0
- package/src/components/Toast/_.utils.ts +23 -0
- package/src/components/Toast/container.tsx +171 -0
- package/src/components/Toast/index.tsx +29 -0
- package/src/components/Tooltip/_.stories.tsx +106 -0
- package/src/components/Tooltip/_.style.ts +27 -0
- package/src/components/Tooltip/_.test.tsx +54 -0
- package/src/components/Tooltip/_.types.ts +31 -0
- package/src/components/Tooltip/index.tsx +80 -0
- package/src/components/developers/AmirHossein.tsx +149 -0
- package/src/components/developers/Fardin.tsx +130 -0
- package/src/components/developers/Maryam.tsx +260 -0
- package/src/components/developers/Milad.tsx +431 -0
- package/src/components/developers/Rasoul.tsx +198 -0
- package/src/components/index.ts +28 -0
- package/src/components/ui/accordion.tsx +162 -0
- package/src/components/ui/avatars-component/avatar-description.tsx +30 -0
- package/src/components/ui/avatars-component/avatar-groups.tsx +68 -0
- package/src/components/ui/avatars-component/avatar-single.tsx +50 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox-group/plan-card/basic/_.test.tsx +66 -0
- package/src/components/ui/checkbox-group/plan-card/basic/index.tsx +70 -0
- package/src/components/ui/checkbox-group/plan-card/with-header/_.test.tsx +110 -0
- package/src/components/ui/checkbox-group/plan-card/with-header/header.test.tsx +96 -0
- package/src/components/ui/checkbox-group/plan-card/with-header/header.tsx +74 -0
- package/src/components/ui/checkbox-group/plan-card/with-header/index.tsx +65 -0
- package/src/components/ui/file-content/File-content.tsx +43 -0
- package/src/components/ui/file-uploader-components/file-uploader-box.tsx +76 -0
- package/src/components/ui/file-uploader-components/file-uploader-item.tsx +64 -0
- package/src/components/ui/icon-wrapper/_.test.tsx +60 -0
- package/src/components/ui/icon-wrapper/index.tsx +19 -0
- package/src/components/ui/input-component/input-label.tsx +11 -0
- package/src/components/ui/number.tsx +18 -0
- package/src/components/ui/pagination/card-minimal-center-align.tsx +96 -0
- package/src/components/ui/pagination/card-minimal-right-aligne.tsx +90 -0
- package/src/components/ui/pagination/default-pagination.tsx +128 -0
- package/src/components/ui/pagination/get-pagination-item.tsx +36 -0
- package/src/components/ui/pagination/pagination-card-button-group-aligned.tsx +94 -0
- package/src/components/ui/pagination/pagination-card-minimal-left-aligned.tsx +90 -0
- package/src/components/ui/pagination/pagination-content.tsx +15 -0
- package/src/components/ui/pagination/pagination-item.tsx +11 -0
- package/src/components/ui/pagination/pagination-link.tsx +42 -0
- package/src/components/ui/tab-components/tabs-content.tsx +15 -0
- package/src/components/ui/tab-components/tabs-list.tsx +27 -0
- package/src/components/ui/tab-components/tabs-trigger.tsx +25 -0
- package/src/components/ui/text-content-wrapper.tsx +36 -0
- package/src/hooks/useClickOutside.ts +23 -0
- package/src/icons/general/ArrowLeft.tsx +31 -0
- package/src/icons/general/ArrowRight.tsx +31 -0
- package/src/icons/general/activity-heart.tsx +31 -0
- package/src/icons/general/activity.tsx +31 -0
- package/src/icons/general/anchor.tsx +31 -0
- package/src/icons/general/archive.tsx +31 -0
- package/src/icons/general/arrow-left.tsx +25 -0
- package/src/icons/general/arrow-right.tsx +25 -0
- package/src/icons/general/asterisk-01.tsx +31 -0
- package/src/icons/general/asterisk-02.tsx +31 -0
- package/src/icons/general/at-sign.tsx +31 -0
- package/src/icons/general/attention-mark.tsx +43 -0
- package/src/icons/general/bookmark-add.tsx +31 -0
- package/src/icons/general/bookmark.tsx +31 -0
- package/src/icons/general/chevron-left.tsx +25 -0
- package/src/icons/general/chevron-right.tsx +25 -0
- package/src/icons/general/circle-minues.tsx +25 -0
- package/src/icons/general/circle-plus.tsx +25 -0
- package/src/icons/general/circle-question-mark.tsx +32 -0
- package/src/icons/general/circle.tsx +32 -0
- package/src/icons/general/copy.tsx +43 -0
- package/src/icons/general/email.tsx +32 -0
- package/src/icons/general/home.tsx +25 -0
- package/src/icons/general/layer.tsx +36 -0
- package/src/icons/general/leading.tsx +19 -0
- package/src/icons/general/master-card.tsx +37 -0
- package/src/icons/general/minus.tsx +36 -0
- package/src/icons/general/plus.tsx +19 -0
- package/src/icons/general/remove.tsx +32 -0
- package/src/icons/general/slash-divider.tsx +26 -0
- package/src/icons/general/tick-box.tsx +37 -0
- package/src/icons/general/trailing.tsx +19 -0
- package/src/icons/general/unkown-format.tsx +25 -0
- package/src/icons/general/visa-card.tsx +38 -0
- package/src/icons/general/x-close.tsx +35 -0
- package/src/icons/icons.type.ts +7 -0
- package/src/index.css +21 -0
- package/src/index.ts +3 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/zIndexUtils.ts +2 -0
- package/src/main.tsx +50 -0
- package/src/vite-env.d.ts +1 -0
- package/tests/setup.ts +8 -0
- package/tsconfig.app.json +31 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +24 -0
- package/tsconfig.rollup.json +12 -0
- package/vite.config.ts +20 -0
- package/vitest.config.ts +47 -0
|
@@ -0,0 +1,96 @@
|
|
|
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 { Header } from "./header";
|
|
5
|
+
|
|
6
|
+
describe("Header Component", () => {
|
|
7
|
+
const onChange = vi.fn();
|
|
8
|
+
const renderFunction = ({
|
|
9
|
+
type = "checkbox",
|
|
10
|
+
}: {
|
|
11
|
+
type?: "checkbox" | "radio";
|
|
12
|
+
}) => {
|
|
13
|
+
return render(
|
|
14
|
+
<Header
|
|
15
|
+
title="Plan Title"
|
|
16
|
+
size="sm"
|
|
17
|
+
disabled={false}
|
|
18
|
+
checkboxIndex={1}
|
|
19
|
+
id="plan-id"
|
|
20
|
+
value="plan-value"
|
|
21
|
+
onChange={onChange}
|
|
22
|
+
type={type}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
it("renders correctly with title", () => {
|
|
28
|
+
renderFunction({ type: "checkbox" });
|
|
29
|
+
const titleElement = screen.getByText("Plan Title");
|
|
30
|
+
expect(titleElement).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("renders the correct icon", () => {
|
|
34
|
+
renderFunction({ type: "checkbox" });
|
|
35
|
+
const iconElement = screen.getByTestId("layer-icon");
|
|
36
|
+
expect(iconElement).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("renders checkbox when type is checkbox", () => {
|
|
40
|
+
renderFunction({ type: "checkbox" });
|
|
41
|
+
|
|
42
|
+
const checkboxElement = screen.getByTestId("checkbox");
|
|
43
|
+
expect(checkboxElement).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("renders radio button when type is radio", () => {
|
|
47
|
+
renderFunction({ type: "radio" });
|
|
48
|
+
|
|
49
|
+
const radioElement = screen.getByRole("radio");
|
|
50
|
+
expect(radioElement).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("calls onChange when checkbox is clicked", () => {
|
|
54
|
+
renderFunction({ type: "checkbox" });
|
|
55
|
+
|
|
56
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
57
|
+
fireEvent.click(checkbox);
|
|
58
|
+
|
|
59
|
+
expect(onChange).toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("calls onChange when radio button is clicked", () => {
|
|
63
|
+
renderFunction({ type: "radio" });
|
|
64
|
+
|
|
65
|
+
const radio = screen.getByRole("radio");
|
|
66
|
+
fireEvent.click(radio);
|
|
67
|
+
|
|
68
|
+
expect(onChange).toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("does not call onChange when checkbox is clicked and disabled", () => {
|
|
72
|
+
renderFunction({ type: "checkbox" });
|
|
73
|
+
|
|
74
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
75
|
+
fireEvent.click(checkbox);
|
|
76
|
+
|
|
77
|
+
expect(onChange).toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("applies the correct classes when disabled", () => {
|
|
81
|
+
renderFunction({ type: "checkbox" });
|
|
82
|
+
|
|
83
|
+
const header = screen.getByTestId("header");
|
|
84
|
+
expect(header).toHaveClass(
|
|
85
|
+
"flex items-center border-b border-rborder-secondary p-4 w-full gap-2 group-focus-within:border-rbg-brand-solid group-focus-within:border-b-2 border-b"
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("applies the correct classes when enabled", () => {
|
|
90
|
+
renderFunction({ type: "checkbox" });
|
|
91
|
+
const header = screen.getByTestId("header");
|
|
92
|
+
expect(header).toHaveClass(
|
|
93
|
+
"group-focus-within:border-rbg-brand-solid group-focus-within:border-b-2 border-b"
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Checkbox } from "@/components/Checkbox";
|
|
2
|
+
import { CommonCheckboxProps } from "@/components/CheckboxGroup/PlanCard/_.types";
|
|
3
|
+
import { Radio } from "@/components/Radio";
|
|
4
|
+
import IconWrapper from "@/components/ui/icon-wrapper";
|
|
5
|
+
import Layer from "@/icons/general/layer";
|
|
6
|
+
|
|
7
|
+
export const Header = ({
|
|
8
|
+
title,
|
|
9
|
+
size,
|
|
10
|
+
disabled,
|
|
11
|
+
checkboxIndex,
|
|
12
|
+
id,
|
|
13
|
+
name = "",
|
|
14
|
+
value = "",
|
|
15
|
+
onChange,
|
|
16
|
+
inputProps,
|
|
17
|
+
checked,
|
|
18
|
+
type,
|
|
19
|
+
...props
|
|
20
|
+
}: {
|
|
21
|
+
title: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
value?: string;
|
|
24
|
+
} & CommonCheckboxProps) => {
|
|
25
|
+
const bgClass =
|
|
26
|
+
disabled ||
|
|
27
|
+
"group-focus-within:border-rbg-brand-solid group-focus-within:border-b-2 border-b";
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
data-testid="header"
|
|
32
|
+
className={`flex items-center border-b-2 border-rborder-secondary p-4 w-full gap-2 ${bgClass}`}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
<IconWrapper>
|
|
36
|
+
<Layer width="20" height="20" />
|
|
37
|
+
</IconWrapper>
|
|
38
|
+
|
|
39
|
+
<div className="flex flex-col grow justify-between">
|
|
40
|
+
<div className="flex text-sm">
|
|
41
|
+
<h3 className="font-medium text-foreground text-rtext-secondary-700">
|
|
42
|
+
{title}
|
|
43
|
+
</h3>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div className="flex items-start gap-2">
|
|
48
|
+
{type === "radio" ? (
|
|
49
|
+
<Radio
|
|
50
|
+
onChange={onChange}
|
|
51
|
+
checked={checked}
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
value={value}
|
|
54
|
+
name={name}
|
|
55
|
+
size={size}
|
|
56
|
+
id={id}
|
|
57
|
+
{...inputProps}
|
|
58
|
+
/>
|
|
59
|
+
) : (
|
|
60
|
+
<Checkbox
|
|
61
|
+
checkboxIndex={checkboxIndex}
|
|
62
|
+
disabled={disabled}
|
|
63
|
+
id={id}
|
|
64
|
+
name={name}
|
|
65
|
+
onChange={onChange}
|
|
66
|
+
size={size}
|
|
67
|
+
value={value}
|
|
68
|
+
{...inputProps}
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Badge } from "@/components/Badge";
|
|
2
|
+
import { PlanCardProps } from "@/components/CheckboxGroup/PlanCard/_.types";
|
|
3
|
+
import { Header } from "./header";
|
|
4
|
+
|
|
5
|
+
export function PlanCardWithHeader({
|
|
6
|
+
per,
|
|
7
|
+
size = "sm",
|
|
8
|
+
title = "",
|
|
9
|
+
price,
|
|
10
|
+
description,
|
|
11
|
+
checked,
|
|
12
|
+
badgeContent,
|
|
13
|
+
checkboxIndex = 1,
|
|
14
|
+
id = "",
|
|
15
|
+
value = "value",
|
|
16
|
+
name = "",
|
|
17
|
+
onChange,
|
|
18
|
+
disabled,
|
|
19
|
+
type,
|
|
20
|
+
}: Readonly<PlanCardProps>) {
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<Header
|
|
24
|
+
type={type}
|
|
25
|
+
onChange={onChange}
|
|
26
|
+
name={name}
|
|
27
|
+
disabled={disabled}
|
|
28
|
+
checked={checked}
|
|
29
|
+
value={value}
|
|
30
|
+
data-testid="header"
|
|
31
|
+
checkboxIndex={checkboxIndex}
|
|
32
|
+
title={title}
|
|
33
|
+
size={size}
|
|
34
|
+
id={id}
|
|
35
|
+
/>
|
|
36
|
+
<div className="p-4 flex w-full">
|
|
37
|
+
<div className="grow space-y-1">
|
|
38
|
+
<div className="flex items-end text-sm gap-1">
|
|
39
|
+
<span className="text-3xl font-semibold text-foreground text-rtext-secondary-700">
|
|
40
|
+
{price}
|
|
41
|
+
</span>
|
|
42
|
+
<span className="h-fit">{per}</span>
|
|
43
|
+
</div>
|
|
44
|
+
<div>{description}</div>
|
|
45
|
+
</div>
|
|
46
|
+
<span>
|
|
47
|
+
{badgeContent && (
|
|
48
|
+
<Badge
|
|
49
|
+
size="md"
|
|
50
|
+
type="badgeColor"
|
|
51
|
+
dir="rtl"
|
|
52
|
+
color="success"
|
|
53
|
+
className="!bg-white !border-rborder-primary !text-rtext-secondary-700"
|
|
54
|
+
icon={
|
|
55
|
+
<span className="w-1.5 h-1.5 rounded-full bg-rfg-success-primary"></span>
|
|
56
|
+
}
|
|
57
|
+
>
|
|
58
|
+
{badgeContent}
|
|
59
|
+
</Badge>
|
|
60
|
+
)}
|
|
61
|
+
</span>
|
|
62
|
+
</div>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cn } from "@/lib/utils";
|
|
2
|
+
|
|
3
|
+
export const FileContent = ({
|
|
4
|
+
icon,
|
|
5
|
+
title,
|
|
6
|
+
size,
|
|
7
|
+
sizeFormat,
|
|
8
|
+
className,
|
|
9
|
+
dir = "rtl",
|
|
10
|
+
}: {
|
|
11
|
+
icon: React.ReactNode;
|
|
12
|
+
title: string;
|
|
13
|
+
size?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
dir?: "rtl" | "ltr";
|
|
16
|
+
sizeFormat?: string;
|
|
17
|
+
}) => {
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className={cn(
|
|
21
|
+
"w-full flex gap-3 py-2.5 px-3.5 border border-rborder-secondary bg-rbg-primary rounded-md",
|
|
22
|
+
className,
|
|
23
|
+
dir == "ltr" && "flex-row-reverse "
|
|
24
|
+
)}
|
|
25
|
+
>
|
|
26
|
+
<div className="w-10 h-10">{icon ?? null}</div>
|
|
27
|
+
<div className="flex flex-col max-w-4/5 ">
|
|
28
|
+
<span className="text-rtext-secondary-700 font-medium text-sm w-full truncate ">
|
|
29
|
+
{title}
|
|
30
|
+
</span>
|
|
31
|
+
<span
|
|
32
|
+
className={cn(
|
|
33
|
+
"text-rtext-tertiary-600 flex gap-0.5 items-center text-sm font-normal truncate",
|
|
34
|
+
dir == "ltr" && "flex-row-reverse"
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{size}
|
|
38
|
+
{sizeFormat}
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Button } from "@/components/Button";
|
|
2
|
+
import { FileUploaderBoxProps } from "@/components/FileUpload/_.types";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { UploadCloud } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
export const FileUploaderBox = ({
|
|
7
|
+
icon,
|
|
8
|
+
mainText,
|
|
9
|
+
subText,
|
|
10
|
+
formatText,
|
|
11
|
+
acceptableFormats,
|
|
12
|
+
disable,
|
|
13
|
+
multiItem,
|
|
14
|
+
onChange,
|
|
15
|
+
}: FileUploaderBoxProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className={cn(
|
|
19
|
+
"relative w-full py-4 px-6 flex justify-center items-center gap-1 rounded-xl border border-rborder-secondary bg-rbg-primary ",
|
|
20
|
+
disable && "bg-rbg-disabled-subtle",
|
|
21
|
+
!disable &&
|
|
22
|
+
"hover:border-rborder-brand focus:border-rborder-brand focus-within:border-rborder-brand"
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
<div className="text-center flex flex-col justify-center items-center gap-2">
|
|
26
|
+
{icon ?? (
|
|
27
|
+
<Button
|
|
28
|
+
variant={"secondaryGray"}
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
disabled={disable}
|
|
31
|
+
>
|
|
32
|
+
<UploadCloud data-testid="default-uploadcloud" />
|
|
33
|
+
</Button>
|
|
34
|
+
)}
|
|
35
|
+
<div className="flex flex-col justify-center items-center gap-1">
|
|
36
|
+
<div className="flex items-center gap-1">
|
|
37
|
+
<label
|
|
38
|
+
htmlFor="file-upload"
|
|
39
|
+
className={cn(
|
|
40
|
+
" cursor-pointer rounded-md text-rbutton-tertiary-color-fg font-normal text-sm",
|
|
41
|
+
disable && "text-rbg-disabled-subtle"
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
<span className={cn(disable && "text-rfg-disabled")}>
|
|
45
|
+
{mainText}
|
|
46
|
+
</span>
|
|
47
|
+
<input
|
|
48
|
+
id="file-upload"
|
|
49
|
+
name="file-upload"
|
|
50
|
+
data-testid="file-input"
|
|
51
|
+
type="file"
|
|
52
|
+
className="absolute overflow-hidden top-0 left-0 w-full h-full opacity-0 cursor-pointer"
|
|
53
|
+
disabled={disable}
|
|
54
|
+
multiple={multiItem}
|
|
55
|
+
accept={
|
|
56
|
+
acceptableFormats
|
|
57
|
+
? Array.isArray(acceptableFormats)
|
|
58
|
+
? acceptableFormats
|
|
59
|
+
.map((f) => (f.startsWith(".") ? f : `.${f}`))
|
|
60
|
+
.join(", ")
|
|
61
|
+
: acceptableFormats
|
|
62
|
+
: undefined
|
|
63
|
+
}
|
|
64
|
+
onChange={onChange}
|
|
65
|
+
/>
|
|
66
|
+
</label>
|
|
67
|
+
<p className="text-rtext-tertiary-600 text-sm">{subText}</p>
|
|
68
|
+
</div>
|
|
69
|
+
<p className="text-xs text-rtext-tertiary-600 font-normal">
|
|
70
|
+
{formatText}
|
|
71
|
+
</p>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Button } from "@/components/Button";
|
|
2
|
+
import { FileUploaderItemProps } from "@/components/FileUpload/_.types";
|
|
3
|
+
import { Progress } from "@/components/Progress";
|
|
4
|
+
import { UnkownFormat } from "@/icons/general/unkown-format";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import { Trash2 } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
export const FileUploaderItem = ({
|
|
9
|
+
item,
|
|
10
|
+
loadType,
|
|
11
|
+
onDelete,
|
|
12
|
+
}: FileUploaderItemProps) => {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
className={cn(
|
|
16
|
+
"p-4 flex gap-3 w-full rounded-xl border border-rborder-secondary bg-rbg-primary",
|
|
17
|
+
item?.status == "failed" && "border-rborder-error"
|
|
18
|
+
)}
|
|
19
|
+
>
|
|
20
|
+
<div className=" flex justify-start items-start w-10 h-10">
|
|
21
|
+
{item?.icon ?? (
|
|
22
|
+
<UnkownFormat width={20} height={20} data-testid="fallback-icon" />
|
|
23
|
+
)}
|
|
24
|
+
</div>
|
|
25
|
+
<div className="flex flex-col gap-1 w-full">
|
|
26
|
+
<div className="flex justify-between">
|
|
27
|
+
<div className="flex flex-col w-1/2">
|
|
28
|
+
<span className="font-medium text-rtext-secondary-700 overflow-hidden text-ellipsis text-sm">
|
|
29
|
+
{item?.title}
|
|
30
|
+
</span>
|
|
31
|
+
<span className="text-rtext-tertiary-600 font-normal text-sm overflow-hidden text-ellipsis">
|
|
32
|
+
{item?.size}
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<Button
|
|
36
|
+
className={cn(
|
|
37
|
+
"self-centertext-rbutton-tertiary-fg",
|
|
38
|
+
item?.status == "failed" && "text-rbutton-secondary-error-fg"
|
|
39
|
+
)}
|
|
40
|
+
onClick={() => {
|
|
41
|
+
onDelete(item?.id);
|
|
42
|
+
}}
|
|
43
|
+
variant={"linkGray"}
|
|
44
|
+
>
|
|
45
|
+
<Trash2 width={20} height={20} />
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
48
|
+
{loadType == "progressBar" && (
|
|
49
|
+
<Progress
|
|
50
|
+
type="line"
|
|
51
|
+
value={item?.progressValue}
|
|
52
|
+
label={item?.percentage}
|
|
53
|
+
size="lg"
|
|
54
|
+
indicatorVariant="bg-rfg-brand-primary-600"
|
|
55
|
+
backgroundVariant="bg-rbg-quaternary"
|
|
56
|
+
dir="rtl"
|
|
57
|
+
className="h-2"
|
|
58
|
+
labelClassName="text-end"
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import "@testing-library/jest-dom";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
import IconWrapper from ".";
|
|
6
|
+
// adjust the import based on your file structure
|
|
7
|
+
|
|
8
|
+
describe("IconWrapper", () => {
|
|
9
|
+
it("renders children correctly", () => {
|
|
10
|
+
render(
|
|
11
|
+
<IconWrapper>
|
|
12
|
+
<span>Test Icon</span>
|
|
13
|
+
</IconWrapper>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(screen.getByText("Test Icon")).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("applies passed className", () => {
|
|
20
|
+
render(
|
|
21
|
+
<IconWrapper className="custom-class">
|
|
22
|
+
<span>Styled Icon</span>
|
|
23
|
+
</IconWrapper>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const wrapper = screen.getByText("Styled Icon").parentElement;
|
|
27
|
+
expect(wrapper).toHaveClass("custom-class");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("merges className with default styles", () => {
|
|
31
|
+
render(
|
|
32
|
+
<IconWrapper className="custom-class">
|
|
33
|
+
<span>Check Class Merge</span>
|
|
34
|
+
</IconWrapper>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const wrapper = screen.getByText("Check Class Merge").parentElement;
|
|
38
|
+
expect(wrapper).toHaveClass("flex items-center justify-center");
|
|
39
|
+
expect(wrapper).toHaveClass("custom-class");
|
|
40
|
+
expect(wrapper).toHaveClass(
|
|
41
|
+
"border",
|
|
42
|
+
"rounded-md",
|
|
43
|
+
"shadow-rshadow-sm-01",
|
|
44
|
+
"p-2.5",
|
|
45
|
+
"w-fit",
|
|
46
|
+
"h-fit"
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("forwards props to div element", () => {
|
|
51
|
+
render(
|
|
52
|
+
<IconWrapper data-testid="icon-wrapper" aria-label="icon-label">
|
|
53
|
+
<span>Forward Props</span>
|
|
54
|
+
</IconWrapper>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const wrapper = screen.getByTestId("icon-wrapper");
|
|
58
|
+
expect(wrapper).toHaveAttribute("aria-label", "icon-label");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function IconWrapper({
|
|
2
|
+
children,
|
|
3
|
+
className,
|
|
4
|
+
...props
|
|
5
|
+
}: {
|
|
6
|
+
className?: string;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
className={`${className} flex items-center justify-center border border-disabled-subtle-br rounded-md shadow-rshadow-sm-01 p-2.5 w-fit h-fit`}
|
|
12
|
+
{...props}
|
|
13
|
+
>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default IconWrapper;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { inputLabelProps } from "@/components/Input/_.types";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
export const InputLabel = ({ id, label, required, labelClass, labelStarClass }: inputLabelProps) => {
|
|
5
|
+
return (
|
|
6
|
+
<label htmlFor={id} className={twMerge("text-sm font-medium text-rtext-secondary-700", labelClass)}>
|
|
7
|
+
{label}
|
|
8
|
+
{required && <span className={twMerge("dv-required-label text-rtext-brand-tertiary-600 mx-1", labelStarClass)}>*</span>}
|
|
9
|
+
</label>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cn } from "@/lib/utils";
|
|
2
|
+
import { TagProps } from "../Tag/_.types";
|
|
3
|
+
import { numberVariants } from "../Tag/_.style";
|
|
4
|
+
|
|
5
|
+
function Number({ number, size }: Readonly<TagProps>) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
className={cn(
|
|
9
|
+
numberVariants({ size }),
|
|
10
|
+
"bg-gray-light-100 rounded-[3px]"
|
|
11
|
+
)}
|
|
12
|
+
>
|
|
13
|
+
{number}
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default Number;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import ArrowLeft from "@/icons/general/arrow-left";
|
|
2
|
+
import ArrowRight from "@/icons/general/arrow-right";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { PaginationProps } from "../../Pagination/type";
|
|
5
|
+
import { PaginationContent } from "./pagination-content";
|
|
6
|
+
import { PaginationItem } from "./pagination-item";
|
|
7
|
+
import { PaginationLink } from "./pagination-link";
|
|
8
|
+
|
|
9
|
+
const PaginationCardMinimalCenter = ({
|
|
10
|
+
currentPage,
|
|
11
|
+
totalPages,
|
|
12
|
+
onPageChange,
|
|
13
|
+
dir = "rtl",
|
|
14
|
+
labels,
|
|
15
|
+
previousClassName,
|
|
16
|
+
nextClassName,
|
|
17
|
+
className,
|
|
18
|
+
prevIcon,
|
|
19
|
+
nextIcon,
|
|
20
|
+
...props
|
|
21
|
+
}: PaginationProps) => {
|
|
22
|
+
const isRtl = dir === "rtl";
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<nav
|
|
26
|
+
role="navigation"
|
|
27
|
+
aria-label="pagination"
|
|
28
|
+
className={cn("", className)}
|
|
29
|
+
{...props}
|
|
30
|
+
>
|
|
31
|
+
<PaginationContent className="flex justify-between items-center">
|
|
32
|
+
<div className="flex">
|
|
33
|
+
<PaginationItem className="md:block hidden">
|
|
34
|
+
<PaginationLink
|
|
35
|
+
size="default"
|
|
36
|
+
aria-label="Go to first page"
|
|
37
|
+
disabled={currentPage === 1}
|
|
38
|
+
onClick={() => onPageChange?.(1)}
|
|
39
|
+
>
|
|
40
|
+
{labels?.first}
|
|
41
|
+
</PaginationLink>
|
|
42
|
+
</PaginationItem>
|
|
43
|
+
|
|
44
|
+
<PaginationItem>
|
|
45
|
+
<PaginationLink
|
|
46
|
+
aria-label="Go to previous page"
|
|
47
|
+
size="default"
|
|
48
|
+
className={cn("gap-1", previousClassName)}
|
|
49
|
+
onClick={() => onPageChange?.(currentPage - 1)}
|
|
50
|
+
disabled={currentPage === 1}
|
|
51
|
+
>
|
|
52
|
+
<div className="md:block hidden">{labels?.prev || "قبلی"}</div>
|
|
53
|
+
<div className="md:hidden block">
|
|
54
|
+
{isRtl ? prevIcon || <ArrowRight /> : nextIcon || <ArrowLeft />}
|
|
55
|
+
</div>
|
|
56
|
+
</PaginationLink>
|
|
57
|
+
</PaginationItem>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<span className="text-sm font-medium">
|
|
61
|
+
{labels?.page} {currentPage} {labels?.of} {totalPages}
|
|
62
|
+
</span>
|
|
63
|
+
|
|
64
|
+
<div className="flex">
|
|
65
|
+
<PaginationItem>
|
|
66
|
+
<PaginationLink
|
|
67
|
+
aria-label="Go to next page"
|
|
68
|
+
size="default"
|
|
69
|
+
className={cn("gap-1", nextClassName)}
|
|
70
|
+
onClick={() => onPageChange?.(currentPage + 1)}
|
|
71
|
+
disabled={currentPage === totalPages}
|
|
72
|
+
>
|
|
73
|
+
<span className="md:block hidden">{labels?.next || "بعدی"}</span>
|
|
74
|
+
<div className="md:hidden block">
|
|
75
|
+
{isRtl ? prevIcon || <ArrowLeft /> : nextIcon || <ArrowRight />}
|
|
76
|
+
</div>
|
|
77
|
+
</PaginationLink>
|
|
78
|
+
</PaginationItem>
|
|
79
|
+
|
|
80
|
+
<PaginationItem className="md:block hidden">
|
|
81
|
+
<PaginationLink
|
|
82
|
+
size="default"
|
|
83
|
+
aria-label="Go to last page"
|
|
84
|
+
disabled={currentPage === totalPages}
|
|
85
|
+
onClick={() => onPageChange?.(totalPages)}
|
|
86
|
+
>
|
|
87
|
+
{labels?.last}
|
|
88
|
+
</PaginationLink>
|
|
89
|
+
</PaginationItem>
|
|
90
|
+
</div>
|
|
91
|
+
</PaginationContent>
|
|
92
|
+
</nav>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default PaginationCardMinimalCenter;
|