@agility/plenum-ui 2.0.0-rc4 → 2.0.0-rc41

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.
Files changed (102) hide show
  1. package/README.md +104 -31
  2. package/build.js +30 -25
  3. package/dist/index.d.ts +278 -89
  4. package/dist/index.js +1 -5980
  5. package/dist/index.js.map +4 -4
  6. package/dist/tailwind.css +63599 -0
  7. package/dist/types/stories/atoms/buttons/Button/Alternative/Alternative.stories.d.ts +1 -0
  8. package/dist/types/stories/atoms/buttons/Button/Button.d.ts +3 -7
  9. package/dist/types/stories/atoms/buttons/Button/Danger/Danger.stories.d.ts +1 -0
  10. package/dist/types/stories/atoms/buttons/Button/Primary/Primary.stories.d.ts +1 -0
  11. package/dist/types/stories/atoms/buttons/Button/Secondary/Secondary.stories.d.ts +1 -0
  12. package/dist/types/stories/atoms/buttons/Capsule/Capsule.d.ts +1 -1
  13. package/dist/types/stories/atoms/icons/DynamicIcon.d.ts +2 -2
  14. package/dist/types/stories/atoms/icons/TablerIcon.d.ts +1 -1
  15. package/dist/types/stories/index.d.ts +4 -4
  16. package/dist/types/stories/molecules/index.d.ts +3 -3
  17. package/dist/types/stories/molecules/inputs/InputCounter/InputCounter.d.ts +10 -0
  18. package/dist/types/stories/molecules/inputs/InputCounter/index.d.ts +2 -0
  19. package/dist/types/stories/molecules/inputs/InputField/InputField.d.ts +6 -4
  20. package/dist/types/stories/molecules/inputs/TextInput/TextInput.d.ts +39 -0
  21. package/dist/types/stories/molecules/inputs/TextInput/index.d.ts +4 -0
  22. package/dist/types/stories/molecules/inputs/index.d.ts +5 -4
  23. package/dist/types/stories/molecules/inputs/select/Select.d.ts +2 -2
  24. package/dist/types/stories/molecules/inputs/textArea/TextArea.d.ts +34 -21
  25. package/dist/types/stories/molecules/inputs/textArea/TextArea.stories.d.ts +4 -4
  26. package/dist/types/stories/molecules/inputs/textArea/index.d.ts +3 -3
  27. package/dist/types/stories/molecules/inputs/toggleSwitch/ToggleSwitch.d.ts +10 -7
  28. package/dist/types/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.d.ts +3 -5
  29. package/dist/types/stories/organisms/AnimatedLabelInput/index.d.ts +1 -1
  30. package/dist/types/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.d.ts +12 -0
  31. package/dist/types/stories/organisms/AnimatedLabelTextArea/index.d.ts +3 -0
  32. package/dist/types/stories/organisms/DropdownComponent/DropdownComponent.d.ts +21 -12
  33. package/dist/types/stories/organisms/DropdownComponent/index.d.ts +2 -2
  34. package/dist/types/stories/organisms/EmptySectionPlaceholder/index.d.ts +1 -1
  35. package/dist/types/stories/organisms/TextInputSelect/InputSelect.d.ts +16 -0
  36. package/dist/types/stories/organisms/TextInputSelect/TextInputSelect.d.ts +48 -0
  37. package/dist/types/stories/organisms/TextInputSelect/index.d.ts +3 -0
  38. package/dist/types/stories/organisms/index.d.ts +5 -3
  39. package/local.sh +100 -0
  40. package/package.json +36 -19
  41. package/rollup.config.mjs +42 -0
  42. package/stories/Introduction.mdx +1 -1
  43. package/stories/atoms/badges/Badge.tsx +1 -1
  44. package/stories/atoms/buttons/Button/Alternative/Alternative.stories.ts +10 -0
  45. package/stories/atoms/buttons/Button/Button.tsx +108 -24
  46. package/stories/atoms/buttons/Button/Danger/Danger.stories.ts +14 -2
  47. package/stories/atoms/buttons/Button/Primary/Primary.stories.ts +14 -2
  48. package/stories/atoms/buttons/Button/Secondary/Secondary.stories.ts +13 -1
  49. package/stories/atoms/buttons/Button/defaultArgs.ts +1 -1
  50. package/stories/atoms/buttons/Capsule/Capsule.tsx +2 -1
  51. package/stories/atoms/icons/DynamicIcon.stories.ts +1 -1
  52. package/stories/atoms/icons/DynamicIcon.tsx +7 -7
  53. package/stories/atoms/icons/IconWithShadow.stories.ts +3 -3
  54. package/stories/atoms/icons/TablerIcon.tsx +1 -1
  55. package/stories/atoms/loaders/Loader.tsx +12 -6
  56. package/stories/index.ts +22 -10
  57. package/stories/molecules/index.ts +22 -6
  58. package/stories/molecules/inputs/InputField/InputField.tsx +10 -9
  59. package/stories/molecules/inputs/TextInput/TextInput.tsx +6 -3
  60. package/stories/molecules/inputs/TextInput/index.tsx +4 -2
  61. package/stories/molecules/inputs/checkbox/Checkbox.tsx +1 -2
  62. package/stories/molecules/inputs/combobox/ComboBox.tsx +126 -135
  63. package/stories/molecules/inputs/index.ts +18 -4
  64. package/stories/molecules/inputs/select/Select.tsx +1 -1
  65. package/stories/molecules/inputs/textArea/TextArea.stories.ts +7 -5
  66. package/stories/molecules/inputs/textArea/TextArea.tsx +139 -48
  67. package/stories/molecules/inputs/textArea/index.ts +3 -3
  68. package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.tsx +63 -57
  69. package/stories/molecules/tabs/index.tsx +2 -3
  70. package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.stories.tsx +10 -1
  71. package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.tsx +43 -37
  72. package/stories/organisms/AnimatedLabelInput/index.tsx +1 -1
  73. package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.stories.tsx +26 -0
  74. package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.tsx +61 -0
  75. package/stories/organisms/AnimatedLabelTextArea/index.tsx +3 -0
  76. package/stories/organisms/ButtonDropdown/ButtonDropdown.stories.tsx +65 -58
  77. package/stories/organisms/ButtonDropdown/ButtonDropdown.tsx +26 -21
  78. package/stories/organisms/DropdownComponent/Dropdown.stories.tsx +2 -2
  79. package/stories/organisms/DropdownComponent/DropdownComponent.tsx +213 -178
  80. package/stories/organisms/DropdownComponent/dropdownItems.ts +30 -9
  81. package/stories/organisms/DropdownComponent/index.ts +2 -2
  82. package/stories/organisms/EmptySectionPlaceholder/EmptySectionPlaceholder.stories.tsx +3 -3
  83. package/stories/organisms/EmptySectionPlaceholder/index.tsx +2 -1
  84. package/stories/organisms/FormInputWithAddons/FormInputWithAddons.stories.tsx +1 -1
  85. package/stories/organisms/FormInputWithAddons/FormInputWithAddons.tsx +7 -2
  86. package/stories/organisms/TextInputSelect/InputSelect.tsx +59 -0
  87. package/stories/organisms/TextInputSelect/TextInputSelect.stories.tsx +33 -0
  88. package/stories/organisms/TextInputSelect/TextInputSelect.tsx +186 -0
  89. package/stories/organisms/TextInputSelect/index.tsx +3 -0
  90. package/stories/organisms/index.ts +15 -4
  91. package/tsconfig.lib.json +13 -6
  92. package/watch.js +49 -0
  93. package/.yarnrc.yml +0 -1
  94. package/dist/types/stories/layouts/index.d.ts +0 -0
  95. package/stories/layouts/CardLayout/CardLayout.stories.tsx +0 -18
  96. package/stories/layouts/CardLayout/CardLayout.tsx +0 -22
  97. package/stories/layouts/CardLayout/index.tsx +0 -3
  98. package/stories/layouts/ModalLayout/ModalLayout.stories.tsx +0 -18
  99. package/stories/layouts/ModalLayout/ModalLayout.tsx +0 -22
  100. package/stories/layouts/ModalLayout/index.tsx +0 -3
  101. package/stories/layouts/index.ts +0 -0
  102. package/stories/organisms/DropdownComponent/Dropdown.test.tsx +0 -0
