kahuna-base-react-components 1.0.7 → 1.1.0

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 (149) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +23 -0
  3. package/dist/components/KButton/KButton.d.ts +17 -3
  4. package/dist/components/KCodeInput/KCodeInput.d.ts +36 -0
  5. package/dist/components/KCodeInput/index.d.ts +1 -0
  6. package/dist/components/KDropdown/KDropdown.d.ts +38 -0
  7. package/dist/components/KDropdown/index.d.ts +1 -0
  8. package/dist/components/KDropdownToggle/KDropdownToggle.d.ts +35 -0
  9. package/dist/components/KDropdownToggle/index.d.ts +1 -0
  10. package/dist/components/KInput/KInput.d.ts +32 -0
  11. package/dist/components/KInput/index.d.ts +1 -0
  12. package/dist/components/KLogo/KLogo.d.ts +18 -0
  13. package/dist/components/KLogo/index.d.ts +1 -0
  14. package/dist/components/KSelectDate/KSelectDate.d.ts +9 -0
  15. package/dist/components/KSelectDate/index.d.ts +1 -0
  16. package/dist/components/KSlider/KSlider.d.ts +15 -0
  17. package/dist/components/KSlider/index.d.ts +1 -0
  18. package/dist/components/KSliderLabel/KSliderLabel.d.ts +19 -0
  19. package/dist/components/KSliderLabel/index.d.ts +1 -0
  20. package/dist/components/KSpan/KSpan.d.ts +14 -4
  21. package/dist/components/KTextArea/KTextArea.d.ts +32 -0
  22. package/dist/components/KTextArea/index.d.ts +1 -0
  23. package/dist/components/KTitleSpan/KTitleSpan.d.ts +14 -0
  24. package/dist/components/KTitleSpan/index.d.ts +1 -0
  25. package/dist/components/KTooltip/KTooltip.d.ts +19 -0
  26. package/dist/components/KTooltip/index.d.ts +1 -0
  27. package/dist/fonts/AeonikPro-Bold/AeonikPro-Bold.otf +0 -0
  28. package/dist/fonts/AeonikPro-Bold/CoType EULA Desktop.pdf +1388 -3
  29. package/dist/fonts/Inter/Inter-VariableFont_slnt,wght.ttf +0 -0
  30. package/dist/fonts/Inter/OFL.txt +93 -0
  31. package/dist/fonts/Inter/README.txt +72 -0
  32. package/dist/fonts/Inter/static/Inter-Black.ttf +0 -0
  33. package/dist/fonts/Inter/static/Inter-Bold.ttf +0 -0
  34. package/dist/fonts/Inter/static/Inter-ExtraBold.ttf +0 -0
  35. package/dist/fonts/Inter/static/Inter-ExtraLight.ttf +0 -0
  36. package/dist/fonts/Inter/static/Inter-Light.ttf +0 -0
  37. package/dist/fonts/Inter/static/Inter-Medium.ttf +0 -0
  38. package/dist/fonts/Inter/static/Inter-Regular.ttf +0 -0
  39. package/dist/fonts/Inter/static/Inter-SemiBold.ttf +0 -0
  40. package/dist/fonts/Inter/static/Inter-Thin.ttf +0 -0
  41. package/dist/index.d.ts +11 -1
  42. package/dist/index.esm.js +9 -1
  43. package/dist/index.esm.js.map +1 -1
  44. package/dist/index.js +9 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/types.d.ts +241 -8
  47. package/package.json +14 -3
  48. package/postcss.config.js +6 -0
  49. package/removeUseClient.js +22 -0
  50. package/rollup.config.js +9 -3
  51. package/src/assets/calendar-hovered.svg +3 -0
  52. package/src/assets/calendar.svg +3 -0
  53. package/src/assets/check.svg +3 -0
  54. package/src/assets/chevron-left.svg +7 -0
  55. package/src/assets/chevron-right.svg +7 -0
  56. package/src/assets/fonts/AeonikPro/AeonikPro-Bold.otf +0 -0
  57. package/src/assets/fonts/AeonikPro/AeonikPro-Medium.otf +0 -0
  58. package/src/assets/fonts/AeonikPro/CoType EULA Desktop.pdf +1388 -3
  59. package/src/assets/fonts/Inter/Inter-VariableFont_slnt,wght.ttf +0 -0
  60. package/src/assets/fonts/Inter/OFL.txt +93 -0
  61. package/src/assets/fonts/Inter/README.txt +72 -0
  62. package/src/assets/fonts/Inter/static/Inter-Black.ttf +0 -0
  63. package/src/assets/fonts/Inter/static/Inter-Bold.ttf +0 -0
  64. package/src/assets/fonts/Inter/static/Inter-ExtraBold.ttf +0 -0
  65. package/src/assets/fonts/Inter/static/Inter-ExtraLight.ttf +0 -0
  66. package/src/assets/fonts/Inter/static/Inter-Light.ttf +0 -0
  67. package/src/assets/fonts/Inter/static/Inter-Medium.ttf +0 -0
  68. package/src/assets/fonts/Inter/static/Inter-Regular.ttf +0 -0
  69. package/src/assets/fonts/Inter/static/Inter-SemiBold.ttf +0 -0
  70. package/src/assets/fonts/Inter/static/Inter-Thin.ttf +0 -0
  71. package/src/assets/kahuna-text.svg +3 -0
  72. package/src/assets/logo-gray.svg +10 -0
  73. package/src/assets/logo-small-hovered.svg +4 -0
  74. package/src/assets/logo-small.svg +11 -0
  75. package/src/assets/logo.svg +11 -0
  76. package/src/assets/progress.svg +37 -0
  77. package/src/assets/separator.svg +3 -0
  78. package/src/assets/slider-dots.svg +7 -0
  79. package/src/assets/slider-step.svg +3 -0
  80. package/src/assets/slider-thumb.svg +3 -0
  81. package/src/assets/tracks.svg +5 -0
  82. package/src/assets/union.svg +3 -0
  83. package/src/assets/vector.svg +3 -0
  84. package/src/components/KButton/KButton.stories.tsx +69 -12
  85. package/src/components/KButton/KButton.tsx +51 -14
  86. package/src/components/KCodeInput/KCodeInput.stories.tsx +84 -0
  87. package/src/components/KCodeInput/KCodeInput.tsx +260 -0
  88. package/src/components/KCodeInput/index.ts +1 -0
  89. package/src/components/KDropdown/KDropdown.stories.tsx +90 -0
  90. package/src/components/KDropdown/KDropdown.tsx +201 -0
  91. package/src/components/KDropdown/index.ts +1 -0
  92. package/src/components/KInput/KInput.stories.tsx +84 -0
  93. package/src/components/KInput/KInput.tsx +128 -0
  94. package/src/components/KInput/index.ts +1 -0
  95. package/src/components/KLogo/KLogo.stories.tsx +24 -0
  96. package/src/components/KLogo/KLogo.tsx +79 -0
  97. package/src/components/KLogo/index.ts +1 -0
  98. package/src/components/KSelectDate/CalendarCustom.css +235 -0
  99. package/src/components/KSelectDate/KSelectDate.stories.tsx +54 -0
  100. package/src/components/KSelectDate/KSelectDate.tsx +314 -0
  101. package/src/components/KSelectDate/index.ts +1 -0
  102. package/src/components/KSlider/KSlider.stories.tsx +19 -0
  103. package/src/components/KSlider/KSlider.tsx +67 -0
  104. package/src/components/KSlider/index.ts +1 -0
  105. package/src/components/KSliderLabel/KSliderLabel.stories.tsx +61 -0
  106. package/src/components/KSliderLabel/KSliderLabel.tsx +137 -0
  107. package/src/components/KSliderLabel/index.ts +1 -0
  108. package/src/components/KSpan/KSpan.stories.tsx +31 -11
  109. package/src/components/KSpan/KSpan.tsx +65 -9
  110. package/src/components/KTextArea/KTextArea.stories.tsx +65 -0
  111. package/src/components/KTextArea/KTextArea.tsx +130 -0
  112. package/src/components/KTextArea/index.ts +1 -0
  113. package/src/components/KTitleSpan/KTitleSpan.stories.tsx +23 -0
  114. package/src/components/KTitleSpan/KTitleSpan.tsx +33 -0
  115. package/src/components/KTitleSpan/index.ts +1 -0
  116. package/src/components/KTooltip/KTooltip.stories.tsx +94 -0
  117. package/src/components/KTooltip/KTooltip.tsx +67 -0
  118. package/src/components/KTooltip/index.ts +1 -0
  119. package/src/index.ts +12 -1
  120. package/src/main.css +251 -0
  121. package/tailwind.config.js +9 -0
  122. package/dist/components/KButton/KButton.stories.d.ts +0 -4
  123. package/dist/components/KSpan/KSpan.stories.d.ts +0 -3
  124. package/src/stories/Button.stories.ts +0 -50
  125. package/src/stories/Button.tsx +0 -48
  126. package/src/stories/Configure.mdx +0 -364
  127. package/src/stories/Header.stories.ts +0 -27
  128. package/src/stories/Header.tsx +0 -56
  129. package/src/stories/Page.stories.ts +0 -32
  130. package/src/stories/Page.tsx +0 -73
  131. package/src/stories/assets/accessibility.png +0 -0
  132. package/src/stories/assets/accessibility.svg +0 -5
  133. package/src/stories/assets/addon-library.png +0 -0
  134. package/src/stories/assets/assets.png +0 -0
  135. package/src/stories/assets/avif-test-image.avif +0 -0
  136. package/src/stories/assets/context.png +0 -0
  137. package/src/stories/assets/discord.svg +0 -15
  138. package/src/stories/assets/docs.png +0 -0
  139. package/src/stories/assets/figma-plugin.png +0 -0
  140. package/src/stories/assets/github.svg +0 -3
  141. package/src/stories/assets/share.png +0 -0
  142. package/src/stories/assets/styling.png +0 -0
  143. package/src/stories/assets/testing.png +0 -0
  144. package/src/stories/assets/theming.png +0 -0
  145. package/src/stories/assets/tutorials.svg +0 -12
  146. package/src/stories/assets/youtube.svg +0 -4
  147. package/src/stories/button.css +0 -30
  148. package/src/stories/header.css +0 -32
  149. package/src/stories/page.css +0 -69
