kahuna-base-react-components 1.0.6 → 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 (150) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +23 -0
  3. package/dist/components/KButton/KButton.d.ts +23 -0
  4. package/dist/components/KButton/index.d.ts +1 -0
  5. package/dist/components/KCodeInput/KCodeInput.d.ts +36 -0
  6. package/dist/components/KCodeInput/index.d.ts +1 -0
  7. package/dist/components/KDropdown/KDropdown.d.ts +38 -0
  8. package/dist/components/KDropdown/index.d.ts +1 -0
  9. package/dist/components/KDropdownToggle/KDropdownToggle.d.ts +35 -0
  10. package/dist/components/KDropdownToggle/index.d.ts +1 -0
  11. package/dist/components/KInput/KInput.d.ts +32 -0
  12. package/dist/components/KInput/index.d.ts +1 -0
  13. package/dist/components/KLogo/KLogo.d.ts +18 -0
  14. package/dist/components/KLogo/index.d.ts +1 -0
  15. package/dist/components/KSelectDate/KSelectDate.d.ts +9 -0
  16. package/dist/components/KSelectDate/index.d.ts +1 -0
  17. package/dist/components/KSlider/KSlider.d.ts +15 -0
  18. package/dist/components/KSlider/index.d.ts +1 -0
  19. package/dist/components/KSliderLabel/KSliderLabel.d.ts +19 -0
  20. package/dist/components/KSliderLabel/index.d.ts +1 -0
  21. package/dist/components/KSpan/KSpan.d.ts +18 -0
  22. package/dist/components/KSpan/index.d.ts +1 -0
  23. package/dist/components/KTextArea/KTextArea.d.ts +32 -0
  24. package/dist/components/KTextArea/index.d.ts +1 -0
  25. package/dist/components/KTitleSpan/KTitleSpan.d.ts +14 -0
  26. package/dist/components/KTitleSpan/index.d.ts +1 -0
  27. package/dist/components/KTooltip/KTooltip.d.ts +19 -0
  28. package/dist/components/KTooltip/index.d.ts +1 -0
  29. package/dist/fonts/AeonikPro-Bold/AeonikPro-Bold.otf +0 -0
  30. package/dist/fonts/AeonikPro-Bold/CoType EULA Desktop.pdf +1388 -3
  31. package/dist/fonts/Inter/Inter-VariableFont_slnt,wght.ttf +0 -0
  32. package/dist/fonts/Inter/OFL.txt +93 -0
  33. package/dist/fonts/Inter/README.txt +72 -0
  34. package/dist/fonts/Inter/static/Inter-Black.ttf +0 -0
  35. package/dist/fonts/Inter/static/Inter-Bold.ttf +0 -0
  36. package/dist/fonts/Inter/static/Inter-ExtraBold.ttf +0 -0
  37. package/dist/fonts/Inter/static/Inter-ExtraLight.ttf +0 -0
  38. package/dist/fonts/Inter/static/Inter-Light.ttf +0 -0
  39. package/dist/fonts/Inter/static/Inter-Medium.ttf +0 -0
  40. package/dist/fonts/Inter/static/Inter-Regular.ttf +0 -0
  41. package/dist/fonts/Inter/static/Inter-SemiBold.ttf +0 -0
  42. package/dist/fonts/Inter/static/Inter-Thin.ttf +0 -0
  43. package/dist/index.d.ts +13 -0
  44. package/dist/index.esm.js +9 -1
  45. package/dist/index.esm.js.map +1 -1
  46. package/dist/index.js +9 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/types.d.ts +241 -8
  49. package/package.json +14 -3
  50. package/postcss.config.js +6 -0
  51. package/removeUseClient.js +22 -0
  52. package/rollup.config.js +9 -3
  53. package/src/assets/calendar-hovered.svg +3 -0
  54. package/src/assets/calendar.svg +3 -0
  55. package/src/assets/check.svg +3 -0
  56. package/src/assets/chevron-left.svg +7 -0
  57. package/src/assets/chevron-right.svg +7 -0
  58. package/src/assets/fonts/AeonikPro/AeonikPro-Bold.otf +0 -0
  59. package/src/assets/fonts/AeonikPro/AeonikPro-Medium.otf +0 -0
  60. package/src/assets/fonts/AeonikPro/CoType EULA Desktop.pdf +1388 -3
  61. package/src/assets/fonts/Inter/Inter-VariableFont_slnt,wght.ttf +0 -0
  62. package/src/assets/fonts/Inter/OFL.txt +93 -0
  63. package/src/assets/fonts/Inter/README.txt +72 -0
  64. package/src/assets/fonts/Inter/static/Inter-Black.ttf +0 -0
  65. package/src/assets/fonts/Inter/static/Inter-Bold.ttf +0 -0
  66. package/src/assets/fonts/Inter/static/Inter-ExtraBold.ttf +0 -0
  67. package/src/assets/fonts/Inter/static/Inter-ExtraLight.ttf +0 -0
  68. package/src/assets/fonts/Inter/static/Inter-Light.ttf +0 -0
  69. package/src/assets/fonts/Inter/static/Inter-Medium.ttf +0 -0
  70. package/src/assets/fonts/Inter/static/Inter-Regular.ttf +0 -0
  71. package/src/assets/fonts/Inter/static/Inter-SemiBold.ttf +0 -0
  72. package/src/assets/fonts/Inter/static/Inter-Thin.ttf +0 -0
  73. package/src/assets/kahuna-text.svg +3 -0
  74. package/src/assets/logo-gray.svg +10 -0
  75. package/src/assets/logo-small-hovered.svg +4 -0
  76. package/src/assets/logo-small.svg +11 -0
  77. package/src/assets/logo.svg +11 -0
  78. package/src/assets/progress.svg +37 -0
  79. package/src/assets/separator.svg +3 -0
  80. package/src/assets/slider-dots.svg +7 -0
  81. package/src/assets/slider-step.svg +3 -0
  82. package/src/assets/slider-thumb.svg +3 -0
  83. package/src/assets/tracks.svg +5 -0
  84. package/src/assets/union.svg +3 -0
  85. package/src/assets/vector.svg +3 -0
  86. package/src/components/KButton/KButton.stories.tsx +69 -12
  87. package/src/components/KButton/KButton.tsx +51 -14
  88. package/src/components/KCodeInput/KCodeInput.stories.tsx +84 -0
  89. package/src/components/KCodeInput/KCodeInput.tsx +260 -0
  90. package/src/components/KCodeInput/index.ts +1 -0
  91. package/src/components/KDropdown/KDropdown.stories.tsx +90 -0
  92. package/src/components/KDropdown/KDropdown.tsx +201 -0
  93. package/src/components/KDropdown/index.ts +1 -0
  94. package/src/components/KInput/KInput.stories.tsx +84 -0
  95. package/src/components/KInput/KInput.tsx +128 -0
  96. package/src/components/KInput/index.ts +1 -0
  97. package/src/components/KLogo/KLogo.stories.tsx +24 -0
  98. package/src/components/KLogo/KLogo.tsx +79 -0
  99. package/src/components/KLogo/index.ts +1 -0
  100. package/src/components/KSelectDate/CalendarCustom.css +235 -0
  101. package/src/components/KSelectDate/KSelectDate.stories.tsx +54 -0
  102. package/src/components/KSelectDate/KSelectDate.tsx +314 -0
  103. package/src/components/KSelectDate/index.ts +1 -0
  104. package/src/components/KSlider/KSlider.stories.tsx +19 -0
  105. package/src/components/KSlider/KSlider.tsx +67 -0
  106. package/src/components/KSlider/index.ts +1 -0
  107. package/src/components/KSliderLabel/KSliderLabel.stories.tsx +61 -0
  108. package/src/components/KSliderLabel/KSliderLabel.tsx +137 -0
  109. package/src/components/KSliderLabel/index.ts +1 -0
  110. package/src/components/KSpan/KSpan.stories.tsx +31 -11
  111. package/src/components/KSpan/KSpan.tsx +65 -9
  112. package/src/components/KTextArea/KTextArea.stories.tsx +65 -0
  113. package/src/components/KTextArea/KTextArea.tsx +130 -0
  114. package/src/components/KTextArea/index.ts +1 -0
  115. package/src/components/KTitleSpan/KTitleSpan.stories.tsx +23 -0
  116. package/src/components/KTitleSpan/KTitleSpan.tsx +33 -0
  117. package/src/components/KTitleSpan/index.ts +1 -0
  118. package/src/components/KTooltip/KTooltip.stories.tsx +94 -0
  119. package/src/components/KTooltip/KTooltip.tsx +67 -0
  120. package/src/components/KTooltip/index.ts +1 -0
  121. package/src/index.ts +12 -1
  122. package/src/main.css +251 -0
  123. package/tailwind.config.js +9 -0
  124. package/tsconfig.json +6 -1
  125. package/src/stories/Button.stories.ts +0 -50
  126. package/src/stories/Button.tsx +0 -48
  127. package/src/stories/Configure.mdx +0 -364
  128. package/src/stories/Header.stories.ts +0 -27
  129. package/src/stories/Header.tsx +0 -56
  130. package/src/stories/Page.stories.ts +0 -32
  131. package/src/stories/Page.tsx +0 -73
  132. package/src/stories/assets/accessibility.png +0 -0
  133. package/src/stories/assets/accessibility.svg +0 -5
  134. package/src/stories/assets/addon-library.png +0 -0
  135. package/src/stories/assets/assets.png +0 -0
  136. package/src/stories/assets/avif-test-image.avif +0 -0
  137. package/src/stories/assets/context.png +0 -0
  138. package/src/stories/assets/discord.svg +0 -15
  139. package/src/stories/assets/docs.png +0 -0
  140. package/src/stories/assets/figma-plugin.png +0 -0
  141. package/src/stories/assets/github.svg +0 -3
  142. package/src/stories/assets/share.png +0 -0
  143. package/src/stories/assets/styling.png +0 -0
  144. package/src/stories/assets/testing.png +0 -0
  145. package/src/stories/assets/theming.png +0 -0
  146. package/src/stories/assets/tutorials.svg +0 -12
  147. package/src/stories/assets/youtube.svg +0 -4
  148. package/src/stories/button.css +0 -30
  149. package/src/stories/header.css +0 -32
  150. package/src/stories/page.css +0 -69