@@ -1,67 +1,158 @@
1
+ import React, { forwardRef, useEffect, useId, useState } from "react"
1
2
  import { default as cn } from "classnames"
3
+ import InputLabel from "../InputLabel"
4
+ import InputCounter from "../InputCounter"
2
5
 
3
- export interface ITextAreaFieldProps extends React.ComponentPropsWithoutRef<"textarea"> {
4
- /** Callback on change */
5
- handleChange: (value: string) => void
6
- /** textarea ID*/
7
- id: string
8
- /** textarea Name */
9
- name: string
10
- /** Force the focus state on the textarea */
11
- isFocused?: boolean
12
- /** Error condition */
6
+ interface ILabelProps extends React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement> {
7
+ display: string
8
+ htmlFor?: string
9
+ }
10
+
11
+ export interface ITextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
12
+ /** Input ID */
13
+ id?: string
14
+ /** Input Name */
15
+ name?: string
16
+ /** Label for the input */
17
+ label?: ILabelProps
18
+ /** Error state */
13
19
  isError?: boolean
20
+ /** If field is required */
21
+ isRequired?: boolean
14
22
  /** Disabled state */
15
23
  isDisabled?: boolean
16
- /** Readonly state */
17
- isReadonly?: boolean
18
- /** textarea value */
19
- value: string
20
- /** If field is required */
21
- required?: boolean
22
- /**Allow Text Area Resize*/
23
- textAreaResize?: boolean
24
+ /** Set default value */
25
+ defaultValue?: string
26
+
27
+ value?: string
28
+
29
+ /** Message shown under the text field */
30
+ message?: string
31
+ /** Input character counter */
32
+ isShowCounter?: boolean
33
+ /** Max length of input character */
34
+ maxLength?: number
35
+ /** Callback on change */
36
+ onChange?(value: string): void
37
+ /** Number of rows */
38
+ rows?: number
39
+ /** Number of cols */
40
+ cols?: number
41
+ placeholder?: string
24
42
  className?: string
43
+ ref?: React.LegacyRef<HTMLTextAreaElement>
25
44
  }
