@agility/plenum-ui 2.1.27 → 2.2.1
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 +7 -6
- package/dist/index.d.ts +130 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/tailwind.css +106 -1
- package/dist/types/stories/atoms/Typography/Heading/Heading.d.ts +8 -0
- package/dist/types/stories/atoms/Typography/Heading/Heading.stories.d.ts +12 -0
- package/dist/types/stories/atoms/Typography/Heading/index.d.ts +3 -0
- package/dist/types/stories/atoms/Typography/Label/Label.d.ts +10 -0
- package/dist/types/stories/atoms/Typography/Label/Label.stories.d.ts +12 -0
- package/dist/types/stories/atoms/Typography/Label/index.d.ts +3 -0
- package/dist/types/stories/atoms/Typography/Paragraph/Paragraph.d.ts +10 -0
- package/dist/types/stories/atoms/Typography/Paragraph/Paragraph.stories.d.ts +11 -0
- package/dist/types/stories/atoms/Typography/Paragraph/index.d.ts +3 -0
- package/dist/types/stories/atoms/buttons/Button/Button.d.ts +1 -1
- package/dist/types/stories/atoms/buttons/Button/DangerSecondary/DangerSecondary.stories.d.ts +15 -0
- package/dist/types/stories/atoms/index.d.ts +5 -2
- package/dist/types/stories/index.d.ts +3 -3
- package/dist/types/stories/molecules/inputs/TextInput/TextInput.d.ts +4 -0
- package/package.json +1 -1
- package/stories/atoms/Typography/Heading/Heading.stories.ts +40 -0
- package/stories/atoms/Typography/Heading/Heading.tsx +26 -0
- package/stories/atoms/Typography/Heading/index.ts +3 -0
- package/stories/atoms/Typography/Label/Label.stories.ts +40 -0
- package/stories/atoms/Typography/Label/Label.tsx +25 -0
- package/stories/atoms/Typography/Label/index.ts +3 -0
- package/stories/atoms/Typography/Paragraph/Paragraph.stories.ts +36 -0
- package/stories/atoms/Typography/Paragraph/Paragraph.tsx +24 -0
- package/stories/atoms/Typography/Paragraph/index.ts +3 -0
- package/stories/atoms/buttons/Button/Button.tsx +39 -38
- package/stories/atoms/buttons/Button/DangerSecondary/DangerSecondary.stories.ts +90 -0
- package/stories/atoms/buttons/Button/tests/Button.test.tsx +0 -37
- package/stories/atoms/index.ts +16 -8
- package/stories/index.ts +15 -3
- package/stories/molecules/inputs/TextInput/TextInput.tsx +59 -46
- package/tailwind.config.js +1 -1
|
@@ -1,39 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { DynamicIcon, UnifiedIconName, IDynamicIconProps } from "../../icons"
|
|
1
|
+
import { default as cn } from "classnames";
|
|
2
|
+
import React, { HTMLAttributeAnchorTarget, forwardRef } from "react";
|
|
3
|
+
import { DynamicIcon, UnifiedIconName, IDynamicIconProps } from "../../icons";
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export type BTNActionType = "primary" | "secondary" | "alternative" | "danger" | "warning"
|
|
5
|
+
export type BTNActionType = "primary" | "secondary" | "alternative" | "danger" | "danger-secondary" | "warning";
|
|
9
6
|
|
|
10
7
|
export interface IButtonProps
|
|
11
8
|
extends Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> {
|
|
12
9
|
/** Is the button a Primary CTA, alternative or danger button? */
|
|
13
|
-
actionType?: BTNActionType
|
|
10
|
+
actionType?: BTNActionType;
|
|
14
11
|
/** How lg should the button be? - Defaults to 'base'. */
|
|
15
|
-
size?: "xs" | "sm" | "md" | "lg" | "xl"
|
|
12
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
16
13
|
/** The Button's text content. */
|
|
17
|
-
label: string
|
|
14
|
+
label: string;
|
|
18
15
|
/** The Icon to be displayed inside the button. */
|
|
19
|
-
icon?: IDynamicIconProps | UnifiedIconName
|
|
16
|
+
icon?: IDynamicIconProps | UnifiedIconName;
|
|
20
17
|
/** Does the button width grow to fill it's container? */
|
|
21
|
-
fullWidth?: boolean
|
|
18
|
+
fullWidth?: boolean;
|
|
22
19
|
/** Optionally render as anchor tag */
|
|
23
20
|
asLink?: {
|
|
24
|
-
href: string
|
|
25
|
-
target: HTMLAttributeAnchorTarget
|
|
26
|
-
title?: string
|
|
27
|
-
}
|
|
21
|
+
href: string;
|
|
22
|
+
target: HTMLAttributeAnchorTarget;
|
|
23
|
+
title?: string;
|
|
24
|
+
};
|
|
28
25
|
/** The placement of the icon relative to the text content. */
|
|
29
|
-
iconPosition?: "trailing" | "leading"
|
|
26
|
+
iconPosition?: "trailing" | "leading";
|
|
30
27
|
/** Use an custom svg element */
|
|
31
|
-
CustomSVGIcon?: JSX.Element
|
|
28
|
+
CustomSVGIcon?: JSX.Element;
|
|
32
29
|
/** Is the associated content loading? */
|
|
33
|
-
isLoading?: boolean
|
|
34
|
-
className?: string
|
|
35
|
-
iconObj?: React.ReactNode
|
|
36
|
-
iconClassName?: string
|
|
30
|
+
isLoading?: boolean;
|
|
31
|
+
className?: string;
|
|
32
|
+
iconObj?: React.ReactNode;
|
|
33
|
+
iconClassName?: string;
|
|
37
34
|
}
|
|
38
35
|
/**
|
|
39
36
|
* Primary UI component for user interaction
|
|
@@ -61,10 +58,10 @@ const _Button = (
|
|
|
61
58
|
{ "text-purple-700 h-5 w-5 stroke-[1.5]": actionType === "secondary" },
|
|
62
59
|
{ "text-gray-400 h-5 w-5 stroke-[1.5]": actionType === "alternative" },
|
|
63
60
|
{ "text-transparent-black-40 h-5 w-5 stroke-[1.5]": actionType === "warning" }
|
|
64
|
-
)
|
|
61
|
+
);
|
|
65
62
|
|
|
66
63
|
if (iconClassName) {
|
|
67
|
-
iconStyles = cn(iconStyles, iconClassName)
|
|
64
|
+
iconStyles = cn(iconStyles, iconClassName);
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
const loaderColors = cn(
|
|
@@ -73,8 +70,8 @@ const _Button = (
|
|
|
73
70
|
{ "border-gray-200 border-r-gray-700": actionType === "alternative" },
|
|
74
71
|
{ "border-red-800 border-r-white": actionType === "danger" },
|
|
75
72
|
{ "border-yellow-800 border-r-transparent-black-70": actionType === "warning" }
|
|
76
|
-
)
|
|
77
|
-
const loaderSize = cn({ "h-4 w-4": size === "sm" }, { "h-5 w-5": size === "md" }, { "h-6 w-6 ": size === "lg" })
|
|
73
|
+
);
|
|
74
|
+
const loaderSize = cn({ "h-4 w-4": size === "sm" }, { "h-5 w-5": size === "md" }, { "h-6 w-6 ": size === "lg" });
|
|
78
75
|
|
|
79
76
|
return asLink ? (
|
|
80
77
|
//@ts-ignore
|
|
@@ -164,13 +161,13 @@ const _Button = (
|
|
|
164
161
|
<button
|
|
165
162
|
type="button"
|
|
166
163
|
className={cn(
|
|
167
|
-
"inline-flex items-center justify-center gap-x-2 rounded
|
|
164
|
+
" px-4 py-2 inline-flex items-center justify-center gap-x-2 rounded !ring-offset-white outline-none focus-visible:ring-2 focus-visible:ring-purple-600 focus-visible:ring-offset-2 focus-within:ring-2 focus-within:ring-purple-600 focus-within:ring-offset-2 focus:ring-2 focus:ring-purple-600 focus:ring-offset-2 active:ring-2 active:ring-purple-600 active:ring-offset-2 transition-all",
|
|
168
165
|
{ "w-full": fullWidth },
|
|
169
|
-
{ "
|
|
170
|
-
{ "
|
|
171
|
-
{ "
|
|
172
|
-
{ "
|
|
173
|
-
{ "
|
|
166
|
+
{ "text-xs": size === "xs" },
|
|
167
|
+
{ "text-sm": size === "sm" },
|
|
168
|
+
{ "text-sm": size === "md" },
|
|
169
|
+
{ "text-base": size === "lg" },
|
|
170
|
+
{ "text-base": size === "xl" },
|
|
174
171
|
{
|
|
175
172
|
"bg-violet-800 text-white hover:border-violet-700 hover:bg-violet-700 disabled:bg-violet-400 disabled:focus-visible:ring-0":
|
|
176
173
|
actionType === "primary"
|
|
@@ -184,11 +181,15 @@ const _Button = (
|
|
|
184
181
|
actionType === "alternative"
|
|
185
182
|
},
|
|
186
183
|
{
|
|
187
|
-
"
|
|
184
|
+
"bg-red-600 text-white hover:bg-red-700 focus-visible:!ring-red-500 focus:!ring-red-500 active:!ring-red-500 focus-within:!ring-red-500 disabled:bg-red-400 disabled:text-gray-50 disabled:focus-visible:ring-0":
|
|
188
185
|
actionType === "danger"
|
|
189
186
|
},
|
|
190
187
|
{
|
|
191
|
-
" bg-
|
|
188
|
+
"border-gray-300 border bg-white text-red-600 hover:bg-red-50 focus-visible:!ring-red-500 focus:!ring-red-500 active:bg-red-100 active:ring-red-500 focus-within:!ring-red-500 disabled:bg-white disabled:text-red-300 disabled:!ring-0 disabled:focus-visible:ring-0":
|
|
189
|
+
actionType === "danger-secondary"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"bg-yellow-500 text-transparent-black-70 hover:bg-yellow-700 focus-visible:!ring-yellow-500 focus:!ring-yellow-500 active:!ring-yellow-500 focus-within:!ring-yellow-500 disabled:bg-yellow-300 disabled:text-transparent-black-30 disabled:focus-visible:ring-0":
|
|
192
193
|
actionType === "warning"
|
|
193
194
|
},
|
|
194
195
|
className ? className : ""
|
|
@@ -241,9 +242,9 @@ const _Button = (
|
|
|
241
242
|
<div className={cn("h-4 rounded-full w-4 border-2 m-0 animate-spin", loaderColors, loaderSize)} />
|
|
242
243
|
))}
|
|
243
244
|
</button>
|
|
244
|
-
)
|
|
245
|
-
}
|
|
245
|
+
);
|
|
246
|
+
};
|
|
246
247
|
|
|
247
|
-
const Button = forwardRef<HTMLButtonElement, IButtonProps>(_Button)
|
|
248
|
+
const Button = forwardRef<HTMLButtonElement, IButtonProps>(_Button);
|
|
248
249
|
|
|
249
|
-
export default Button
|
|
250
|
+
export default Button;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import Button from "../Button";
|
|
3
|
+
import { defaultIcon } from "../defaultArgs";
|
|
4
|
+
|
|
5
|
+
// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
|
|
6
|
+
const meta: Meta<typeof Button> = {
|
|
7
|
+
title: "Design System/atoms/Buttons/Button/DangerSecondary",
|
|
8
|
+
component: Button,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Button>;
|
|
15
|
+
// #region Danger Button Stories
|
|
16
|
+
export const DangerSecondary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
actionType: "danger-secondary",
|
|
19
|
+
label: "Danger Secondary",
|
|
20
|
+
onClick: () => {
|
|
21
|
+
window.alert("Button clicked!");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const DangerSecondaryDisabled: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
actionType: "danger-secondary",
|
|
29
|
+
label: "Danger Secondary",
|
|
30
|
+
disabled: true,
|
|
31
|
+
onClick: () => {
|
|
32
|
+
window.alert("Button clicked!");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const DangerSecondaryTrailingIcon: Story = {
|
|
38
|
+
args: {
|
|
39
|
+
...DangerSecondary.args,
|
|
40
|
+
icon: {
|
|
41
|
+
...defaultIcon,
|
|
42
|
+
icon: "IconTrash"
|
|
43
|
+
},
|
|
44
|
+
iconPosition: "trailing"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
export const DangerSecondaryLeadingIcon: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
...DangerSecondaryTrailingIcon.args,
|
|
50
|
+
iconPosition: "leading"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export const DangerSecondarySimpleIconName: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
...DangerSecondary.args,
|
|
56
|
+
icon: "IconTrash",
|
|
57
|
+
iconPosition: "leading"
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const DangerSecondaryExtraSmall: Story = {
|
|
61
|
+
args: {
|
|
62
|
+
...DangerSecondary.args,
|
|
63
|
+
size: "sm"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
export const DangerSecondarySmall: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
...DangerSecondary.args,
|
|
69
|
+
size: "sm"
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
export const DangerSecondaryMedium: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
...DangerSecondary.args,
|
|
75
|
+
size: "md"
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
export const DangerSecondaryLarge: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
...DangerSecondary.args,
|
|
81
|
+
size: "lg"
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
export const DangerSecondaryExtraLarge: Story = {
|
|
85
|
+
args: {
|
|
86
|
+
...DangerSecondary.args,
|
|
87
|
+
size: "xl"
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
// #endregion
|
|
@@ -51,43 +51,6 @@ describe("<Button>", () => {
|
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
describe("size", () => {
|
|
55
|
-
it("defaults to size sm", () => {
|
|
56
|
-
render(<Button {...defaultProps} />);
|
|
57
|
-
|
|
58
|
-
const buttonElement = screen.getByRole("button");
|
|
59
|
-
expect(buttonElement).toHaveClass("px-[13px]");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("renders with size xs", () => {
|
|
63
|
-
render(<Button {...defaultProps} size="xs" />);
|
|
64
|
-
|
|
65
|
-
const buttonElement = screen.getByRole("button");
|
|
66
|
-
expect(buttonElement).toHaveClass("px-[11px]");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("renders with size md", () => {
|
|
70
|
-
render(<Button {...defaultProps} size="md" />);
|
|
71
|
-
|
|
72
|
-
const buttonElement = screen.getByRole("button");
|
|
73
|
-
expect(buttonElement).toHaveClass("px-[17px] text-sm");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("renders with size lg", () => {
|
|
77
|
-
render(<Button {...defaultProps} size="lg" />);
|
|
78
|
-
|
|
79
|
-
const buttonElement = screen.getByRole("button");
|
|
80
|
-
expect(buttonElement).toHaveClass("px-[17px] text-base");
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("renders with size xl", () => {
|
|
84
|
-
render(<Button {...defaultProps} size="xl" />);
|
|
85
|
-
|
|
86
|
-
const buttonElement = screen.getByRole("button");
|
|
87
|
-
expect(buttonElement).toHaveClass("px-[25px]");
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
54
|
describe("asLink", () => {
|
|
92
55
|
it("renders as <a /> when asLink is true", () => {
|
|
93
56
|
render(<Button {...defaultProps} asLink={{ href: "#", target: "_blank" }} />);
|
package/stories/atoms/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import Avatar, { IAvatarProps } from "./Avatar"
|
|
2
|
-
import Badge, { IBadgeProps } from "./badges"
|
|
3
|
-
import { Button, Capsule, BTNActionType, IButtonProps, ICapsuleProps } from "./buttons"
|
|
1
|
+
import Avatar, { IAvatarProps } from "./Avatar";
|
|
2
|
+
import Badge, { IBadgeProps } from "./badges";
|
|
3
|
+
import { Button, Capsule, BTNActionType, IButtonProps, ICapsuleProps } from "./buttons";
|
|
4
4
|
import {
|
|
5
5
|
DynamicIcon,
|
|
6
6
|
FAIconName,
|
|
@@ -13,9 +13,11 @@ import {
|
|
|
13
13
|
isHeroIcon,
|
|
14
14
|
isTablerIcon,
|
|
15
15
|
isUnifiedIconName
|
|
16
|
-
} from "./icons"
|
|
17
|
-
import { ILoaderProps, IRadialProgressProps, Loader, RadialProgress } from "./loaders"
|
|
18
|
-
|
|
16
|
+
} from "./icons";
|
|
17
|
+
import { ILoaderProps, IRadialProgressProps, Loader, RadialProgress } from "./loaders";
|
|
18
|
+
import { Heading, HeadingProps } from "./Typography/Heading";
|
|
19
|
+
import { Label, LabelProps } from "./Typography/Label";
|
|
20
|
+
import { Paragraph, ParagraphProps } from "./Typography/Paragraph";
|
|
19
21
|
export type {
|
|
20
22
|
IAvatarProps,
|
|
21
23
|
IBadgeProps,
|
|
@@ -25,11 +27,14 @@ export type {
|
|
|
25
27
|
IIconWithShadowProps,
|
|
26
28
|
ILoaderProps,
|
|
27
29
|
IRadialProgressProps,
|
|
30
|
+
HeadingProps,
|
|
31
|
+
LabelProps,
|
|
32
|
+
ParagraphProps,
|
|
28
33
|
UnifiedIconName,
|
|
29
34
|
IconName,
|
|
30
35
|
FAIconName,
|
|
31
36
|
BTNActionType
|
|
32
|
-
}
|
|
37
|
+
};
|
|
33
38
|
export {
|
|
34
39
|
Avatar,
|
|
35
40
|
Badge,
|
|
@@ -39,8 +44,11 @@ export {
|
|
|
39
44
|
IconWithShadow,
|
|
40
45
|
Loader,
|
|
41
46
|
RadialProgress,
|
|
47
|
+
Heading,
|
|
48
|
+
Label,
|
|
49
|
+
Paragraph,
|
|
42
50
|
isFAIcon,
|
|
43
51
|
isHeroIcon,
|
|
44
52
|
isTablerIcon,
|
|
45
53
|
isUnifiedIconName
|
|
46
|
-
}
|
|
54
|
+
};
|
package/stories/index.ts
CHANGED
|
@@ -23,7 +23,13 @@ import {
|
|
|
23
23
|
isFAIcon,
|
|
24
24
|
isHeroIcon,
|
|
25
25
|
isTablerIcon,
|
|
26
|
-
isUnifiedIconName
|
|
26
|
+
isUnifiedIconName,
|
|
27
|
+
Heading,
|
|
28
|
+
HeadingProps,
|
|
29
|
+
Label,
|
|
30
|
+
LabelProps,
|
|
31
|
+
Paragraph,
|
|
32
|
+
ParagraphProps
|
|
27
33
|
} from "./atoms";
|
|
28
34
|
// Molecular Components, props, and type guards.
|
|
29
35
|
import {
|
|
@@ -107,7 +113,10 @@ export type {
|
|
|
107
113
|
ITextInputProps,
|
|
108
114
|
ISimpleSelectOptions,
|
|
109
115
|
IAnimatedFormInputWithAddons,
|
|
110
|
-
MultiSelectItemProps
|
|
116
|
+
MultiSelectItemProps,
|
|
117
|
+
HeadingProps,
|
|
118
|
+
LabelProps,
|
|
119
|
+
ParagraphProps
|
|
111
120
|
};
|
|
112
121
|
export {
|
|
113
122
|
Avatar,
|
|
@@ -140,5 +149,8 @@ export {
|
|
|
140
149
|
TextInput,
|
|
141
150
|
TextInputSelect,
|
|
142
151
|
AnimatedFormInputWithAddons,
|
|
143
|
-
DropdownWithMultiSelect
|
|
152
|
+
DropdownWithMultiSelect,
|
|
153
|
+
Heading,
|
|
154
|
+
Label,
|
|
155
|
+
Paragraph
|
|
144
156
|
};
|
|
@@ -1,44 +1,49 @@
|
|
|
1
|
-
import React, { forwardRef, useEffect, useId, useRef, useState } from "react"
|
|
2
|
-
import { default as cn } from "classnames"
|
|
3
|
-
import InputLabel from "../InputLabel"
|
|
4
|
-
import InputField, { AcceptedInputTypes } from "../InputField"
|
|
5
|
-
import InputCounter from "../InputCounter"
|
|
1
|
+
import React, { forwardRef, useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { default as cn } from "classnames";
|
|
3
|
+
import InputLabel from "../InputLabel";
|
|
4
|
+
import InputField, { AcceptedInputTypes } from "../InputField";
|
|
5
|
+
import InputCounter from "../InputCounter";
|
|
6
6
|
|
|
7
7
|
export interface ITextInputProps {
|
|
8
8
|
/** Input type*/
|
|
9
|
-
type: AcceptedInputTypes
|
|
9
|
+
type: AcceptedInputTypes;
|
|
10
10
|
/** Input ID */
|
|
11
|
-
id?: string
|
|
11
|
+
id?: string;
|
|
12
12
|
/** Input Name */
|
|
13
|
-
name?: string
|
|
13
|
+
name?: string;
|
|
14
14
|
/** Label for the input */
|
|
15
|
-
label?: string
|
|
15
|
+
label?: string;
|
|
16
16
|
/** Force the focus state on the input */
|
|
17
|
-
isFocused?: boolean
|
|
17
|
+
isFocused?: boolean;
|
|
18
18
|
/** Error state */
|
|
19
|
-
isError?: boolean
|
|
19
|
+
isError?: boolean;
|
|
20
20
|
/** If field is required */
|
|
21
|
-
isRequired?: boolean
|
|
21
|
+
isRequired?: boolean;
|
|
22
22
|
/** Disabled state */
|
|
23
|
-
isDisabled?: boolean
|
|
23
|
+
isDisabled?: boolean;
|
|
24
24
|
/** Readonly state */
|
|
25
|
-
isReadonly?: boolean
|
|
25
|
+
isReadonly?: boolean;
|
|
26
26
|
/** Set default value */
|
|
27
|
-
defaultValue?: string
|
|
27
|
+
defaultValue?: string;
|
|
28
28
|
/** Message shown under the text field */
|
|
29
|
-
message?: string
|
|
29
|
+
message?: string;
|
|
30
30
|
/** Input character counter */
|
|
31
|
-
isShowCounter?: boolean
|
|
31
|
+
isShowCounter?: boolean;
|
|
32
32
|
/** Max length of input character */
|
|
33
|
-
maxLength?: number
|
|
33
|
+
maxLength?: number;
|
|
34
34
|
/** Callback on change */
|
|
35
|
-
handleChange(value: string): void
|
|
35
|
+
handleChange(value: string): void;
|
|
36
36
|
/** input value */
|
|
37
|
-
value: string
|
|
37
|
+
value: string;
|
|
38
38
|
/**Placeholder input text*/
|
|
39
|
-
placeholder?: string
|
|
39
|
+
placeholder?: string;
|
|
40
40
|
|
|
41
|
-
className?: string
|
|
41
|
+
className?: string;
|
|
42
|
+
|
|
43
|
+
/** Callback on focus */
|
|
44
|
+
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
45
|
+
/** Callback on blur */
|
|
46
|
+
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
const TextInput = (
|
|
@@ -60,48 +65,56 @@ const TextInput = (
|
|
|
60
65
|
placeholder,
|
|
61
66
|
value: externalValue,
|
|
62
67
|
className,
|
|
68
|
+
onFocus,
|
|
69
|
+
onBlur,
|
|
63
70
|
...props
|
|
64
71
|
}: ITextInputProps,
|
|
65
72
|
ref: React.Ref<HTMLInputElement>
|
|
66
73
|
) => {
|
|
67
|
-
const uniqueID = useId()
|
|
68
|
-
const [isFocus, setIsFocus] = useState<boolean>(Boolean(isFocused))
|
|
74
|
+
const uniqueID = useId();
|
|
75
|
+
const [isFocus, setIsFocus] = useState<boolean>(Boolean(isFocused));
|
|
69
76
|
|
|
70
|
-
const [value, setValue] = useState<string>(externalValue || defaultValue || "")
|
|
71
|
-
const inputRef = useRef<HTMLInputElement>(null)
|
|
77
|
+
const [value, setValue] = useState<string>(externalValue || defaultValue || "");
|
|
78
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
72
79
|
|
|
73
80
|
useEffect(() => {
|
|
74
81
|
//if the external value is updated by the parent component, reset the value in here...
|
|
75
82
|
if (externalValue !== undefined && externalValue !== null) {
|
|
76
|
-
setValue(externalValue)
|
|
83
|
+
setValue(externalValue);
|
|
77
84
|
}
|
|
78
|
-
}, [externalValue])
|
|
85
|
+
}, [externalValue]);
|
|
79
86
|
|
|
80
87
|
// set force focus
|
|
81
88
|
useEffect(() => {
|
|
82
|
-
const input = inputRef.current
|
|
83
|
-
if (!input || isFocus === undefined || isDisabled) return
|
|
89
|
+
const input = inputRef.current;
|
|
90
|
+
if (!input || isFocus === undefined || isDisabled) return;
|
|
84
91
|
if (isFocus) {
|
|
85
|
-
input.focus()
|
|
92
|
+
input.focus();
|
|
86
93
|
} else {
|
|
87
|
-
input.blur()
|
|
94
|
+
input.blur();
|
|
88
95
|
}
|
|
89
96
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
-
}, [isFocus])
|
|
97
|
+
}, [isFocus]);
|
|
91
98
|
|
|
92
99
|
// set label as active if default value is set
|
|
93
100
|
useEffect(() => {
|
|
94
|
-
const input = inputRef.current
|
|
95
|
-
if (!input || defaultValue === undefined || defaultValue === "") return
|
|
96
|
-
}, [defaultValue])
|
|
101
|
+
const input = inputRef.current;
|
|
102
|
+
if (!input || defaultValue === undefined || defaultValue === "") return;
|
|
103
|
+
}, [defaultValue]);
|
|
97
104
|
|
|
98
|
-
const handleInputFocus = () =>
|
|
105
|
+
const handleInputFocus = (e: React.FocusEvent<HTMLInputElement>) => {
|
|
106
|
+
setIsFocus(true);
|
|
107
|
+
if (onFocus) onFocus(e);
|
|
108
|
+
};
|
|
99
109
|
// add other focus effects here
|
|
100
110
|
|
|
101
|
-
const handleInputBlur = () =>
|
|
111
|
+
const handleInputBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
|
112
|
+
setIsFocus(false);
|
|
113
|
+
if (onBlur) onBlur(e);
|
|
114
|
+
};
|
|
102
115
|
|
|
103
|
-
if (!id) id = `input-${uniqueID}
|
|
104
|
-
if (!name) name = id
|
|
116
|
+
if (!id) id = `input-${uniqueID}`;
|
|
117
|
+
if (!name) name = id;
|
|
105
118
|
|
|
106
119
|
return (
|
|
107
120
|
<div className="relative group">
|
|
@@ -118,8 +131,8 @@ const TextInput = (
|
|
|
118
131
|
onFocus={handleInputFocus}
|
|
119
132
|
onBlur={handleInputBlur}
|
|
120
133
|
handleChange={(v: string) => {
|
|
121
|
-
setValue(v)
|
|
122
|
-
handleChange(v)
|
|
134
|
+
setValue(v);
|
|
135
|
+
handleChange(v);
|
|
123
136
|
}}
|
|
124
137
|
ref={ref}
|
|
125
138
|
type={type}
|
|
@@ -163,8 +176,8 @@ const TextInput = (
|
|
|
163
176
|
)}
|
|
164
177
|
</div>
|
|
165
178
|
</div>
|
|
166
|
-
)
|
|
167
|
-
}
|
|
179
|
+
);
|
|
180
|
+
};
|
|
168
181
|
|
|
169
|
-
const _TextInput = forwardRef<HTMLInputElement, ITextInputProps>(TextInput)
|
|
170
|
-
export default _TextInput
|
|
182
|
+
const _TextInput = forwardRef<HTMLInputElement, ITextInputProps>(TextInput);
|
|
183
|
+
export default _TextInput;
|