react-restyle-components 0.1.59 → 0.1.60
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/lib/package.json +4 -5
- package/package.json +5 -6
- package/src/App.css +38 -0
- package/src/App.test.tsx +9 -0
- package/src/App.tsx +26 -0
- package/src/core-components/atoms/buttons/button.stories.tsx +42 -0
- package/src/core-components/atoms/buttons/buttons.component.tsx +33 -0
- package/src/core-components/atoms/buttons/buttons.test.tsx +13 -0
- package/src/core-components/atoms/check-box/checkBox.component.tsx +54 -0
- package/src/core-components/atoms/check-box/checkBox.stories.tsx +29 -0
- package/src/core-components/atoms/check-box/checkBox.test.tsx +11 -0
- package/src/core-components/atoms/date-picker/date-picker.component.tsx +60 -0
- package/src/core-components/atoms/date-picker/date-picker.stories.tsx +23 -0
- package/src/core-components/atoms/date-picker/date-picker.test.tsx +17 -0
- package/src/core-components/atoms/form/form.component.tsx +604 -0
- package/src/core-components/atoms/form/form.test.tsx +120 -0
- package/src/core-components/atoms/icons/icons.component.tsx +65 -0
- package/src/core-components/atoms/icons/icons.stories.tsx +24 -0
- package/src/core-components/atoms/icons/icons.test.tsx +15 -0
- package/src/core-components/atoms/input/input-otp.component.tsx +107 -0
- package/src/core-components/atoms/input/input-otp.styles.css +35 -0
- package/src/core-components/atoms/input/input-pin.component.tsx +144 -0
- package/src/core-components/atoms/input/input-pin.stories.tsx +25 -0
- package/src/core-components/atoms/input/input-pin.test.tsx +30 -0
- package/src/core-components/atoms/input/input.component.tsx +74 -0
- package/src/core-components/atoms/input/input.stories.tsx +26 -0
- package/src/core-components/atoms/input/input.styles.css +35 -0
- package/src/core-components/atoms/input/input.test.tsx +32 -0
- package/src/core-components/atoms/input-dropdown/input-dropdown.component.tsx +91 -0
- package/src/core-components/atoms/input-dropdown/input-dropdown.stories.tsx +22 -0
- package/src/core-components/atoms/input-dropdown/input-dropdown.test.tsx +16 -0
- package/src/core-components/atoms/loader/loader.component.tsx +78 -0
- package/src/core-components/atoms/loader/loader.stories.tsx +18 -0
- package/src/core-components/atoms/loader/loader.test.tsx +9 -0
- package/src/core-components/atoms/radio/radio.component.tsx +48 -0
- package/src/core-components/atoms/radio/radio.stories.tsx +27 -0
- package/src/core-components/atoms/radio/radio.test.tsx +11 -0
- package/src/core-components/atoms/stepper/stepper.component.tsx +72 -0
- package/src/core-components/atoms/stepper/stepper.stories.tsx +23 -0
- package/src/core-components/atoms/stepper/stepper.test.tsx +14 -0
- package/src/core-components/atoms/tabs/tabs.component.tsx +41 -0
- package/src/core-components/atoms/tabs/tabs.stories.tsx +27 -0
- package/src/core-components/atoms/tabs/tabs.test.tsx +19 -0
- package/src/core-components/atoms/timer/timer.component.tsx +89 -0
- package/src/core-components/atoms/timer/timer.test.tsx +16 -0
- package/src/core-components/atoms/tooltip/tooltip.component.test.tsx +10 -0
- package/src/core-components/atoms/tooltip/tooltip.component.tsx +54 -0
- package/src/core-components/atoms/tooltip/tooltip.stories.tsx +18 -0
- package/src/core-components/index.ts +21 -0
- package/src/core-components/molecules/auto-complete-filter-multiple-select-multiple-fields-display/auto-complete-filter-multiple-select-multiple-fields-display.component.test.tsx +18 -0
- package/src/core-components/molecules/auto-complete-filter-multiple-select-multiple-fields-display/auto-complete-filter-multiple-select-multiple-fields-display.component.tsx +182 -0
- package/src/core-components/molecules/auto-complete-filter-multiple-select-multiple-fields-display/auto-complete-filter-multiple-select-multiple-fields-display.stories.tsx +55 -0
- package/src/core-components/molecules/auto-complete-filter-single-select-multiple-fields-display/auto-complete-filter-single-select-multiple-fields-display.component.test.tsx +23 -0
- package/src/core-components/molecules/auto-complete-filter-single-select-multiple-fields-display/auto-complete-filter-single-select-multiple-fields-display.component.tsx +190 -0
- package/src/core-components/molecules/auto-complete-filter-single-select-multiple-fields-display/auto-complete-filter-single-select-multiple-fields-display.stories.tsx +35 -0
- package/src/core-components/molecules/css-multiline-input/css-multiline-input.component.tsx +135 -0
- package/src/core-components/molecules/css-multiline-input/css-multiline-input.stories.tsx +18 -0
- package/src/core-components/molecules/css-multiline-input/css-multiline-input.test.tsx +11 -0
- package/src/core-components/molecules/css-multiline-input/css-properties.ts +177 -0
- package/src/core-utils/index.ts +1 -0
- package/src/core-utils/unit-test.utils.tsx +12 -0
- package/src/custom.d.ts +4 -0
- package/src/index.css +17 -0
- package/src/index.ts +1 -0
- package/src/index.tsx +18 -0
- package/src/library/assets/svg/DownArrow.svg +14 -0
- package/src/library/assets/svg/UpArrow.svg +14 -0
- package/src/library/assets/svg/checkedBox.svg +14 -0
- package/src/library/assets/svg/checkedRadio.svg +13 -0
- package/src/library/assets/svg/datePicker.svg +3 -0
- package/src/library/assets/svg/index.ts +38 -0
- package/src/library/assets/svg/timer copy.svg +3 -0
- package/src/library/assets/svg/timer.svg +3 -0
- package/src/library/assets/svg/unCheckbox.svg +3 -0
- package/src/library/assets/svg/uncheckRadio.svg +3 -0
- package/src/logo.svg +1 -0
- package/src/react-app-env.d.ts +1 -0
- package/src/reportWebVitals.ts +16 -0
- package/src/setupTests.ts +5 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.-z-1 {
|
|
2
|
+
z-index: -1;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.origin-0 {
|
|
6
|
+
transform-origin: 0%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
input:focus ~ label,
|
|
10
|
+
input:not(:placeholder-shown) ~ label,
|
|
11
|
+
textarea:focus ~ label,
|
|
12
|
+
textarea:not(:placeholder-shown) ~ label,
|
|
13
|
+
select:focus ~ label,
|
|
14
|
+
select:not([value=""]):valid ~ label {
|
|
15
|
+
/* @apply transform; scale-75; -translate-y-6; */
|
|
16
|
+
--tw-translate-x: 0;
|
|
17
|
+
--tw-translate-y: 0;
|
|
18
|
+
--tw-rotate: 0;
|
|
19
|
+
--tw-skew-x: 0;
|
|
20
|
+
--tw-skew-y: 0;
|
|
21
|
+
transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))
|
|
22
|
+
rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y))
|
|
23
|
+
scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
24
|
+
--tw-scale-x: 0.75;
|
|
25
|
+
--tw-scale-y: 0.75;
|
|
26
|
+
--tw-translate-y: -1.5rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
input:focus ~ label,
|
|
30
|
+
select:focus ~ label {
|
|
31
|
+
/* @apply text-black; left-0; */
|
|
32
|
+
--tw-text-opacity: 1;
|
|
33
|
+
color: "#696969";
|
|
34
|
+
left: 0px;
|
|
35
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable testing-library/render-result-naming-convention */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {render} from '@core-utils';
|
|
4
|
+
import {Input} from './input.component';
|
|
5
|
+
|
|
6
|
+
it('render Input correctly without error', () => {
|
|
7
|
+
const input = render(
|
|
8
|
+
<Input
|
|
9
|
+
className="h-1 relative top-1 border-red-600 border-b-0 dummy"
|
|
10
|
+
title={'input'}
|
|
11
|
+
hasError={false}
|
|
12
|
+
defaultValue={''}
|
|
13
|
+
inputStyle=" border-b-0 invisible "
|
|
14
|
+
onChange={() => jest.fn()}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
expect(input).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('render Input correctly with error', () => {
|
|
21
|
+
const input = render(
|
|
22
|
+
<Input
|
|
23
|
+
className="h-1 relative top-1 border-red-600 border-b-0 dummy"
|
|
24
|
+
title={'input'}
|
|
25
|
+
hasError={true}
|
|
26
|
+
defaultValue={''}
|
|
27
|
+
inputStyle=" border-b-0 invisible "
|
|
28
|
+
onChange={() => jest.fn()}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
expect(input).toMatchSnapshot();
|
|
32
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, {useState, useEffect, useRef} from 'react';
|
|
2
|
+
import {UpArrow, DownArrow} from '../../../library/assets/svg';
|
|
3
|
+
interface InputDropdownProps {
|
|
4
|
+
title: string;
|
|
5
|
+
items: Array<string>;
|
|
6
|
+
hasError?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
onChange?: (item: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const InputDropdown = ({
|
|
12
|
+
items,
|
|
13
|
+
className,
|
|
14
|
+
hasError,
|
|
15
|
+
title,
|
|
16
|
+
onChange,
|
|
17
|
+
}: InputDropdownProps) => {
|
|
18
|
+
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
19
|
+
const [value, setValue] = useState<string>('');
|
|
20
|
+
|
|
21
|
+
const useOutsideAlerter = (ref) => {
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
function handleClickOutside(event) {
|
|
24
|
+
if (
|
|
25
|
+
ref.current &&
|
|
26
|
+
!ref.current.contains(event.target) &&
|
|
27
|
+
isOpen &&
|
|
28
|
+
isOpen
|
|
29
|
+
)
|
|
30
|
+
setIsOpen(!isOpen);
|
|
31
|
+
}
|
|
32
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
33
|
+
return () => {
|
|
34
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
35
|
+
};
|
|
36
|
+
}, [ref]);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const wrapperRef = useRef(null);
|
|
40
|
+
useOutsideAlerter(wrapperRef);
|
|
41
|
+
return (
|
|
42
|
+
<div className={`${className} relative`}>
|
|
43
|
+
<div className="flex flex-row items-center ">
|
|
44
|
+
<input
|
|
45
|
+
type="text"
|
|
46
|
+
name="name"
|
|
47
|
+
placeholder={title}
|
|
48
|
+
value={value}
|
|
49
|
+
className=" pt-3 pb-2 w-full px-0 mt-0 bg-transparent border-gray-secondary border-0 border-b appearance-none focus:outline-none focus:ring-0 font-nunitoSansRegular text-md"
|
|
50
|
+
onClick={() => {
|
|
51
|
+
setIsOpen(!isOpen);
|
|
52
|
+
}}
|
|
53
|
+
onChange={(event) => onChange && onChange(event.target.value)}
|
|
54
|
+
/>
|
|
55
|
+
{!isOpen && (
|
|
56
|
+
<img src={UpArrow as any} className="absolute h-4 w-4 right-0" />
|
|
57
|
+
)}
|
|
58
|
+
{isOpen && (
|
|
59
|
+
<img src={DownArrow as any} className="absolute h-4 w-4 right-0" />
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
{isOpen && (
|
|
63
|
+
<div
|
|
64
|
+
className="z-10 w-full absolute text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
|
|
65
|
+
ref={wrapperRef}
|
|
66
|
+
>
|
|
67
|
+
<ul className="py-1">
|
|
68
|
+
{items.map((item, index) => (
|
|
69
|
+
<li
|
|
70
|
+
key={index}
|
|
71
|
+
className="block py-2 px-4 text-md hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 font-nunitoSansRegular"
|
|
72
|
+
onClick={() => {
|
|
73
|
+
setValue(item);
|
|
74
|
+
setIsOpen(!isOpen);
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{item}
|
|
78
|
+
</li>
|
|
79
|
+
))}
|
|
80
|
+
</ul>
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
|
|
84
|
+
{hasError && (
|
|
85
|
+
<span className="text-primaryCharcoal text-4xs" id="error">
|
|
86
|
+
{`${title} is required`}
|
|
87
|
+
</span>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
+
import {InputDropdown} from './input-dropdown.component';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof InputDropdown> = {
|
|
6
|
+
title: 'Design System/Atoms/InputDropdown',
|
|
7
|
+
component: InputDropdown,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
componentSubtitle: `import { InputDropdown } from 'react-restyle-components'`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof InputDropdown>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
title: 'Source of funds',
|
|
19
|
+
items: ['Bank account', 'UPI', 'Credit Card'],
|
|
20
|
+
hasError: true,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable testing-library/render-result-naming-convention */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {render} from '@core-utils';
|
|
4
|
+
import {InputDropdown} from './input-dropdown.component';
|
|
5
|
+
|
|
6
|
+
it('render InputDropdown correctly', () => {
|
|
7
|
+
const inputDropDown = render(
|
|
8
|
+
<InputDropdown
|
|
9
|
+
title="Source of funds"
|
|
10
|
+
items={['Bank account', 'UPI', 'Credit Card']}
|
|
11
|
+
hasError={true}
|
|
12
|
+
onChange={() => jest.fn()}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
expect(inputDropDown).toMatchSnapshot();
|
|
16
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {Container, Row, Spinner} from 'reactstrap';
|
|
3
|
+
|
|
4
|
+
export const Loader = () => (
|
|
5
|
+
<Container fluid className="vh-50 d-flex">
|
|
6
|
+
<Row className="justify-content-center align-self-center w-100 text-center">
|
|
7
|
+
<Spinner color="primary" />
|
|
8
|
+
</Row>
|
|
9
|
+
</Container>
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export const ModalLoader = () => {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<>
|
|
16
|
+
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
|
|
17
|
+
<div className="relative mx-auto ">
|
|
18
|
+
{/*content*/}
|
|
19
|
+
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
|
|
20
|
+
{/*body*/}
|
|
21
|
+
<div className="relative p-2 flex-auto flex flex-col items-center">
|
|
22
|
+
<style>
|
|
23
|
+
{`
|
|
24
|
+
.spinner .background {
|
|
25
|
+
fill: #555;
|
|
26
|
+
}
|
|
27
|
+
.spinner .line {
|
|
28
|
+
animation: PacMan 5s infinite;
|
|
29
|
+
fill: none;
|
|
30
|
+
stroke: #d26188;
|
|
31
|
+
stroke-width: 25;
|
|
32
|
+
}
|
|
33
|
+
.spinner .spinner {
|
|
34
|
+
animation: Spin 2s infinite linear;
|
|
35
|
+
}
|
|
36
|
+
@keyframes PacMan {
|
|
37
|
+
0% {
|
|
38
|
+
stroke-dasharray: 79px 79;
|
|
39
|
+
}
|
|
40
|
+
50% {
|
|
41
|
+
stroke-dasharray: 1px 79;
|
|
42
|
+
}
|
|
43
|
+
100% {
|
|
44
|
+
stroke-dasharray: 79px 79;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
@keyframes Spin {
|
|
48
|
+
0% {
|
|
49
|
+
transform: rotate(0deg);
|
|
50
|
+
}
|
|
51
|
+
100% {
|
|
52
|
+
transform: rotate(360deg);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`}
|
|
56
|
+
</style>
|
|
57
|
+
<svg
|
|
58
|
+
className="spinner"
|
|
59
|
+
width="100"
|
|
60
|
+
height="100"
|
|
61
|
+
viewBox="0 0 100 100"
|
|
62
|
+
>
|
|
63
|
+
<circle className="background" cx="0" cy="0"></circle>
|
|
64
|
+
<path
|
|
65
|
+
className="line"
|
|
66
|
+
d="M 37.5,50 C 37.5,43.096441 43.096441,37.5 50,37.5 C 56.903559,37.5 62.5,43.096441 62.5,50 C 62.5,56.903559 56.903559,62.5 50,62.5 C 43.096441,62.5 37.5,56.903559 37.5,50"
|
|
67
|
+
></path>
|
|
68
|
+
</svg>{' '}
|
|
69
|
+
<span style={{marginTop: -15}}>loading ...</span>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
|
|
75
|
+
</>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
+
import {Loader} from './loader.component';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Loader> = {
|
|
6
|
+
title: 'Design System/Atoms/Loader',
|
|
7
|
+
component: Loader,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
componentSubtitle: `import { Loader } from 'react-restyle-components'`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Loader>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {},
|
|
18
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* eslint-disable testing-library/render-result-naming-convention */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {render} from '@core-utils';
|
|
4
|
+
import {Loader} from './loader.component';
|
|
5
|
+
|
|
6
|
+
it('render Loader correctly', () => {
|
|
7
|
+
const loader = render(<Loader />);
|
|
8
|
+
expect(loader).toMatchSnapshot();
|
|
9
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import {CheckedRadio, UncheckRadio} from '../../../library/assets/svg';
|
|
3
|
+
import {InputWrapper} from '../form/form.component';
|
|
4
|
+
interface RadioProps {
|
|
5
|
+
title: string;
|
|
6
|
+
data: Array<any>;
|
|
7
|
+
className?: string;
|
|
8
|
+
onChange: (item) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Radio = ({
|
|
12
|
+
title = 'Source',
|
|
13
|
+
data = [],
|
|
14
|
+
className,
|
|
15
|
+
onChange,
|
|
16
|
+
}: RadioProps) => {
|
|
17
|
+
const [list, setList] = useState<any>(data);
|
|
18
|
+
const width = 20;
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<InputWrapper label={title}>
|
|
22
|
+
{list?.map((item, index) => (
|
|
23
|
+
<div
|
|
24
|
+
className={`${className} flex items-center mb-1`}
|
|
25
|
+
onClick={() => {
|
|
26
|
+
const result = list?.map((e, i) => {
|
|
27
|
+
if (i == index) return {...e, checked: true};
|
|
28
|
+
else return {...e, checked: false};
|
|
29
|
+
});
|
|
30
|
+
setList(result);
|
|
31
|
+
onChange(result?.find((item) => item.checked));
|
|
32
|
+
}}
|
|
33
|
+
key={index}
|
|
34
|
+
>
|
|
35
|
+
<div className="flex flex-row gap-1 items-center">
|
|
36
|
+
{item.checked ? (
|
|
37
|
+
<CheckedRadio width={width} height={width} />
|
|
38
|
+
) : (
|
|
39
|
+
<UncheckRadio width={width} height={width} />
|
|
40
|
+
)}
|
|
41
|
+
<span className="text-4xs">{item?.title}</span>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
))}
|
|
45
|
+
</InputWrapper>
|
|
46
|
+
</>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
+
import {Radio} from './radio.component';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Radio> = {
|
|
6
|
+
title: 'Design System/Atoms/Radio',
|
|
7
|
+
component: Radio,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
componentSubtitle: `import { Radio } from 'react-restyle-components'`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Radio>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
title: 'Source',
|
|
19
|
+
data: [
|
|
20
|
+
{title: 'Salary', checked: false},
|
|
21
|
+
{title: 'Business', checked: false},
|
|
22
|
+
],
|
|
23
|
+
onChange: (item) => {
|
|
24
|
+
console.log({item});
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* eslint-disable testing-library/render-result-naming-convention */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {render} from '@core-utils';
|
|
4
|
+
import {Radio} from './radio.component';
|
|
5
|
+
|
|
6
|
+
it('render Radio correctly', () => {
|
|
7
|
+
const radio = render(
|
|
8
|
+
<Radio title="Title" data={[]} onChange={() => jest.fn()} />
|
|
9
|
+
);
|
|
10
|
+
expect(radio).toMatchSnapshot();
|
|
11
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface StepperProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
steps: Array<string>;
|
|
6
|
+
currentStep: number;
|
|
7
|
+
onStepClick: (currentStep, index) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Stepper = ({
|
|
11
|
+
className = '',
|
|
12
|
+
steps,
|
|
13
|
+
currentStep = 1,
|
|
14
|
+
onStepClick,
|
|
15
|
+
}: StepperProps) => {
|
|
16
|
+
const finalClass = `${className} w-full px-4 sm:px-8`;
|
|
17
|
+
const progressClass =
|
|
18
|
+
'absolute my-4 top-1/2 left-0 h-0.5 transform -translate-y-1/2 bg-orange transition-width ease-in-out duration-500';
|
|
19
|
+
const Steps = steps?.map((step, index) => {
|
|
20
|
+
let stepClass =
|
|
21
|
+
'inline-block transform -translate-x-1/2 pt-1 w-8 h-8 rounded-full text-center';
|
|
22
|
+
if (index < currentStep)
|
|
23
|
+
stepClass +=
|
|
24
|
+
' font-medium border border-orange bg-background-secondary text-gray';
|
|
25
|
+
else if (index > currentStep)
|
|
26
|
+
stepClass +=
|
|
27
|
+
' font-medium border border-gray-dark-secondary text-gray bg-background-secondary';
|
|
28
|
+
else if (currentStep === index)
|
|
29
|
+
stepClass += ' font-medium bg-orange text-white';
|
|
30
|
+
if (typeof onStepClick === 'function') stepClass += ' cursor-pointer';
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
key={step}
|
|
34
|
+
style={{left: `${(index / (steps.length - 1)) * 100}%`}}
|
|
35
|
+
className="absolute"
|
|
36
|
+
>
|
|
37
|
+
<span
|
|
38
|
+
className={`${stepClass} font-nunitoSansRegular text-4xs text-center`}
|
|
39
|
+
onClick={() => {
|
|
40
|
+
if (typeof onStepClick === 'function') onStepClick(index + 1, step);
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
{step}
|
|
44
|
+
</span>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
return (
|
|
49
|
+
<div className={finalClass}>
|
|
50
|
+
<div className="w-full relative">
|
|
51
|
+
<div
|
|
52
|
+
className={progressClass}
|
|
53
|
+
style={{
|
|
54
|
+
width: `${(currentStep / (steps.length - 1)) * 100}%`,
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
<div className="w-3 h-3 bg-orange rounded-full absolute right-0 top-1/2 transform translate-x-1/2 -translate-y-1/2" />
|
|
58
|
+
</div>
|
|
59
|
+
<div
|
|
60
|
+
className={
|
|
61
|
+
'absolute h-0.5 my-4 top-1/2 left-0 transform -translate-y-1/2 bg-gray-dark-secondary transition-width ease-in-out duration-500'
|
|
62
|
+
}
|
|
63
|
+
style={{
|
|
64
|
+
marginLeft: `${(currentStep / (steps.length - 1)) * 100}%`,
|
|
65
|
+
width: `${100 - (currentStep / (steps.length - 1)) * 100}%`,
|
|
66
|
+
}}
|
|
67
|
+
></div>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="relative sm:block">{Steps}</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
+
import {Stepper} from './stepper.component';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Stepper> = {
|
|
6
|
+
title: 'Design System/Atoms/Stepper',
|
|
7
|
+
component: Stepper,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
componentSubtitle: `import { Stepper } from 'react-restyle-components'`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Stepper>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
steps: ['1', '2', '3', '4'],
|
|
19
|
+
currentStep: 2,
|
|
20
|
+
onStepClick: (currentStep, step) => {},
|
|
21
|
+
className: 'mt-4',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {render} from '@core-utils';
|
|
3
|
+
import {Stepper} from './stepper.component';
|
|
4
|
+
it('render Stepper correctly', () => {
|
|
5
|
+
const stepper = render(
|
|
6
|
+
<Stepper
|
|
7
|
+
steps={['1', '2', '3', '4']}
|
|
8
|
+
currentStep={3}
|
|
9
|
+
onStepClick={() => jest.fn()}
|
|
10
|
+
className="mt-4"
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
expect(stepper).toMatchSnapshot();
|
|
14
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import {Icon} from '../..';
|
|
3
|
+
|
|
4
|
+
interface TabsProps {
|
|
5
|
+
options: Array<{title: string; icon: string}>;
|
|
6
|
+
onSelect: (item: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Tabs = ({options, onSelect}: TabsProps) => {
|
|
10
|
+
const [selected, setSelected] = useState(options[0].title);
|
|
11
|
+
return (
|
|
12
|
+
<div className="flex justify-center">
|
|
13
|
+
<ul className="flex flex-wrap items-center justify-center -mb-px text-sm font-medium text-center text-black cursor-pointer gap-2">
|
|
14
|
+
{options?.map((item, index) => (
|
|
15
|
+
<li key={index} className="bg-[#EF4444] rounded-md">
|
|
16
|
+
<div
|
|
17
|
+
className={`inline-flex items-center justify-center p-3 border-b-2 gap-1 ${
|
|
18
|
+
item.title == selected
|
|
19
|
+
? 'text-white font-bold md:text-md border-primary active'
|
|
20
|
+
: ' text-gray-200 md:text-md border-transparent'
|
|
21
|
+
}`}
|
|
22
|
+
onClick={() => {
|
|
23
|
+
setSelected(item.title);
|
|
24
|
+
onSelect(item.title);
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
<Icon
|
|
28
|
+
nameIcon={item.icon}
|
|
29
|
+
propsIcon={{
|
|
30
|
+
color: item.title == selected ? '#ffffff' : '#000000',
|
|
31
|
+
size: 24,
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
{item.title}
|
|
35
|
+
</div>
|
|
36
|
+
</li>
|
|
37
|
+
))}
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
+
import {Tabs} from './tabs.component';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Tabs> = {
|
|
6
|
+
title: 'Design System/Atoms/Tabs',
|
|
7
|
+
component: Tabs,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
componentSubtitle: `import { Tabs } from 'react-restyle-components'`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Tabs>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
options: [
|
|
19
|
+
{title: 'Work History', icon: 'FaHistory'},
|
|
20
|
+
{title: 'Book Order', icon: 'FaBook'},
|
|
21
|
+
{title: 'Make Frame', icon: 'MdFilterFrames'},
|
|
22
|
+
],
|
|
23
|
+
onSelect: (item) => {
|
|
24
|
+
console.log({item});
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {render} from '@core-utils';
|
|
3
|
+
import {Tabs} from './tabs.component';
|
|
4
|
+
it('render Tabs correctly', () => {
|
|
5
|
+
const tabs = render(
|
|
6
|
+
<Tabs
|
|
7
|
+
options={[
|
|
8
|
+
{title: 'Work History', icon: 'FaHistory'},
|
|
9
|
+
{title: 'Book Order', icon: 'FaBook'},
|
|
10
|
+
{title: 'Make Frame', icon: 'MdFilterFrames'},
|
|
11
|
+
]}
|
|
12
|
+
onSelect={(item) => {
|
|
13
|
+
console.log({item});
|
|
14
|
+
|
|
15
|
+
}}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
expect(tabs).toMatchSnapshot();
|
|
19
|
+
});
|