26
- const TextAreaField: React.FC<ITextAreaFieldProps> = ({
45
+
46
+ const Textarea: React.FC<ITextareaProps> = ({
27
47
  id,
28
48
  name,
29
- value,
30
- isFocused,
49
+ label,
31
50
  isError,
32
- isReadonly,
51
+ isRequired,
33
52
  isDisabled,
34
- handleChange,
35
- required,
53
+ defaultValue,
54
+ message,
55
+ isShowCounter,
56
+ maxLength,
57
+ rows = 12,
58
+ cols = 48,
59
+ onChange,
60
+ value,
36
61
  placeholder,
37
62
  className,
63
+ ref,
38
64
  ...rest
39
65
  }) => {
40
- return (
41
- <textarea
42
- {...{
43
- id,
44
- name,
45
- value,
46
- onChange: (e) => {
47
- handleChange(e.target.value)
48
- },
49
- autoFocus: isFocused,
50
- readOnly: isReadonly,
51
- disabled: isDisabled,
52
- required,
53
- placeholder: placeholder || " ",
54
- "aria-invalid": isError,
55
- "aria-disabled": isDisabled,
56
- className: cn(
57
- "peer w-full resize-y auto-resize rounded border border-gray-300 py-2 px-3 pt-2 text-sm font-normal leading-5 outline-offset-0 ring-offset-0 focus:border-purple-600 focus:ring-purple-600",
58
- isError ? "border-red-600 text-red-600" : "",
66
+ const uniqueID = useId()
67
+
68
+ const discriptionStyles = cn("text-sm mt-1 block", { "text-gray-500": !isError }, { "text-red-500": isError })
69
+
70
+ if (!id) id = `ta-${uniqueID}`
71
+
72
+ if (!label) {
73
+ return (
74
+ <textarea
75
+ ref={ref}
76
+ maxLength={maxLength}
77
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
78
+ const targetValue = e.target.value
79
+ if (onChange) {
80
+ onChange(targetValue)
81
+ }
82
+ }}
83
+ rows={rows}
84
+ name={name}
85
+ id={id}
86
+ cols={cols}
87
+ className={cn(
88
+ "peer block w-full rounded focus:border-purple-500 focus:ring-purple-500 sm:text-sm",
89
+ { "border-gray-300 ": !isError },
90
+ {
91
+ "border-red-500 outline-red-500 focus:ring-red-500": isError
92
+ },
59
93
  className
60
- ),
61
- ...rest
62
- }}
63
- />
94
+ )}
95
+ disabled={isDisabled}
96
+ defaultValue={defaultValue}
97
+ value={value}
98
+ placeholder={placeholder}
99
+ {...rest}
100
+ />
101
+ )
102
+ }
103
+
104
+ //with label
105
+ return (
106
+ <div>
107
+ <InputLabel
108
+ isPlaceholder
109
+ isActive
110
+ label={label.display}
111
+ isRequired={isRequired}
112
+ id={id}
113
+ isError={isError}
114
+ isDisabled={isDisabled}
115
+ />
116
+
117
+ <div>
118
+ <textarea
119
+ ref={ref}
120
+ maxLength={maxLength}
121
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
122
+ const targetValue = e.target.value
123
+ if (onChange) {
124
+ onChange(targetValue)
125
+ }
126
+ }}
127
+ rows={rows}
128
+ name={name}
129
+ id={id}
130
+ cols={cols}
131
+ className={cn(
132
+ "block w-full rounded focus:border-purple-500 focus:ring-purple-500 sm:text-sm",
133
+ { "border-gray-300 ": !isError },
134
+ {
135
+ "border-red-500 outline-red-500 focus:ring-red-500": isError
136
+ },
137
+ className
138
+ )}
139
+ disabled={isDisabled}
140
+ defaultValue={defaultValue}
141
+ value={value}
142
+ placeholder={placeholder}
143
+ {...rest}
144
+ />
145
+ </div>
146
+ <div className="flex flex-row space-x-3">
147
+ <div className="grow">{message && <span className={discriptionStyles}>{message}</span>}</div>
148
+ {isShowCounter && (
149
+ <div className="shrink-0">
150
+ <InputCounter current={Number(value?.length)} limit={maxLength} />
151
+ </div>
152
+ )}
153
+ </div>
154
+ </div>
64
155
  )