@@ -0,0 +1,314 @@
1
+ import React, { CSSProperties, useEffect, useState } from "react"
2
+ import Calendar from "react-calendar"
3
+ import "./CalendarCustom.css"
4
+ //@ts-ignore
5
+ import LeftIcon from "../../assets/chevron-left.svg"
6
+ //@ts-ignore
7
+ import SeparatorIcon from "../../assets/separator.svg"
8
+ //@ts-ignore
9
+ import CalendarIcon from "../../assets/calendar.svg"
10
+ //@ts-ignore
11
+ import RightIcon from "../../assets/chevron-right.svg"
12
+ import "../../main.css"
13
+ import KButton from "../KButton"
14
+ import KSpan from "../KSpan"
15
+
16
+ export interface KSelectDateProps {
17
+ value: Date | undefined
18
+ onChange: (date: Date | undefined) => void
19
+ }
20
+ interface MonthSelectorType {
21
+ monthName: string
22
+ year: string
23
+ date: Date
24
+ }
25
+ interface DaySelectorType {
26
+ dayName: string
27
+ dayOrderInMonth: number
28
+ date: Date
29
+ }
30
+ interface MonthTextType {
31
+ [key: string]: string
32
+ }
33
+
34
+ const KSelectDate: React.FC<KSelectDateProps> = (props) => {
35
+ const [value, setValue] = useState<Date | undefined>(props.value)
36
+ const [calendarDate, setCalendarDate] = useState<Date | undefined>(props.value)
37
+ const [dummyDate, setDummyDate] = useState<Date | undefined>(props.value)
38
+ const [nextMonths, setNextMonths] = useState<MonthSelectorType[]>([])
39
+ const [weekDays, setWeekDays] = useState<DaySelectorType[]>([])
40
+ const [openCalendar, setOpenCalendar] = useState<boolean>(false)
41
+
42
+ const formatShortWeekday = (locale: string | undefined, date: Date): string => {
43
+ return date.toLocaleDateString(locale, { weekday: "short" }).charAt(0) // Return only the first letter of the weekday
44
+ }
45
+
46
+ const formatMonthYear = (locale: string | undefined, date: Date): string => {
47
+ const formattedDate = date.toLocaleDateString(locale, { month: "short", year: "numeric" })
48
+ const [month, year] = formattedDate.split(" ")
49
+ const capitalizedMonth = month.charAt(0).toUpperCase() + month.slice(1).toLowerCase()
50
+ return `${capitalizedMonth}, ${year}`
51
+ }
52
+
53
+ const onClickDay = (date: Date) => {
54
+ if (date.getTime() === calendarDate?.getTime()) {
55
+ setCalendarDate(undefined)
56
+ } else {
57
+ setCalendarDate(date)
58
+ }
59
+ }
60
+
61
+ const getNextMonths = (date: Date | undefined) => {
62
+ if (date) {
63
+ const updatedMonths = Array.from({ length: 4 }, (_, i) => {
64
+ const newDate = new Date(date.getFullYear(), date.getMonth() + (i - 1), 1)
65
+ return {
66
+ monthName: newDate.toLocaleString("en-US", { month: "long" }),
67
+ year: newDate.getFullYear().toString(),
68
+ date: newDate
69
+ }
70
+ })
71
+ setNextMonths(updatedMonths)
72
+ }
73
+ }
74
+
75
+ const getWeekDays = (date: Date | undefined) => {
76
+ if (date) {
77
+ const startOfWeek = new Date(date)
78
+ const dayOfWeek = startOfWeek.getDay()
79
+ const diffToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek // If Sunday (0), move back 6 days; otherwise move back (1 - dayOfWeek) days
80
+ startOfWeek.setDate(startOfWeek.getDate() + diffToMonday)
81
+
82
+ const updatedDays = Array.from({ length: 7 }, (_, i) => {
83
+ const day = new Date(startOfWeek)
84
+ day.setDate(startOfWeek.getDate() + i)
85
+ return {
86
+ dayName: day.toLocaleDateString("en-US", { weekday: "short" }),
87
+ dayOrderInMonth: day.getDate(),
88
+ date: day
89
+ }
90
+ })
91
+
92
+ setWeekDays(updatedDays)
93
+ }
94
+ }
95
+
96
+ const renderPopUpCalendar = () => {
97
+ return (
98
+ <div className="flex flex-col gap-0">
99
+ <Calendar
100
+ onClickDay={onClickDay}
101
+ locale="en-US"
102
+ value={calendarDate || null}
103
+ defaultValue={null}
104
+ next2Label={null}
105
+ prev2Label={null}
106
+ prevLabel={<img src={LeftIcon} />}
107
+ nextLabel={<img src={RightIcon} />}
108
+ formatShortWeekday={formatShortWeekday}
109
+ formatMonthYear={formatMonthYear}
110
+ />
111
+ <div className="h-19 w-[350px] bg-[#FFF] flex flex-row gap-4 py-4 justify-center border-[1px] border-[#E7E7E7] border-t-0 rounded-b-[10px]">
112
+ <KButton
113
+ text="Cancel"
114
+ height="44px"
115
+ width="160px"
116
+ background="#FFF"
117
+ textColor="#111"
118
+ onClick={() => {
119
+ setOpenCalendar(false)
120
+ }}
121
+ />
122
+ <KButton
123
+ text="Apply"
124
+ height="44px"
125
+ width="160px"
126
+ background="#F2FE67"
127
+ textColor="#111"
128
+ onClick={() => {
129
+ setValue(calendarDate)
130
+ setOpenCalendar(false)
131
+ }}
132
+ />
133
+ </div>
134
+ </div>
135
+ )
136
+ }
137
+
138
+ const monthSelector = (month: string, year: string, date: Date) => {
139
+ const monthText: MonthTextType = {
140
+ January: "Jan",
141
+ February: "Feb",
142
+ March: "March",
143
+ April: "April",
144
+ May: "May",
145
+ June: "June",
146
+ July: "July",
147
+ August: "August",
148
+ September: "Sept",
149
+ October: "Oct",
150
+ November: "Nov",
151
+ December: "Dec"
152
+ }
153
+
154
+ const text = `${monthText[month]}, ${year}`
155
+
156
+ const inMonth = dummyDate ? dummyDate?.getMonth() === date.getMonth() : new Date().getMonth() === date.getMonth()
157
+
158
+ return (
159
+ <div
160
+ key={`${text}-${date}`}
161
+ className={`w-[135px] h-9 box-sizing`}
162
+ style={{
163
+ borderRadius: 999,
164
+ border: inMonth ? "1px solid #111" : "1px solid #E7E7E7"
165
+ }}
166
+ >
167
+ <KButton
168
+ text={text}
169
+ shadowDisabled={true}
170
+ onClick={() => {
171
+ if (date.getTime()) {
172
+ setDummyDate(date)
173
+ }
174
+ }}
175
+ background={inMonth ? "#111" : "#FFF"}
176
+ textColor={inMonth? "#FFF" : "#111"}
177
+ borderRadius={999}
178
+ padding="8px 16px"
179
+ height="34px"
180
+ />
181
+ </div>
182
+ )
183
+ }
184
+
185
+ const daySelector = (text: string, date: Date) => {
186
+ return (
187
+ <div
188
+ key={`${text}-${date}`}
189
+ className={`w-[85px] h-[104px] flex flex-col justify-between py-3 px-2.5 rounded-[10px] ${
190
+ date.getTime() === value?.getTime() ? "bg-[#F8FEA3]" : "bg-[#F5F5F5]"
191
+ } cursor-pointer`}
192
+ onClick={() => {
193
+ if (date.getTime() === value?.getTime()) {
194
+ setValue(undefined)
195
+ } else {
196
+ setValue(date)
197
+ }
198
+ }}
199
+ >
200
+ <div>
201
+ <img src={CalendarIcon} alt="calendar" />
202
+ </div>
203
+ <KSpan text={text} fontWeight={500} color="#111" />
204
+ </div>
205
+ )
206
+ }
207
+
208
+ const changeWeeks = (date: Date | undefined, isNextWeek: boolean) => {
209
+ if (date) {
210
+ const newDate = new Date(date)
211
+ if (isNextWeek) {
212
+ newDate.setDate(newDate.getDate() + 7)
213
+ } else {
214
+ newDate.setDate(newDate.getDate() - 7)
215
+ }
216
+ setDummyDate(newDate)
217
+ } else {
218
+ const newDate = new Date()
219
+ if (isNextWeek) {
220
+ newDate.setDate(newDate.getDate() + 7)
221
+ } else {
222
+ newDate.setDate(newDate.getDate() - 7)
223
+ }
224
+ setDummyDate(newDate)
225
+ }
226
+ }
227
+
228
+ useEffect(() => {
229
+ if (value) {
230
+ setDummyDate(value)
231
+ }
232
+ props.onChange(value)
233
+ }, [value])
234
+
235
+ useEffect(() => {
236
+ const today = new Date()
237
+ if (!props.value) {
238
+ getNextMonths(today)
239
+ getWeekDays(today)
240
+ }
241
+ }, [])
242
+
243
+ useEffect(() => {
244
+ getNextMonths(dummyDate)
245
+ getWeekDays(dummyDate)
246
+ }, [dummyDate])
247
+
248
+ return (
249
+ <React.Fragment>
250
+ {openCalendar && (
251
+ <div className="w-[100vw] h-[100vh] fixed left-0 top-0 flex items-center justify-center z-50">
252
+ <div>{renderPopUpCalendar()}</div>
253
+ </div>
254
+ )}
255
+ <div>
256
+ <div className={`flex flex-col gap-4 ${openCalendar && "blur-2xl"}`}>
257
+ <div className="flex flex-row justify-between gap-2 items-center">
258
+ <div className="flex flex-row gap-2">
259
+ {nextMonths.map((month, i) => {
260
+ return monthSelector(month.monthName, month.year, month.date)
261
+ })}
262
+ </div>
263
+ <div>
264
+ <img src={SeparatorIcon} />
265
+ </div>
266
+ <div>
267
+ <KButton
268
+ icon={CalendarIcon}
269
+ onClick={() => {
270
+ setOpenCalendar(true)
271
+ setCalendarDate(value)
272
+ }}
273
+ padding="8px"
274
+ height="36px"
275
+ background="#FFF"
276
+ />
277
+ </div>
278
+ </div>
279
+ <div className="flex flex-row justify-between gap-1 items-center">
280
+ {weekDays.map((day, i) => {
281
+ return daySelector(`${day.dayOrderInMonth}, ${day.dayName}`, day.date)
282
+ })}
283
+ </div>
284
+ <div className="flex flex-row justify-between items-center">
285
+ <KButton
286
+ text="Previous Week"
287
+ padding="6px"
288
+ leftIcon={LeftIcon}
289
+ onClick={() => {
290
+ changeWeeks(dummyDate, false)
291
+ }}
292
+ width="130px"
293
+ height="32px"
294
+ background="#FFF"
295
+ />
296
+ <KButton
297
+ text="Next Week"
298
+ padding="6px"
299
+ rightIcon={RightIcon}
300
+ onClick={() => {
301
+ changeWeeks(dummyDate, true)
302
+ }}
303
+ width="130px"
304
+ height="32px"
305
+ background="#FFF"
306
+ />
307
+ </div>
308
+ </div>
309
+ </div>
310
+ </React.Fragment>
311
+ )
312
+ }
313
+
314
+ export default KSelectDate
@@ -0,0 +1 @@
1
+ export {default} from './KSelectDate';
@@ -0,0 +1,19 @@
1
+ import {Meta, StoryFn} from "@storybook/react";
2
+ import KSlider, {SliderOption} from "./KSlider";
3
+
4
+ export default {
5
+ title: "ReactComponentLibrary/KSlider",
6
+ component: KSlider,
7
+ } as Meta<typeof KSlider>;
8
+
9
+ const Template: StoryFn<typeof KSlider> = (args) => <KSlider {...args} />;
10
+
11
+ export const KSliderPrimary = Template.bind({});
12
+ KSliderPrimary.args = {
13
+ options: [{label: "0%", value: 0}, {label: "25%", value: 1}, {label: "50%", value: 2}, {label: "75%", value: 3}],
14
+ onChange: (option: SliderOption) => {
15
+ // Do Nothing
16
+ },
17
+ width: "200px",
18
+ value: 3
19
+ };
@@ -0,0 +1,67 @@
1
+ import React from "react"
2
+ import "../../main.css"
3
+ // @ts-ignore
4
+ import StepIcon from "../../assets/slider-step.svg"
5
+
6
+ export interface SliderOption {
7
+ label: string
8
+ value: number
9
+ }
10
+
11
+ export interface KSliderProps {
12
+ options: SliderOption[]
13
+ onChange: (option: SliderOption) => void
14
+ value?: number
15
+ disabled?: boolean
16
+ width?: string
17
+ }
18
+
19
+ const KSlider: React.FC<KSliderProps> = (props) => {
20
+ const disabled = props.disabled || false
21
+ const width = props.width || "100%"
22
+ const height = "8px"
23
+
24
+ const calculateSpanWidth = ():number => {
25
+ const min = props.options[0].value
26
+ const max = props.options[props.options.length - 1].value
27
+ const spanWidth = (props.value! - min) / (max - min) * 100
28
+ if (spanWidth >= 100 ) {
29
+ return 99
30
+ }
31
+ return spanWidth
32
+ }
33
+
34
+ return (
35
+ <div className="inline-block bg-[#E7E7E7] rounded-full relative z-0" style={{ width, height }}>
36
+ <span className="w-full flex justify-between absolute top-0 z-0 items-center px-0.5" style={{ height }}>
37
+ {props.options.map((option, index) => {
38
+ return <img key={`step-icon-${index}`} src={StepIcon} className="w-1 h-1 !z-0 " />
39
+ })}
40
+ </span>
41
+ <span
42
+ className="block z-50 absolute top-0"
43
+ style={{
44
+ height,
45
+ width: `${calculateSpanWidth()}%`,
46
+ borderRadius: "10px",
47
+ backgroundColor: "black"
48
+ }}
49
+ />
50
+ <input
51
+ disabled={disabled}
52
+ style={{ width, height }}
53
+ className={"k-slider-input absolute top-0 !z-50"}
54
+ onChange={(e) => {
55
+ const option = props.options.find((option) => option.value.toString() === e.target.value)
56
+ if (option) return props.onChange(option)
57
+ }}
58
+ value={props.value}
59
+ type="range"
60
+ min={props.options[0].value}
61
+ max={props.options[props.options.length - 1].value}
62
+ />
63
+ </div>
64
+ )
65
+ };
66
+
67
+ export default KSlider;
@@ -0,0 +1 @@
1
+ export {default} from './KSlider';
@@ -0,0 +1,61 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+ import KSliderLabel, { SliderLabelProps, SliderLabelOption } from "./KSliderLabel";
4
+
5
+ export default {
6
+ title: "ReactComponentLibrary/KSliderLabel",
7
+ component: KSliderLabel,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ } as Meta<typeof KSliderLabel>;
12
+
13
+ const KSliderLabelWrapper: React.FC<SliderLabelProps> = (args) => {
14
+ const [selectedValue, setSelectedValue] = useState<number | undefined>(0);
15
+
16
+ useEffect(() => {
17
+ console.log("selectedValue: ", selectedValue);
18
+ }, [selectedValue]);
19
+
20
+ return (
21
+ <KSliderLabel
22
+ {...args}
23
+ value={selectedValue}
24
+ onChange={(option) => {
25
+ console.log("option: ", option);
26
+ setSelectedValue(option.value);
27
+ console.log("Value updated to: ", option.value);
28
+ }}
29
+ />
30
+ );
31
+ };
32
+
33
+ const Template: StoryFn<typeof KSliderLabelWrapper> = (args) => <KSliderLabelWrapper {...args} />;
34
+
35
+ const options: SliderLabelOption[] = [
36
+ { label: "Low", value: 0 },
37
+ { label: "Medium", value: 1 },
38
+ { label: "Medium", value: 3 },
39
+ { label: "Medium", value: 4 },
40
+ { label: "Medium", value: 5 },
41
+ ];
42
+
43
+ export const KSliderLabelPrimary = Template.bind({});
44
+ KSliderLabelPrimary.args = {
45
+ options,
46
+ disabled: false,
47
+ width: "440px",
48
+ titleText: "Slider Title",
49
+ valueText: "50",
50
+ fontSize: 14,
51
+ color: "#000",
52
+ };
53
+
54
+ export const KSliderLabelHoverText = Template.bind({});
55
+ KSliderLabelHoverText.args = {
56
+ options,
57
+ titleText: "Hover to see me!",
58
+ valueText: "50",
59
+ fontSize: 14,
60
+ color: "#000",
61
+ };
@@ -0,0 +1,137 @@
1
+ import React, { useEffect, useRef, useState } from "react"
2
+ import "../../main.css"
3
+ //@ts-ignore
4
+ import ThumbIcon from "../../assets/slider-thumb.svg"
5
+ import KSpan from "../KSpan"
6
+
7
+ export interface SliderLabelOption {
8
+ label: string
9
+ value: number
10
+ }
11
+
12
+ export interface SliderLabelProps {
13
+ options: SliderLabelOption[]
14
+ onChange: (option: SliderLabelOption) => void
15
+ value?: number
16
+ disabled?: boolean
17
+ width?: string
18
+ titleText?: string
19
+ valueText?: string,
20
+ fontSize?: number,
21
+ color?: string
22
+ }
23
+
24
+ const KSliderLabel: React.FC<SliderLabelProps> = (props) => {
25
+ const disabled = props.disabled || false
26
+ const width = props.width || "100%"
27
+ const height = "48px"
28
+ const fontSize = props.fontSize || 14
29
+ const color = props.color || "#000"
30
+
31
+ const [titleFits, setTitleFits] = useState<boolean>(false)
32
+ const [valueFits, setValueFits] = useState<boolean>(false)
33
+
34
+ const titleTextRef = useRef<HTMLDivElement>(null)
35
+ const valueTextRef = useRef<HTMLDivElement>(null)
36
+ const progressRef = useRef<HTMLDivElement>(null)
37
+ const mainDivRef = useRef<HTMLDivElement>(null)
38
+
39
+ useEffect(() => {
40
+
41
+ if (!titleTextRef.current || !progressRef.current || !valueTextRef.current || !mainDivRef.current) return
42
+
43
+ const titleWidth = titleTextRef.current.getBoundingClientRect().width
44
+ const progressWidth = progressRef.current.getBoundingClientRect().width
45
+
46
+ setTitleFits(titleWidth < progressWidth - 30)
47
+
48
+ const valueWidth = valueTextRef.current.getBoundingClientRect().width
49
+ const restWidth = mainDivRef.current.getBoundingClientRect().width - progressWidth
50
+
51
+ setValueFits(valueWidth < restWidth)
52
+
53
+ }, [props.value])
54
+
55
+ const calculateSpanWidth = (): string => {
56
+ if (!props.value) return "32px"
57
+ const min = props.options[0].value
58
+ const max = props.options[props.options.length - 1].value
59
+ const spanWidth = `calc((((${props.value! - min}) / (${max - min})) * (100% - 32px)) + 32px)`
60
+ return spanWidth
61
+ }
62
+
63
+ return (
64
+ <div className="flex flex-col gap-1 w-full">
65
+ <div className={"flex flex-row items-center justify-between z-[200]"}>
66
+ <div
67
+ ref={titleTextRef}
68
+ className="relative pl-4"
69
+ style={{
70
+ top: titleFits ? "40px" : "0px",
71
+ transitionDuration: "0.3s"
72
+ }}
73
+ >
74
+ <KSpan
75
+ text={props.titleText || ""}
76
+ color={color}
77
+ fontSize={fontSize}
78
+ lineHeight="20px"
79
+ letterSpacing="-0.084px"
80
+ fontWeight={500}
81
+ />
82
+ </div>
83
+ <div
84
+ ref={valueTextRef}
85
+ className="relative pr-4"
86
+ style={{
87
+ top: valueFits ? "40px" : "0px",
88
+ transitionDuration: "0.3s"
89
+
90
+ }}
91
+ >
92
+ <KSpan
93
+ text={props.valueText || ""}
94
+ color={color}
95
+ fontSize={fontSize}
96
+ lineHeight="20px"
97
+ letterSpacing="-0.084px"
98
+ fontWeight={500}
99
+ />
100
+ </div>
101
+ </div>
102
+
103
+ <div ref={mainDivRef} className="inline-block bg-[#f7f7f7] rounded-[8px] relative z-0" style={{ width, height }}>
104
+ <span className="w-full flex justify-between absolute top-0 z-0 items-center" style={{ height }} />
105
+ <span
106
+ ref={progressRef}
107
+ className="block items-center z-50 top-0 relative"
108
+ style={{
109
+ height,
110
+ width: calculateSpanWidth(),
111
+ borderRadius: "8px",
112
+ backgroundColor: "rgba(102, 102, 102, 0.05)"
113
+ }}
114
+ >
115
+ <span className="flex justify-center h-4 w-4 absolute right-2 top-4 z-[1000]">
116
+ <img src={ThumbIcon} alt="thumb" className="" />
117
+ </span>
118
+ </span>
119
+ <input
120
+ disabled={disabled}
121
+ style={{ width, height }}
122
+ className={"k-slider-label-input absolute top-0 !z-50"}
123
+ onChange={(e) => {
124
+ const option = props.options.find((option) => option.value.toString() === e.target.value)
125
+ if (option) return props.onChange(option)
126
+ }}
127
+ value={props.value}
128
+ type="range"
129
+ min={props.options[0].value}
130
+ max={props.options[props.options.length - 1].value}
131
+ />
132
+ </div>
133
+ </div>
134
+ )
135
+ }
136
+
137
+ export default KSliderLabel
@@ -0,0 +1 @@
1
+ export {default} from './KSliderLabel';
@@ -1,17 +1,37 @@
1
- import {Meta, StoryFn} from "@storybook/react";
2
- import KButton from "./KSpan";
3
- import KSpan from "./KSpan";
1
+ import { Meta, StoryFn } from "@storybook/react"
2
+ import KSpan from "./KSpan"
4
3
 
