pixel-react 1.0.5 → 1.0.7
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/.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
|
+
}
|