65
156
  }
66
157
 
67
- export default TextAreaField
158
+ export default Textarea
@@ -1,3 +1,3 @@
1
- import TextAreaField, { ITextAreaFieldProps } from "./TextArea"
2
- export type { ITextAreaFieldProps }
3
- export default TextAreaField
1
+ import TextArea, { ITextareaProps } from "./TextArea"
2
+ export type { ITextareaProps }
3
+ export default TextArea
@@ -2,74 +2,80 @@ import React, { useEffect, useState } from "react"
2
2
  import { default as cn } from "classnames"
3
3
  import { Switch } from "@headlessui/react"
4
4
  import { DynamicIcon, IDynamicIconProps } from "@/stories/atoms"
5
+
6
+ interface ToggleSwitchLabel {
7
+ text: string | JSX.Element
8
+ className?: string
9
+ xPosition?: "left" | "right"
10
+ }
11
+
5
12
  export interface IToggleSwitchProps {
6
13
  isChecked: boolean
7
14
  onChange: (isChecked: boolean) => void
8
- label?: {
9
- text: string | JSX.Element
10
- className?: string
11
- xPosition?: "left" | "right"
12
- }
13
- screenReaderLabel: string
15
+ label?: ToggleSwitchLabel
16
+ screenReaderLabel?: string
14
17
  name: string
15
18
  id: string
16
- variant: "base" | "short"
19
+ variant?: "base" | "short"
17
20
  withIcon?: IDynamicIconProps
21
+ disabled?: boolean,
22
+ groupClassName?: string
18
23
  }
19
24
 
