@campxdev/react-blueprint 0.1.24 → 0.1.25
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/.storybook/preview.tsx +0 -1
- package/package.json +2 -1
- package/src/components/DataDisplay/Avatar/Avatar.tsx +70 -0
- package/src/components/DataDisplay/Avatar/CircularAvatar.stories.tsx +27 -0
- package/src/components/DataDisplay/Avatar/SquareAvatar.stories.tsx +47 -0
- package/src/components/DataDisplay/SidePanel/SidePanel.stories.tsx +36 -0
- package/src/components/DataDisplay/SidePanel/SidePanel.tsx +9 -0
- package/src/components/{FeedBack → Feedback}/Spinner/Spinner.stories.tsx +2 -2
- package/src/components/Feedback/Tooltip/Tooltip.stories.tsx +44 -0
- package/src/components/Feedback/Tooltip/Tooltip.tsx +45 -0
- package/src/components/Icons/IconComponents/{TooltipIcon.tsx → BulbIcon.tsx} +4 -4
- package/src/components/Icons/IconComponents/CrossIcon.tsx +25 -0
- package/src/components/Icons/IconComponents/InfoIcon.tsx +1 -1
- package/src/components/Icons/export.ts +4 -2
- package/src/components/Input/Chips/Chips.stories.tsx +54 -0
- package/src/components/Input/Chips/Chips.tsx +44 -0
- package/src/components/Input/HelpButton/HelpButton.stories.tsx +21 -0
- package/src/components/Input/HelpButton/HelpButton.tsx +17 -0
- package/src/components/Input/LabelWrapper/LabelWrapper.tsx +1 -1
- package/src/components/Input/OtpInput/OtpInput.stories.tsx +20 -0
- package/src/components/Input/OtpInput/OtpInput.tsx +85 -0
- package/src/components/Input/RadioGroup/RadioGroup.stories.tsx +1 -3
- package/src/components/Input/RadioGroup/RadioGroup.tsx +2 -1
- package/src/components/Input/SearchBar/SearchBar.stories.tsx +51 -0
- package/src/components/Input/SearchBar/SearchBar.tsx +48 -0
- package/src/components/Input/SingleCheckBox/SIngleCheckBox.tsx +14 -1
- package/src/components/Input/SingleCheckBox/SingleCheckBox.stories.tsx +0 -1
- package/src/components/Input/SingleSelect/SingleSelect.stories.tsx +20 -1
- package/src/components/Input/SingleSelect/SingleSelect.tsx +86 -11
- package/src/components/Input/TextField/TextField.stories.tsx +20 -0
- package/src/components/Input/components/FetchingOptionsLoader.tsx +2 -2
- package/src/components/Layout/Header/AppHeader.stories.tsx +2 -1
- package/src/components/Layout/Header/AppHeader.tsx +6 -6
- package/src/components/Layout/Header/HeaderActions/HeaderActions.tsx +14 -21
- package/src/components/Layout/LayoutWrapper/LayoutWrapper.stories.tsx +1 -1
- package/src/components/Navigation/DropDownMenu/DropDownMenu.stories.tsx +3 -12
- package/src/components/export.ts +2 -0
- package/src/themes/colorTokens.ts +4 -4
- package/src/themes/commonTheme.ts +45 -1
- package/src/utils/campxAxios.ts +1 -3
- package/types/theme.d.ts +4 -0
- /package/src/components/{FeedBack → Feedback}/Spinner/Spinner.css +0 -0
- /package/src/components/{FeedBack → Feedback}/Spinner/Spinner.tsx +0 -0
- /package/src/components/{Modals → Navigation/DialogButton}/DialogButton.stories.tsx +0 -0
- /package/src/components/{Modals → Navigation/DialogButton}/DialogButton.tsx +0 -0
package/.storybook/preview.tsx
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@campxdev/react-blueprint",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"main": "./export.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"dependencies": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"axios": "^1.7.2",
|
|
21
21
|
"framer-motion": "^11.2.9",
|
|
22
22
|
"js-cookie": "^3.0.5",
|
|
23
|
+
"lodash": "^4.17.21",
|
|
23
24
|
"pullstate": "^1.24.0",
|
|
24
25
|
"react": "^18.3.1",
|
|
25
26
|
"react-dom": "^18.3.1",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Avatar as MuiAvatar,
|
|
3
|
+
AvatarProps as MuiAvatarProps,
|
|
4
|
+
styled,
|
|
5
|
+
useTheme,
|
|
6
|
+
} from "@mui/material";
|
|
7
|
+
import { Typography } from "../Typography/Typography";
|
|
8
|
+
|
|
9
|
+
export type CircularAvatarProps = {
|
|
10
|
+
text: string;
|
|
11
|
+
} & Omit<MuiAvatarProps, "sx">;
|
|
12
|
+
|
|
13
|
+
export const CircularAvatar = ({ text, ...rest }: CircularAvatarProps) => {
|
|
14
|
+
const stringAvatar = (text: string) => {
|
|
15
|
+
if (!text) return "";
|
|
16
|
+
return text
|
|
17
|
+
.split(" ")
|
|
18
|
+
?.map((w) => w[0])
|
|
19
|
+
?.join("")
|
|
20
|
+
.toUpperCase();
|
|
21
|
+
};
|
|
22
|
+
const theme = useTheme();
|
|
23
|
+
|
|
24
|
+
const StyledCircularAvatar = styled(MuiAvatar)(({ theme }) => ({
|
|
25
|
+
height: "42px",
|
|
26
|
+
width: "42px",
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<StyledCircularAvatar variant="circular" {...rest}>
|
|
31
|
+
<Typography variant="subtitle3">{stringAvatar(text)}</Typography>
|
|
32
|
+
</StyledCircularAvatar>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type SquareAvatarProps = {
|
|
37
|
+
text: string;
|
|
38
|
+
onlyStartLetters: boolean;
|
|
39
|
+
} & Omit<MuiAvatarProps, "sx">;
|
|
40
|
+
|
|
41
|
+
export const SquareAvatar = ({
|
|
42
|
+
onlyStartLetters = false,
|
|
43
|
+
text,
|
|
44
|
+
...rest
|
|
45
|
+
}: SquareAvatarProps) => {
|
|
46
|
+
const stringAvatar = (text: string) => {
|
|
47
|
+
if (!text) return "";
|
|
48
|
+
return text
|
|
49
|
+
.split(" ")
|
|
50
|
+
?.map((w) => w[0])
|
|
51
|
+
?.join("")
|
|
52
|
+
.toUpperCase();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const StyledSquareAvatar = styled(MuiAvatar)(({ theme }) => ({
|
|
56
|
+
height: "150px",
|
|
57
|
+
width: "210px",
|
|
58
|
+
backgroundColor: theme.palette.secondary.dark,
|
|
59
|
+
borderRadius: "5px",
|
|
60
|
+
border: "none",
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<StyledSquareAvatar variant="square" {...rest}>
|
|
65
|
+
<Typography variant="h6">
|
|
66
|
+
{onlyStartLetters ? stringAvatar(text) : text}
|
|
67
|
+
</Typography>
|
|
68
|
+
</StyledSquareAvatar>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Import React and other necessary elements
|
|
2
|
+
|
|
3
|
+
import { Meta } from "@storybook/react";
|
|
4
|
+
import { CircularAvatar, CircularAvatarProps } from "./Avatar";
|
|
5
|
+
|
|
6
|
+
// Define the default export with Meta type including the component type
|
|
7
|
+
export default {
|
|
8
|
+
title: "DataDisplay/CircularAvatar",
|
|
9
|
+
component: CircularAvatar,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
argTypes: {},
|
|
12
|
+
} as Meta<typeof CircularAvatar>;
|
|
13
|
+
|
|
14
|
+
// Define stories directly as objects with render function
|
|
15
|
+
export const withText = {
|
|
16
|
+
render: (args: CircularAvatarProps) => <CircularAvatar {...args} />,
|
|
17
|
+
args: {
|
|
18
|
+
text: "Sh auy",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const withImage = {
|
|
23
|
+
render: (args: CircularAvatarProps) => <CircularAvatar {...args} />,
|
|
24
|
+
args: {
|
|
25
|
+
src: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwyNzM3ODF8MHwxfGFsbHwxfHx8fHx8fHwxNjM4MjM2MDg0&ixlib=rb-1.2.1&q=80&w=400",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Import React and other necessary elements
|
|
2
|
+
|
|
3
|
+
import { Meta } from "@storybook/react";
|
|
4
|
+
import { SquareAvatar, SquareAvatarProps } from "./Avatar";
|
|
5
|
+
|
|
6
|
+
// Define the default export with Meta type including the component type
|
|
7
|
+
export default {
|
|
8
|
+
title: "DataDisplay/SquareAvatar",
|
|
9
|
+
component: SquareAvatar,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
argTypes: {
|
|
12
|
+
children: {
|
|
13
|
+
control: "text",
|
|
14
|
+
description: "Content inside the SquareAvatar component",
|
|
15
|
+
},
|
|
16
|
+
src: {
|
|
17
|
+
control: "text",
|
|
18
|
+
description: "Image source for the SquareAvatar component",
|
|
19
|
+
},
|
|
20
|
+
variant: {
|
|
21
|
+
control: {
|
|
22
|
+
type: "select",
|
|
23
|
+
options: ["circular", "rounded", "square"],
|
|
24
|
+
},
|
|
25
|
+
description: "Variant of the SquareAvatar component",
|
|
26
|
+
},
|
|
27
|
+
sx: {
|
|
28
|
+
control: "object",
|
|
29
|
+
description: "Custom styling for the SquareAvatar component",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
} as Meta<typeof SquareAvatar>;
|
|
33
|
+
|
|
34
|
+
// Define stories directly as objects with render function
|
|
35
|
+
export const withText = {
|
|
36
|
+
render: (args: SquareAvatarProps) => <SquareAvatar {...args} />,
|
|
37
|
+
args: {
|
|
38
|
+
text: "SQC01",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const withImage = {
|
|
43
|
+
render: (args: SquareAvatarProps) => <SquareAvatar {...args} />,
|
|
44
|
+
args: {
|
|
45
|
+
src: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwyNzM3ODF8MHwxfGFsbHwxfHx8fHx8fHwxNjM4MjM2MDg0&ixlib=rb-1.2.1&q=80&w=400",
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Meta } from "@storybook/react/*";
|
|
2
|
+
import { SidePanel, SidePanelProps } from "./SidePanel";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: "DataDisplay/SidePanel",
|
|
6
|
+
component: SidePanel,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
argTypes: {
|
|
9
|
+
children: {
|
|
10
|
+
control: "text",
|
|
11
|
+
description: "Content inside the Avatar component",
|
|
12
|
+
},
|
|
13
|
+
src: {
|
|
14
|
+
control: "text",
|
|
15
|
+
description: "Image source for the Avatar component",
|
|
16
|
+
},
|
|
17
|
+
variant: {
|
|
18
|
+
control: {
|
|
19
|
+
type: "select",
|
|
20
|
+
options: ["circular", "rounded", "square"],
|
|
21
|
+
},
|
|
22
|
+
description: "Variant of the Avatar component",
|
|
23
|
+
},
|
|
24
|
+
sx: {
|
|
25
|
+
control: "object",
|
|
26
|
+
description: "Custom styling for the Avatar component",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
} as Meta<typeof SidePanel>;
|
|
30
|
+
|
|
31
|
+
export const withText = {
|
|
32
|
+
render: (args: SidePanelProps) => <SidePanel {...args} />,
|
|
33
|
+
args: {
|
|
34
|
+
children: "SS",
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -7,7 +7,7 @@ import { Spinner } from "./Spinner";
|
|
|
7
7
|
|
|
8
8
|
// Define the default export with Meta type including the component type
|
|
9
9
|
export default {
|
|
10
|
-
title: "
|
|
10
|
+
title: "Feedback/Spinner",
|
|
11
11
|
component: Spinner,
|
|
12
12
|
tags: ["autodocs"],
|
|
13
13
|
argTypes: {},
|
|
@@ -17,4 +17,4 @@ export default {
|
|
|
17
17
|
export const Primary = {
|
|
18
18
|
render: (args: any) => <Spinner {...args} />,
|
|
19
19
|
args: {},
|
|
20
|
-
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { ToolTipContent, Tooltip } from "./Tooltip";
|
|
3
|
+
import { InfoIcon } from "../../Icons/IconComponents/InfoIcon";
|
|
4
|
+
import { Button } from "../../Input/Button/Button";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Feedback/Tooltip",
|
|
8
|
+
component: Tooltip,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {
|
|
11
|
+
icon: { control: false },
|
|
12
|
+
message: { control: "text" },
|
|
13
|
+
},
|
|
14
|
+
} as Meta<typeof Tooltip>;
|
|
15
|
+
|
|
16
|
+
export const IconTooltip: StoryObj<typeof Tooltip> = {
|
|
17
|
+
render: (args) => <Tooltip {...args} />,
|
|
18
|
+
args: {
|
|
19
|
+
title: (
|
|
20
|
+
<ToolTipContent message="Duis rhoncus dui venenatis consequat porttitor. Etiam aliquet congue consequat. In posuere, nunc sit amet laoreet blandit, urna sapien imperdiet lectusui." />
|
|
21
|
+
),
|
|
22
|
+
children: <InfoIcon />,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const TextTooltip: StoryObj<typeof Tooltip> = {
|
|
27
|
+
render: (args) => <Tooltip {...args} />,
|
|
28
|
+
args: {
|
|
29
|
+
title: (
|
|
30
|
+
<ToolTipContent message="Duis rhoncus dui venenatis consequat porttitor. Etiam aliquet congue consequat. In posuere, nunc sit amet laoreet blandit, urna sapien imperdiet lectusui." />
|
|
31
|
+
),
|
|
32
|
+
children: <>Info</>,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const ButtonTooltip: StoryObj<typeof Tooltip> = {
|
|
37
|
+
render: (args) => <Tooltip {...args} />,
|
|
38
|
+
args: {
|
|
39
|
+
title: (
|
|
40
|
+
<ToolTipContent message="Duis rhoncus dui venenatis consequat porttitor. Etiam aliquet congue consequat. In posuere, nunc sit amet laoreet blandit, urna sapien imperdiet lectusui." />
|
|
41
|
+
),
|
|
42
|
+
children: <Button>Info</Button>,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Stack,
|
|
3
|
+
Tooltip as MuiTooltip,
|
|
4
|
+
TooltipProps as MuiTooltipProps,
|
|
5
|
+
IconButton,
|
|
6
|
+
Button,
|
|
7
|
+
} from "@mui/material";
|
|
8
|
+
import { BulbIcon } from "../../Icons/IconComponents/BulbIcon";
|
|
9
|
+
import { Typography } from "../../DataDisplay/Typography/Typography";
|
|
10
|
+
import { InfoIcon } from "../../Icons/IconComponents/InfoIcon";
|
|
11
|
+
import { Children, ReactElement, useState } from "react";
|
|
12
|
+
|
|
13
|
+
export type TooltipProps = {
|
|
14
|
+
children: ReactElement | string;
|
|
15
|
+
} & MuiTooltipProps;
|
|
16
|
+
export type TooltipContentProps = { message: string };
|
|
17
|
+
|
|
18
|
+
export const Tooltip = ({
|
|
19
|
+
placement = "right",
|
|
20
|
+
arrow = true,
|
|
21
|
+
...props
|
|
22
|
+
}: TooltipProps) => {
|
|
23
|
+
const isIconButton = Children.only(props.children).type === IconButton;
|
|
24
|
+
return (
|
|
25
|
+
<MuiTooltip {...props} placement={placement} arrow={arrow}>
|
|
26
|
+
{isIconButton ? (
|
|
27
|
+
props.children
|
|
28
|
+
) : (
|
|
29
|
+
<IconButton>{props.children}</IconButton>
|
|
30
|
+
)}
|
|
31
|
+
</MuiTooltip>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const ToolTipContent = ({ message }: TooltipContentProps) => {
|
|
36
|
+
return (
|
|
37
|
+
<Stack gap={1}>
|
|
38
|
+
<Stack direction="row" gap={1}>
|
|
39
|
+
<BulbIcon />
|
|
40
|
+
<Typography variant="subtitle3">Note:</Typography>
|
|
41
|
+
</Stack>
|
|
42
|
+
<Typography variant="caption">{message}</Typography>
|
|
43
|
+
</Stack>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useTheme } from "@mui/material";
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const BulbIcon = () => {
|
|
4
4
|
const theme = useTheme();
|
|
5
|
-
const color = theme.palette.
|
|
5
|
+
const color = theme.palette.info.main;
|
|
6
6
|
|
|
7
7
|
return (
|
|
8
8
|
<svg
|
|
9
9
|
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
-
width="
|
|
11
|
-
height="
|
|
10
|
+
width="16"
|
|
11
|
+
height="18"
|
|
12
12
|
viewBox="0 0 20.182 21.03"
|
|
13
13
|
style={{
|
|
14
14
|
fill: color,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useTheme } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
export const CrossIcon = () => {
|
|
4
|
+
const theme = useTheme();
|
|
5
|
+
const color = theme.palette.text.primary;
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
width="8"
|
|
10
|
+
height="8"
|
|
11
|
+
viewBox="0 0 8 8"
|
|
12
|
+
style={{
|
|
13
|
+
stroke: color,
|
|
14
|
+
}}
|
|
15
|
+
>
|
|
16
|
+
<path
|
|
17
|
+
id="cross-small_3_"
|
|
18
|
+
data-name="cross-small (3)"
|
|
19
|
+
d="M13.521,5.893h0a.636.636,0,0,0-.9,0L9.707,8.808,6.792,5.893a.636.636,0,0,0-.9,0h0a.636.636,0,0,0,0,.9L8.808,9.707,5.893,12.622a.636.636,0,0,0,0,.9h0a.636.636,0,0,0,.9,0l2.915-2.915,2.915,2.915a.636.636,0,0,0,.9,0h0a.636.636,0,0,0,0-.9L10.606,9.707l2.915-2.915A.636.636,0,0,0,13.521,5.893Z"
|
|
20
|
+
transform="translate(-5.707 -5.707)"
|
|
21
|
+
opacity="0.5"
|
|
22
|
+
/>
|
|
23
|
+
</svg>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -13,6 +13,8 @@ import { HelpIcon } from "./IconComponents/HelpIcon";
|
|
|
13
13
|
import { HomeIcon } from "./IconComponents/HomeIcon";
|
|
14
14
|
import { InfoIcon } from "./IconComponents/InfoIcon";
|
|
15
15
|
|
|
16
|
+
import { BulbIcon } from "./IconComponents/BulbIcon";
|
|
17
|
+
import { CrossIcon } from "./IconComponents/CrossIcon";
|
|
16
18
|
import { InstitutionsIcon } from "./IconComponents/InstitutionsIcon";
|
|
17
19
|
import { LeftIcon } from "./IconComponents/LeftIcon";
|
|
18
20
|
import { LocationIcon } from "./IconComponents/LocationIcon";
|
|
@@ -22,7 +24,6 @@ import { NotificationIcon } from "./IconComponents/NotificationIcon";
|
|
|
22
24
|
import { ProfileIcon } from "./IconComponents/ProfileIcon";
|
|
23
25
|
import { RightIcon } from "./IconComponents/RightIcon";
|
|
24
26
|
import { TicketsIcon } from "./IconComponents/TicketsIcon";
|
|
25
|
-
import { TooltipIcon } from "./IconComponents/TooltipIcon";
|
|
26
27
|
import { UnCheckedCheckboxIcon } from "./IconComponents/UncheckCheckBoxIcon";
|
|
27
28
|
import { UnCheckedRadioIcon } from "./IconComponents/UncheckedRadioIcon";
|
|
28
29
|
export const Icons = {
|
|
@@ -48,8 +49,9 @@ export const Icons = {
|
|
|
48
49
|
CheckedCheckboxIcon,
|
|
49
50
|
UnCheckedRadioIcon,
|
|
50
51
|
CheckedRadioIcon,
|
|
51
|
-
|
|
52
|
+
BulbIcon,
|
|
52
53
|
InfoIcon,
|
|
53
54
|
LocationIcon,
|
|
54
55
|
DeviceIcon,
|
|
56
|
+
CrossIcon,
|
|
55
57
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Import React and other necessary elements
|
|
2
|
+
import { Meta } from "@storybook/react";
|
|
3
|
+
import { Chips } from "./Chips";
|
|
4
|
+
|
|
5
|
+
const sampleChips = [
|
|
6
|
+
{
|
|
7
|
+
label: "Chip1",
|
|
8
|
+
value: 1,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: "Chip2",
|
|
12
|
+
value: 2,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: "Chip3",
|
|
16
|
+
value: 3,
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// Define the default export with Meta type including the component type
|
|
21
|
+
export default {
|
|
22
|
+
title: "Input/Chips",
|
|
23
|
+
component: Chips,
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
argTypes: {},
|
|
26
|
+
} as Meta<typeof Chips>;
|
|
27
|
+
|
|
28
|
+
// Define stories directly as objects with render function
|
|
29
|
+
export const Default = {
|
|
30
|
+
render: () => <Chips chips={sampleChips} />,
|
|
31
|
+
args: {},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const ClickableChip = {
|
|
35
|
+
render: () => (
|
|
36
|
+
<Chips
|
|
37
|
+
chips={sampleChips}
|
|
38
|
+
onClick={(clickedChip) => {
|
|
39
|
+
console.log(clickedChip);
|
|
40
|
+
}}
|
|
41
|
+
/>
|
|
42
|
+
),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const DeletableChip = {
|
|
46
|
+
render: () => (
|
|
47
|
+
<Chips
|
|
48
|
+
chips={sampleChips}
|
|
49
|
+
onDelete={(deletedChip) => {
|
|
50
|
+
console.log(deletedChip);
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Chip } from "@mui/material";
|
|
2
|
+
import { styled } from "@mui/material/styles";
|
|
3
|
+
import { Typography } from "../../DataDisplay/Typography/Typography";
|
|
4
|
+
import { Icons } from "../../export";
|
|
5
|
+
|
|
6
|
+
const ChipList = styled("ul")(({ theme }) => ({
|
|
7
|
+
display: "flex",
|
|
8
|
+
justifyContent: "center",
|
|
9
|
+
flexWrap: "wrap",
|
|
10
|
+
listStyle: "none",
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
export type ChipsProps = {
|
|
14
|
+
chips: { label: string; value: any }[];
|
|
15
|
+
onClick?: (clickedChip: any) => void;
|
|
16
|
+
onDelete?: (deletedChip: any) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Chips = ({ chips, onClick, onDelete }: ChipsProps) => {
|
|
20
|
+
return (
|
|
21
|
+
<ChipList>
|
|
22
|
+
{chips.map(({ label, value }) => (
|
|
23
|
+
<Chip
|
|
24
|
+
label={<Typography variant="body2">{label}</Typography>}
|
|
25
|
+
onClick={
|
|
26
|
+
onClick
|
|
27
|
+
? () => {
|
|
28
|
+
onClick(value);
|
|
29
|
+
}
|
|
30
|
+
: undefined
|
|
31
|
+
}
|
|
32
|
+
onDelete={
|
|
33
|
+
onDelete
|
|
34
|
+
? (e) => {
|
|
35
|
+
onDelete(value);
|
|
36
|
+
}
|
|
37
|
+
: undefined
|
|
38
|
+
}
|
|
39
|
+
deleteIcon={<Icons.CrossIcon />}
|
|
40
|
+
/>
|
|
41
|
+
))}
|
|
42
|
+
</ChipList>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Meta } from "@storybook/react";
|
|
3
|
+
import HelpButton from "./HelpButton";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Input/HelpButton",
|
|
7
|
+
component: HelpButton,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
argTypes: {
|
|
10
|
+
href: {
|
|
11
|
+
control: "text",
|
|
12
|
+
description: "The URL the button links to",
|
|
13
|
+
defaultValue: "https://example.com/help",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
} as Meta<typeof HelpButton>;
|
|
17
|
+
|
|
18
|
+
export const Default = (args: any) => <HelpButton {...args} />;
|
|
19
|
+
Default.args = {
|
|
20
|
+
href: "https://example.com/help",
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// HelpButton.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { IconButton } from "@mui/material";
|
|
4
|
+
import { Icons } from "../../export";
|
|
5
|
+
|
|
6
|
+
const HelpButton = () => {
|
|
7
|
+
return (
|
|
8
|
+
<IconButton
|
|
9
|
+
href={"https://campx.atlassian.net/servicedesk/customer/portal/2"}
|
|
10
|
+
target="_blank"
|
|
11
|
+
>
|
|
12
|
+
<Icons.HelpIcon />
|
|
13
|
+
</IconButton>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default HelpButton;
|
|
@@ -16,7 +16,7 @@ export const LabelWrapper = ({
|
|
|
16
16
|
}) => {
|
|
17
17
|
const theme = useTheme();
|
|
18
18
|
return (
|
|
19
|
-
<Stack margin="15px 20px" {...containerProps}
|
|
19
|
+
<Stack margin="15px 20px" {...containerProps}>
|
|
20
20
|
{typeof label === "string" ? (
|
|
21
21
|
<Typography htmlFor={name} component="label" variant="label1">
|
|
22
22
|
{label}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Meta } from "@storybook/react";
|
|
3
|
+
import OtpInput, { OtpInputProps } from "./OtpInput";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Input/OtpInput",
|
|
7
|
+
component: OtpInput,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
argTypes: {},
|
|
10
|
+
} as Meta<typeof OtpInput>;
|
|
11
|
+
|
|
12
|
+
export const Default = {
|
|
13
|
+
render: (args: OtpInputProps) => <OtpInput {...args} />,
|
|
14
|
+
args: {
|
|
15
|
+
length: 6,
|
|
16
|
+
onChangeOtp: (otp: string) => {
|
|
17
|
+
console.log("OTP Value:", otp);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React, { useState, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
interface OtpInputProps {
|
|
4
|
+
length: number;
|
|
5
|
+
onChangeOtp: (otp: string) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const OtpInput = ({ length, onChangeOtp }:OtpInputProps) => {
|
|
9
|
+
const [otp, setOtp] = useState<string[]>(Array(length).fill(""));
|
|
10
|
+
const inputRefs = useRef<HTMLInputElement[]>([]);
|
|
11
|
+
|
|
12
|
+
const handleChange = (element: HTMLInputElement, index: number) => {
|
|
13
|
+
const value = element.value;
|
|
14
|
+
if (/^[0-9]$/.test(value) || value === "") {
|
|
15
|
+
const newOtp = [...otp];
|
|
16
|
+
newOtp[index] = value;
|
|
17
|
+
setOtp(newOtp);
|
|
18
|
+
onChangeOtp(newOtp.join(""));
|
|
19
|
+
|
|
20
|
+
if (value && index < length - 1) {
|
|
21
|
+
inputRefs.current[index + 1].focus();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const handleKeyDown = (
|
|
27
|
+
event: React.KeyboardEvent<HTMLInputElement>,
|
|
28
|
+
index: number
|
|
29
|
+
) => {
|
|
30
|
+
if (event.key === "Backspace" && !otp[index] && index > 0) {
|
|
31
|
+
inputRefs.current[index - 1].focus();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
const paste = event.clipboardData.getData("text");
|
|
38
|
+
const digits = paste.split("").filter((char) => /^[0-9]$/.test(char));
|
|
39
|
+
|
|
40
|
+
if (digits.length > 0) {
|
|
41
|
+
const newOtp = [...otp];
|
|
42
|
+
const startIndex = Number(event.currentTarget.dataset.index) || 0;
|
|
43
|
+
let focusIndex = startIndex;
|
|
44
|
+
|
|
45
|
+
for (let i = startIndex; i < length; i++) {
|
|
46
|
+
if (digits.length > 0) {
|
|
47
|
+
newOtp[i] = digits.shift()!;
|
|
48
|
+
focusIndex = i;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setOtp(newOtp);
|
|
53
|
+
onChangeOtp(newOtp.join(""));
|
|
54
|
+
inputRefs.current[Math.min(focusIndex + 1, length - 1)].focus();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div style={{ display: "flex", gap: "10px" }}>
|
|
60
|
+
{otp.map((value, index) => (
|
|
61
|
+
<input
|
|
62
|
+
className="MuiOtpInput"
|
|
63
|
+
key={index}
|
|
64
|
+
ref={(el) => (inputRefs.current[index] = el!)}
|
|
65
|
+
type="text"
|
|
66
|
+
value={value ? "•" : ""}
|
|
67
|
+
onChange={(e) => handleChange(e.target, index)}
|
|
68
|
+
onKeyDown={(e) => handleKeyDown(e, index)}
|
|
69
|
+
onPaste={handlePaste}
|
|
70
|
+
data-index={index}
|
|
71
|
+
maxLength={1}
|
|
72
|
+
style={{
|
|
73
|
+
width: "40px",
|
|
74
|
+
height: "40px",
|
|
75
|
+
textAlign: "center",
|
|
76
|
+
fontSize: "20px",
|
|
77
|
+
}}
|
|
78
|
+
/>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default OtpInput;
|
|
85
|
+
export type { OtpInputProps };
|