@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.
- package/README.md +104 -31
- package/build.js +30 -25
- package/dist/index.d.ts +103 -79
- package/dist/index.js +1 -6295
- package/dist/index.js.map +4 -4
- package/dist/{lib/tailwind.css → tailwind.css} +3754 -8120
- package/dist/types/stories/atoms/buttons/Button/Alternative/Alternative.stories.d.ts +1 -0
- package/dist/types/stories/atoms/buttons/Button/Button.d.ts +3 -7
- package/dist/types/stories/atoms/buttons/Button/Danger/Danger.stories.d.ts +1 -0
- package/dist/types/stories/atoms/buttons/Button/Primary/Primary.stories.d.ts +1 -0
- package/dist/types/stories/atoms/buttons/Button/Secondary/Secondary.stories.d.ts +1 -0
- package/dist/types/stories/atoms/buttons/Capsule/Capsule.d.ts +1 -1
- package/dist/types/stories/atoms/icons/DynamicIcon.d.ts +2 -2
- package/dist/types/stories/atoms/icons/TablerIcon.d.ts +1 -1
- package/dist/types/stories/index.d.ts +4 -4
- package/dist/types/stories/molecules/inputs/InputField/InputField.d.ts +7 -7
- package/dist/types/stories/molecules/inputs/TextInput/TextInput.d.ts +1 -1
- package/dist/types/stories/molecules/inputs/checkbox/Checkbox.d.ts +2 -0
- package/dist/types/stories/molecules/inputs/select/Select.d.ts +4 -2
- package/dist/types/stories/molecules/inputs/textArea/TextArea.d.ts +5 -1
- package/dist/types/stories/molecules/inputs/toggleSwitch/ToggleSwitch.d.ts +10 -7
- package/dist/types/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.d.ts +5 -5
- package/dist/types/stories/organisms/AnimatedLabelInput/index.d.ts +1 -1
- package/dist/types/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.d.ts +12 -0
- package/dist/types/stories/organisms/AnimatedLabelTextArea/index.d.ts +3 -0
- package/dist/types/stories/organisms/ButtonDropdown/ButtonDropdown.d.ts +1 -0
- package/dist/types/stories/organisms/DropdownComponent/DropdownComponent.d.ts +24 -13
- package/dist/types/stories/organisms/DropdownComponent/index.d.ts +2 -2
- package/dist/types/stories/organisms/EmptySectionPlaceholder/index.d.ts +1 -1
- package/dist/types/stories/organisms/index.d.ts +4 -3
- package/local.sh +100 -0
- package/package.json +35 -18
- package/rollup.config.mjs +42 -0
- package/stories/atoms/badges/Badge.tsx +1 -1
- package/stories/atoms/buttons/Button/Alternative/Alternative.stories.ts +10 -0
- package/stories/atoms/buttons/Button/Button.tsx +111 -25
- package/stories/atoms/buttons/Button/Danger/Danger.stories.ts +14 -2
- package/stories/atoms/buttons/Button/Primary/Primary.stories.ts +14 -2
- package/stories/atoms/buttons/Button/Secondary/Secondary.stories.ts +13 -1
- package/stories/atoms/buttons/Button/defaultArgs.ts +1 -1
- package/stories/atoms/buttons/Capsule/Capsule.tsx +2 -1
- package/stories/atoms/icons/DynamicIcon.stories.ts +1 -1
- package/stories/atoms/icons/DynamicIcon.tsx +7 -7
- package/stories/atoms/icons/IconWithShadow.stories.ts +3 -3
- package/stories/atoms/icons/TablerIcon.tsx +1 -1
- package/stories/atoms/loaders/Loader.tsx +12 -6
- package/stories/atoms/loaders/NProgress/RadialProgress.tsx +0 -2
- package/stories/index.ts +8 -4
- package/stories/molecules/inputs/InputCounter/InputCounter.tsx +2 -2
- package/stories/molecules/inputs/InputField/InputField.tsx +31 -29
- package/stories/molecules/inputs/InputLabel/InputLabel.tsx +6 -6
- package/stories/molecules/inputs/TextInput/TextInput.stories.tsx +31 -1
- package/stories/molecules/inputs/TextInput/TextInput.tsx +15 -7
- package/stories/molecules/inputs/checkbox/Checkbox.stories.ts +1 -1
- package/stories/molecules/inputs/checkbox/Checkbox.tsx +7 -4
- package/stories/molecules/inputs/combobox/ComboBox.tsx +126 -135
- package/stories/molecules/inputs/radio/Radio.stories.ts +2 -2
- package/stories/molecules/inputs/select/Select.stories.tsx +53 -0
- package/stories/molecules/inputs/select/Select.tsx +11 -3
- package/stories/molecules/inputs/textArea/{TextArea.stories.ts → TextArea.stories.tsx} +25 -2
- package/stories/molecules/inputs/textArea/TextArea.tsx +58 -28
- package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.stories.tsx +15 -16
- package/stories/molecules/inputs/toggleSwitch/ToggleSwitch.tsx +63 -57
- package/stories/molecules/tabs/index.tsx +2 -3
- package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.stories.tsx +32 -2
- package/stories/organisms/AnimatedLabelInput/AnimatedLabelInput.tsx +66 -37
- package/stories/organisms/AnimatedLabelInput/index.tsx +1 -1
- package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.stories.tsx +26 -0
- package/stories/organisms/AnimatedLabelTextArea/AnimatedLabelTextArea.tsx +61 -0
- package/stories/organisms/AnimatedLabelTextArea/index.tsx +3 -0
- package/stories/organisms/ButtonDropdown/ButtonDropdown.stories.tsx +59 -59
- package/stories/organisms/ButtonDropdown/ButtonDropdown.tsx +42 -30
- package/stories/organisms/DropdownComponent/Dropdown.stories.tsx +26 -2
- package/stories/organisms/DropdownComponent/DropdownComponent.tsx +232 -180
- package/stories/organisms/DropdownComponent/dropdownItems.ts +30 -9
- package/stories/organisms/DropdownComponent/index.ts +2 -2
- package/stories/organisms/EmptySectionPlaceholder/EmptySectionPlaceholder.stories.tsx +3 -3
- package/stories/organisms/EmptySectionPlaceholder/index.tsx +2 -1
- package/stories/organisms/FormInputWithAddons/FormInputWithAddons.stories.tsx +1 -1
- package/stories/organisms/FormInputWithAddons/FormInputWithAddons.tsx +7 -2
- package/stories/organisms/index.ts +12 -3
- package/tailwind.config.js +139 -38
- package/tsconfig.lib.json +13 -6
- package/watch.js +49 -0
- package/.yarnrc.yml +0 -1
- package/dist/types/stories/layouts/index.d.ts +0 -0
- package/dist/types/stories/molecules/inputs/select/Select.stories.d.ts +0 -6
- package/dist/types/stories/molecules/inputs/textArea/TextArea.stories.d.ts +0 -6
- package/stories/layouts/CardLayout/CardLayout.stories.tsx +0 -18
- package/stories/layouts/CardLayout/CardLayout.tsx +0 -22
- package/stories/layouts/CardLayout/index.tsx +0 -3
- package/stories/layouts/ModalLayout/ModalLayout.stories.tsx +0 -18
- package/stories/layouts/ModalLayout/ModalLayout.tsx +0 -22
- package/stories/layouts/ModalLayout/index.tsx +0 -3
- package/stories/layouts/index.ts +0 -0
- package/stories/molecules/inputs/select/Select.stories.ts +0 -23
- 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
|
-
|
|
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
|
-
|
|
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) =>
|
|
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":
|
|
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>
|
|
@@ -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
|
|
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
|
-
|
|
89
|
+
<>
|
|
88
90
|
<InputLabel label={label} isRequired={isRequired} id={id} />
|
|
89
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (displayValue) {
|
|
75
|
+
const dv = items.find((i) => i[displayProperty] === displayValue)
|
|
76
|
+
setSelectedItem(dv)
|
|
77
|
+
}
|
|
78
|
+
}, [displayValue])
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
typeof onChange === "function" && onChange(selectedItem)
|
|
82
|
+
}, [selectedItem])
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
157
|
-
|
|
161
|
+
"absolute inset-y-0 right-0 flex items-center pr-4",
|
|
162
|
+
active ? "text-white" : "text-purple-600"
|
|
158
163
|
)}
|
|
159
164
|
>
|
|
160
|
-
|
|
165
|
+
<DynamicIcon icon="IconCheck" className="h-5 w-5" aria-hidden="true" />
|
|
161
166
|
</span>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
20
|
+
|
|
21
21
|
},
|
|
22
22
|
onClick: (value: string, checked: boolean) => {
|
|
23
|
-
|
|
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
|
|
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?:
|
|
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
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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={
|
|
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}
|