20
25
  const ToggleSwitch: React.FC<IToggleSwitchProps> = ({
21
- isChecked,
22
- onChange,
23
- label,
24
- screenReaderLabel,
25
- name,
26
- id,
27
- variant = "base",
28
- withIcon,
26
+ isChecked,
27
+ onChange,
28
+ label,
29
+ screenReaderLabel,
30
+ name,
31
+ id,
32
+ variant = "base",
33
+ withIcon,
34
+ disabled,
35
+ groupClassName,
29
36
  }) => {
30
- const [checked, setChecked] = useState<boolean>(isChecked)
31
- useEffect(() => setChecked(isChecked), [isChecked])
37
+ const [checked, setChecked] = useState<boolean>(isChecked)
38
+ useEffect(() => setChecked(isChecked), [isChecked])
32
39
 
33
- return (
34
- <Switch.Group as={"div"} className={"flex items-center gap-2"}>
35
- {label && label.xPosition === "left" && (
36
- <Switch.Label className={label.className}>{label.text}</Switch.Label>
37
- )}
38
- <Switch
39
- name={name}
40
- id={id}
41
- checked={checked}
42
- onChange={(v: boolean) => {
43
- onChange(v)
44
- setChecked(v)
45
- }}
46
- className={cn(
47
- { "w-9 h-4": variant === "short", " h-6 w-11": variant === "base" },
48
- checked ? "bg-purple-600" : "bg-gray-200",
49
- "relative inline-flex items-center rounded-full 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"
50
- )}
51
- >
52
- <span className="sr-only">{screenReaderLabel}</span>
53
- <span
54
- className={cn(
55
- checked ? "translate-x-[22px]" : "translate-x-[2px]",
56
- {
57
- "border border-gray-200 translate-x-0": variant === "short",
58
- "!translate-x-[22px]": checked && variant === "short",
59
- },
60
- " h-5 w-5 transform rounded-full bg-white transition shadow-sm drop-shadow flex items-center justify-center"
61
- )}
62
- >
63
- {withIcon && (
64
- <DynamicIcon {...withIcon} className={"text-gray-400 m-[2px]"} />
65
- )}
66
- </span>
67
- </Switch>
68
- {label && label.xPosition === "right" && (
69
- <Switch.Label className={label.className}>{label.text}</Switch.Label>
70
- )}
71
- </Switch.Group>
72
- )
40
+ return (
41
+ <Switch.Group as={"div"} className={cn("flex items-center gap-2", groupClassName)}>
42
+ {label && (label.xPosition === "left" || !label?.xPosition) && (
43
+ <Switch.Label className={label.className}>{label.text}</Switch.Label>
44
+ )}
45
+ <Switch
46
+ name={name}
47
+ id={id}
48
+ checked={checked}
49
+ onChange={(v: boolean) => {
50
+ onChange(v)
51
+ setChecked(v)
52
+ }}
53
+ className={cn(
54
+ { "w-9 h-4 transition-all": variant === "short", " h-6 w-11": variant === "base" },
55
+ checked && disabled ? "bg-purple-200" : checked ? "bg-purple-600" : "bg-gray-200",
56
+ "relative inline-flex items-center rounded-full 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"
57
+ )}
58
+ disabled={disabled}
59
+ >
60
+ {screenReaderLabel && <span className="sr-only">{screenReaderLabel}</span>}
61
+ <span
62
+ className={cn(
63
+ checked ? "translate-x-[22px]" : "translate-x-[2px]",
64
+ {
65
+ "border border-gray-200 translate-x-0": variant === "short",
66
+ "!translate-x-[22px]": checked && variant === "short"
67
+ },
68
+ " h-5 w-5 transform rounded-full bg-white transition shadow-sm drop-shadow flex items-center justify-center"
69
+ )}
70
+ >
71
+ {withIcon && <DynamicIcon {...withIcon} className={"text-gray-400 m-[2px]"} />}
72
+ </span>
73
+ </Switch>
74
+ {label && label.xPosition === "right" && (
75
+ <Switch.Label className={label.className}>{label.text}</Switch.Label>
76
+ )}
77
+ </Switch.Group>
78
+ )
73
79
  }
74
80
 
75
81
  export default ToggleSwitch
