@agility/plenum-ui 2.0.0-rc9 → 2.0.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.
Files changed (97) hide show
  1. package/README.md +104 -31
  2. package/build.js +30 -25
  3. package/dist/index.d.ts +103 -79
  4. package/dist/index.js +1 -6295
  5. package/dist/index.js.map +4 -4
  6. package/dist/{lib/tailwind.css → tailwind.css} +3754 -8120
  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/inputs/InputField/InputField.d.ts +7 -7
  17. package/dist/types/stories/molecules/inputs/TextInput/TextInput.d.ts +1 -1
  18. package/dist/types/stories/molecules/inputs/checkbox/Checkbox.d.ts +2 -0
  19. package/dist/types/stories/molecules/inputs/select/Select.d.ts +4 -2
  20. package/dist/types/stories/molecules/inputs/textArea/TextArea.d.ts +5 -1
  21. package/dist/types/stories/molecules/inputs/toggleSwitch/ToggleSwitch.d.ts +10 -7
  22. package/dist/types/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.d.ts +5 -5
  23. package/dist/types/stories/organisms/AnimatedLabelInput/index.d.ts +1 -1
  24. package/dist/types/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.d.ts +12 -0
  25. package/dist/types/stories/organisms/AnimatedLabelTextArea/index.d.ts +3 -0
  26. package/dist/types/stories/organisms/ButtonDropdown/ButtonDropdown.d.ts +1 -0
  27. package/dist/types/stories/organisms/DropdownComponent/DropdownComponent.d.ts +24 -13
  28. package/dist/types/stories/organisms/DropdownComponent/index.d.ts +2 -2
  29. package/dist/types/stories/organisms/EmptySectionPlaceholder/index.d.ts +1 -1
  30. package/dist/types/stories/organisms/index.d.ts +4 -3
  31. package/local.sh +100 -0
  32. package/package.json +35 -18
  33. package/rollup.config.mjs +42 -0
  34. package/stories/atoms/badges/Badge.tsx +1 -1
  35. package/stories/atoms/buttons/Button/Alternative/Alternative.stories.ts +10 -0
  36. package/stories/atoms/buttons/Button/Button.tsx +111 -25
  37. package/stories/atoms/buttons/Button/Danger/Danger.stories.ts +14 -2
  38. package/stories/atoms/buttons/Button/Primary/Primary.stories.ts +14 -2
  39. package/stories/atoms/buttons/Button/Secondary/Secondary.stories.ts +13 -1
  40. package/stories/atoms/buttons/Button/defaultArgs.ts +1 -1
  41. package/stories/atoms/buttons/Capsule/Capsule.tsx +2 -1
  42. package/stories/atoms/icons/DynamicIcon.stories.ts +1 -1
  43. package/stories/atoms/icons/DynamicIcon.tsx +7 -7
  44. package/stories/atoms/icons/IconWithShadow.stories.ts +3 -3
  45. package/stories/atoms/icons/TablerIcon.tsx +1 -1
  46. package/stories/atoms/loaders/Loader.tsx +12 -6
  47. package/stories/atoms/loaders/NProgress/RadialProgress.tsx +0 -2
  48. package/stories/index.ts +8 -4
  49. package/stories/molecules/inputs/InputCounter/InputCounter.tsx +2 -2
  50. package/stories/molecules/inputs/InputField/InputField.tsx +31 -29
  51. package/stories/molecules/inputs/InputLabel/InputLabel.tsx +6 -6
  52. package/stories/molecules/inputs/TextInput/TextInput.stories.tsx +31 -1
  53. package/stories/molecules/inputs/TextInput/TextInput.tsx +15 -7
  54. package/stories/molecules/inputs/checkbox/Checkbox.stories.ts +1 -1
  55. package/stories/molecules/inputs/checkbox/Checkbox.tsx +7 -4
  56. package/stories/molecules/inputs/combobox/ComboBox.tsx +126 -135
  57. package/stories/molecules/inputs/radio/Radio.stories.ts +2 -2
  58. package/stories/molecules/inputs/select/Select.stories.tsx +53 -0
  59. package/stories/molecules/inputs/select/Select.tsx +11 -3
  60. package/stories/molecules/inputs/textArea/{TextArea.stories.ts → TextArea.stories.tsx} +25 -2
  61. package/stories/molecules/inputs/textArea/TextArea.tsx +58 -28
  62. package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.stories.tsx +15 -16
  63. package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.tsx +63 -57
  64. package/stories/molecules/tabs/index.tsx +2 -3
  65. package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.stories.tsx +32 -2
  66. package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.tsx +66 -37
  67. package/stories/organisms/AnimatedLabelInput/index.tsx +1 -1
  68. package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.stories.tsx +26 -0
  69. package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.tsx +61 -0
  70. package/stories/organisms/AnimatedLabelTextArea/index.tsx +3 -0
  71. package/stories/organisms/ButtonDropdown/ButtonDropdown.stories.tsx +59 -59
  72. package/stories/organisms/ButtonDropdown/ButtonDropdown.tsx +42 -30
  73. package/stories/organisms/DropdownComponent/Dropdown.stories.tsx +26 -2
  74. package/stories/organisms/DropdownComponent/DropdownComponent.tsx +232 -180
  75. package/stories/organisms/DropdownComponent/dropdownItems.ts +30 -9
  76. package/stories/organisms/DropdownComponent/index.ts +2 -2
  77. package/stories/organisms/EmptySectionPlaceholder/EmptySectionPlaceholder.stories.tsx +3 -3
  78. package/stories/organisms/EmptySectionPlaceholder/index.tsx +2 -1
  79. package/stories/organisms/FormInputWithAddons/FormInputWithAddons.stories.tsx +1 -1
  80. package/stories/organisms/FormInputWithAddons/FormInputWithAddons.tsx +7 -2
  81. package/stories/organisms/index.ts +12 -3
  82. package/tailwind.config.js +139 -38
  83. package/tsconfig.lib.json +13 -6
  84. package/watch.js +49 -0
  85. package/.yarnrc.yml +0 -1
  86. package/dist/types/stories/layouts/index.d.ts +0 -0
  87. package/dist/types/stories/molecules/inputs/select/Select.stories.d.ts +0 -6
  88. package/dist/types/stories/molecules/inputs/textArea/TextArea.stories.d.ts +0 -6
  89. package/stories/layouts/CardLayout/CardLayout.stories.tsx +0 -18
  90. package/stories/layouts/CardLayout/CardLayout.tsx +0 -22
  91. package/stories/layouts/CardLayout/index.tsx +0 -3
  92. package/stories/layouts/ModalLayout/ModalLayout.stories.tsx +0 -18
  93. package/stories/layouts/ModalLayout/ModalLayout.tsx +0 -22
  94. package/stories/layouts/ModalLayout/index.tsx +0 -3
  95. package/stories/layouts/index.ts +0 -0
  96. package/stories/molecules/inputs/select/Select.stories.ts +0 -23
  97. package/stories/organisms/DropdownComponent/Dropdown.test.tsx +0 -0
