@agility/plenum-ui 2.0.0-rc47 → 2.0.0-rc49
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/.eslintrc.json +6 -6
- package/.prettierrc +13 -13
- package/.storybook/Layout.jsx +12 -12
- package/.storybook/head.tsx +4 -4
- package/.storybook/main.ts +18 -18
- package/.storybook/manager-head.html +1 -1
- package/.storybook/manager.ts +25 -25
- package/.storybook/plenumTheme.ts +8 -8
- package/.storybook/preview-head.html +3 -3
- package/.storybook/preview.tsx +28 -28
- package/.vscode/settings.json +3 -3
- package/README.md +271 -271
- package/app/globals.css +99 -99
- package/app/head.tsx +59 -59
- package/app/layout.tsx +28 -28
- package/app/page.tsx +7 -7
- package/build.js +45 -45
- package/dist/index.d.ts +232 -230
- package/dist/index.js +1 -1
- package/dist/index.js.map +3 -3
- package/dist/types/stories/molecules/inputs/select/Select.d.ts +2 -0
- package/local.sh +100 -100
- package/next.config.js +8 -8
- package/package.json +82 -82
- package/pages/api/hello.ts +13 -13
- package/postcss.config.js +6 -6
- package/rollup.config.mjs +41 -41
- package/scripts/create-component.js +97 -97
- package/stories/Introduction.mdx +314 -314
- package/stories/assets/stackalt.svg +1 -1
- package/stories/atoms/Avatar/Avatar.stories.tsx +96 -96
- package/stories/atoms/Avatar/Avatar.tsx +123 -123
- package/stories/atoms/Avatar/index.ts +3 -3
- package/stories/atoms/badges/Badge.tsx +127 -127
- package/stories/atoms/badges/Pill/Pill.stories.tsx +75 -75
- package/stories/atoms/badges/Rounded/Rounded.stories.tsx +75 -75
- package/stories/atoms/badges/index.ts +3 -3
- package/stories/atoms/buttons/Button/Alternative/Alternative.stories.ts +86 -86
- package/stories/atoms/buttons/Button/Button.tsx +232 -232
- package/stories/atoms/buttons/Button/Danger/Danger.stories.ts +90 -90
- package/stories/atoms/buttons/Button/Primary/Primary.stories.ts +97 -97
- package/stories/atoms/buttons/Button/Secondary/Secondary.stories.ts +93 -93
- package/stories/atoms/buttons/Button/defaultArgs.ts +9 -9
- package/stories/atoms/buttons/Button/index.ts +3 -3
- package/stories/atoms/buttons/Capsule/Alternative/Alternative.stories.ts +27 -27
- package/stories/atoms/buttons/Capsule/Capsule.tsx +88 -88
- package/stories/atoms/buttons/Capsule/Danger/Danger.stories.ts +27 -27
- package/stories/atoms/buttons/Capsule/Primary/Primary.stories.ts +27 -27
- package/stories/atoms/buttons/Capsule/Secondary/Secondary.stories.ts +27 -27
- package/stories/atoms/buttons/Capsule/index.ts +3 -3
- package/stories/atoms/buttons/FloatingActionButton/FloatingActionButton.stories.tsx +15 -15
- package/stories/atoms/buttons/FloatingActionButton/FloatingActionButton.tsx +22 -22
- package/stories/atoms/buttons/FloatingActionButton/index.tsx +3 -3
- package/stories/atoms/buttons/index.ts +4 -4
- package/stories/atoms/crumb/Crumb.stories.tsx +18 -18
- package/stories/atoms/crumb/Crumb.tsx +22 -22
- package/stories/atoms/crumb/index.tsx +3 -3
- package/stories/atoms/icons/DynamicIcon.stories.ts +43 -43
- package/stories/atoms/icons/DynamicIcon.tsx +90 -90
- package/stories/atoms/icons/IconWithShadow.stories.ts +43 -43
- package/stories/atoms/icons/IconWithShadow.tsx +16 -16
- package/stories/atoms/icons/TablerIcon.tsx +22 -22
- package/stories/atoms/icons/index.tsx +14 -14
- package/stories/atoms/icons/tablerIconNames.ts +4336 -4336
- package/stories/atoms/index.ts +46 -46
- package/stories/atoms/loaders/Loader.stories.ts +15 -15
- package/stories/atoms/loaders/Loader.tsx +21 -21
- package/stories/atoms/loaders/NProgress/RadialProgress.stories.tsx +19 -19
- package/stories/atoms/loaders/NProgress/RadialProgress.tsx +74 -74
- package/stories/atoms/loaders/NProgress/index.ts +3 -3
- package/stories/atoms/loaders/index.ts +4 -4
- package/stories/index.ts +136 -136
- package/stories/molecules/index.ts +51 -51
- package/stories/molecules/inputs/InputCounter/InputCounter.stories.tsx +18 -18
- package/stories/molecules/inputs/InputCounter/InputCounter.tsx +24 -24
- package/stories/molecules/inputs/InputCounter/index.tsx +3 -3
- package/stories/molecules/inputs/InputField/InputField.stories.tsx +29 -29
- package/stories/molecules/inputs/InputField/InputField.tsx +96 -96
- package/stories/molecules/inputs/InputField/index.tsx +3 -3
- package/stories/molecules/inputs/InputLabel/InputLabel.stories.tsx +19 -19
- package/stories/molecules/inputs/InputLabel/InputLabel.tsx +45 -45
- package/stories/molecules/inputs/InputLabel/index.tsx +3 -3
- package/stories/molecules/inputs/NestedInputButton/NestedInputButton.stories.tsx +52 -52
- package/stories/molecules/inputs/NestedInputButton/NestedInputButton.tsx +64 -64
- package/stories/molecules/inputs/NestedInputButton/index.tsx +3 -3
- package/stories/molecules/inputs/TextInput/TextInput.stories.tsx +32 -32
- package/stories/molecules/inputs/TextInput/TextInput.tsx +165 -165
- package/stories/molecules/inputs/TextInput/index.tsx +5 -5
- package/stories/molecules/inputs/checkbox/Checkbox.stories.ts +23 -23
- package/stories/molecules/inputs/checkbox/Checkbox.tsx +98 -98
- package/stories/molecules/inputs/checkbox/index.ts +3 -3
- package/stories/molecules/inputs/combobox/ComboBox.stories.ts +41 -41
- package/stories/molecules/inputs/combobox/ComboBox.tsx +185 -185
- package/stories/molecules/inputs/combobox/index.ts +3 -3
- package/stories/molecules/inputs/index.ts +38 -38
- package/stories/molecules/inputs/radio/Radio.stories.ts +27 -27
- package/stories/molecules/inputs/radio/Radio.tsx +92 -92
- package/stories/molecules/inputs/radio/index.ts +3 -3
- package/stories/molecules/inputs/select/Select.stories.ts +23 -23
- package/stories/molecules/inputs/select/Select.tsx +108 -100
- package/stories/molecules/inputs/select/index.ts +3 -3
- package/stories/molecules/inputs/textArea/TextArea.stories.ts +22 -22
- package/stories/molecules/inputs/textArea/TextArea.tsx +158 -158
- package/stories/molecules/inputs/textArea/index.ts +3 -3
- package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.stories.tsx +118 -118
- package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.tsx +81 -81
- package/stories/molecules/inputs/toggleSwitch/index.ts +3 -3
- package/stories/molecules/tabs/Tabs.stories.tsx +18 -18
- package/stories/molecules/tabs/Tabs.tsx +22 -22
- package/stories/molecules/tabs/index.tsx +2 -2
- package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.stories.tsx +30 -30
- package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.tsx +66 -66
- package/stories/organisms/AnimatedLabelInput/index.tsx +3 -3
- package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.stories.tsx +26 -26
- package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.tsx +61 -61
- package/stories/organisms/AnimatedLabelTextArea/index.tsx +3 -3
- package/stories/organisms/ButtonDropdown/ButtonDropdown.stories.tsx +125 -125
- package/stories/organisms/ButtonDropdown/ButtonDropdown.tsx +86 -86
- package/stories/organisms/ButtonDropdown/index.tsx +3 -3
- package/stories/organisms/DropdownComponent/Dropdown.stories.tsx +73 -73
- package/stories/organisms/DropdownComponent/DropdownComponent.tsx +346 -346
- package/stories/organisms/DropdownComponent/dropdownItems.ts +122 -122
- package/stories/organisms/DropdownComponent/index.ts +4 -4
- package/stories/organisms/EmptySectionPlaceholder/EmptySectionPlaceholder.stories.tsx +76 -76
- package/stories/organisms/EmptySectionPlaceholder/EmptySectionPlaceholder.tsx +52 -52
- package/stories/organisms/EmptySectionPlaceholder/index.tsx +4 -4
- package/stories/organisms/FormInputWithAddons/FormInputWithAddons.stories.tsx +29 -29
- package/stories/organisms/FormInputWithAddons/FormInputWithAddons.tsx +145 -145
- package/stories/organisms/FormInputWithAddons/index.tsx +3 -3
- package/stories/organisms/TextInputSelect/InputSelect.tsx +59 -59
- package/stories/organisms/TextInputSelect/TextInputSelect.stories.tsx +33 -33
- package/stories/organisms/TextInputSelect/TextInputSelect.tsx +186 -186
- package/stories/organisms/TextInputSelect/index.tsx +3 -3
- package/stories/organisms/index.ts +27 -27
- package/tailwind.config.js +192 -192
- package/tsconfig.json +29 -29
- package/tsconfig.lib.json +25 -25
- package/utils/types.d.ts +2 -2
- package/utils/types.ts +3 -3
- package/utils/useId.d.ts +1 -1
- package/utils/useId.tsx +16 -16
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton"
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof NestedInputButton> = {
|
|
5
|
-
title: "Design System/molecules/inputs/Nested Input Button",
|
|
6
|
-
component: NestedInputButton,
|
|
7
|
-
tags: ["autodocs"],
|
|
8
|
-
argTypes: {},
|
|
9
|
-
parameters: {
|
|
10
|
-
design: {
|
|
11
|
-
type: "figma",
|
|
12
|
-
url: "https://www.figma.com/file/Rb5fJ8hD3pwvLnidgCaGgB/Agility-UI?type=design&node-id=114-2290&mode=dev&device-scaling=100%25&page-id=0%3A1"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default meta
|
|
18
|
-
type Story = StoryObj<typeof NestedInputButton>
|
|
19
|
-
|
|
20
|
-
export const RightAligned: Story = {
|
|
21
|
-
args: {
|
|
22
|
-
icon: {
|
|
23
|
-
icon: "IconSearch",
|
|
24
|
-
className: "h-5 w-5 text-gray-400"
|
|
25
|
-
},
|
|
26
|
-
ctaLabel: "Search",
|
|
27
|
-
align: "right",
|
|
28
|
-
isClear: false,
|
|
29
|
-
onClickHandler: () => window.alert("Clicked"),
|
|
30
|
-
buttonProps: {
|
|
31
|
-
type: "button"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export const LeftAligned: Story = {
|
|
36
|
-
args: {
|
|
37
|
-
...RightAligned.args,
|
|
38
|
-
align: "left"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export const IsClear: Story = {
|
|
42
|
-
args: {
|
|
43
|
-
...RightAligned.args,
|
|
44
|
-
isClear: true
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export const NoIcon: Story = {
|
|
48
|
-
args: {
|
|
49
|
-
...RightAligned.args,
|
|
50
|
-
icon: undefined
|
|
51
|
-
}
|
|
52
|
-
}
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton"
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof NestedInputButton> = {
|
|
5
|
+
title: "Design System/molecules/inputs/Nested Input Button",
|
|
6
|
+
component: NestedInputButton,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
argTypes: {},
|
|
9
|
+
parameters: {
|
|
10
|
+
design: {
|
|
11
|
+
type: "figma",
|
|
12
|
+
url: "https://www.figma.com/file/Rb5fJ8hD3pwvLnidgCaGgB/Agility-UI?type=design&node-id=114-2290&mode=dev&device-scaling=100%25&page-id=0%3A1"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default meta
|
|
18
|
+
type Story = StoryObj<typeof NestedInputButton>
|
|
19
|
+
|
|
20
|
+
export const RightAligned: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
icon: {
|
|
23
|
+
icon: "IconSearch",
|
|
24
|
+
className: "h-5 w-5 text-gray-400"
|
|
25
|
+
},
|
|
26
|
+
ctaLabel: "Search",
|
|
27
|
+
align: "right",
|
|
28
|
+
isClear: false,
|
|
29
|
+
onClickHandler: () => window.alert("Clicked"),
|
|
30
|
+
buttonProps: {
|
|
31
|
+
type: "button"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export const LeftAligned: Story = {
|
|
36
|
+
args: {
|
|
37
|
+
...RightAligned.args,
|
|
38
|
+
align: "left"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export const IsClear: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
...RightAligned.args,
|
|
44
|
+
isClear: true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export const NoIcon: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
...RightAligned.args,
|
|
50
|
+
icon: undefined
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import { DynamicIcon, IDynamicIconProps } from "@/stories/atoms/icons"
|
|
3
|
-
import { default as cn } from "classnames"
|
|
4
|
-
export interface INestedInputButtonProps {
|
|
5
|
-
/** Icon to be included*/
|
|
6
|
-
icon?: IDynamicIconProps
|
|
7
|
-
/** CTA label */
|
|
8
|
-
ctaLabel?: string
|
|
9
|
-
/** Alignment */
|
|
10
|
-
align: "left" | "right"
|
|
11
|
-
/** Show the CTA without Background color and a border seperator */
|
|
12
|
-
isClear?: boolean
|
|
13
|
-
/** Onclick callback */
|
|
14
|
-
onClickHandler?(): void
|
|
15
|
-
buttonProps?: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const NestedInputButton: React.FC<INestedInputButtonProps> = ({
|
|
19
|
-
icon,
|
|
20
|
-
ctaLabel,
|
|
21
|
-
align = "right",
|
|
22
|
-
isClear = false,
|
|
23
|
-
onClickHandler,
|
|
24
|
-
buttonProps
|
|
25
|
-
}) => {
|
|
26
|
-
const handleClick = () => {
|
|
27
|
-
onClickHandler && onClickHandler()
|
|
28
|
-
}
|
|
29
|
-
const buttonStyle = cn(
|
|
30
|
-
"relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-300 text-sm font-medium focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500",
|
|
31
|
-
{
|
|
32
|
-
"rounded-r text-gray-500 -ml-px": align === "right"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"rounded-l text-gray-500 -mr-px": align === "left"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"cursor-default": !onClickHandler
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"hover:bg-gray-100": onClickHandler && !isClear
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"!border-l-white": isClear && align === "right"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"!border-r-white": isClear && align === "left"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"bg-gray-50": !isClear
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
"bg-white": isClear
|
|
54
|
-
}
|
|
55
|
-
)
|
|
56
|
-
return (
|
|
57
|
-
<button {...{ ...buttonProps, className: buttonStyle, onClick: handleClick }}>
|
|
58
|
-
{icon && <DynamicIcon {...{ ...icon, className: "text-gray-400" }} />}
|
|
59
|
-
{ctaLabel && <span>{ctaLabel}</span>}
|
|
60
|
-
</button>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export default NestedInputButton
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { DynamicIcon, IDynamicIconProps } from "@/stories/atoms/icons"
|
|
3
|
+
import { default as cn } from "classnames"
|
|
4
|
+
export interface INestedInputButtonProps {
|
|
5
|
+
/** Icon to be included*/
|
|
6
|
+
icon?: IDynamicIconProps
|
|
7
|
+
/** CTA label */
|
|
8
|
+
ctaLabel?: string
|
|
9
|
+
/** Alignment */
|
|
10
|
+
align: "left" | "right"
|
|
11
|
+
/** Show the CTA without Background color and a border seperator */
|
|
12
|
+
isClear?: boolean
|
|
13
|
+
/** Onclick callback */
|
|
14
|
+
onClickHandler?(): void
|
|
15
|
+
buttonProps?: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const NestedInputButton: React.FC<INestedInputButtonProps> = ({
|
|
19
|
+
icon,
|
|
20
|
+
ctaLabel,
|
|
21
|
+
align = "right",
|
|
22
|
+
isClear = false,
|
|
23
|
+
onClickHandler,
|
|
24
|
+
buttonProps
|
|
25
|
+
}) => {
|
|
26
|
+
const handleClick = () => {
|
|
27
|
+
onClickHandler && onClickHandler()
|
|
28
|
+
}
|
|
29
|
+
const buttonStyle = cn(
|
|
30
|
+
"relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-300 text-sm font-medium focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500",
|
|
31
|
+
{
|
|
32
|
+
"rounded-r text-gray-500 -ml-px": align === "right"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"rounded-l text-gray-500 -mr-px": align === "left"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"cursor-default": !onClickHandler
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"hover:bg-gray-100": onClickHandler && !isClear
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"!border-l-white": isClear && align === "right"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"!border-r-white": isClear && align === "left"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"bg-gray-50": !isClear
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"bg-white": isClear
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
return (
|
|
57
|
+
<button {...{ ...buttonProps, className: buttonStyle, onClick: handleClick }}>
|
|
58
|
+
{icon && <DynamicIcon {...{ ...icon, className: "text-gray-400" }} />}
|
|
59
|
+
{ctaLabel && <span>{ctaLabel}</span>}
|
|
60
|
+
</button>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default NestedInputButton
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton"
|
|
2
|
-
export type { INestedInputButtonProps }
|
|
3
|
-
export default NestedInputButton
|
|
1
|
+
import NestedInputButton, { INestedInputButtonProps } from "./NestedInputButton"
|
|
2
|
+
export type { INestedInputButtonProps }
|
|
3
|
+
export default NestedInputButton
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
import TextInput, { ITextInputProps } from "./TextInput"
|
|
3
|
-
import React from "react"
|
|
4
|
-
|
|
5
|
-
const meta: Meta<typeof TextInput> = {
|
|
6
|
-
title: "Design System/molecules/inputs/TextInput",
|
|
7
|
-
component: TextInput,
|
|
8
|
-
tags: ["autodocs"],
|
|
9
|
-
argTypes: {}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default meta
|
|
13
|
-
type Story = StoryObj<typeof TextInput>
|
|
14
|
-
|
|
15
|
-
export const DefaultTextInputStory: Story = {
|
|
16
|
-
args: {
|
|
17
|
-
type: "text",
|
|
18
|
-
label: "Label",
|
|
19
|
-
isFocused: true,
|
|
20
|
-
isError: false,
|
|
21
|
-
id: "id",
|
|
22
|
-
name: "name",
|
|
23
|
-
isRequired: true,
|
|
24
|
-
|
|
25
|
-
isDisabled: false,
|
|
26
|
-
isReadonly: false,
|
|
27
|
-
message: "message",
|
|
28
|
-
isShowCounter: true,
|
|
29
|
-
maxLength: 100,
|
|
30
|
-
placeholder: "placeholder"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import TextInput, { ITextInputProps } from "./TextInput"
|
|
3
|
+
import React from "react"
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof TextInput> = {
|
|
6
|
+
title: "Design System/molecules/inputs/TextInput",
|
|
7
|
+
component: TextInput,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
argTypes: {}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default meta
|
|
13
|
+
type Story = StoryObj<typeof TextInput>
|
|
14
|
+
|
|
15
|
+
export const DefaultTextInputStory: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
type: "text",
|
|
18
|
+
label: "Label",
|
|
19
|
+
isFocused: true,
|
|
20
|
+
isError: false,
|
|
21
|
+
id: "id",
|
|
22
|
+
name: "name",
|
|
23
|
+
isRequired: true,
|
|
24
|
+
|
|
25
|
+
isDisabled: false,
|
|
26
|
+
isReadonly: false,
|
|
27
|
+
message: "message",
|
|
28
|
+
isShowCounter: true,
|
|
29
|
+
maxLength: 100,
|
|
30
|
+
placeholder: "placeholder"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,165 +1,165 @@
|
|
|
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
|
-
|
|
7
|
-
export interface ITextInputProps {
|
|
8
|
-
/** Input type*/
|
|
9
|
-
type: AcceptedInputTypes
|
|
10
|
-
/** Input ID */
|
|
11
|
-
id?: string
|
|
12
|
-
/** Input Name */
|
|
13
|
-
name?: string
|
|
14
|
-
/** Label for the input */
|
|
15
|
-
label?: string
|
|
16
|
-
/** Force the focus state on the input */
|
|
17
|
-
isFocused?: boolean
|
|
18
|
-
/** Error state */
|
|
19
|
-
isError?: boolean
|
|
20
|
-
/** If field is required */
|
|
21
|
-
isRequired?: boolean
|
|
22
|
-
/** Disabled state */
|
|
23
|
-
isDisabled?: boolean
|
|
24
|
-
/** Readonly state */
|
|
25
|
-
isReadonly?: boolean
|
|
26
|
-
/** Set default value */
|
|
27
|
-
defaultValue?: string
|
|
28
|
-
/** Message shown under the text field */
|
|
29
|
-
message?: string
|
|
30
|
-
/** Input character counter */
|
|
31
|
-
isShowCounter?: boolean
|
|
32
|
-
/** Max length of input character */
|
|
33
|
-
maxLength?: number
|
|
34
|
-
/** Callback on change */
|
|
35
|
-
handleChange(value: string): void
|
|
36
|
-
/** input value */
|
|
37
|
-
value: string
|
|
38
|
-
/**Placeholder input text*/
|
|
39
|
-
placeholder?: string
|
|
40
|
-
|
|
41
|
-
className?: string
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const TextInput = (
|
|
45
|
-
{
|
|
46
|
-
label,
|
|
47
|
-
isFocused,
|
|
48
|
-
isError,
|
|
49
|
-
id,
|
|
50
|
-
name,
|
|
51
|
-
isRequired,
|
|
52
|
-
type,
|
|
53
|
-
defaultValue,
|
|
54
|
-
isDisabled,
|
|
55
|
-
isReadonly,
|
|
56
|
-
message,
|
|
57
|
-
isShowCounter,
|
|
58
|
-
maxLength,
|
|
59
|
-
handleChange,
|
|
60
|
-
placeholder,
|
|
61
|
-
value: externalValue,
|
|
62
|
-
className,
|
|
63
|
-
...props
|
|
64
|
-
}: ITextInputProps,
|
|
65
|
-
ref: React.Ref<HTMLInputElement>
|
|
66
|
-
) => {
|
|
67
|
-
const uniqueID = useId()
|
|
68
|
-
const [isFocus, setIsFocus] = useState<boolean>(Boolean(isFocused))
|
|
69
|
-
|
|
70
|
-
const [value, setValue] = useState<string>(externalValue || defaultValue || "")
|
|
71
|
-
const inputRef = useRef<HTMLInputElement>(null)
|
|
72
|
-
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
//if the external value is updated by the parent component, reset the value in here...
|
|
75
|
-
if (externalValue !== undefined && externalValue !== null) {
|
|
76
|
-
setValue(externalValue)
|
|
77
|
-
}
|
|
78
|
-
}, [externalValue])
|
|
79
|
-
|
|
80
|
-
// set force focus
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
const input = inputRef.current
|
|
83
|
-
if (!input || isFocus === undefined || isDisabled) return
|
|
84
|
-
if (isFocus) {
|
|
85
|
-
input.focus()
|
|
86
|
-
} else {
|
|
87
|
-
input.blur()
|
|
88
|
-
}
|
|
89
|
-
}, [isFocus])
|
|
90
|
-
|
|
91
|
-
// set label as active if default value is set
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
const input = inputRef.current
|
|
94
|
-
if (!input || defaultValue === undefined || defaultValue === "") return
|
|
95
|
-
}, [defaultValue])
|
|
96
|
-
|
|
97
|
-
const handleInputFocus = () => setIsFocus(true)
|
|
98
|
-
// add other focus effects here
|
|
99
|
-
|
|
100
|
-
const handleInputBlur = () => setIsFocus(false)
|
|
101
|
-
|
|
102
|
-
if (!id) id = `input-${uniqueID}`
|
|
103
|
-
if (!name) name = id
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<div className="relative">
|
|
107
|
-
<InputLabel
|
|
108
|
-
isPlaceholder={true}
|
|
109
|
-
label={label}
|
|
110
|
-
isRequired={isRequired}
|
|
111
|
-
id={id}
|
|
112
|
-
isError={isError}
|
|
113
|
-
isActive={true}
|
|
114
|
-
isDisabled={isDisabled}
|
|
115
|
-
/>
|
|
116
|
-
<InputField
|
|
117
|
-
onFocus={handleInputFocus}
|
|
118
|
-
onBlur={handleInputBlur}
|
|
119
|
-
handleChange={(v: string) => {
|
|
120
|
-
setValue(v)
|
|
121
|
-
handleChange(v)
|
|
122
|
-
}}
|
|
123
|
-
ref={ref}
|
|
124
|
-
type={type}
|
|
125
|
-
name={name}
|
|
126
|
-
id={id}
|
|
127
|
-
className={cn(
|
|
128
|
-
"w-full rounded border py-2 px-3 text-sm font-normal leading-5",
|
|
129
|
-
{ "border-gray-300": !isFocus && !isError },
|
|
130
|
-
{
|
|
131
|
-
"!border-purple-500 shadow-none outline-purple-500 focus:!ring-purple-500": isFocus && !isError
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
"!border-red-500 shadow-none focus:ring-red-500": isError
|
|
135
|
-
},
|
|
136
|
-
className
|
|
137
|
-
)}
|
|
138
|
-
isDisabled={isDisabled}
|
|
139
|
-
isReadonly={isReadonly}
|
|
140
|
-
value={value}
|
|
141
|
-
defaultValue={defaultValue}
|
|
142
|
-
maxLength={maxLength}
|
|
143
|
-
placeholder={placeholder}
|
|
144
|
-
{...props}
|
|
145
|
-
/>
|
|
146
|
-
<div className="flex flex-row space-x-3">
|
|
147
|
-
<div className="grow">
|
|
148
|
-
{message && (
|
|
149
|
-
<span className={cn("mt-1 block text-sm", isError ? "text-red-500" : "text-gray-500")}>
|
|
150
|
-
{message}
|
|
151
|
-
</span>
|
|
152
|
-
)}
|
|
153
|
-
</div>
|
|
154
|
-
{isShowCounter && (
|
|
155
|
-
<div className="shrink-0">
|
|
156
|
-
<InputCounter current={Number(value?.length)} limit={maxLength} />
|
|
157
|
-
</div>
|
|
158
|
-
)}
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const _TextInput = forwardRef<HTMLInputElement, ITextInputProps>(TextInput)
|
|
165
|
-
export default _TextInput
|
|
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
|
+
|
|
7
|
+
export interface ITextInputProps {
|
|
8
|
+
/** Input type*/
|
|
9
|
+
type: AcceptedInputTypes
|
|
10
|
+
/** Input ID */
|
|
11
|
+
id?: string
|
|
12
|
+
/** Input Name */
|
|
13
|
+
name?: string
|
|
14
|
+
/** Label for the input */
|
|
15
|
+
label?: string
|
|
16
|
+
/** Force the focus state on the input */
|
|
17
|
+
isFocused?: boolean
|
|
18
|
+
/** Error state */
|
|
19
|
+
isError?: boolean
|
|
20
|
+
/** If field is required */
|
|
21
|
+
isRequired?: boolean
|
|
22
|
+
/** Disabled state */
|
|
23
|
+
isDisabled?: boolean
|
|
24
|
+
/** Readonly state */
|
|
25
|
+
isReadonly?: boolean
|
|
26
|
+
/** Set default value */
|
|
27
|
+
defaultValue?: string
|
|
28
|
+
/** Message shown under the text field */
|
|
29
|
+
message?: string
|
|
30
|
+
/** Input character counter */
|
|
31
|
+
isShowCounter?: boolean
|
|
32
|
+
/** Max length of input character */
|
|
33
|
+
maxLength?: number
|
|
34
|
+
/** Callback on change */
|
|
35
|
+
handleChange(value: string): void
|
|
36
|
+
/** input value */
|
|
37
|
+
value: string
|
|
38
|
+
/**Placeholder input text*/
|
|
39
|
+
placeholder?: string
|
|
40
|
+
|
|
41
|
+
className?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const TextInput = (
|
|
45
|
+
{
|
|
46
|
+
label,
|
|
47
|
+
isFocused,
|
|
48
|
+
isError,
|
|
49
|
+
id,
|
|
50
|
+
name,
|
|
51
|
+
isRequired,
|
|
52
|
+
type,
|
|
53
|
+
defaultValue,
|
|
54
|
+
isDisabled,
|
|
55
|
+
isReadonly,
|
|
56
|
+
message,
|
|
57
|
+
isShowCounter,
|
|
58
|
+
maxLength,
|
|
59
|
+
handleChange,
|
|
60
|
+
placeholder,
|
|
61
|
+
value: externalValue,
|
|
62
|
+
className,
|
|
63
|
+
...props
|
|
64
|
+
}: ITextInputProps,
|
|
65
|
+
ref: React.Ref<HTMLInputElement>
|
|
66
|
+
) => {
|
|
67
|
+
const uniqueID = useId()
|
|
68
|
+
const [isFocus, setIsFocus] = useState<boolean>(Boolean(isFocused))
|
|
69
|
+
|
|
70
|
+
const [value, setValue] = useState<string>(externalValue || defaultValue || "")
|
|
71
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
//if the external value is updated by the parent component, reset the value in here...
|
|
75
|
+
if (externalValue !== undefined && externalValue !== null) {
|
|
76
|
+
setValue(externalValue)
|
|
77
|
+
}
|
|
78
|
+
}, [externalValue])
|
|
79
|
+
|
|
80
|
+
// set force focus
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const input = inputRef.current
|
|
83
|
+
if (!input || isFocus === undefined || isDisabled) return
|
|
84
|
+
if (isFocus) {
|
|
85
|
+
input.focus()
|
|
86
|
+
} else {
|
|
87
|
+
input.blur()
|
|
88
|
+
}
|
|
89
|
+
}, [isFocus])
|
|
90
|
+
|
|
91
|
+
// set label as active if default value is set
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const input = inputRef.current
|
|
94
|
+
if (!input || defaultValue === undefined || defaultValue === "") return
|
|
95
|
+
}, [defaultValue])
|
|
96
|
+
|
|
97
|
+
const handleInputFocus = () => setIsFocus(true)
|
|
98
|
+
// add other focus effects here
|
|
99
|
+
|
|
100
|
+
const handleInputBlur = () => setIsFocus(false)
|
|
101
|
+
|
|
102
|
+
if (!id) id = `input-${uniqueID}`
|
|
103
|
+
if (!name) name = id
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div className="relative">
|
|
107
|
+
<InputLabel
|
|
108
|
+
isPlaceholder={true}
|
|
109
|
+
label={label}
|
|
110
|
+
isRequired={isRequired}
|
|
111
|
+
id={id}
|
|
112
|
+
isError={isError}
|
|
113
|
+
isActive={true}
|
|
114
|
+
isDisabled={isDisabled}
|
|
115
|
+
/>
|
|
116
|
+
<InputField
|
|
117
|
+
onFocus={handleInputFocus}
|
|
118
|
+
onBlur={handleInputBlur}
|
|
119
|
+
handleChange={(v: string) => {
|
|
120
|
+
setValue(v)
|
|
121
|
+
handleChange(v)
|
|
122
|
+
}}
|
|
123
|
+
ref={ref}
|
|
124
|
+
type={type}
|
|
125
|
+
name={name}
|
|
126
|
+
id={id}
|
|
127
|
+
className={cn(
|
|
128
|
+
"w-full rounded border py-2 px-3 text-sm font-normal leading-5",
|
|
129
|
+
{ "border-gray-300": !isFocus && !isError },
|
|
130
|
+
{
|
|
131
|
+
"!border-purple-500 shadow-none outline-purple-500 focus:!ring-purple-500": isFocus && !isError
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"!border-red-500 shadow-none focus:ring-red-500": isError
|
|
135
|
+
},
|
|
136
|
+
className
|
|
137
|
+
)}
|
|
138
|
+
isDisabled={isDisabled}
|
|
139
|
+
isReadonly={isReadonly}
|
|
140
|
+
value={value}
|
|
141
|
+
defaultValue={defaultValue}
|
|
142
|
+
maxLength={maxLength}
|
|
143
|
+
placeholder={placeholder}
|
|
144
|
+
{...props}
|
|
145
|
+
/>
|
|
146
|
+
<div className="flex flex-row space-x-3">
|
|
147
|
+
<div className="grow">
|
|
148
|
+
{message && (
|
|
149
|
+
<span className={cn("mt-1 block text-sm", isError ? "text-red-500" : "text-gray-500")}>
|
|
150
|
+
{message}
|
|
151
|
+
</span>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
{isShowCounter && (
|
|
155
|
+
<div className="shrink-0">
|
|
156
|
+
<InputCounter current={Number(value?.length)} limit={maxLength} />
|
|
157
|
+
</div>
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const _TextInput = forwardRef<HTMLInputElement, ITextInputProps>(TextInput)
|
|
165
|
+
export default _TextInput
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import TextInput from "./TextInput"
|
|
2
|
-
import { ITextInputProps } from "./TextInput"
|
|
3
|
-
|
|
4
|
-
export type { ITextInputProps }
|
|
5
|
-
export default TextInput
|
|
1
|
+
import TextInput from "./TextInput"
|
|
2
|
+
import { ITextInputProps } from "./TextInput"
|
|
3
|
+
|
|
4
|
+
export type { ITextInputProps }
|
|
5
|
+
export default TextInput
|