pixel-react 1.0.5 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- package/.yarn/install-state.gz +0 -0
- package/lib/StyleGuide/ColorPalette/types.d.ts +2 -0
- package/lib/assets/utils/functionUtils.d.ts +3 -0
- package/lib/components/DatePicker/DatePicker.d.ts +5 -0
- package/lib/components/DatePicker/DatePicker.stories.d.ts +9 -0
- package/lib/components/DatePicker/Timepicker.d.ts +4 -0
- package/lib/components/DatePicker/index.d.ts +1 -0
- package/lib/components/DatePicker/types.d.ts +81 -0
- package/lib/components/DragAndDrop/DragAndDrop.d.ts +9 -0
- package/lib/components/DragAndDrop/DragAndDrop.stories.d.ts +6 -0
- package/lib/components/DragAndDrop/DragAndDropList.d.ts +20 -0
- package/lib/components/DragAndDrop/index.d.ts +1 -0
- package/lib/components/Drawer/Drawer.d.ts +2 -1
- package/lib/components/IconButton/IconButton.d.ts +5 -0
- package/lib/components/IconButton/IconButton.stories.d.ts +6 -0
- package/lib/components/IconButton/index.d.ts +1 -0
- package/lib/components/{AddButton → IconButton}/types.d.ts +3 -2
- package/lib/components/InputWithDropdown/InputWithDropdown.d.ts +1 -1
- package/lib/components/InputWithDropdown/types.d.ts +3 -7
- package/lib/components/Modal/Modal.d.ts +5 -0
- package/lib/components/Modal/Modal.stories.d.ts +7 -0
- package/lib/components/Modal/index.d.ts +1 -0
- package/lib/components/Modal/types.d.ts +26 -0
- package/lib/components/TableTree/TableTree.d.ts +2 -2
- package/lib/components/ThemeProvider/CustomThemeProvider.d.ts +8 -0
- package/lib/hooks/useCustomThemeProvider.d.ts +11 -0
- package/lib/index.d.ts +76 -16
- package/lib/index.esm.js +13365 -414
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +13368 -415
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -23
- package/src/StyleGuide/ColorPalette/ColorPalette.scss +5 -0
- package/src/StyleGuide/ColorPalette/ColorPalette.tsx +10 -1
- package/src/StyleGuide/ColorPalette/colorPaletteList.ts +2 -2
- package/src/StyleGuide/ColorPalette/types.ts +2 -0
- package/src/assets/Themes/BaseTheme.scss +9 -1
- package/src/assets/Themes/DarkTheme.scss +8 -1
- package/src/assets/icons/add_variable_icon.svg +5 -0
- package/src/assets/icons/calendar_icon.svg +9 -0
- package/src/assets/icons/clock_icon.svg +11 -0
- package/src/assets/icons/collapse-icon.svg +6 -0
- package/src/assets/icons/copy-icon.svg +3 -0
- package/src/assets/icons/download-icon.svg +3 -0
- package/src/assets/icons/expand-icon.svg +6 -0
- package/src/assets/icons/info_icon.svg +4 -0
- package/src/assets/icons/left_arrow_icon.svg +3 -0
- package/src/assets/icons/license_info.svg +28 -0
- package/src/assets/icons/license_warning.svg +10 -0
- package/src/assets/icons/refresh-icon.svg +4 -0
- package/src/assets/icons/right_arrow_icon.svg +4 -0
- package/src/assets/styles/_mixins.scss +1 -0
- package/src/assets/utils/functionUtils.ts +37 -0
- package/src/components/DatePicker/DatePicker.scss +387 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +161 -0
- package/src/components/DatePicker/DatePicker.tsx +438 -0
- package/src/components/DatePicker/Timepicker.tsx +372 -0
- package/src/components/DatePicker/index.ts +1 -0
- package/src/components/DatePicker/types.ts +100 -0
- package/src/components/DragAndDrop/DragAndDrop.d.ts +5 -0
- package/src/components/DragAndDrop/DragAndDrop.stories.tsx +25 -0
- package/src/components/DragAndDrop/DragAndDrop.ts +7 -0
- package/src/components/DragAndDrop/DragAndDropList.scss +69 -0
- package/src/components/DragAndDrop/DragAndDropList.tsx +150 -0
- package/src/components/DragAndDrop/index.ts +1 -0
- package/src/components/Drawer/Drawer.scss +0 -1
- package/src/components/Drawer/Drawer.tsx +7 -15
- package/src/components/Icon/iconList.ts +31 -9
- package/src/components/{AddButton/AddButton.scss → IconButton/IconButton.scss} +6 -2
- package/src/components/IconButton/IconButton.stories.tsx +25 -0
- package/src/components/{AddButton/AddButton.tsx → IconButton/IconButton.tsx} +10 -7
- package/src/components/IconButton/index.ts +1 -0
- package/src/components/{AddButton → IconButton}/types.ts +3 -2
- package/src/components/InputWithDropdown/InputWithDropdown.scss +1 -1
- package/src/components/InputWithDropdown/InputWithDropdown.stories.tsx +10 -13
- package/src/components/InputWithDropdown/InputWithDropdown.tsx +10 -8
- package/src/components/InputWithDropdown/types.ts +4 -7
- package/src/components/Modal/Modal.stories.tsx +63 -0
- package/src/components/Modal/Modal.tsx +71 -0
- package/src/components/Modal/index.tsx +1 -0
- package/src/components/Modal/modal.scss +37 -0
- package/src/components/Modal/types.ts +37 -0
- package/src/components/RadioButton/RadioButton.scss +3 -3
- package/src/components/Select/Select.scss +1 -1
- package/src/components/TableTree/TableTree.tsx +5 -1
- package/src/components/ThemeProvider/ThemeProvider.tsx +11 -8
- package/src/index.ts +6 -6
- package/lib/components/AddButton/AddButton.d.ts +0 -5
- package/lib/components/AddButton/AddButton.stories.d.ts +0 -6
- package/lib/components/AddButton/index.d.ts +0 -1
- package/src/assets/icons/expired_license_icon.svg +0 -3
- package/src/assets/icons/expiringSoon_license_icon.svg +0 -3
- package/src/components/AddButton/AddButton.stories.tsx +0 -24
- package/src/components/AddButton/index.ts +0 -1
@@ -0,0 +1,372 @@
|
|
1
|
+
import React, { useState, useRef, useEffect } from 'react';
|
2
|
+
import Typography from '../Typography';
|
3
|
+
import { TimePickerProps } from './types';
|
4
|
+
import Icon from '../Icon';
|
5
|
+
import classNames from 'classnames';
|
6
|
+
import { convertTo24Hour } from '../../assets/utils/functionUtils';
|
7
|
+
import { convertTo12Hour } from '../../assets/utils/functionUtils';
|
8
|
+
import { isValid12HourTime } from '../../assets/utils/functionUtils';
|
9
|
+
|
10
|
+
const TimePicker: React.FC<TimePickerProps> = ({
|
11
|
+
value,
|
12
|
+
onChange,
|
13
|
+
minTime,
|
14
|
+
maxTime,
|
15
|
+
onErrorChange,
|
16
|
+
}) => {
|
17
|
+
const [inputValue, setInputValue] = useState<string>('');
|
18
|
+
const [period, setPeriod] = useState<string | undefined>('AM');
|
19
|
+
const [timeFieldError, setTimeFieldError] = useState<boolean>(false);
|
20
|
+
const [isPeriodDropdownOpen, setIsPeriodDropdownOpen] = useState(false);
|
21
|
+
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 });
|
22
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
23
|
+
const periodRef = useRef<HTMLDivElement>(null);
|
24
|
+
|
25
|
+
useEffect(() => {
|
26
|
+
if (value) {
|
27
|
+
const time12h = convertTo12Hour(value);
|
28
|
+
const [time, periodValue] = time12h.split(' ') as [string, 'AM' | 'PM'];
|
29
|
+
setInputValue(time);
|
30
|
+
setPeriod(periodValue);
|
31
|
+
|
32
|
+
setTimeFieldError(!isTimeWithInBounds(time12h, minTime, maxTime));
|
33
|
+
}
|
34
|
+
}, [value, minTime, maxTime]);
|
35
|
+
|
36
|
+
useEffect(() => {
|
37
|
+
const handleClickOutside = (e: MouseEvent) => {
|
38
|
+
if (
|
39
|
+
isPeriodDropdownOpen &&
|
40
|
+
periodRef.current &&
|
41
|
+
!periodRef.current.contains(e.target as Node)
|
42
|
+
) {
|
43
|
+
setIsPeriodDropdownOpen(false);
|
44
|
+
}
|
45
|
+
};
|
46
|
+
document.addEventListener('mousedown', handleClickOutside);
|
47
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
48
|
+
}, [isPeriodDropdownOpen]);
|
49
|
+
|
50
|
+
useEffect(() => {
|
51
|
+
onErrorChange(timeFieldError);
|
52
|
+
}, [timeFieldError]);
|
53
|
+
|
54
|
+
const generateTimeOptions = (): string[] => {
|
55
|
+
const options: string[] = [];
|
56
|
+
const start = 0;
|
57
|
+
const end = 23 * 60 + 45;
|
58
|
+
const interval = 15;
|
59
|
+
|
60
|
+
for (let i = start; i <= end; i += interval) {
|
61
|
+
const hours = Math.floor(i / 60);
|
62
|
+
const minutes = i % 60;
|
63
|
+
const period = hours >= 12 ? 'PM' : 'AM';
|
64
|
+
const displayHour = hours % 12 || 12;
|
65
|
+
const displayMinutes = minutes < 10 ? '0' + minutes : minutes;
|
66
|
+
options.push(`${displayHour}:${displayMinutes} ${period}`);
|
67
|
+
}
|
68
|
+
return options;
|
69
|
+
};
|
70
|
+
|
71
|
+
const timeOptions = generateTimeOptions();
|
72
|
+
|
73
|
+
const isTimeWithInBounds = (
|
74
|
+
time: string,
|
75
|
+
minTime?: string,
|
76
|
+
maxTime?: string
|
77
|
+
): boolean => {
|
78
|
+
const [hours = 0, minutes = 0] = convertTo24Hour(time)
|
79
|
+
.split(':')
|
80
|
+
.map(Number);
|
81
|
+
const timeValue = hours * 60 + minutes;
|
82
|
+
|
83
|
+
if (minTime) {
|
84
|
+
const [minHours = 0, minMinutes = 0] = minTime.split(':').map(Number);
|
85
|
+
const minValue = minHours * 60 + minMinutes;
|
86
|
+
if (timeValue < minValue) return false;
|
87
|
+
}
|
88
|
+
|
89
|
+
if (maxTime) {
|
90
|
+
const [maxHours = 0, maxMinutes = 0] = maxTime.split(':').map(Number);
|
91
|
+
const maxValue = maxHours * 60 + maxMinutes;
|
92
|
+
if (timeValue > maxValue) return false;
|
93
|
+
}
|
94
|
+
|
95
|
+
return true;
|
96
|
+
};
|
97
|
+
|
98
|
+
const handleTimeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
99
|
+
let [hourSection, minuteSection] = inputValue.split(':');
|
100
|
+
let [newHour, newMinute] = event.target.value.split(':');
|
101
|
+
const selectionStart = inputRef.current?.selectionStart ?? 0;
|
102
|
+
|
103
|
+
// Handle hour part input
|
104
|
+
if (selectionStart <= 2) {
|
105
|
+
const currentHour = parseInt(hourSection ?? '0') || 0;
|
106
|
+
|
107
|
+
if (newHour?.length === 1) {
|
108
|
+
hourSection = currentHour
|
109
|
+
? hourSection?.slice(-1) + newHour
|
110
|
+
: `0${newHour}`; // Single digit input
|
111
|
+
} else {
|
112
|
+
hourSection = newHour?.padStart(2, '0'); // Two digits for hour
|
113
|
+
}
|
114
|
+
|
115
|
+
// Ensure hour part is valid (between 1 and 12)
|
116
|
+
let parsedHour = parseInt(hourSection ?? '0') || 0;
|
117
|
+
if (parsedHour > 12) {
|
118
|
+
parsedHour = parseInt(newHour ?? '0'); // Fix if hour exceeds 12
|
119
|
+
}
|
120
|
+
|
121
|
+
hourSection = parsedHour.toString().padStart(2, '0');
|
122
|
+
|
123
|
+
// Move to minute part if hour is greater than 1, otherwise stay on hour
|
124
|
+
if (parsedHour > 1) {
|
125
|
+
setTimeout(() => {
|
126
|
+
inputRef.current?.setSelectionRange(3, 5); // Move to minute part
|
127
|
+
}, 0);
|
128
|
+
} else {
|
129
|
+
setTimeout(() => {
|
130
|
+
inputRef.current?.setSelectionRange(0, 2); // Keep cursor on hour part
|
131
|
+
}, 0);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
// Handle minute part input
|
136
|
+
if (selectionStart >= 3) {
|
137
|
+
const currentMinute = parseInt(minuteSection ?? '0') || 0;
|
138
|
+
|
139
|
+
if (newMinute?.length === 1) {
|
140
|
+
minuteSection = currentMinute
|
141
|
+
? minuteSection?.slice(-1) + newMinute
|
142
|
+
: `0${newMinute}`; // Single digit input
|
143
|
+
} else {
|
144
|
+
minuteSection = newMinute?.padStart(2, '0'); // Two digits for minute
|
145
|
+
}
|
146
|
+
|
147
|
+
// Ensure minute part is valid (between 00 and 59)
|
148
|
+
let parsedMinute = parseInt(minuteSection ?? '0') || 0;
|
149
|
+
if (parsedMinute > 59) {
|
150
|
+
parsedMinute = parseInt(newMinute ?? '0'); // Fix if minute exceeds 59
|
151
|
+
}
|
152
|
+
|
153
|
+
minuteSection = parsedMinute.toString().padStart(2, '0');
|
154
|
+
|
155
|
+
if (parsedMinute < 6) {
|
156
|
+
setTimeout(() => {
|
157
|
+
inputRef.current?.setSelectionRange(3, 5); // Keep cursor on minute part
|
158
|
+
}, 0);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
setInputValue(`${hourSection}:${minuteSection}`);
|
163
|
+
if (isValid12HourTime(`${hourSection}:${minuteSection}`)) {
|
164
|
+
const time24h = convertTo24Hour(
|
165
|
+
`${hourSection}:${minuteSection} ${period}`
|
166
|
+
);
|
167
|
+
onChange(time24h);
|
168
|
+
setTimeFieldError(false);
|
169
|
+
} else {
|
170
|
+
setTimeFieldError(true);
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
const togglePeriodDropdown = () => {
|
175
|
+
setIsPeriodDropdownOpen((prev) => !prev);
|
176
|
+
if (periodRef.current) {
|
177
|
+
const { top, left, height } = periodRef.current.getBoundingClientRect();
|
178
|
+
setDropdownPosition({ top: top + height, left: left });
|
179
|
+
}
|
180
|
+
};
|
181
|
+
|
182
|
+
const handlePeriodChange = (option: string) => {
|
183
|
+
setPeriod(option);
|
184
|
+
const time24h = convertTo24Hour(`${inputValue} ${option}`);
|
185
|
+
onChange(time24h);
|
186
|
+
setIsPeriodDropdownOpen(false);
|
187
|
+
};
|
188
|
+
|
189
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
190
|
+
const { key } = event;
|
191
|
+
const selectionStart = inputRef.current?.selectionStart ?? 0;
|
192
|
+
const selectionEnd = inputRef.current?.selectionEnd ?? 0;
|
193
|
+
let [hourSection, minuteSection] = inputValue.split(':');
|
194
|
+
|
195
|
+
if (key === 'Backspace' && selectionStart <= 2) {
|
196
|
+
event.preventDefault();
|
197
|
+
hourSection = 'HH';
|
198
|
+
setInputValue(`${hourSection}:${minuteSection}`);
|
199
|
+
setTimeout(() => inputRef.current?.setSelectionRange(0, 2), 0);
|
200
|
+
setTimeFieldError(true);
|
201
|
+
}
|
202
|
+
|
203
|
+
if (key === 'Backspace' && selectionStart >= 3) {
|
204
|
+
event.preventDefault();
|
205
|
+
minuteSection = 'MM';
|
206
|
+
setInputValue(`${hourSection}:${minuteSection}`);
|
207
|
+
setTimeout(() => inputRef.current?.setSelectionRange(3, 5), 0);
|
208
|
+
setTimeFieldError(true);
|
209
|
+
}
|
210
|
+
|
211
|
+
if (key === 'ArrowRight') {
|
212
|
+
if (selectionEnd === 2) {
|
213
|
+
event.preventDefault();
|
214
|
+
inputRef.current?.setSelectionRange(3, 5);
|
215
|
+
} else if (selectionStart === 0) {
|
216
|
+
event.preventDefault();
|
217
|
+
inputRef.current?.setSelectionRange(0, 2);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
if (key === 'ArrowLeft') {
|
222
|
+
if (selectionStart === 3) {
|
223
|
+
event.preventDefault();
|
224
|
+
inputRef.current?.setSelectionRange(0, 2);
|
225
|
+
} else if (selectionStart === 5) {
|
226
|
+
event.preventDefault();
|
227
|
+
inputRef.current?.setSelectionRange(3, 5);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
};
|
231
|
+
|
232
|
+
const handleFocus = () => {
|
233
|
+
if (inputValue === '') {
|
234
|
+
setInputValue('HH:MM');
|
235
|
+
}
|
236
|
+
setTimeout(() => {
|
237
|
+
inputRef.current?.setSelectionRange(0, 2);
|
238
|
+
}, 0);
|
239
|
+
};
|
240
|
+
|
241
|
+
const handleBlur = () => {
|
242
|
+
if (inputValue === 'HH:MM') {
|
243
|
+
setInputValue('');
|
244
|
+
}
|
245
|
+
};
|
246
|
+
|
247
|
+
const handleClick = () => {
|
248
|
+
const selectionStart = inputRef.current?.selectionStart ?? 0;
|
249
|
+
if (selectionStart >= 3) {
|
250
|
+
inputRef.current?.setSelectionRange(3, 5);
|
251
|
+
} else {
|
252
|
+
inputRef.current?.setSelectionRange(0, 2);
|
253
|
+
}
|
254
|
+
};
|
255
|
+
|
256
|
+
const handleTimeOptionClick = (time: string) => {
|
257
|
+
const [timeValue, periodValue] = time.split(' ') as [string, 'AM' | 'PM'];
|
258
|
+
setInputValue(timeValue);
|
259
|
+
setPeriod(periodValue);
|
260
|
+
const time24h = convertTo24Hour(`${timeValue} ${periodValue}`);
|
261
|
+
onChange(time24h);
|
262
|
+
setTimeFieldError(false);
|
263
|
+
};
|
264
|
+
|
265
|
+
return (
|
266
|
+
<div className="ff-time-picker-container">
|
267
|
+
<div className="ff-time-picker-fields">
|
268
|
+
<div
|
269
|
+
className={classNames(
|
270
|
+
'ff-time-input-container',
|
271
|
+
{ 'ff-time-input-container--float': !!inputValue },
|
272
|
+
{ 'ff-time-input-container--danger': !!timeFieldError }
|
273
|
+
)}
|
274
|
+
>
|
275
|
+
<Typography
|
276
|
+
as="label"
|
277
|
+
htmlFor="time"
|
278
|
+
className={classNames('ff-time-input-label', {
|
279
|
+
'ff-time-input-label--danger': !!timeFieldError,
|
280
|
+
})}
|
281
|
+
>
|
282
|
+
Time
|
283
|
+
</Typography>
|
284
|
+
<input
|
285
|
+
name="time"
|
286
|
+
ref={inputRef}
|
287
|
+
type="text"
|
288
|
+
id="time-input"
|
289
|
+
value={inputValue}
|
290
|
+
inputMode="numeric"
|
291
|
+
placeholder="HH:MM"
|
292
|
+
onChange={handleTimeInput}
|
293
|
+
onKeyDown={handleKeyDown}
|
294
|
+
onFocus={handleFocus}
|
295
|
+
onClick={handleClick}
|
296
|
+
onBlur={handleBlur}
|
297
|
+
maxLength={5}
|
298
|
+
className={classNames('ff-time-input', {
|
299
|
+
'ff-time-input--danger': !!timeFieldError,
|
300
|
+
})}
|
301
|
+
/>
|
302
|
+
</div>
|
303
|
+
<div
|
304
|
+
className={classNames('ff-time-period-container', {
|
305
|
+
'ff-time-period-container--active': !!isPeriodDropdownOpen,
|
306
|
+
})}
|
307
|
+
ref={periodRef}
|
308
|
+
>
|
309
|
+
<div
|
310
|
+
onClick={togglePeriodDropdown}
|
311
|
+
className="ff-time-period-select"
|
312
|
+
aria-haspopup="listbox"
|
313
|
+
aria-expanded={isPeriodDropdownOpen}
|
314
|
+
>
|
315
|
+
<Typography>{period}</Typography>
|
316
|
+
<Icon
|
317
|
+
name={isPeriodDropdownOpen ? 'arrow_up' : 'arrow_down'}
|
318
|
+
className="ff-time-period-icon"
|
319
|
+
height={12}
|
320
|
+
width={12}
|
321
|
+
/>
|
322
|
+
</div>
|
323
|
+
|
324
|
+
{isPeriodDropdownOpen && (
|
325
|
+
<ul
|
326
|
+
className="ff-time-period-options"
|
327
|
+
style={{
|
328
|
+
top: `${dropdownPosition.top}px`,
|
329
|
+
left: `${dropdownPosition.left}px`,
|
330
|
+
}}
|
331
|
+
role="listbox"
|
332
|
+
>
|
333
|
+
<Typography
|
334
|
+
as="li"
|
335
|
+
className="ff-option-item"
|
336
|
+
onClick={() => handlePeriodChange('AM')}
|
337
|
+
aria-selected={period === 'AM'}
|
338
|
+
>
|
339
|
+
AM
|
340
|
+
</Typography>
|
341
|
+
<Typography
|
342
|
+
as="li"
|
343
|
+
className="ff-option-item"
|
344
|
+
onClick={() => handlePeriodChange('PM')}
|
345
|
+
aria-selected={period === 'PM'}
|
346
|
+
>
|
347
|
+
PM
|
348
|
+
</Typography>
|
349
|
+
</ul>
|
350
|
+
)}
|
351
|
+
</div>
|
352
|
+
</div>
|
353
|
+
<div className="ff-time-picker-options">
|
354
|
+
{timeOptions
|
355
|
+
.filter((time) => isTimeWithInBounds(time, minTime, maxTime))
|
356
|
+
.map((time, index) => (
|
357
|
+
<div
|
358
|
+
key={index}
|
359
|
+
className="ff-time-option"
|
360
|
+
onClick={() => handleTimeOptionClick(time)}
|
361
|
+
>
|
362
|
+
<Typography lineHeight="18px" textAlign="center">
|
363
|
+
{time}
|
364
|
+
</Typography>
|
365
|
+
</div>
|
366
|
+
))}
|
367
|
+
</div>
|
368
|
+
</div>
|
369
|
+
);
|
370
|
+
};
|
371
|
+
|
372
|
+
export default TimePicker;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from './DatePicker';
|
@@ -0,0 +1,100 @@
|
|
1
|
+
export interface DatePickerProps {
|
2
|
+
/**
|
3
|
+
* The minimum selectable date.
|
4
|
+
*/
|
5
|
+
minDate?: DateValue;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* The maximum selectable date.
|
9
|
+
*/
|
10
|
+
maxDate?: DateValue;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Selected date value.
|
14
|
+
*/
|
15
|
+
value?: DateValue;
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Function to handle date selection.
|
19
|
+
*/
|
20
|
+
onChange: (value: DateValue) => void;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Placeholder text for the input field.
|
24
|
+
*/
|
25
|
+
placeholder?: string;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Disables the date picker.
|
29
|
+
*/
|
30
|
+
disabled?: boolean;
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Format for displaying the selected date. Default is 'EEEE, dd MMM yyyy'.
|
34
|
+
*/
|
35
|
+
dateFormat?: string;
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Format for displaying the selected time. Default is 'hh:mm a'.
|
39
|
+
*/
|
40
|
+
timeFormat?: string;
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Timezone for the date picker.
|
44
|
+
*/
|
45
|
+
timezone?: string;
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Custom width for the calendar. This will override the default width of the calendar.
|
49
|
+
*/
|
50
|
+
calendarWidth?: number;
|
51
|
+
|
52
|
+
/**
|
53
|
+
* When true, displays the input field error.
|
54
|
+
*/
|
55
|
+
error?: boolean;
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Helper text to display below the input field, used for error messages or instructions.
|
59
|
+
*/
|
60
|
+
helperText?: string | undefined;
|
61
|
+
}
|
62
|
+
|
63
|
+
export type DateValue = Date | undefined;
|
64
|
+
|
65
|
+
export interface CustomCaptionProps {
|
66
|
+
children?: React.ReactNode; // You can use ReactNode as a fallback for dynamic content
|
67
|
+
}
|
68
|
+
|
69
|
+
export interface CustomCalenderButtonProps {
|
70
|
+
className?: string;
|
71
|
+
disabled?: boolean | undefined;
|
72
|
+
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
73
|
+
}
|
74
|
+
|
75
|
+
export interface TimePickerProps {
|
76
|
+
/**
|
77
|
+
* The current time value, in string format (e.g., '14:30').
|
78
|
+
*/
|
79
|
+
value: string;
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Function to handle time selection changes, receiving the selected time as a string.
|
83
|
+
*/
|
84
|
+
onChange: (time: string) => void;
|
85
|
+
|
86
|
+
/**
|
87
|
+
* The minimum selectable time, used to restrict the earliest selectable time.
|
88
|
+
*/
|
89
|
+
minTime?: string;
|
90
|
+
|
91
|
+
/**
|
92
|
+
* The maximum selectable time, used to restrict the latest selectable time.
|
93
|
+
*/
|
94
|
+
maxTime?: string;
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Function to handle error state changes, receiving a boolean indicating the presence of an error.
|
98
|
+
*/
|
99
|
+
onErrorChange: (error: boolean) => void;
|
100
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
2
|
+
import DragAndDropList from './DragAndDropList';
|
3
|
+
|
4
|
+
const meta: Meta<typeof DragAndDropList> = {
|
5
|
+
title: 'Components/DragAndDrop',
|
6
|
+
component: DragAndDropList,
|
7
|
+
parameters: {
|
8
|
+
layout: 'centered',
|
9
|
+
docs: {
|
10
|
+
description: {
|
11
|
+
component: `It is a drag and drop list component that allows users to reorder items by dragging and dropping them. Library used is dnd-kit/core, dnd-kit/sortable, dnd-kit/utilities`,
|
12
|
+
story:
|
13
|
+
'This is a link of [dnd-kit library](https://www.npmjs.com/package/@dnd-kit/core) for reference to an external website.',
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
tags: ['autodocs'],
|
18
|
+
};
|
19
|
+
|
20
|
+
type Story = StoryObj<typeof DragAndDropList>;
|
21
|
+
|
22
|
+
export const Primary: Story = {
|
23
|
+
render: () => <DragAndDropList />,
|
24
|
+
};
|
25
|
+
export default meta;
|
@@ -0,0 +1,69 @@
|
|
1
|
+
$primary-color: #2563eb;
|
2
|
+
$primary-hover-color: #235dda;
|
3
|
+
$background-color: #f2f2f3;
|
4
|
+
$white-color: #fff;
|
5
|
+
$border-radius: 5px;
|
6
|
+
$box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
|
7
|
+
$checkbox-size: 20px;
|
8
|
+
|
9
|
+
.drag-and-drop-list {
|
10
|
+
height: max-content;
|
11
|
+
width: fit-content;
|
12
|
+
display: flex;
|
13
|
+
flex-direction: column;
|
14
|
+
align-items: center;
|
15
|
+
gap: 30px;
|
16
|
+
}
|
17
|
+
|
18
|
+
.column {
|
19
|
+
background-color: $background-color;
|
20
|
+
border-radius: $border-radius;
|
21
|
+
padding: 15px;
|
22
|
+
width: 80%;
|
23
|
+
max-width: 500px;
|
24
|
+
display: flex;
|
25
|
+
flex-direction: column;
|
26
|
+
gap: 15px;
|
27
|
+
|
28
|
+
.task {
|
29
|
+
background-color: $white-color;
|
30
|
+
border-radius: $border-radius;
|
31
|
+
box-shadow: $box-shadow;
|
32
|
+
padding: 4px 8px;
|
33
|
+
display: flex;
|
34
|
+
align-items: center;
|
35
|
+
justify-content: flex-start;
|
36
|
+
gap: 20px;
|
37
|
+
cursor: grab;
|
38
|
+
&-title {
|
39
|
+
word-break: break-all;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
.container {
|
45
|
+
display: flex;
|
46
|
+
justify-content: space-between;
|
47
|
+
gap: 10px;
|
48
|
+
|
49
|
+
.input {
|
50
|
+
border: 2px solid #ddd;
|
51
|
+
border-radius: $border-radius;
|
52
|
+
padding: 10px;
|
53
|
+
width: 200px;
|
54
|
+
}
|
55
|
+
|
56
|
+
.button {
|
57
|
+
border: none;
|
58
|
+
border-radius: $border-radius;
|
59
|
+
padding: 10px 15px;
|
60
|
+
background-color: $primary-color;
|
61
|
+
color: $white-color;
|
62
|
+
cursor: pointer;
|
63
|
+
margin-left: 10px;
|
64
|
+
|
65
|
+
&:hover {
|
66
|
+
background-color: $primary-hover-color;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|