@@ -1,3 +1,2 @@
1
-
2
- export { default } from './Tabs';
3
- export * from './Tabs';
1
+ export * from "./Tabs"
2
+ export { default } from "./Tabs"
@@ -11,11 +11,20 @@ const meta: Meta<typeof AnimatedLabelInput> = {
11
11
  export default meta
12
12
  type Story = StoryObj<typeof AnimatedLabelInput>
13
13
  export const DefaultAnimatedLabelInputsStory: Story = {
14
+ args: {
15
+ id: "test",
16
+ label: {
17
+ display: "Label"
18
+ }
19
+ } as IAnimatedLabelInputProps
20
+ }
21
+
22
+ export const DefaultAnimatedLabelInputsStoryWithPlaceHolder: Story = {
14
23
  args: {
15
24
  id: "test",
16
25
  label: {
17
26
  display: "Label"
18
27
  },
19
- input: {}
28
+ placeholder: "Placeholder"
20
29
  } as IAnimatedLabelInputProps
21
30
  }
@@ -1,59 +1,65 @@
1
1
  import React from "react"
2
2
  import { default as cn } from "classnames"
3
3
  import InputField, { IInputFieldProps } from "@/stories/molecules/inputs/InputField"
4
- import TextAreaField, { ITextAreaFieldProps } from "@/stories/molecules/inputs/textArea/TextArea"
5
4
 
6
- interface ILabelProps extends React.ComponentPropsWithoutRef<"label"> {
5
+ interface ILabelProps extends React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement> {
7
6
  display: string
8
7
  }
9
8
 
10
- export interface IAnimatedLabelInputProps {
9
+ export interface IAnimatedLabelInputProps extends Omit<IInputFieldProps, "handleChange"> {
11
10
  id: string
12
11
  containerStyles?: string
13
12
  message?: string
14
- input?: IInputFieldProps
15
- textarea?: ITextAreaFieldProps
16
13
  required?: boolean
17
14
  isError?: boolean
18
15
  label: ILabelProps
16
+ handleChange: (value: string) => void
19
17
  }
20
18
 
21
- const AnimatedLabelInput: React.FC<IAnimatedLabelInputProps> = ({
22
- id,
23
- label,
24
- input,
25
- message,
26
- textarea,
27
- required,
28
- isError,
29
- containerStyles
30
- }) => {
19
+ const AnimatedLabelInput: React.FC<IAnimatedLabelInputProps> = (props: IAnimatedLabelInputProps) => {
20
+ const { id, containerStyles, message, required, isError, label, value, handleChange, ...input } = props
21
+
22
+ const [hasValue, setHasValue] = React.useState<boolean>(!!value)
23
+
31
24
  return (
32
- <div className={cn("group relative", containerStyles ? containerStyles : "")}>
33
- {input && <InputField isError={isError} {...input} />}
34
- {textarea && <TextAreaField isError={isError} {...textarea} />}
35
- <label
36
- className={cn(
37
- "absolute left-1 z-10 ml-[.172rem] inline-block bg-white px-1 text-xs transition-all peer-placeholder-shown:top-2 peer-placeholder-shown:text-sm peer-placeholder-shown:text-gray-600",
38
- "-top-[9px] group-focus-within:!-top-[12px] group-focus-within:!left-1 group-focus-within:!ml-[.172rem] group-focus-within:!text-xs",
39
- isError && "!text-red-600"
40
- )}
41
- htmlFor={id}
42
- >
43
- {label.display}
44
- {required && <span className="text-red-600">*</span>}
45
- </label>
46
-
47
- <div className="flex flex-row space-x-3">
48
- <div className="grow transition-all">
49
- {message && (
50
- <span className={cn("mt-1 block text-sm", isError ? "text-red-500" : "text-gray-500")}>
51
- {message}
52
- </span>
25
+ <>
26
+ <div className={cn("group relative", containerStyles ? containerStyles : "")}>
27
+ <InputField
28
+ id={id}
29
+ isError={isError}
30
+ value={value}
31
+ handleChange={(v) => {
32
+ setHasValue(!!v)
33
+ if (handleChange) handleChange(v)
34
+ }}
35
+ {...input}
36
+ />
37
+ <label
38
+ className={cn(
39
+ "absolute z-10 ml-[3px] inline-block bg-white text-sm transition-all text-gray-500 left-1 px-1",
40
+ hasValue ? "!-top-[8px] !ml-[.172rem] !text-xs text-gray-600" : "top-[9px]",
41
+ "peer-placeholder-shown:!-top-[8px] peer-placeholder-shown:!ml-[.172rem] peer-placeholder-shown:!text-xs peer-placeholder-shown:text-gray-600",
42
+ "group-focus-within:!-top-[8px] group-focus-within:!ml-[.172rem] group-focus-within:!text-xs group-focus-within:text-gray-600",
43
+
44
+ isError && "!text-red-600"
53
45
  )}
46
+ htmlFor={id}
47
+ >
48
+ {label.display}
49
+ {required && <span className="text-red-600 ml-1">*</span>}
50
+ </label>
51
+
52
+ <div className="flex flex-row space-x-3">
53
+ <div className="grow transition-all">
54
+ {message && (
55
+ <span className={cn("mt-1 block text-sm", isError ? "text-red-500" : "text-gray-500")}>
56
+ {message}
57
+ </span>
58
+ )}
59
+ </div>
54
60
  </div>
55
61
  </div>
56
- </div>
62
+ </>
57
63
  )
58
64
  }
59
65
 
@@ -1,3 +1,3 @@
1
1
  import AnimatedLabelInput, { IAnimatedLabelInputProps } from "./AnimatedLabelInput"
2
- export default AnimatedLabelInput
3
2
  export type { IAnimatedLabelInputProps }
3
+ export default AnimatedLabelInput
@@ -0,0 +1,26 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import AnimatedLabelTextArea, { IAnimatedLabelTextAreaProps } from "./AnimatedLabelTextArea"
3
+
4
+ const meta: Meta<typeof AnimatedLabelTextArea> = {
5
+ title: "Design System/organisms/Animated Label Text Area",
6
+ component: AnimatedLabelTextArea,
7
+ tags: ["autodocs"],
8
+ argTypes: {}
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof AnimatedLabelTextArea>
13
+ export const DefaultAnimatedLabelTextAreasStory: Story = {
14
+ args: {
15
+ id: "test",
16
+ label: "Label"
17
+ } as IAnimatedLabelTextAreaProps
18
+ }
19
+
20
+ export const DefaultAnimatedLabelTextAreasStoryWithPlaceholder: Story = {
21
+ args: {
22
+ id: "test",
23
+ label: "Label",
24
+ placeholder: "Placeholder"
25
+ } as IAnimatedLabelTextAreaProps
26
+ }
@@ -0,0 +1,61 @@
1
+ import React from "react"
2
+ import { default as cn } from "classnames"
3
+
4
+ import TextArea, { ITextareaProps } from "@/stories/molecules/inputs/textArea"
5
+
6
+ export interface IAnimatedLabelTextAreaProps extends ITextareaProps {
7
+ id: string
8
+ containerStyles?: string
9
+ message?: string
10
+ required?: boolean
11
+ isError?: boolean
12
+ handleChange: (value: string) => void
13
+ }
14
+
15
+ const AnimatedLabelTextArea: React.FC<IAnimatedLabelTextAreaProps> = (props: IAnimatedLabelTextAreaProps) => {
16
+ const { id, containerStyles, message, required, isError, label, value, handleChange, onChange, ...input } = props
17
+
18
+ const [hasValue, setHasValue] = React.useState<boolean>(!!value)
19
+
20
+ return (
21
+ <div className={cn("group relative", containerStyles ? containerStyles : "")}>
22
+ <TextArea
23
+ id={id}
24
+ isError={isError}
25
+ value={value}
26
+ {...input}
27
+ onChange={(v) => {
28
+ setHasValue(!!v)
29
+ if (handleChange) handleChange(v)
30
+ }}
31
+ label={undefined}
32
+ />
33
+ <label
34
+ className={cn(
35
+ "absolute z-10 ml-[3px] inline-block bg-white text-sm transition-all text-gray-500 left-1 px-1",
36
+ hasValue ? "!-top-[8px] !ml-[.172rem] !text-xs text-gray-600" : "top-[9px]",
37
+ "peer-placeholder-shown:!-top-[8px] peer-placeholder-shown:!ml-[.172rem] peer-placeholder-shown:!text-xs peer-placeholder-shown:text-gray-600",
38
+ "group-focus-within:!-top-[8px] group-focus-within:!ml-[.172rem] group-focus-within:!text-xs group-focus-within:text-gray-600",
39
+
40
+ isError && "!text-red-600"
41
+ )}
42
+ htmlFor={label?.htmlFor || id}
43
+ >
44
+ {label?.display}
45
+ {required && <span className="text-red-600 ml-1">*</span>}
46
+ </label>
47
+
48
+ <div className="flex flex-row space-x-3">
49
+ <div className="grow transition-all">
50
+ {message && (
51
+ <span className={cn("mt-1 block text-sm", isError ? "text-red-500" : "text-gray-500")}>
52
+ {message}
53
+ </span>
54
+ )}
55
+ </div>
56
+ </div>
57
+ </div>
58
+ )
59
+ }
60
+
61
+ export default AnimatedLabelTextArea
@@ -0,0 +1,3 @@
1
+ import AnimatedLabelTextArea, { IAnimatedLabelTextAreaProps } from "./AnimatedLabelTextArea"
2
+ export type { IAnimatedLabelTextAreaProps }
3
+ export default AnimatedLabelTextArea