5
4
  export default {
6
5
  title: "ReactComponentLibrary/KSpan",
7
6
  component: KSpan,
8
- } as Meta<typeof KSpan>;
7
+ parameters: {
8
+ layout: "centered"
9
+ }
10
+ } as Meta<typeof KSpan>
9
11
 
10
- const Template: StoryFn<typeof KButton> = (args) => <KButton {...args} />;
12
+ const Template: StoryFn<typeof KSpan> = (args) => <KSpan {...args} />
11
13
 
12
- export const SpanTest = Template.bind({});
13
- SpanTest.args = {
14
- text: "Spanning :))!",
15
- theme: "primary",
16
- testIdPrefix: "rating",
17
- };
14
+ export const KSpanPrimary = Template.bind({})
15
+ KSpanPrimary.args = {
16
+ text: "Hello World",
17
+ fontSize: 14,
18
+ color: "#737373",
19
+ fontWeight: 400,
20
+ lineHeight: "20px",
21
+ fontStyle: "normal",
22
+ letterSpacing: "-0.084px",
23
+ textDecoration: "underline"
24
+ }
25
+
26
+
27
+ export const KSpanHoverText = Template.bind({})
28
+ KSpanHoverText.args = {
29
+ text: "Hello World",
30
+ fontSize: 14,
31
+ fontWeight: 400,
32
+ lineHeight: "20px",
33
+ color: "#111",
34
+ fontStyle: "normal",
35
+ letterSpacing: "-0.084px",
36
+ hoverText: "Hover"
37
+ }