@@ -32,7 +32,7 @@ export interface ITextInputProps {
32
32
  /** Max length of input character */
33
33
  maxLength?: number
34
34
  /** Callback on change */
35
- onChange(value: string): void
35
+ handleChange(value: string): void
36
36
  /** input value */
37
37
  value: string
38
38
  /**Placeholder input text*/
@@ -56,7 +56,7 @@ const TextInput = (
56
56
  message,
57
57
  isShowCounter,
58
58
  maxLength,
59
- onChange,
59
+ handleChange,
60
60
  placeholder,
61
61
  value: externalValue,
62
62
  className,
@@ -86,6 +86,7 @@ const TextInput = (
86
86
  } else {
87
87
  input.blur()
88
88
  }
89
+ // eslint-disable-next-line react-hooks/exhaustive-deps
89
90
  }, [isFocus])
90
91
 
91
92
  // set label as active if default value is set
@@ -103,7 +104,7 @@ const TextInput = (
103
104
  if (!name) name = id
104
105
 
105
106
  return (
106
- <div className="relative">
107
+ <div className="relative group">
107
108
  <InputLabel
108
109
  isPlaceholder={true}
109
110
  label={label}
@@ -116,20 +117,27 @@ const TextInput = (
116
117
  <InputField
117
118
  onFocus={handleInputFocus}
118
119
  onBlur={handleInputBlur}
119
- handleChange={(v) => setValue(v)}
120
+ handleChange={(v: string) => {
121
+ setValue(v)
122
+ handleChange(v)
123
+ }}
120
124
  ref={ref}
121
125
  type={type}
122
126
  name={name}
123
127
  id={id}
124
128
  className={cn(
125
129
  "w-full rounded border py-2 px-3 text-sm font-normal leading-5",
126
- { "border-gray-300": !isFocus && !isError },
130
+ { "border-gray-300": !isFocus && !isError && !isDisabled },
127
131
  {
128
- "!border-purple-500 shadow-none outline-purple-500 focus:!ring-purple-500": isFocus && !isError
132
+ "!border-purple-500 shadow-none outline-purple-500 focus:!ring-purple-500":
133
+ isFocus && !isError && !isDisabled
129
134
  },
130
135
  {
131
136
  "!border-red-500 shadow-none focus:ring-red-500": isError
132
137
  },
138
+ {
139
+ "placeholder:text-gray-300 !border-gray-300 !outline-gray-300 focus:!ring-gray-300": isDisabled
140
+ },
133
141
  className
134
142
  )}
135
143
  isDisabled={isDisabled}
@@ -150,7 +158,7 @@ const TextInput = (
150
158
  </div>
151
159
  {isShowCounter && (
152
160
  <div className="shrink-0">
153
- <InputCounter current={Number(value?.length)} limit={maxLength} />
161
+ <InputCounter current={Number(value?.length)} limit={maxLength ?? 150} />
154
162
  </div>
155
163
  )}
156
164
  </div>
@@ -16,7 +16,7 @@ export const DefaultCheckbox: Story = {
16
16
  isError: false,
17
17
  message: "",
18
18
  onChange: (value: string) => {
19
- console.log(`onChange ${value}`)
19
+
20
20
  }
21
21
  }
22
22
  }
@@ -26,6 +26,8 @@ export interface ICheckboxProps {
26
26
  hasBorder?: boolean
27
27
  /** any arbitrary classNames to add to the wrapper */
28
28
  className?: string
29
+ /** Label ClassName */
30
+ labelClassName?: string
29
31
  }
30
32
 
31
33
  /** Comment */
@@ -41,6 +43,7 @@ const Checkbox: FC<ICheckboxProps> = ({
41
43
  onChange,
42
44
  hasBorder,
43
45
  className,
46
+ labelClassName,
44
47
  ...props
45
48
  }: ICheckboxProps) => {
46
49
  const uniqueID = useId()
@@ -53,13 +56,12 @@ const Checkbox: FC<ICheckboxProps> = ({
53
56
  const wrapperStyles = cn(
54
57
  "relative flex items-center min-h-[38px]",
55
58
  { "opacity-50": isDisabled },
56
- { "rounded-sm ring-1 px-3 ring-gray-300": hasBorder },
59
+ { "rounded-sm border border-1 px-3 border-gray-200": hasBorder },
57
60
  { "py-3": hasBorder && message },
58
61
  className
59
62
  )
60
63
 
61
64
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
62
- console.log(e)
63
65
  const targetValue = e.target.value
64
66
  const targetChecked = e.target.checked
65
67
  typeof onChange === "function" && onChange(targetValue, targetChecked)
@@ -84,9 +86,10 @@ const Checkbox: FC<ICheckboxProps> = ({
84
86
  />
85
87
  </div>
86
88
  <div className="ml-3 text-sm ">
87
- <label htmlFor={id} className="font-medium text-gray-700">
89
+ <>
88
90
  <InputLabel label={label} isRequired={isRequired} id={id} />
89
- </label>
91
+ </>
92
+
90
93
  {message && (
91
94
  <p id={`${id}-description`} className="text-gray-500">
92
95
  {message}
@@ -44,151 +44,142 @@ function classNames(...classes: string[]) {
44
44
  return classes.filter(Boolean).join(" ")
45
45
  }
46
46
 
47
- const Combobox = <T extends Record<string, unknown>>({
48
- label,
49
- items,
50
- displayProperty,
51
- displayValue,
52
- keyProperty,
53
- onChange,
54
- placeholder,
55
- message,
56
- isDisabled,
57
- isError,
58
- isRequired,
59
- id,
60
- nullable
61
- }: IComboboxProps<T>) => {
62
- const [query, setQuery] = useState<string>("")
63
- const [selectedItem, setSelectedItem] = useState<T | undefined>()
47
+ const Combobox = <T extends Record<string, unknown>>({
48
+ label,
49
+ items,
50
+ displayProperty,
51
+ displayValue,
52
+ keyProperty,
53
+ onChange,
54
+ placeholder,
55
+ message,
56
+ isDisabled,
57
+ isError,
58
+ isRequired,
59
+ id,
60
+ nullable
61
+ }: IComboboxProps<T>) => {
62
+ const [query, setQuery] = useState<string>("")
63
+ const [selectedItem, setSelectedItem] = useState<T | undefined>()
64
64
 
65
- const onChangeValue = (value: T | undefined) => {
66
- if (value && selectedItem && value[keyProperty] === selectedItem[keyProperty]) {
67
- setSelectedItem(undefined)
68
- } else {
69
- setSelectedItem(value)
70
- }
65
+ const onChangeValue = (value: T | undefined) => {
66
+ if (value && selectedItem && value[keyProperty] === selectedItem[keyProperty]) {
67
+ setSelectedItem(undefined)
68
+ } else {
69
+ setSelectedItem(value)
71
70
  }
71
+ }
72
72
 
73
- useEffect(() => {
74
- if (displayValue) {
75
- const dv = items.find((i) => i[displayProperty] === displayValue)
76
- setSelectedItem(dv)
77
- }
78
- }, [displayValue])
73
+ useEffect(() => {
74
+ if (displayValue) {
75
+ const dv = items.find((i) => i[displayProperty] === displayValue)
76
+ setSelectedItem(dv)
77
+ }
78
+ }, [displayValue])
79
79
 
80
- useEffect(() => {
81
- typeof onChange === "function" && onChange(selectedItem)
82
- }, [selectedItem])
80
+ useEffect(() => {
81
+ typeof onChange === "function" && onChange(selectedItem)
82
+ }, [selectedItem])
83
83
 
84
- const filteredItems =
85
- query === ""
86
- ? items
87
- : items.filter((item) => {
88
- return `${item[displayProperty]}`.toLowerCase().includes(query.toLowerCase())
89
- })
90
- const labelStyles = cn("block text-sm font-medium text-gray-700")
91
- const buttonStyles = cn("absolute inset-y-0 right-0 flex items-center rounded-r px-2 focus:outline-none")
92
- const optionStyles = cn(
93
- "absolute z-30 mt-1 max-h-60 w-full overflow-auto rounded bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
94
- )
95
- return (
96
- <HeadlessUICombobox
97
- as="div"
98
- value={selectedItem}
99
- onChange={(e: T | undefined) => onChangeValue(e)}
100
- disabled={isDisabled}
101
- nullable={nullable ? undefined : false}
102
- >
103
- {label && (
104
- <HeadlessUICombobox.Label className={labelStyles}>
105
- <InputLabel
106
- isPlaceholder
107
- isActive
108
- label={label}
109
- isRequired={isRequired}
110
- id={id}
111
- isError={isError}
112
- isDisabled={isDisabled}
113
- />
114
- </HeadlessUICombobox.Label>
115
- )}
84
+ const filteredItems =
85
+ query === ""
86
+ ? items
87
+ : items.filter((item) => {
88
+ return `${item[displayProperty]}`.toLowerCase().includes(query.toLowerCase())
89
+ })
90
+ const labelStyles = cn("block text-sm font-medium text-gray-700")
91
+ const buttonStyles = cn("absolute inset-y-0 right-0 flex items-center rounded-r px-2 focus:outline-none")
92
+ const optionStyles = cn(
93
+ "absolute z-30 mt-1 max-h-60 w-full overflow-auto rounded bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
94
+ )
95
+ return (
96
+ <HeadlessUICombobox
97
+ as="div"
98
+ value={selectedItem}
99
+ onChange={(e: T | undefined) => onChangeValue(e)}
100
+ disabled={isDisabled}
101
+ nullable={nullable ? undefined : false}
102
+ >
103
+ {label && (
104
+ <HeadlessUICombobox.Label className={labelStyles}>
105
+ <InputLabel
106
+ isPlaceholder
107
+ isActive
108
+ label={label}
109
+ isRequired={isRequired}
110
+ id={id}
111
+ isError={isError}
112
+ isDisabled={isDisabled}
113
+ />
114
+ </HeadlessUICombobox.Label>
115
+ )}
116
+ <div className="relative">
116
117
  <div className="relative">
117
- <div className="relative">
118
- <HeadlessUICombobox.Input
119
- className={`w-full rounded border border-gray-300 focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm ${
120
- isError ? "border-red-500" : ""
121
- }`}
122
- onChange={(event) => setQuery(event.target.value)}
123
- displayValue={(item: Record<string, unknown>) => `${item ? item[displayProperty] : ""}`}
124
- placeholder={placeholder}
125
- />
126
- {selectedItem && nullable && (
127
- <button
128
- className="absolute right-8 top-[1px] h-9 w-5 text-gray-400 hover:text-gray-500"
129
- onClick={() => setSelectedItem(undefined)}
118
+ <HeadlessUICombobox.Input
119
+ className={`w-full rounded border border-gray-300 focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm ${
120
+ isError ? "border-red-500" : ""
121
+ }`}
122
+ onChange={(event) => setQuery(event.target.value)}
123
+ displayValue={(item: Record<string, unknown>) => `${item ? item[displayProperty] : ""}`}
124
+ placeholder={placeholder}
125
+ />
126
+ {selectedItem && nullable && (
127
+ <button
128
+ className="absolute right-8 top-[1px] h-9 w-5 text-gray-400 hover:text-gray-500"
129
+ onClick={() => setSelectedItem(undefined)}
130
+ >
131
+ <DynamicIcon icon="IconX" className="h-4 w-4 " aria-hidden="true" />
132
+ </button>
133
+ )}
134
+ </div>
135
+ <HeadlessUICombobox.Button className={buttonStyles}>
136
+ <DynamicIcon icon="IconSelector" className="h-5 w-5 text-gray-400" aria-hidden="true" />
137
+ </HeadlessUICombobox.Button>
138
+
139
+ {filteredItems.length > 0 && (
140
+ <HeadlessUICombobox.Options className={optionStyles}>
141
+ {filteredItems.map((item, index) => (
142
+ <HeadlessUICombobox.Option
143
+ key={`${item[keyProperty]}-${index}`}
144
+ value={item}
145
+ className={({ active }) =>
146
+ classNames(
147
+ "relative cursor-default select-none py-2 pl-3 pr-9",
148
+ active ? "bg-purple-600 text-white" : "text-gray-900"
149
+ )
150
+ }
130
151
  >
131
- <DynamicIcon icon="XIcon" className="h-4 w-4 " aria-hidden="true" />
132
- </button>
133
- )}
134
- </div>
135
- <HeadlessUICombobox.Button className={buttonStyles}>
136
- <DynamicIcon icon="SelectorIcon" className="h-5 w-5 text-gray-400" aria-hidden="true" />
137
- </HeadlessUICombobox.Button>
152
+ {({ active, selected }) => (
153
+ <>
154
+ <span className={classNames("block truncate", selected ? "font-semibold" : "")}>
155
+ {`${item[displayProperty]}`}
156
+ </span>
138
157
 
139
- {filteredItems.length > 0 && (
140
- <HeadlessUICombobox.Options className={optionStyles}>
141
- {filteredItems.map((item, index) => (
142
- <HeadlessUICombobox.Option
143
- key={`${item[keyProperty]}-${index}`}
144
- value={item}
145
- className={({ active }) =>
146
- classNames(
147
- "relative cursor-default select-none py-2 pl-3 pr-9",
148
- active ? "bg-purple-600 text-white" : "text-gray-900"
149
- )
150
- }
151
- >
152
- {({ active, selected }) => (
153
- <>
158
+ {selected && (
154
159
  <span
155
160
  className={classNames(
156
- "block truncate",
157
- selected ? "font-semibold" : ""
161
+ "absolute inset-y-0 right-0 flex items-center pr-4",
162
+ active ? "text-white" : "text-purple-600"
158
163
  )}
159
164
  >
160
- {`${item[displayProperty]}`}
165
+ <DynamicIcon icon="IconCheck" className="h-5 w-5" aria-hidden="true" />
161
166
  </span>
162
-
163
- {selected && (
164
- <span
165
- className={classNames(
166
- "absolute inset-y-0 right-0 flex items-center pr-4",
167
- active ? "text-white" : "text-purple-600"
168
- )}
169
- >
170
- <DynamicIcon
171
- icon="CheckIcon"
172
- className="h-5 w-5"
173
- aria-hidden="true"
174
- />
175
- </span>
176
- )}
177
- </>
178
- )}
179
- </HeadlessUICombobox.Option>
180
- ))}
181
- </HeadlessUICombobox.Options>
182
- )}
183
- </div>
184
- <div className="grow">
185
- {message && (
186
- <span className={`mt-1 block text-sm ${isError ? `text-red-500` : `text-gray-500`}`}>
187
- {message}
188
- </span>
189
- )}
190
- </div>
191
- </HeadlessUICombobox>
192
- )
193
- }
194
- export default Combobox
167
+ )}
168
+ </>
169
+ )}
170
+ </HeadlessUICombobox.Option>
171
+ ))}
172
+ </HeadlessUICombobox.Options>
173
+ )}
174
+ </div>
175
+ <div className="grow">
176
+ {message && (
177
+ <span className={`mt-1 block text-sm ${isError ? `text-red-500` : `text-gray-500`}`}>
178
+ {message}
179
+ </span>
180
+ )}
181
+ </div>
182
+ </HeadlessUICombobox>
183
+ )
184
+ }
185
+ export default Combobox
@@ -17,10 +17,10 @@ export const DefaultRadio: Story = {
17
17
  message: "",
18
18
  name: "radio-group",
19
19
  onChange: (value: string, checked: boolean) => {
20
- console.log(`onChange ${value} ${checked}`)
20
+
21
21
  },
22
22
  onClick: (value: string, checked: boolean) => {
23
- console.log(`onClick ${value} ${checked}`)
23
+
24
24
  }
25
25
  }
26
26
  }
@@ -0,0 +1,53 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import Select from "./Select"
3
+
4
+ const meta: Meta<typeof Select> = {
5
+ title: "Design System/Molecules/Inputs/Select",
6
+ component: Select,
7
+ tags: ["autodocs"],
8
+ argTypes: {},
9
+ decorators: [
10
+ (Story, context) => {
11
+ if (context.name === "Default Select Dark BG") {
12
+ return (
13
+ <div className="bg-transparent-black-03 rounded p-6">
14
+ <Story />
15
+ </div>
16
+ )
17
+ }
18
+ return <Story />
19
+ }
20
+ ]
21
+ }
22
+
23
+ export default meta
24
+ type TStory = StoryObj<typeof Select>
25
+
26
+ export const DefaultSelect: TStory = {
27
+ args: {
28
+ label: "Label",
29
+ id: "select",
30
+ name: "select",
31
+ options: [
32
+ { label: "Canada", value: "value1" },
33
+ { label: "USA", value: "value2" }
34
+ ],
35
+ isDisabled: false,
36
+ isError: false,
37
+ isRequired: false
38
+ }
39
+ }
40
+ export const DefaultSelectDarkBG: TStory = {
41
+ args: {
42
+ label: "Label",
43
+ id: "select",
44
+ name: "select",
45
+ options: [
46
+ { label: "Canada", value: "value1" },
47
+ { label: "USA", value: "value2" }
48
+ ],
49
+ isDisabled: false,
50
+ isError: false,
51
+ isRequired: false
52
+ }
53
+ }
@@ -3,7 +3,7 @@ import InputLabel from "@/stories/molecules/inputs/InputLabel"
3
3
  import { useId } from "@/utils/useId"
4
4
  import { default as cn } from "classnames"
5
5
 
6
- export type ISimpleSelectOptions = {
6
+ export interface ISimpleSelectOptions {
7
7
  label: string
8
8
  value: string
9
9
  }
@@ -28,6 +28,10 @@ export interface ISelectProps {
28
28
  value?: string
29
29
 
30
30
  className?: string
31
+
32
+ onFocus?: () => void
33
+
34
+ onBlur?: () => void
31
35
  }
32
36
  const Select: React.FC<ISelectProps> = ({
33
37
  label,
@@ -39,7 +43,9 @@ const Select: React.FC<ISelectProps> = ({
39
43
  isError,
40
44
  isRequired,
41
45
  value,
42
- className
46
+ className,
47
+ onFocus,
48
+ onBlur
43
49
  }) => {
44
50
  const [selectedOption, setSelectedOption] = useState<string>(value || options[0].value)
45
51
  const uniqueID = useId()
@@ -57,7 +63,7 @@ const Select: React.FC<ISelectProps> = ({
57
63
  typeof onChange == "function" && onChange(targetValue)
58
64
  setSelectedOption(targetValue)
59
65
  }
60
- const wrapperStyle = cn({ "opacity-50": isDisabled })
66
+ const wrapperStyle = cn("group", { "opacity-50": isDisabled })
61
67
  return (
62
68
  <div className={wrapperStyle}>
63
69
  {label && (
@@ -84,6 +90,8 @@ const Select: React.FC<ISelectProps> = ({
84
90
  onChange={handleChange}
85
91
  disabled={isDisabled}
86
92
  value={selectedOption}
93
+ onFocus={onFocus}
94
+ onBlur={onBlur}
87
95
  >
88
96
  {options.map(({ value, label }) => {
89
97
  return (
@@ -3,7 +3,20 @@ import Textarea from "./TextArea"
3
3
  const meta: Meta<typeof Textarea> = {
4
4
  title: "Design System/Molecules/Inputs/TextArea",
5
5
  component: Textarea,
6
- tags: ["autodocs"]
6
+ tags: ["autodocs"],
7
+ argTypes: {},
8
+ decorators: [
9
+ (Story, context) => {
10
+ if (context.name === "Default Textarea Dark BG") {
11
+ return (
12
+ <div className="bg-transparent-black-03 rounded p-6">
13
+ <Story />
14
+ </div>
15
+ )
16
+ }
17
+ return <Story />
18
+ }
19
+ ]
7
20
  }
8
21
  const dummyText: string = `Checkmate... Life finds a way. Is this my espresso machine? Wh-what is-h-how did you get my espresso machine? You're a very talented young man, with your own clever thoughts and ideas. Do you need a manager? Is this my espresso machine? Wh-what is-h-how did you get my espresso machine?
9
22
 
@@ -15,7 +28,17 @@ export const DefaultTextarea: Story = {
15
28
  name: "description",
16
29
  rows: 12,
17
30
  cols: 18,
18
- label: "Description",
31
+ label: { display: "Description" },
32
+ placeholder: dummyText
33
+ }
34
+ }
35
+ export const DefaultTextareaDarkBG: Story = {
36
+ args: {
37
+ id: "appDescription",
38
+ name: "description",
39
+ rows: 12,
40
+ cols: 18,
41
+ label: { display: "Description" },
19
42
  placeholder: dummyText
20
43
  }
21
44
  }
@@ -2,13 +2,19 @@ import React, { forwardRef, useEffect, useId, useState } from "react"
2
2
  import { default as cn } from "classnames"
3
3
  import InputLabel from "../InputLabel"
4
4
  import InputCounter from "../InputCounter"
5
+
6
+ interface ILabelProps extends React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement> {
7
+ display: string
8
+ htmlFor?: string
9
+ }
10
+
5
11
  export interface ITextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
6
12
  /** Input ID */
7
13
  id?: string
8
14
  /** Input Name */
9
15
  name?: string
10
16
  /** Label for the input */
11
- label?: string
17
+ label?: ILabelProps
12
18
  /** Error state */
13
19
  isError?: boolean
14
20
  /** If field is required */
@@ -51,49 +57,73 @@ const Textarea: React.FC<ITextareaProps> = ({
51
57
  rows = 12,
52
58
  cols = 48,
53
59
  onChange,
54
- value: externalValue,
60
+ value,
55
61
  placeholder,
56
62
  className,
57
63
  ref,
58
64
  ...rest
59
65
  }) => {
60
66
  const uniqueID = useId()
61
- const [value, setValue] = useState<string | undefined>(externalValue || defaultValue || "")
62
- const handleOnchange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
63
- const targetValue = e.currentTarget.value
64
- typeof onChange === "function" && onChange(targetValue)
65
- setValue(targetValue)
66
- }
67
67
 
68
68
  const discriptionStyles = cn("text-sm mt-1 block", { "text-gray-500": !isError }, { "text-red-500": isError })
69
69
 
70
- useEffect(() => {
71
- //if the external value is updated by the parent component, reset the value in here...
72
- if (externalValue !== undefined && externalValue !== null) {
73
- setValue(externalValue)
74
- }
75
- }, [externalValue])
76
-
77
70
  if (!id) id = `ta-${uniqueID}`
78
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
+ },
93
+ className
94
+ )}
95
+ disabled={isDisabled}
96
+ defaultValue={defaultValue}
97
+ value={value}
98
+ placeholder={placeholder}
99
+ {...rest}
100
+ />
101
+ )
102
+ }
103
+
104
+ //with label
79
105
  return (
80
- <div>
81
- {label && (
82
- <InputLabel
83
- isPlaceholder
84
- isActive
85
- label={label}
86
- isRequired={isRequired}
87
- id={id}
88
- isError={isError}
89
- isDisabled={isDisabled}
90
- />
91
- )}
106
+ <div className="group">
107
+ <InputLabel
108
+ isPlaceholder
109
+ isActive
110
+ label={label.display}
111
+ isRequired={isRequired}
112
+ id={id}
113
+ isError={isError}
114
+ isDisabled={isDisabled}
115
+ />
116
+
92
117
  <div>
93
118
  <textarea
94
119
  ref={ref}
95
120
  maxLength={maxLength}
96
- onChange={handleOnchange}
121
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
122
+ const targetValue = e.target.value
123
+ if (onChange) {
124
+ onChange(targetValue)
125
+ }
126
+ }}
97
127
  rows={rows}
98
128
  name={name}
99
129
  id={id}