kahuna-base-react-components 0.2.19 → 0.2.21
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/dist/components/KCodeInput/KCodeInput.d.ts +36 -0
- package/dist/components/KCodeInput/index.d.ts +1 -0
- package/dist/components/KTextArea/KTextArea.d.ts +32 -0
- package/dist/components/KTextArea/index.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +36 -2
- package/package.json +1 -1
- package/src/components/KCodeInput/KCodeInput.stories.tsx +84 -0
- package/src/components/KCodeInput/KCodeInput.tsx +260 -0
- package/src/components/KCodeInput/index.ts +1 -0
- package/src/components/KTextArea/KTextArea.stories.tsx +65 -0
- package/src/components/KTextArea/KTextArea.tsx +130 -0
- package/src/components/KTextArea/index.ts +1 -0
- package/src/index.ts +3 -1
- package/src/main.css +10 -0
package/dist/types.d.ts
CHANGED
|
@@ -94,7 +94,7 @@ interface KInputProps {
|
|
|
94
94
|
iconSize?: string;
|
|
95
95
|
checked?: boolean;
|
|
96
96
|
}
|
|
97
|
-
declare const KInput: React.FC<KInputProps>;
|
|
97
|
+
declare const KInput$1: React.FC<KInputProps>;
|
|
98
98
|
|
|
99
99
|
interface KSelectOption {
|
|
100
100
|
label: string;
|
|
@@ -184,4 +184,38 @@ interface SliderLabelProps {
|
|
|
184
184
|
}
|
|
185
185
|
declare const KSliderLabel: React.FC<SliderLabelProps>;
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
interface KCodeInputProps {
|
|
188
|
+
onChange: (value: string) => void;
|
|
189
|
+
length?: number;
|
|
190
|
+
borderRadius?: number;
|
|
191
|
+
disabled?: boolean;
|
|
192
|
+
padding?: string;
|
|
193
|
+
gap?: number;
|
|
194
|
+
fontSize?: string;
|
|
195
|
+
fontWeight?: string;
|
|
196
|
+
color?: string;
|
|
197
|
+
lineHeight?: string;
|
|
198
|
+
allowedCharacters?: "numeric" | "alphaNumeric" | "alpha";
|
|
199
|
+
width?: number;
|
|
200
|
+
height?: number;
|
|
201
|
+
autoFocus?: boolean;
|
|
202
|
+
isPassword?: boolean;
|
|
203
|
+
background?: string;
|
|
204
|
+
hoverBackground?: string;
|
|
205
|
+
focusedBackground?: string;
|
|
206
|
+
filledBackground?: string;
|
|
207
|
+
border?: string;
|
|
208
|
+
hoverBorder?: string;
|
|
209
|
+
focusedBorder?: string;
|
|
210
|
+
filledBorder?: string;
|
|
211
|
+
boxShadow?: string;
|
|
212
|
+
hoverBoxShadow?: string;
|
|
213
|
+
focusedBoxShadow?: string;
|
|
214
|
+
filledBoxShadow?: string;
|
|
215
|
+
fitInContainer?: boolean;
|
|
216
|
+
isCodeCorrect?: boolean;
|
|
217
|
+
autoBlur?: boolean;
|
|
218
|
+
}
|
|
219
|
+
declare const KInput: React.FC<KCodeInputProps>;
|
|
220
|
+
|
|
221
|
+
export { KButton, KInput as KCodeInput, KDropdown, KInput$1 as KInput, KLogo, KSelectDate, KSlider, KSliderLabel, KSpan, KTitleSpan, KTooltip };
|
package/package.json
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Meta, StoryFn } from "@storybook/react"
|
|
2
|
+
import KCodeInput, { KCodeInputProps } from "./KCodeInput"
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { useEffect, useState } from "react"
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "ReactComponentLibrary/KCodeInput",
|
|
8
|
+
component: KCodeInput,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "centered"
|
|
11
|
+
}
|
|
12
|
+
} as Meta<typeof KCodeInput>
|
|
13
|
+
|
|
14
|
+
const KCodeInputWrapper: React.FC<KCodeInputProps> = (args) => {
|
|
15
|
+
const [code, setCode] = useState<string>("");
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
console.log("code: ", code);
|
|
19
|
+
}, [code]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className="w-[300px] p-4">
|
|
23
|
+
<KCodeInput
|
|
24
|
+
{...args}
|
|
25
|
+
onChange={(value:string) => {
|
|
26
|
+
//console.log("value: ", value);
|
|
27
|
+
setCode(value);
|
|
28
|
+
//console.log("Value updated to: ", option.value);
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
const Template: StoryFn<typeof KCodeInput> = (args) => <KCodeInputWrapper {...args} />
|
|
37
|
+
|
|
38
|
+
export const KCodeInputPrimary = Template.bind({})
|
|
39
|
+
KCodeInputPrimary.args = {
|
|
40
|
+
length: 6,
|
|
41
|
+
allowedCharacters: 'alpha',
|
|
42
|
+
isPassword: false,
|
|
43
|
+
disabled: false,
|
|
44
|
+
autoFocus:true,
|
|
45
|
+
gap:2,
|
|
46
|
+
width: 150,
|
|
47
|
+
background: "red",
|
|
48
|
+
hoverBackground: "green",
|
|
49
|
+
focusedBackground: "blue",
|
|
50
|
+
filledBackground: "black",
|
|
51
|
+
fitInContainer: true,
|
|
52
|
+
border: "1px solid black",
|
|
53
|
+
hoverBorder: "1px solid yellow",
|
|
54
|
+
focusedBorder: "1px solid white",
|
|
55
|
+
filledBorder: "1px solid gray",
|
|
56
|
+
fontSize: "15px",
|
|
57
|
+
padding: "10px",
|
|
58
|
+
color: "white",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const KCodeInputSecondary = Template.bind({})
|
|
62
|
+
KCodeInputSecondary.args = {
|
|
63
|
+
isCodeCorrect: true,
|
|
64
|
+
boxShadow: "1px 2px 10px black",
|
|
65
|
+
hoverBoxShadow: "1px 2px 10px red",
|
|
66
|
+
focusedBoxShadow: "1px 2px 10px yellow",
|
|
67
|
+
filledBoxShadow: "1px 2px 10px purple",
|
|
68
|
+
fontSize: "30px",
|
|
69
|
+
padding: "10px",
|
|
70
|
+
color: "orange",
|
|
71
|
+
autoBlur: true,
|
|
72
|
+
autoFocus: true,
|
|
73
|
+
width: 50,
|
|
74
|
+
height: 90,
|
|
75
|
+
fitInContainer: true,
|
|
76
|
+
gap: 12
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const KCodeInputDefault = Template.bind({})
|
|
80
|
+
KCodeInputDefault.args = {
|
|
81
|
+
isCodeCorrect: false,
|
|
82
|
+
allowedCharacters:"numeric",
|
|
83
|
+
autoBlur:true
|
|
84
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import React, { useEffect, useState, KeyboardEvent, useRef } from "react"
|
|
2
|
+
import "../../main.css"
|
|
3
|
+
|
|
4
|
+
export interface KCodeInputProps {
|
|
5
|
+
onChange: (value: string) => void
|
|
6
|
+
length?: number
|
|
7
|
+
borderRadius?: number
|
|
8
|
+
disabled?: boolean
|
|
9
|
+
padding?: string
|
|
10
|
+
gap?: number
|
|
11
|
+
fontSize?: string
|
|
12
|
+
fontWeight?: string
|
|
13
|
+
color?: string
|
|
14
|
+
lineHeight?: string
|
|
15
|
+
allowedCharacters?: "numeric" | "alphaNumeric" | "alpha"
|
|
16
|
+
width?: number
|
|
17
|
+
height?: number
|
|
18
|
+
autoFocus?: boolean
|
|
19
|
+
isPassword?: boolean
|
|
20
|
+
background?: string
|
|
21
|
+
hoverBackground?: string
|
|
22
|
+
focusedBackground?: string
|
|
23
|
+
filledBackground?: string
|
|
24
|
+
border?: string
|
|
25
|
+
hoverBorder?: string
|
|
26
|
+
focusedBorder?: string
|
|
27
|
+
filledBorder?: string
|
|
28
|
+
boxShadow?: string
|
|
29
|
+
hoverBoxShadow?: string
|
|
30
|
+
focusedBoxShadow?: string
|
|
31
|
+
filledBoxShadow?: string
|
|
32
|
+
fitInContainer?: boolean
|
|
33
|
+
isCodeCorrect?: boolean
|
|
34
|
+
autoBlur?: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const KInput: React.FC<KCodeInputProps> = (props) => {
|
|
38
|
+
const autoFocus = props.autoFocus || false
|
|
39
|
+
const autoBlur = props.autoBlur || false
|
|
40
|
+
const borderRadius = props.borderRadius || 10
|
|
41
|
+
const disabled = props.disabled || false
|
|
42
|
+
const length = props.length || 6
|
|
43
|
+
const padding = props.padding || "6px"
|
|
44
|
+
const gap = props.gap || 6
|
|
45
|
+
const allowedCharacters = props.allowedCharacters || "numeric"
|
|
46
|
+
const password = props.isPassword || false
|
|
47
|
+
const fitInContainer = props.fitInContainer || false
|
|
48
|
+
const width = props.width || "60px"
|
|
49
|
+
const height = props.height || "60px"
|
|
50
|
+
const fontSize = props.fontSize || "24px"
|
|
51
|
+
const fontWeight = props.fontWeight || 500
|
|
52
|
+
const lineHeight = props.lineHeight || "32px"
|
|
53
|
+
const defaultBorder = props.border || ""
|
|
54
|
+
const hoverBorder = props.hoverBorder || "1px solid #F3F3F3"
|
|
55
|
+
const focusedBorder = props.focusedBorder || "1px solid #F3F3F3"
|
|
56
|
+
const filledBorder = props.filledBorder || "1px solid #B7B7B7"
|
|
57
|
+
const defaultBoxShadow = props.boxShadow || ""
|
|
58
|
+
const hoverBoxShadow = props.hoverBoxShadow || ""
|
|
59
|
+
const focusedBoxShadow = props.focusedBoxShadow || " 0px 1px 2px 0px rgba(228, 229, 231, 0.24)"
|
|
60
|
+
const filledBoxShadow = props.filledBoxShadow || " 0px 1px 2px 0px rgba(228, 229, 231, 0.24)"
|
|
61
|
+
const defaultBackground = props.background || "#F5F5F5"
|
|
62
|
+
const hoverBackground = props.hoverBackground || defaultBackground
|
|
63
|
+
const focusedBackground = props.focusedBackground || "#FFF"
|
|
64
|
+
const filledBackground = props.filledBackground || "#FFF"
|
|
65
|
+
const color = props.color || "#000"
|
|
66
|
+
const isCodeCorrect = props.isCodeCorrect !== undefined ? props.isCodeCorrect : true
|
|
67
|
+
|
|
68
|
+
const [focusedIndex, setFocusedIndex] = useState<number>(autoFocus ? 0 : -1)
|
|
69
|
+
const inputRefs = useRef<HTMLInputElement[]>([])
|
|
70
|
+
|
|
71
|
+
const [allCharactersWritten, setAllCharactersWritten] = useState<boolean>(false)
|
|
72
|
+
|
|
73
|
+
const [values, setValues] = useState<string[]>(Array(length).fill(""))
|
|
74
|
+
const [hoveredIndexes, setHoveredIndexes] = useState<boolean[]>(Array(length).fill(false))
|
|
75
|
+
const [focusedIndexes, setFocusedIndexes] = useState<boolean[]>(Array(length).fill(false))
|
|
76
|
+
|
|
77
|
+
const handleMouseEnter = (index: number) => {
|
|
78
|
+
setHoveredIndexes((prev) => prev.map((hovered, i) => (i === index ? true : hovered)))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const handleMouseLeave = (index: number) => {
|
|
82
|
+
setHoveredIndexes((prev) => prev.map((hovered, i) => (i === index ? false : hovered)))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const handleFocus = (index: number) => {
|
|
86
|
+
setFocusedIndexes((prev) => prev.map((focused, i) => (i === index ? true : focused)))
|
|
87
|
+
}
|
|
88
|
+
const handleBlur = (index: number) => {
|
|
89
|
+
setFocusedIndexes((prev) => prev.map((focused, i) => (i === index ? false : focused)))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (inputRefs.current[focusedIndex]) {
|
|
94
|
+
inputRefs.current[focusedIndex].focus()
|
|
95
|
+
}
|
|
96
|
+
}, [focusedIndex])
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (disabled) {
|
|
100
|
+
setFocusedIndexes((prev) => prev.map((focused, i) => false))
|
|
101
|
+
setHoveredIndexes((prev) => prev.map((hovered, i) => false))
|
|
102
|
+
setValues(Array(length).fill(""))
|
|
103
|
+
setAllCharactersWritten(false)
|
|
104
|
+
}
|
|
105
|
+
}, [disabled])
|
|
106
|
+
|
|
107
|
+
const handleClick = (index: number) => {
|
|
108
|
+
if (values[index]) {
|
|
109
|
+
setFocusedIndex(index)
|
|
110
|
+
} else if (!values[index]) {
|
|
111
|
+
const firstEmptyInputIndex = values.findIndex((value) => value === "")
|
|
112
|
+
setFocusedIndex(firstEmptyInputIndex)
|
|
113
|
+
if (inputRefs.current[focusedIndex]) {
|
|
114
|
+
inputRefs.current[focusedIndex].focus()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const handleChange = (text: string, index: number) => {
|
|
120
|
+
const patterns: Record<string, RegExp> = {
|
|
121
|
+
numeric: /^\d*$/,
|
|
122
|
+
alpha: /^[a-zA-Z]*$/,
|
|
123
|
+
alphaNumeric: /^[a-zA-Z0-9]*$/
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (patterns[allowedCharacters]?.test(text)) {
|
|
127
|
+
const newValues = [...values]
|
|
128
|
+
if (text.length === 1) {
|
|
129
|
+
newValues[index] = text
|
|
130
|
+
} else if (text.length === 2) {
|
|
131
|
+
newValues[index] = newValues[index] === text[0] ? text[1] : text[0]
|
|
132
|
+
}
|
|
133
|
+
setValues(newValues)
|
|
134
|
+
if (text && index < length - 1) {
|
|
135
|
+
setFocusedIndex(index + 1)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const handleDelete = (event: React.KeyboardEvent<HTMLInputElement>, index: number) => {
|
|
141
|
+
if (event?.key === "Backspace") {
|
|
142
|
+
const newValues = [...values]
|
|
143
|
+
newValues[index] = ""
|
|
144
|
+
if (index > 0) {
|
|
145
|
+
setFocusedIndex(index - 1)
|
|
146
|
+
}
|
|
147
|
+
setValues(newValues)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
|
|
152
|
+
event.preventDefault()
|
|
153
|
+
const pastedText = event.clipboardData.getData("text").replace(/\s+/g, "")
|
|
154
|
+
const patterns: Record<string, RegExp> = {
|
|
155
|
+
numeric: /^\d*$/,
|
|
156
|
+
alpha: /^[a-zA-Z]*$/,
|
|
157
|
+
alphaNumeric: /^[a-zA-Z0-9]*$/
|
|
158
|
+
}
|
|
159
|
+
if (patterns[allowedCharacters]?.test(pastedText) && pastedText.length > 0) {
|
|
160
|
+
const newValues = [...values]
|
|
161
|
+
const currentIndex = focusedIndex
|
|
162
|
+
const pastedCharacters = pastedText.includes(" ") ? pastedText.split(" ") : pastedText.split("")
|
|
163
|
+
pastedCharacters.forEach((character, index) => {
|
|
164
|
+
const i = currentIndex + index
|
|
165
|
+
if (i < length) {
|
|
166
|
+
newValues[i] = character
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
setValues(newValues)
|
|
170
|
+
setFocusedIndex(
|
|
171
|
+
pastedCharacters.length + currentIndex >= length ? length - 1 : pastedCharacters.length + currentIndex
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
const allDone = values.every((value) => value.length > 0)
|
|
178
|
+
setAllCharactersWritten(allDone)
|
|
179
|
+
props.onChange(values.join(""))
|
|
180
|
+
}, [values])
|
|
181
|
+
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (allCharactersWritten && autoBlur) {
|
|
184
|
+
inputRefs.current[focusedIndex].blur()
|
|
185
|
+
}
|
|
186
|
+
}, [allCharactersWritten])
|
|
187
|
+
|
|
188
|
+
const renderCharacterComponent = (index: number) => {
|
|
189
|
+
const isHovered = hoveredIndexes[index]
|
|
190
|
+
const isFocused = focusedIndexes[index]
|
|
191
|
+
const isFilled = values[index]
|
|
192
|
+
|
|
193
|
+
const background = isFilled
|
|
194
|
+
? filledBackground
|
|
195
|
+
: isFocused
|
|
196
|
+
? focusedBackground
|
|
197
|
+
: isHovered
|
|
198
|
+
? hoverBackground
|
|
199
|
+
: defaultBackground
|
|
200
|
+
|
|
201
|
+
const boxShadow = isFilled
|
|
202
|
+
? filledBoxShadow
|
|
203
|
+
: isFocused
|
|
204
|
+
? focusedBoxShadow
|
|
205
|
+
: isHovered
|
|
206
|
+
? hoverBoxShadow
|
|
207
|
+
: defaultBoxShadow
|
|
208
|
+
|
|
209
|
+
const border = isFilled ? filledBorder : isFocused ? focusedBorder : isHovered ? hoverBorder : defaultBorder
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<input
|
|
213
|
+
key={`k-code-input-${index}`}
|
|
214
|
+
value={values[index]}
|
|
215
|
+
className={`k-code-input-character-container`}
|
|
216
|
+
style={{
|
|
217
|
+
padding,
|
|
218
|
+
background,
|
|
219
|
+
borderRadius,
|
|
220
|
+
height,
|
|
221
|
+
border: allCharactersWritten && !isCodeCorrect ? "1px solid #FF5865" : border,
|
|
222
|
+
boxShadow,
|
|
223
|
+
fontSize,
|
|
224
|
+
fontWeight,
|
|
225
|
+
lineHeight,
|
|
226
|
+
color,
|
|
227
|
+
width: !fitInContainer ? width : `calc((100% - ${(length - 1) * gap}px) / ${length})`
|
|
228
|
+
}}
|
|
229
|
+
required
|
|
230
|
+
type={password ? "password" : "text"}
|
|
231
|
+
onChange={(event) => {
|
|
232
|
+
handleChange(event.target.value, index)
|
|
233
|
+
}}
|
|
234
|
+
onClick={(event) => {
|
|
235
|
+
handleClick(index)
|
|
236
|
+
}}
|
|
237
|
+
onKeyDown={(event) => {
|
|
238
|
+
handleDelete(event, index)
|
|
239
|
+
}}
|
|
240
|
+
onPaste={(event) => {
|
|
241
|
+
handlePaste(event)
|
|
242
|
+
}}
|
|
243
|
+
ref={(el: HTMLInputElement) => (inputRefs.current[index] = el)}
|
|
244
|
+
disabled={disabled}
|
|
245
|
+
onMouseEnter={() => handleMouseEnter(index)}
|
|
246
|
+
onMouseLeave={() => handleMouseLeave(index)}
|
|
247
|
+
onFocus={() => handleFocus(index)}
|
|
248
|
+
onBlur={() => handleBlur(index)}
|
|
249
|
+
/>
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<div className="flex flex-row items-center justify-between" style={{ width: "100%", gap }}>
|
|
255
|
+
{Array.from({ length }, (_, index) => renderCharacterComponent(index))}
|
|
256
|
+
</div>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default KInput
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from './KCodeInput';
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Meta, StoryFn } from "@storybook/react"
|
|
2
|
+
import KTextArea from "./KTextArea"
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import TracksIcon from "../../assets/tracks.svg"
|
|
5
|
+
import { KeyboardEvent } from "react"
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "ReactComponentLibrary/KTextArea",
|
|
9
|
+
component: KTextArea,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered"
|
|
12
|
+
}
|
|
13
|
+
} as Meta<typeof KTextArea>
|
|
14
|
+
|
|
15
|
+
const Template: StoryFn<typeof KTextArea> = (args) => <KTextArea {...args} />
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export const KTextAreaPrimary = Template.bind({})
|
|
19
|
+
KTextAreaPrimary.args = {
|
|
20
|
+
onChange: (value: string) => {
|
|
21
|
+
console.log("value:", value)
|
|
22
|
+
},
|
|
23
|
+
onKeyDown: (event: KeyboardEvent) => {
|
|
24
|
+
if (event.key === "Enter") {
|
|
25
|
+
console.log("Enter is clicked and our value is:", event.currentTarget)
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
rows: 4,
|
|
29
|
+
placeholder: "Placeholder...",
|
|
30
|
+
hoverBackground: "white"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const KTextAreaLeftIcon = Template.bind({})
|
|
34
|
+
KTextAreaLeftIcon.args = {
|
|
35
|
+
onChange: (value: string) => {},
|
|
36
|
+
placeholder: "Placeholder...",
|
|
37
|
+
leftIcon: TracksIcon,
|
|
38
|
+
leftIconClick: () => {
|
|
39
|
+
alert("left icon clicked")
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const KTextAreaRightIcon = Template.bind({})
|
|
44
|
+
KTextAreaRightIcon.args = {
|
|
45
|
+
onChange: (value: string) => {},
|
|
46
|
+
placeholder: "Placeholder...",
|
|
47
|
+
rightIcon: TracksIcon,
|
|
48
|
+
rightIconClick: () => {
|
|
49
|
+
alert("right icon clicked")
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const KTextAreaLeftRightIcon = Template.bind({})
|
|
54
|
+
KTextAreaLeftRightIcon.args = {
|
|
55
|
+
onChange: (value: string) => {},
|
|
56
|
+
placeholder: "Placeholder...",
|
|
57
|
+
leftIcon: TracksIcon,
|
|
58
|
+
rightIcon: TracksIcon,
|
|
59
|
+
leftIconClick: () => {
|
|
60
|
+
alert("left icon clicked")
|
|
61
|
+
},
|
|
62
|
+
rightIconClick: () => {
|
|
63
|
+
alert("right icon clicked")
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import React, { useEffect, useState, KeyboardEvent } from "react"
|
|
2
|
+
import "../../main.css"
|
|
3
|
+
|
|
4
|
+
export interface KTextAreaProps {
|
|
5
|
+
value: string
|
|
6
|
+
onChange: (value: string) => void
|
|
7
|
+
rows?: number
|
|
8
|
+
onBlur?: (value: string) => void
|
|
9
|
+
onKeyDown?: (event: KeyboardEvent) => void
|
|
10
|
+
width?: number
|
|
11
|
+
height?: number
|
|
12
|
+
leftIcon?: string
|
|
13
|
+
rightIcon?: string
|
|
14
|
+
background?: string
|
|
15
|
+
activeBackground?: string
|
|
16
|
+
borderRadius?: number
|
|
17
|
+
disabled?: boolean
|
|
18
|
+
placeholder?: string
|
|
19
|
+
shadowDisabled?: boolean
|
|
20
|
+
leftIconClick?: () => void
|
|
21
|
+
rightIconClick?: () => void
|
|
22
|
+
accentColor?: string
|
|
23
|
+
hoverBackground?: string
|
|
24
|
+
padding?: string
|
|
25
|
+
gap?: string
|
|
26
|
+
border?: string
|
|
27
|
+
boxShadow?: string
|
|
28
|
+
fontSize?: string
|
|
29
|
+
iconSize?: string
|
|
30
|
+
checked?: boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const KTextArea: React.FC<KTextAreaProps> = (props) => {
|
|
34
|
+
const [background, setBackground] = useState("#F5F5F5")
|
|
35
|
+
const [hover, setHover] = useState(false)
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const emptyBackground = props.background || "#F5F5F5"
|
|
39
|
+
const activeBackground = props.activeBackground || "#FFF"
|
|
40
|
+
|
|
41
|
+
const background = props.value ? activeBackground : emptyBackground
|
|
42
|
+
setBackground(background)
|
|
43
|
+
}, [props.value])
|
|
44
|
+
|
|
45
|
+
const width = props.width || "100%"
|
|
46
|
+
const height = props.height || 60
|
|
47
|
+
const borderRadius = props.borderRadius || 10
|
|
48
|
+
const boxShadow = props.shadowDisabled
|
|
49
|
+
? ""
|
|
50
|
+
: props.boxShadow
|
|
51
|
+
? props.boxShadow
|
|
52
|
+
: "0 0 0 1px rgba(17, 17, 17, 0.04), 0 1px 1px 0 rgba(17, 17, 17, 0.04)"
|
|
53
|
+
const accentColor = props.accentColor || ""
|
|
54
|
+
const disabled = props.disabled || false
|
|
55
|
+
const hoverBackground = props.hoverBackground || background
|
|
56
|
+
const padding = props.padding || "8px"
|
|
57
|
+
const gap = props.gap || "12px"
|
|
58
|
+
const border = props.border || "none"
|
|
59
|
+
const fontSize = props.fontSize || "14px"
|
|
60
|
+
const iconSize = props.iconSize || "20px"
|
|
61
|
+
const rows = props.rows || 2
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
onMouseEnter={() => setHover(true)}
|
|
66
|
+
onMouseLeave={() => setHover(false)}
|
|
67
|
+
className={"k-input-container"}
|
|
68
|
+
style={{ background: hover ? hoverBackground : background, borderRadius, boxShadow, padding, gap, border }}
|
|
69
|
+
>
|
|
70
|
+
{props.leftIcon && (
|
|
71
|
+
<img
|
|
72
|
+
src={props.leftIcon}
|
|
73
|
+
style={{
|
|
74
|
+
width: iconSize,
|
|
75
|
+
height: iconSize
|
|
76
|
+
}}
|
|
77
|
+
alt={"l-icon"}
|
|
78
|
+
className={props.leftIconClick && "cursor-pointer"}
|
|
79
|
+
onClick={() => {
|
|
80
|
+
if (props.leftIconClick) props.leftIconClick()
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
|
|
85
|
+
<textarea
|
|
86
|
+
className={"k-input"}
|
|
87
|
+
style={{
|
|
88
|
+
background: hover ? hoverBackground : background,
|
|
89
|
+
width,
|
|
90
|
+
height,
|
|
91
|
+
accentColor,
|
|
92
|
+
fontSize
|
|
93
|
+
}}
|
|
94
|
+
rows={rows}
|
|
95
|
+
value={props.value}
|
|
96
|
+
placeholder={props.placeholder || ""}
|
|
97
|
+
disabled={disabled}
|
|
98
|
+
onBlur={(event) => {
|
|
99
|
+
console.log("onBulur", event.target.value)
|
|
100
|
+
if (props.onBlur) props.onBlur(event.target.value)
|
|
101
|
+
}}
|
|
102
|
+
onChange={(event) => {
|
|
103
|
+
console.log("OnChange", event.target.value)
|
|
104
|
+
props.onChange(event.target.value)
|
|
105
|
+
}}
|
|
106
|
+
onKeyDown={(event) => {
|
|
107
|
+
console.log("OnKeyDown", event)
|
|
108
|
+
if (props.onKeyDown) props.onKeyDown(event)
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
{props.rightIcon && (
|
|
113
|
+
<img
|
|
114
|
+
src={props.rightIcon}
|
|
115
|
+
style={{
|
|
116
|
+
width: iconSize,
|
|
117
|
+
height: iconSize
|
|
118
|
+
}}
|
|
119
|
+
alt={"r-icon"}
|
|
120
|
+
className={props.rightIconClick && "cursor-pointer"}
|
|
121
|
+
onClick={() => {
|
|
122
|
+
if (props.rightIconClick) props.rightIconClick()
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export default KTextArea
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from './KTextArea';
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,9 @@ import KSlider from "./components/KSlider"
|
|
|
8
8
|
import KSelectDate from "./components/KSelectDate"
|
|
9
9
|
import KTooltip from "./components/KTooltip"
|
|
10
10
|
import KSliderLabel from "./components/KSliderLabel"
|
|
11
|
+
import KCodeInput from "./components/KCodeInput"
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
export {
|
|
13
|
-
KButton, KSpan, KLogo, KTitleSpan, KInput, KDropdown, KSlider, KSelectDate, KTooltip, KSliderLabel
|
|
15
|
+
KButton, KSpan, KLogo, KTitleSpan, KInput, KDropdown, KSlider, KSelectDate, KTooltip, KSliderLabel, KCodeInput
|
|
14
16
|
}
|
package/src/main.css
CHANGED
|
@@ -238,4 +238,14 @@
|
|
|
238
238
|
}
|
|
239
239
|
.k-slider-label-input::-webkit-slider-thumb:active {
|
|
240
240
|
cursor: grabbing;
|
|
241
|
+
}
|
|
242
|
+
.k-code-input-character-container {
|
|
243
|
+
outline: none !important;
|
|
244
|
+
text-align: center;
|
|
245
|
+
font-family: "Inter";
|
|
246
|
+
caret-color: #B7B7B7;
|
|
247
|
+
}
|
|
248
|
+
.k-code-input-character-container:disabled {
|
|
249
|
+
background: #F7F7F7 !important;
|
|
250
|
+
border: none !important;
|
|
241
251
|
}
|