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 type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Checkbox } from "."; // adjust the path if needed
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Checkbox> = {
|
|
5
|
+
title: "Components/Checkbox",
|
|
6
|
+
component: Checkbox,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
argTypes: {
|
|
9
|
+
onClick: { action: "clicked" },
|
|
10
|
+
onChange: { action: "changed" },
|
|
11
|
+
size: {
|
|
12
|
+
control: { type: "select" },
|
|
13
|
+
options: ["sm", "md", "lg"],
|
|
14
|
+
},
|
|
15
|
+
disabled: { control: "boolean" },
|
|
16
|
+
defaultChecked: { control: "boolean" },
|
|
17
|
+
isIndeterminate: { control: "boolean" },
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
id: "default-checkbox",
|
|
21
|
+
name: "default-checkbox",
|
|
22
|
+
children: "Accept Terms",
|
|
23
|
+
size: "md",
|
|
24
|
+
disabled: false,
|
|
25
|
+
defaultChecked: false,
|
|
26
|
+
isIndeterminate: false,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
|
|
32
|
+
type Story = StoryObj<typeof Checkbox>;
|
|
33
|
+
|
|
34
|
+
export const Default: Story = {};
|
|
35
|
+
|
|
36
|
+
export const DefaultChecked: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
defaultChecked: true,
|
|
39
|
+
id: "checked-checkbox",
|
|
40
|
+
name: "checked-checkbox",
|
|
41
|
+
children: "Pre-checked Option",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Disabled: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
disabled: true,
|
|
48
|
+
id: "disabled-checkbox",
|
|
49
|
+
name: "disabled-checkbox",
|
|
50
|
+
children: "Disabled Checkbox",
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Indeterminate: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
isIndeterminate: true,
|
|
57
|
+
id: "indeterminate-checkbox",
|
|
58
|
+
name: "indeterminate-checkbox",
|
|
59
|
+
children: "Indeterminate Checkbox",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const Sizes: Story = {
|
|
64
|
+
render: () => (
|
|
65
|
+
<div className="flex flex-col gap-3">
|
|
66
|
+
<Checkbox id="checkbox-sm" name="checkbox-sm" size="sm">
|
|
67
|
+
Small
|
|
68
|
+
</Checkbox>
|
|
69
|
+
<Checkbox id="checkbox-md" name="checkbox-md" size="md">
|
|
70
|
+
Medium
|
|
71
|
+
</Checkbox>
|
|
72
|
+
<Checkbox id="checkbox-lg" name="checkbox-lg" size="lg">
|
|
73
|
+
Large
|
|
74
|
+
</Checkbox>
|
|
75
|
+
</div>
|
|
76
|
+
),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const WithName: Story = {
|
|
80
|
+
render: () => (
|
|
81
|
+
<div className="flex flex-col gap-3">
|
|
82
|
+
<div className="flex items-center gap-2">
|
|
83
|
+
<Checkbox id="checkbox-name-1" name="checkbox-name-1" />
|
|
84
|
+
<label htmlFor="checkbox-name-1" className="ml-2">
|
|
85
|
+
Checkbox controlled by name
|
|
86
|
+
</label>
|
|
87
|
+
</div>
|
|
88
|
+
<div className="flex items-center gap-2">
|
|
89
|
+
<Checkbox id="checkbox-name-2" name="checkbox-name-2" size="lg" />
|
|
90
|
+
<label htmlFor="checkbox-name-2" className="ml-2">
|
|
91
|
+
Large checkbox with name
|
|
92
|
+
</label>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
),
|
|
96
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
|
|
3
|
+
const baseStyles =
|
|
4
|
+
"border-rborder-primary rounded-xs border-[1px] peer-checked:border-rbg-brand-solid peer-checked:bg-rbg-brand-solid flex items-center justify-center";
|
|
5
|
+
|
|
6
|
+
const sizeStyle = {
|
|
7
|
+
sm: "w-3.5 h-3.5",
|
|
8
|
+
md: "w-4 h-4",
|
|
9
|
+
lg: "w-4.5 h-4.5",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const checkboxVariants = cva(baseStyles, {
|
|
13
|
+
variants: {
|
|
14
|
+
size: sizeStyle,
|
|
15
|
+
disabled: {
|
|
16
|
+
true: " bg-rbg-disabled-subtle cursor-auto",
|
|
17
|
+
false: " group cursor-pointer",
|
|
18
|
+
undefined: "group cursor-pointer",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
size: "sm",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { Checkbox } from "."; // update the import path to match your project structure
|
|
5
|
+
|
|
6
|
+
describe("Checkbox Component", () => {
|
|
7
|
+
it("renders with default props", () => {
|
|
8
|
+
render(<Checkbox id="checkbox-default" name="checkbox-default" />);
|
|
9
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
10
|
+
expect(checkbox).toBeInTheDocument();
|
|
11
|
+
expect(checkbox).not.toBeChecked();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("renders as checked when `checked` is true", () => {
|
|
15
|
+
render(<Checkbox id="checkbox-checked" checked name="checkbox-checked" />);
|
|
16
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
17
|
+
expect(checkbox).toBeChecked();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("calls onChange when clicked", () => {
|
|
21
|
+
const onChange = vi.fn();
|
|
22
|
+
render(<Checkbox id="checkbox-onchange" onChange={onChange} name="checkbox-onchange" />);
|
|
23
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
24
|
+
fireEvent.click(checkbox);
|
|
25
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("does NOT call onChange when disabled", () => {
|
|
29
|
+
const onChange = vi.fn();
|
|
30
|
+
render(<Checkbox id="checkbox-disabled" disabled onChange={onChange} name="checkbox-disabled" />);
|
|
31
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
32
|
+
fireEvent.click(checkbox);
|
|
33
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("renders children and toggles checkbox on child click (manual toggle)", () => {
|
|
37
|
+
render(
|
|
38
|
+
<Checkbox id="checkbox-children" defaultChecked={false} name="checkbox-children">
|
|
39
|
+
<span>Click label</span>
|
|
40
|
+
</Checkbox>
|
|
41
|
+
);
|
|
42
|
+
const label = screen.getByText("Click label");
|
|
43
|
+
expect(label).toBeInTheDocument();
|
|
44
|
+
fireEvent.click(label);
|
|
45
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
46
|
+
expect(checkbox).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("renders minus icon when indeterminate is true", () => {
|
|
50
|
+
render(<Checkbox id="checkbox-minus" isIndeterminate name="checkbox-minus" />);
|
|
51
|
+
const minus = screen.getByTestId("minus-icon");
|
|
52
|
+
expect(minus).toBeInTheDocument();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("renders tick icon when not indeterminate", () => {
|
|
56
|
+
render(<Checkbox id="checkbox-tick" name="checkbox-tick" />);
|
|
57
|
+
const tick = screen.getByTestId("tickbox-icon");
|
|
58
|
+
expect(tick).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("applies correct size variant classes", () => {
|
|
62
|
+
const { rerender, container } = render(
|
|
63
|
+
<Checkbox id="checkbox-size-sm" size="sm" name="checkbox-size-sm" />
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
let label = container.querySelector("label");
|
|
67
|
+
expect(label?.className).toMatch(/w-3\.5/);
|
|
68
|
+
|
|
69
|
+
rerender(<Checkbox id="checkbox-size-md" size="md" name="checkbox-size-md" />);
|
|
70
|
+
label = container.querySelector("label");
|
|
71
|
+
expect(label?.className).toMatch(/w-4/);
|
|
72
|
+
|
|
73
|
+
rerender(<Checkbox id="checkbox-size-lg" size="lg" name="checkbox-size-lg" />);
|
|
74
|
+
label = container.querySelector("label");
|
|
75
|
+
expect(label?.className).toMatch(/w-4\.5/);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("calls onClick prop when label is clicked", () => {
|
|
79
|
+
const handleClick = vi.fn();
|
|
80
|
+
render(<Checkbox id="checkbox-click" onClick={handleClick} name="checkbox-click" />);
|
|
81
|
+
const checkbox = screen.getByTestId("checkbox");
|
|
82
|
+
fireEvent.click(checkbox);
|
|
83
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const ringPadding = {
|
|
2
|
+
sm: "p-1",
|
|
3
|
+
md: "p-[5px]",
|
|
4
|
+
lg: "p-1.5",
|
|
5
|
+
};
|
|
6
|
+
export interface CommonCheckboxProps {
|
|
7
|
+
id?: string; // required string
|
|
8
|
+
name: string; // required string for form control
|
|
9
|
+
checkboxIndex?: number; // required number
|
|
10
|
+
checked?: boolean; // required
|
|
11
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void; // required
|
|
12
|
+
size?: "sm" | "md" | "lg";
|
|
13
|
+
type?: "radio" | "checkbox";
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface CheckboxProps extends CommonCheckboxProps {
|
|
17
|
+
defaultChecked?: boolean;
|
|
18
|
+
label?: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
onClick?: () => void;
|
|
21
|
+
children?: React.ReactNode;
|
|
22
|
+
isIndeterminate?: boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import Minus from "@/icons/general/minus";
|
|
2
|
+
import TickBox from "@/icons/general/tick-box";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { checkboxVariants } from "./_.style";
|
|
6
|
+
import { CheckboxProps, ringPadding } from "./_.types";
|
|
7
|
+
|
|
8
|
+
export const Checkbox = ({
|
|
9
|
+
size = "sm",
|
|
10
|
+
children,
|
|
11
|
+
id,
|
|
12
|
+
disabled = false,
|
|
13
|
+
checkboxIndex = 1,
|
|
14
|
+
isIndeterminate = false,
|
|
15
|
+
checked,
|
|
16
|
+
onChange,
|
|
17
|
+
onClick,
|
|
18
|
+
defaultChecked,
|
|
19
|
+
name,
|
|
20
|
+
label,
|
|
21
|
+
...props
|
|
22
|
+
}: Readonly<CheckboxProps>) => {
|
|
23
|
+
const checkboxRef = useRef<HTMLInputElement | null>(null);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (checkboxRef.current) {
|
|
27
|
+
checkboxRef.current.indeterminate = isIndeterminate;
|
|
28
|
+
}
|
|
29
|
+
}, [isIndeterminate]);
|
|
30
|
+
|
|
31
|
+
// for handling label text click
|
|
32
|
+
function handleCheckText() {
|
|
33
|
+
if (checkboxRef.current && !disabled) {
|
|
34
|
+
checkboxRef.current.click();
|
|
35
|
+
checkboxRef.current.focus();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const strokeColor = disabled ? "#D0D5DD" : "white";
|
|
39
|
+
let icon = null as React.ReactNode;
|
|
40
|
+
if (disabled) {
|
|
41
|
+
if (checked) {
|
|
42
|
+
icon = isIndeterminate ? (
|
|
43
|
+
<Minus stroke={strokeColor} />
|
|
44
|
+
) : (
|
|
45
|
+
<TickBox stroke={strokeColor} />
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
icon = isIndeterminate ? (
|
|
50
|
+
<Minus stroke={strokeColor} />
|
|
51
|
+
) : (
|
|
52
|
+
<TickBox stroke={strokeColor} />
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
<div className="flex items-center cursor-pointer gap-2 justify-start">
|
|
57
|
+
<input
|
|
58
|
+
type="checkbox"
|
|
59
|
+
data-testid="checkbox"
|
|
60
|
+
id={id}
|
|
61
|
+
ref={checkboxRef}
|
|
62
|
+
onChange={(e) => !disabled && onChange && onChange(e)}
|
|
63
|
+
onClick={onClick}
|
|
64
|
+
disabled={disabled}
|
|
65
|
+
checked={checked}
|
|
66
|
+
defaultChecked={defaultChecked}
|
|
67
|
+
className="peer hidden"
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
<label
|
|
71
|
+
htmlFor={id ?? name}
|
|
72
|
+
tabIndex={checkboxIndex}
|
|
73
|
+
className={cn(
|
|
74
|
+
checkboxVariants({ size, disabled }),
|
|
75
|
+
`${disabled && "!bg-rbg-disabled !border-rborder-primary"} `
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<div
|
|
79
|
+
className={`${ringPadding[size]} ${
|
|
80
|
+
!disabled && "group-focus-within:border-2 border-rbg-brand-solid "
|
|
81
|
+
} flex items-center justify-center rounded-md`}
|
|
82
|
+
>
|
|
83
|
+
{icon}
|
|
84
|
+
</div>
|
|
85
|
+
</label>
|
|
86
|
+
{(children ?? label) && (
|
|
87
|
+
<div className="leading-none" onClick={() => handleCheckText()}>
|
|
88
|
+
{children ?? label}
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import IconWrapper from "@/components/ui/icon-wrapper";
|
|
2
|
+
import MasterCard from "@/icons/general/master-card";
|
|
3
|
+
import { Meta, StoryFn } from "@storybook/react-vite";
|
|
4
|
+
import { ReactNode } from "react";
|
|
5
|
+
import { PaymentCard } from ".";
|
|
6
|
+
|
|
7
|
+
// Define the types for the args
|
|
8
|
+
interface PaymentCardArgs {
|
|
9
|
+
checked?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
size?: "sm" | "md";
|
|
12
|
+
type?: "radio" | "checkbox";
|
|
13
|
+
hasHeader?: boolean;
|
|
14
|
+
title: string;
|
|
15
|
+
description: string;
|
|
16
|
+
value?: string;
|
|
17
|
+
footer: ReactNode;
|
|
18
|
+
icon: ReactNode;
|
|
19
|
+
cardOnclick?: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Default export for Storybook to associate this with the component
|
|
23
|
+
export default {
|
|
24
|
+
title: "Components/PaymentCard",
|
|
25
|
+
component: PaymentCard,
|
|
26
|
+
argTypes: {
|
|
27
|
+
checked: { control: "boolean" },
|
|
28
|
+
disabled: { control: "boolean" },
|
|
29
|
+
size: {
|
|
30
|
+
control: {
|
|
31
|
+
type: "select",
|
|
32
|
+
options: ["sm", "md"],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
hasHeader: { control: "boolean" },
|
|
36
|
+
title: { control: "text" },
|
|
37
|
+
description: { control: "text" },
|
|
38
|
+
value: { control: "text" },
|
|
39
|
+
footer: { control: "text" },
|
|
40
|
+
icon: { control: "text" },
|
|
41
|
+
},
|
|
42
|
+
} as Meta;
|
|
43
|
+
|
|
44
|
+
// Template function for stories using StoryFn
|
|
45
|
+
const Template: StoryFn<PaymentCardArgs> = (args) => {
|
|
46
|
+
const footer: ReactNode = (
|
|
47
|
+
<div className="text-xs text-gray-500">Footer Content</div>
|
|
48
|
+
);
|
|
49
|
+
const icon: ReactNode = (
|
|
50
|
+
<IconWrapper className="!h-8 !w-[46px]" data-testid="icon-wrapper">
|
|
51
|
+
<MasterCard />
|
|
52
|
+
</IconWrapper>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<PaymentCard
|
|
57
|
+
title={args.title}
|
|
58
|
+
description={args.description}
|
|
59
|
+
value={args.value}
|
|
60
|
+
footer={footer}
|
|
61
|
+
icon={icon}
|
|
62
|
+
checked={args.checked}
|
|
63
|
+
type={args.type}
|
|
64
|
+
size={args.size}
|
|
65
|
+
disabled={args.disabled}
|
|
66
|
+
onChange={() => { }}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Story with Header
|
|
72
|
+
export const Default = Template.bind({});
|
|
73
|
+
Default.args = {
|
|
74
|
+
title: "Premium Plan",
|
|
75
|
+
description: "Description for the premium plan",
|
|
76
|
+
value: "premium-plan",
|
|
77
|
+
checked: true,
|
|
78
|
+
size: "md",
|
|
79
|
+
disabled: false,
|
|
80
|
+
type: "checkbox",
|
|
81
|
+
hasHeader: true, // This will enable the header in the PaymentCard
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Story with Disabled State
|
|
85
|
+
export const Disabled = Template.bind({});
|
|
86
|
+
Disabled.args = {
|
|
87
|
+
title: "Disabled Plan",
|
|
88
|
+
description: "Description for the disabled plan",
|
|
89
|
+
value: "disabled-plan",
|
|
90
|
+
checked: false,
|
|
91
|
+
size: "md",
|
|
92
|
+
disabled: true, // This will disable the PaymentCard
|
|
93
|
+
hasHeader: false,
|
|
94
|
+
};
|
|
95
|
+
// Story with Header
|
|
96
|
+
export const RadioCard = Template.bind({});
|
|
97
|
+
RadioCard.args = {
|
|
98
|
+
title: "Premium Plan",
|
|
99
|
+
description: "Description for the premium plan",
|
|
100
|
+
value: "premium-plan",
|
|
101
|
+
size: "md",
|
|
102
|
+
disabled: false,
|
|
103
|
+
type: "radio",
|
|
104
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const textSizeStyle = {
|
|
2
|
+
sm: "text-sm",
|
|
3
|
+
md: "text-md",
|
|
4
|
+
};
|
|
5
|
+
const labelBaseClass = `
|
|
6
|
+
rounded-2xl md:w-3xl text-md h-fit min-w-[343px] text-rtext-tertiary-600 flex gap-2 cursor-pointer
|
|
7
|
+
border-2 border-rborder-secondary rounded-2xl`;
|
|
8
|
+
|
|
9
|
+
export const paymentCardStyles = ({
|
|
10
|
+
checked,
|
|
11
|
+
disabled,
|
|
12
|
+
size,
|
|
13
|
+
hasHeader,
|
|
14
|
+
}: {
|
|
15
|
+
checked?: boolean;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
hasHeader?: boolean;
|
|
18
|
+
size?: "md" | "sm";
|
|
19
|
+
}) => {
|
|
20
|
+
return {
|
|
21
|
+
label: ` ${labelBaseClass} ${hasHeader ? "flex-col" : "p-4"} ${size && textSizeStyle[size]
|
|
22
|
+
} ${disabled
|
|
23
|
+
? "bg-rbg-disabled-subtle"
|
|
24
|
+
: "group"
|
|
25
|
+
} ${checked ? "!border-rbg-brand-solid" : ""}`,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
2
|
+
import { describe, it, expect, vi } from "vitest";
|
|
3
|
+
import { PaymentCard } from ".";
|
|
4
|
+
|
|
5
|
+
describe("PaymentCard", () => {
|
|
6
|
+
const baseProps = {
|
|
7
|
+
id: "test-card",
|
|
8
|
+
title: "Test Title",
|
|
9
|
+
description: "Test Description",
|
|
10
|
+
checked: true,
|
|
11
|
+
value: "test-value",
|
|
12
|
+
name: "test-name",
|
|
13
|
+
footer: <div data-testid="footer">Footer Content</div>,
|
|
14
|
+
icon: <span data-testid="icon">Icon</span>,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
it("renders title and description", () => {
|
|
18
|
+
render(<PaymentCard {...baseProps} />);
|
|
19
|
+
expect(screen.getByText("Test Title")).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText("Test Description")).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders a checkbox by default", () => {
|
|
24
|
+
render(<PaymentCard {...baseProps} type="checkbox" />);
|
|
25
|
+
expect(screen.getByRole("checkbox")).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("renders a radio when type is 'radio'", () => {
|
|
29
|
+
render(<PaymentCard {...baseProps} type="radio" />);
|
|
30
|
+
expect(screen.getByRole("radio")).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("calls onChange when input is clicked", () => {
|
|
34
|
+
const onChange = vi.fn();
|
|
35
|
+
render(<PaymentCard {...baseProps} onChange={onChange} />);
|
|
36
|
+
fireEvent.click(screen.getByRole("checkbox"));
|
|
37
|
+
expect(onChange).toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("calls cardOnclick when the card is clicked", () => {
|
|
41
|
+
const cardOnclick = vi.fn();
|
|
42
|
+
render(<PaymentCard {...baseProps} cardOnclick={cardOnclick} />);
|
|
43
|
+
// Target the label element itself, not just the title
|
|
44
|
+
fireEvent.click(screen.getByText("Test Title"));
|
|
45
|
+
expect(cardOnclick).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("disables input when disabled prop is true", () => {
|
|
49
|
+
render(<PaymentCard {...baseProps} disabled={true} />);
|
|
50
|
+
expect(screen.getByRole("checkbox")).toBeDisabled();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("renders custom icon and footer", () => {
|
|
54
|
+
render(<PaymentCard {...baseProps} />);
|
|
55
|
+
expect(screen.getByTestId("icon")).toBeInTheDocument();
|
|
56
|
+
expect(screen.getByTestId("footer")).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export const ringPadding = {
|
|
4
|
+
sm: "p-1",
|
|
5
|
+
md: "p-[5px]",
|
|
6
|
+
lg: "p-1.5",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface CommonCheckboxProps {
|
|
10
|
+
id?: string; // required string
|
|
11
|
+
checkboxIndex?: number; // required number
|
|
12
|
+
checked?: boolean; // required
|
|
13
|
+
size?: "sm" | "md";
|
|
14
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void; // required
|
|
15
|
+
inputProps?: object;
|
|
16
|
+
type?: "radio" | "checkbox";
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface paymentCardProps extends CommonCheckboxProps {
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
value?: string;
|
|
24
|
+
footer: ReactNode;
|
|
25
|
+
icon: ReactNode;
|
|
26
|
+
name?: string;
|
|
27
|
+
cardOnclick?: () => void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Checkbox } from "@/components/Checkbox";
|
|
2
|
+
import { Radio } from "@/components/Radio";
|
|
3
|
+
import { paymentCardStyles } from "./_.style";
|
|
4
|
+
import { paymentCardProps } from "./_.types";
|
|
5
|
+
|
|
6
|
+
export const PaymentCard = ({
|
|
7
|
+
size = "sm",
|
|
8
|
+
title = "",
|
|
9
|
+
description,
|
|
10
|
+
checked,
|
|
11
|
+
disabled,
|
|
12
|
+
id,
|
|
13
|
+
value = "",
|
|
14
|
+
footer,
|
|
15
|
+
icon,
|
|
16
|
+
type = "checkbox",
|
|
17
|
+
onChange,
|
|
18
|
+
name = "",
|
|
19
|
+
cardOnclick,
|
|
20
|
+
inputProps,
|
|
21
|
+
checkboxIndex,
|
|
22
|
+
}: Readonly<paymentCardProps>) => {
|
|
23
|
+
const styles = paymentCardStyles({
|
|
24
|
+
checked,
|
|
25
|
+
disabled,
|
|
26
|
+
size,
|
|
27
|
+
});
|
|
28
|
+
return (
|
|
29
|
+
<label
|
|
30
|
+
onClick={cardOnclick}
|
|
31
|
+
htmlFor={id}
|
|
32
|
+
tabIndex={checkboxIndex}
|
|
33
|
+
className={styles.label}
|
|
34
|
+
>
|
|
35
|
+
{icon}
|
|
36
|
+
<div className="flex flex-col gap-3 grow justify-between">
|
|
37
|
+
<div className="flex flex-col">
|
|
38
|
+
<h3 className="font-medium text-foreground text-rtext-secondary-700">
|
|
39
|
+
{title}
|
|
40
|
+
</h3>
|
|
41
|
+
|
|
42
|
+
<span className="text-rtext-tertiary-600">{description}</span>
|
|
43
|
+
</div>
|
|
44
|
+
{footer}
|
|
45
|
+
</div>
|
|
46
|
+
<div className="flex items-start gap-2">
|
|
47
|
+
{type === "radio" ? (
|
|
48
|
+
<Radio
|
|
49
|
+
onChange={onChange}
|
|
50
|
+
checked={checked}
|
|
51
|
+
disabled={disabled}
|
|
52
|
+
value={value}
|
|
53
|
+
name={name}
|
|
54
|
+
size={size}
|
|
55
|
+
id={id}
|
|
56
|
+
{...inputProps}
|
|
57
|
+
/>
|
|
58
|
+
) : (
|
|
59
|
+
<Checkbox
|
|
60
|
+
{...inputProps}
|
|
61
|
+
disabled={disabled}
|
|
62
|
+
id={id}
|
|
63
|
+
name={name}
|
|
64
|
+
onChange={onChange}
|
|
65
|
+
size={size}
|
|
66
|
+
/>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
</label>
|
|
70
|
+
);
|
|
71
|
+
};
|