@@ -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,90 @@
1
+ import { Meta, StoryFn } from "@storybook/react"
2
+ import KDropdown, { KSelectOption } from "./KDropdown"
3
+ // @ts-ignore
4
+ import TracksIcon from "../../assets/tracks.svg"
5
+ import { MultiValue } from "react-select"
6
+
7
+ export default {
8
+ title: "ReactComponentLibrary/KDropdown",
9
+ component: KDropdown,
10
+ parameters: {
11
+ layout: "centered"
12
+ }
13
+ } as Meta<typeof KDropdown>
14
+
15
+ const Template: StoryFn<typeof KDropdown> = (args) => <KDropdown {...args} />
16
+
17
+ export const KDropdownSingle = Template.bind({})
18
+ KDropdownSingle.args = {
19
+ onSelect: (value: KSelectOption | MultiValue<KSelectOption> | undefined) => {
20
+ if (value === undefined) {
21
+ console.log("our value is undefined, deleting process can be performed")
22
+ } else {
23
+ console.log("update process can be performed")
24
+ }
25
+ },
26
+ width: 250,
27
+ placeholder: "Select single...",
28
+ isClearable: true,
29
+ isEllipsis: true,
30
+ // defaultValue: { label: "Label 1", value: 1, icon: TracksIcon },
31
+ defaultValuePrimitive: 7,
32
+ options: [
33
+ { label: "Label 1", value: 1, icon: TracksIcon },
34
+ { label: "Label 4", value: 2, icon: TracksIcon },
35
+ { label: "Label 3", value: 3 },
36
+ { label: "Label 2", value: 4 },
37
+ { label: "R&B", value: 5 },
38
+ { label: "Çınar", value: 6 },
39
+ { label: "ELEKTRONIC ", value: 7 },
40
+ { label: "TANIK", value: 8 },
41
+ { label: "Very very very very very long content.", value: 9 },
42
+ { label: "TANIK", value: 10 }
43
+ ]
44
+ }
45
+
46
+ export const KDropdownMulti = Template.bind({})
47
+ KDropdownMulti.args = {
48
+ onSelect: (value: KSelectOption | MultiValue<KSelectOption> | undefined) => {},
49
+ width: 250,
50
+ placeholder: "Multi...",
51
+ options: [
52
+ { label: "Label 1", value: 1, icon: TracksIcon },
53
+ { label: "Label 2", value: 2, icon: TracksIcon },
54
+ { label: "Label 3", value: 3 }
55
+ ],
56
+ isMulti: true
57
+ }
58
+
59
+ export const KDropdownLeftIcon = Template.bind({})
60
+ KDropdownLeftIcon.args = {
61
+ onSelect: (value: KSelectOption | MultiValue<KSelectOption> | undefined) => {},
62
+ placeholder: "Placeholder...",
63
+ leftIcon: TracksIcon
64
+ }
65
+
66
+ export const KDropdownRightIcon = Template.bind({})
67
+ KDropdownRightIcon.args = {
68
+ onSelect: (value: KSelectOption | MultiValue<KSelectOption> | undefined) => {},
69
+ placeholder: "Placeholder...",
70
+ rightIcon: TracksIcon,
71
+ width: 250,
72
+ options: [
73
+ { label: "Label 1", value: 1, icon: TracksIcon },
74
+ { label: "Label 4", value: 2, icon: TracksIcon },
75
+ { label: "Label 3", value: 3 },
76
+ { label: "Label 2", value: 4 },
77
+ { label: "Sevinç", value: 5 },
78
+ { label: "Çınar", value: 6 },
79
+ { label: "Ümit", value: 7 },
80
+ { label: "TANIK", value: 8 }
81
+ ]
82
+ }
83
+
84
+ export const KDropdownLeftRightIcon = Template.bind({})
85
+ KDropdownLeftRightIcon.args = {
86
+ onSelect: (value: KSelectOption | MultiValue<KSelectOption> | undefined) => {},
87
+ placeholder: "Placeholder...",
88
+ leftIcon: TracksIcon,
89
+ rightIcon: TracksIcon
90
+ }
@@ -0,0 +1,201 @@
1
+ import React, { useEffect, useState } from "react"
2
+ import "../../main.css"
3
+ import Select, { MultiValue } from "react-select"
4
+ // @ts-ignore
5
+ import CheckIcon from "../../assets/check.svg"
6
+ import KSpan from "../KSpan"
7
+ import { FilterOptionOption } from "react-select/dist/declarations/src/filters"
8
+
9
+ export interface KSelectOption {
10
+ label: string
11
+ value: number
12
+ type?: string
13
+ label2?: string
14
+ value2?: string
15
+ icon?: string
16
+ }
17
+
18
+ export interface KDropdownProps {
19
+ defaultValue?: KSelectOption | MultiValue<KSelectOption>
20
+ defaultValuePrimitive?: string | number
21
+ selected?: KSelectOption | MultiValue<KSelectOption>
22
+ onSelect: (selected: KSelectOption | MultiValue<KSelectOption> | undefined) => void
23
+ options: KSelectOption[]
24
+ width?: number
25
+ height?: number
26
+ leftIcon?: string
27
+ rightIcon?: string
28
+ background?: string
29
+ activeBackground?: string
30
+ borderRadius?: number
31
+ placeholder?: string
32
+ isMulti?: boolean
33
+ label?: string
34
+ textColor?: string
35
+ shadowDisabled?: boolean
36
+ menuBackground?: string
37
+ padding?: string
38
+ gap?: string
39
+ hideChosenOptionIcon?: boolean
40
+ isClearable?: boolean
41
+ isEllipsis?: boolean
42
+ }
43
+
44
+ const KDropdown: React.FC<KDropdownProps> = (props) => {
45
+ const [selectedOption, setSelectedOption] = useState<KSelectOption | MultiValue<KSelectOption>>()
46
+ const [background, setBackground] = useState("#F5F5F5")
47
+
48
+ useEffect(() => {
49
+ const emptyBackground = props.background || "#F5F5F5"
50
+ const activeBackground = props.activeBackground || "#FFF"
51
+
52
+ const background = props.selected ? activeBackground : emptyBackground
53
+ setBackground(background)
54
+ }, [props.selected])
55
+
56
+ const width = props.width || "100%"
57
+ const height = props.height || "auto"
58
+ const borderRadius = props.borderRadius || 10
59
+ const isMulti = props.isMulti || false
60
+ const textColor = props.textColor || "#111"
61
+ const boxShadow = props.shadowDisabled ? "" : "0 0 0 1px rgba(17, 17, 17, 0.04), 0 1px 1px 0 rgba(17, 17, 17, 0.04)"
62
+ const menuBackground = props.menuBackground || "rgb(249, 249, 249)"
63
+ const padding = props.padding || "8px"
64
+ const gap = props.gap || "4px"
65
+ const hideIcon = props.hideChosenOptionIcon || false
66
+ const isClearable = props.isClearable || false
67
+ const isEllipsis = props.isEllipsis || false
68
+
69
+ let defaultValue = props.defaultValue
70
+ if (!defaultValue && props.defaultValuePrimitive) {
71
+ defaultValue = props.options.find(
72
+ (option) => option.value === props.defaultValuePrimitive || option.value2 === props.defaultValuePrimitive
73
+ )
74
+ }
75
+
76
+ const customFilterOption = (option: FilterOptionOption<KSelectOption>, inputValue: string) => {
77
+ return option.data.label.toLocaleLowerCase("en").includes(inputValue.toLocaleLowerCase("en"))
78
+ }
79
+
80
+ const getOptionLabels = (option: KSelectOption) => {
81
+ return (
82
+ <div className="flex justify-between" style={{ width: "100%" }}>
83
+ <div className="flex">
84
+ {option.icon && <img src={option.icon} className="mr-2" width={20} alt={"option-icon"} />}
85
+ <KSpan text={option.label} color="#111" />
86
+ </div>
87
+ {
88
+ //@ts-ignore
89
+ !isMulti && selectedOption?.value === option.value && <img src={CheckIcon} width={24} alt={"check-icon"} />
90
+ }
91
+ </div>
92
+ )
93
+ }
94
+ return (
95
+ <div
96
+ className={"k-dropdown-container"}
97
+ style={{ background, borderRadius, width, height, boxShadow, padding, gap }}
98
+ >
99
+ {props.leftIcon && <img src={props.leftIcon} width={20} alt={"l-icon"} />}
100
+
101
+ <Select
102
+ defaultValue={defaultValue}
103
+ isMulti={isMulti}
104
+ name={props.label || ""}
105
+ placeholder={props.placeholder || ""}
106
+ options={props.options}
107
+ className={"k-dropdown"}
108
+ filterOption={customFilterOption}
109
+ isClearable={isClearable}
110
+ styles={{
111
+ control: (baseStyles, state) => ({
112
+ ...baseStyles,
113
+ background: "transparent !important",
114
+ padding: "0px !important",
115
+ boxShadow: "none",
116
+ fontSize: 14,
117
+ lineHeight: "20px",
118
+ cursor: "pointer",
119
+ minHeight: "20px",
120
+ border: "none"
121
+ }),
122
+ menu: (base) => ({
123
+ ...base,
124
+ borderRadius: 10,
125
+ background: menuBackground,
126
+ boxShadow:
127
+ "0px 3px 3px 0px rgba(17, 17, 17, 0.03), 0px 1px 1px 0px rgba(17, 17, 17, 0.04), 0px 0px 0px 1px rgba(17, 17, 17, 0.04)",
128
+ backdropFilter: "blur(2px)",
129
+ paddingRight: 3,
130
+ paddingLeft: 3
131
+ }),
132
+ menuList: (base) => ({
133
+ ...base,
134
+ paddingTop: 0,
135
+ paddingBottom: 0
136
+ }),
137
+ singleValue: (provided) => ({
138
+ ...provided,
139
+ color: textColor
140
+ }),
141
+ option: (provided, state) => ({
142
+ ...provided,
143
+ display: "flex",
144
+ alignItems: "center",
145
+ background: "white",
146
+ marginBottom: 4,
147
+ marginTop: 4,
148
+ borderRadius: 10,
149
+ color: "#111"
150
+ }),
151
+ valueContainer: (base) => ({
152
+ ...base,
153
+ padding: 0
154
+ }),
155
+
156
+ input: (base) => ({
157
+ ...base,
158
+ padding: 0,
159
+ margin: 0,
160
+ height: "20px"
161
+ }),
162
+ placeholder: (base) => ({
163
+ ...base,
164
+ margin: 0
165
+ }),
166
+ clearIndicator: (base) => ({
167
+ ...base,
168
+ padding: 0
169
+ })
170
+ }}
171
+ components={{
172
+ IndicatorSeparator: () => null,
173
+ DropdownIndicator: () => null,
174
+ SingleValue: ({ data, ...props }) => (
175
+ <div className={`flex ${isEllipsis ? "w-full" : ""}`} style={{ position: "absolute" }}>
176
+ {data.icon && !hideIcon && <img src={data.icon} className="mr-2" width={20} alt={"data-icon"} />}
177
+ <KSpan text={data.label} color="#111" ellipsis={isEllipsis} />
178
+ </div>
179
+ )
180
+ }}
181
+ onChange={(event) => {
182
+ if (!event) {
183
+ if (props.isClearable) {
184
+ setSelectedOption(undefined)
185
+ props.onSelect(undefined)
186
+ }
187
+ return
188
+ }
189
+ setSelectedOption(event)
190
+ props.onSelect(event)
191
+ }}
192
+ //@ts-ignore
193
+ getOptionLabel={(option: KSelectOption) => getOptionLabels(option)}
194
+ />
195
+
196
+ {props.rightIcon && <img src={props.rightIcon} width={20} alt={"r-icon"} />}
197
+ </div>
198
+ )
199
+ }
200
+
201
+ export default KDropdown
@@ -0,0 +1 @@
1
+ export {default} from './KDropdown';
@@ -0,0 +1,84 @@
1
+ import { Meta, StoryFn } from "@storybook/react"
2
+ import KInput from "./KInput"
3
+ // @ts-ignore
4
+ import TracksIcon from "../../assets/tracks.svg"
5
+ import { KeyboardEvent } from "react"
6
+
7
+ export default {
8
+ title: "ReactComponentLibrary/KInput",
9
+ component: KInput,
10
+ parameters: {
11
+ layout: "centered"
12
+ }
13
+ } as Meta<typeof KInput>
14
+
15
+ const Template: StoryFn<typeof KInput> = (args) => <KInput {...args} />
16
+
17
+ export const KInputRange = Template.bind({})
18
+ KInputRange.args = {
19
+ onChange: (value: string) => {},
20
+ placeholder: "Placeholder...",
21
+ hoverBackground: "white",
22
+ type: "range",
23
+ leftIcon: TracksIcon,
24
+ rightIcon: TracksIcon
25
+ }
26
+
27
+ export const KInputCheckbox = Template.bind({})
28
+ KInputCheckbox.args = {
29
+ onChange: (value: string) => {},
30
+ placeholder: "Placeholder...",
31
+ hoverBackground: "white",
32
+ type: "checkbox",
33
+ leftIcon: TracksIcon,
34
+ rightIcon: TracksIcon,
35
+ checked: false
36
+ }
37
+
38
+ export const KInputPrimary = Template.bind({})
39
+ KInputPrimary.args = {
40
+ onChange: (value: string) => {
41
+ console.log("value:", value)
42
+ },
43
+ onKeyDown: (event: KeyboardEvent) => {
44
+ if (event.key === "Enter") {
45
+ console.log("Enter is clicked and our value is:", event.currentTarget)
46
+ }
47
+ },
48
+ placeholder: "Placeholder...",
49
+ hoverBackground: "white"
50
+ }
51
+
52
+ export const KInputLeftIcon = Template.bind({})
53
+ KInputLeftIcon.args = {
54
+ onChange: (value: string) => {},
55
+ placeholder: "Placeholder...",
56
+ leftIcon: TracksIcon,
57
+ leftIconClick: () => {
58
+ alert("left icon clicked")
59
+ }
60
+ }
61
+
62
+ export const KInputRightIcon = Template.bind({})
63
+ KInputRightIcon.args = {
64
+ onChange: (value: string) => {},
65
+ placeholder: "Placeholder...",
66
+ rightIcon: TracksIcon,
67
+ rightIconClick: () => {
68
+ alert("right icon clicked")
69
+ }
70
+ }
71
+
72
+ export const KInputLeftRightIcon = Template.bind({})
73
+ KInputLeftRightIcon.args = {
74
+ onChange: (value: string) => {},
75
+ placeholder: "Placeholder...",
76
+ leftIcon: TracksIcon,
77
+ rightIcon: TracksIcon,
78
+ leftIconClick: () => {
79
+ alert("left icon clicked")
80
+ },
81
+ rightIconClick: () => {
82
+ alert("right icon clicked")
83
+ }
84
+ }