pixel-react 1.0.4 → 1.0.6
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/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/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/IconButton/types.d.ts +5 -0
- package/lib/components/InputWithDropdown/InputWithDropdown.d.ts +1 -1
- package/lib/components/InputWithDropdown/types.d.ts +3 -7
- package/lib/components/TableTree/TableTree.d.ts +1 -1
- package/lib/index.d.ts +68 -10
- package/lib/index.esm.js +8556 -224
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +8558 -224
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/src/assets/Themes/BaseTheme.scss +7 -0
- package/src/assets/Themes/DarkTheme.scss +7 -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/info_icon.svg +4 -0
- package/src/assets/icons/left_arrow_icon.svg +3 -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/Drawer/Drawer.scss +0 -1
- package/src/components/Drawer/Drawer.tsx +10 -14
- package/src/components/Icon/iconList.ts +17 -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/RadioButton/RadioButton.scss +3 -3
- package/src/components/Select/Select.scss +1 -1
- package/src/components/StateDropdown/StateDropdown.tsx +10 -15
- package/src/components/TableTree/TableTree.tsx +4 -0
- package/src/index.ts +5 -0
- 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
|
+
}
|
@@ -3,10 +3,10 @@ import { DrawerProps } from './Types.js';
|
|
3
3
|
import Button from '../Button/Button.js';
|
4
4
|
import classNames from 'classnames';
|
5
5
|
import './Drawer.scss';
|
6
|
-
import { useEffect, useState } from 'react';
|
6
|
+
import { useContext, useEffect, useState } from 'react';
|
7
7
|
import Icon from '../Icon';
|
8
8
|
import useEscapeKey from '../../hooks/keyboardevents/useEscKeyEvent.js';
|
9
|
-
|
9
|
+
import { ThemeContext } from '../ThemeProvider/ThemeProvider.js';
|
10
10
|
const Drawer = ({
|
11
11
|
isOpen = true,
|
12
12
|
children = 'Drawer content area',
|
@@ -57,9 +57,10 @@ const Drawer = ({
|
|
57
57
|
};
|
58
58
|
|
59
59
|
const drawerSize = isExpanded ? 'x-large' : size;
|
60
|
-
|
60
|
+
const themeContext = useContext(ThemeContext);
|
61
|
+
const currentTheme = themeContext?.currentTheme;
|
61
62
|
return createPortal(
|
62
|
-
<div className=
|
63
|
+
<div className={classNames('ff-drawer-container', currentTheme)}>
|
63
64
|
{overlay && <div className="ff-overlay" />}
|
64
65
|
|
65
66
|
<div
|
@@ -102,16 +103,11 @@ const Drawer = ({
|
|
102
103
|
<div className="ff-drawer-title">{title}</div>
|
103
104
|
</div>
|
104
105
|
{_isCloseModalButtonVisible && (
|
105
|
-
<
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
width={16}
|
111
|
-
hoverEffect={false}
|
112
|
-
/>
|
113
|
-
</button>
|
114
|
-
</div>
|
106
|
+
<Icon
|
107
|
+
name="close"
|
108
|
+
hoverEffect={false}
|
109
|
+
onClick={onClose}
|
110
|
+
/>
|
115
111
|
)}
|
116
112
|
</div>
|
117
113
|
</div>
|
@@ -29,23 +29,27 @@ import WrongMarkIcon from '../../assets/icons/wrong_mark.svg?react';
|
|
29
29
|
import Tick from '../../assets/Icons/tick_icon.svg?react';
|
30
30
|
import Search from '../../assets/icons/search.svg?react';
|
31
31
|
import Filter from '../../assets/icons/filter.svg?react';
|
32
|
+
import RightArrow from '../../assets/icons/right_arrow_icon.svg?react';
|
33
|
+
import LeftArrow from '../../assets/icons/left_arrow_icon.svg?react';
|
34
|
+
import ClockIcon from '../../assets/icons/clock_icon.svg?react';
|
32
35
|
import Edit from '../../assets/icons/edit_icon.svg?react';
|
33
36
|
import ViewIcon from '../../assets/icons/view_icon.svg?react';
|
34
|
-
import HideIcon from '../../assets/icons/hide_icon.svg?react';
|
35
37
|
import ExportCollection from '../../assets/icons/export_collection_icon.svg?react';
|
36
38
|
import RunIcon from '../../assets/icons/run_icon.svg?react';
|
39
|
+
import AddVariable from '../../assets/icons/add_variable_icon.svg?react';
|
37
40
|
|
38
|
-
import
|
39
|
-
import ExpiredLicenseIcon from '../../assets/icons/expired_license_icon.svg?react';
|
40
|
-
import ExpiringSoonLicenseIcon from '../../assets/icons/expiringSoon_license_icon.svg?react';
|
41
|
+
import LicenseIcon from '../../assets/icons/active_license_icon.svg?react';
|
41
42
|
import DeleteIcon from '../../assets/icons/delete.svg?react';
|
42
43
|
import DetailsIcon from '../../assets/icons/details.svg?react';
|
43
44
|
import ImpactListIcon from '../../assets/icons/impactList.svg?react';
|
45
|
+
import InfoIcon from '../../assets/icons/info_icon.svg?react';
|
46
|
+
import CalendarIcon from '../../assets/icons/calendar_icon.svg?react';
|
47
|
+
import HideIcon from '../../assets/icons/hide_icon.svg?react';
|
44
48
|
//icons
|
45
49
|
Components['delete_info'] = DeleteInfoIcon;
|
46
50
|
Components['success'] = ToastSuccessIcon;
|
47
51
|
Components['warning'] = WarningIcon;
|
48
|
-
Components['
|
52
|
+
Components['toast_info'] = ToastInfoIcon;
|
49
53
|
Components['error'] = ToastErrorIcon;
|
50
54
|
Components['close'] = ToastCloseIcon;
|
51
55
|
Components['more'] = MoreIcon;
|
@@ -71,16 +75,20 @@ Components['tick'] = Tick;
|
|
71
75
|
Components['arrow_right'] = ArrowRight;
|
72
76
|
Components['search'] = Search;
|
73
77
|
Components['filter'] = Filter;
|
78
|
+
Components['right_arrow_icon'] = RightArrow;
|
79
|
+
Components['left_arrow_icon'] = LeftArrow;
|
80
|
+
Components['clock_icon'] = ClockIcon;
|
74
81
|
Components['edit'] = Edit;
|
75
82
|
Components['view_icon'] = ViewIcon;
|
76
|
-
Components['hide_icon'] = HideIcon;
|
77
83
|
Components['export_collection'] = ExportCollection;
|
78
84
|
Components['run_icon'] = RunIcon;
|
79
|
-
Components['
|
80
|
-
Components['expired_license_icon'] = ExpiredLicenseIcon;
|
81
|
-
Components['expiringSoon_license_icon'] = ExpiringSoonLicenseIcon;
|
85
|
+
Components['license'] = LicenseIcon;
|
82
86
|
Components['delete'] = DeleteIcon;
|
83
87
|
Components['details'] = DetailsIcon;
|
84
88
|
Components['impactList'] = ImpactListIcon;
|
89
|
+
Components['add_variable'] = AddVariable;
|
90
|
+
Components['info'] = InfoIcon;
|
91
|
+
Components['calendar_icon'] = CalendarIcon;
|
92
|
+
Components['hide_icon'] = HideIcon;
|
85
93
|
|
86
94
|
export default Components;
|
@@ -15,7 +15,9 @@
|
|
15
15
|
padding: 2px 8px 2px 2px;
|
16
16
|
border: 1px solid transparent;
|
17
17
|
.ff-icon-color {
|
18
|
-
|
18
|
+
path {
|
19
|
+
color: var(--primary-icon-color);
|
20
|
+
}
|
19
21
|
}
|
20
22
|
.icon-name {
|
21
23
|
min-width: 33px;
|
@@ -32,7 +34,9 @@
|
|
32
34
|
color: var(--secondary-icon-color);
|
33
35
|
}
|
34
36
|
.ff-icon-color {
|
35
|
-
|
37
|
+
path {
|
38
|
+
color: var(--secondary-icon-color);
|
39
|
+
}
|
36
40
|
}
|
37
41
|
}
|
38
42
|
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
2
|
+
import IconButton from './IconButton';
|
3
|
+
|
4
|
+
const meta: Meta<typeof IconButton> = {
|
5
|
+
title: 'Components/IconButton',
|
6
|
+
component: IconButton,
|
7
|
+
parameters: {
|
8
|
+
layout: 'centered',
|
9
|
+
},
|
10
|
+
tags: ['autodocs'],
|
11
|
+
};
|
12
|
+
|
13
|
+
type Story = StoryObj<typeof IconButton>;
|
14
|
+
|
15
|
+
export const PrimaryIconButton: Story = {
|
16
|
+
render: () => {
|
17
|
+
const name = 'Project';
|
18
|
+
const icon = 'plus_icon';
|
19
|
+
const onClick = () => {};
|
20
|
+
|
21
|
+
return <IconButton label={name} iconName={icon} onClick={onClick} />;
|
22
|
+
},
|
23
|
+
};
|
24
|
+
|
25
|
+
export default meta;
|
@@ -1,25 +1,28 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import Icon from '../Icon';
|
3
|
-
import './
|
3
|
+
import './IconButton.scss';
|
4
4
|
import classNames from 'classnames';
|
5
5
|
import Typography from '../Typography';
|
6
|
-
import {
|
6
|
+
import { IconButtonProps } from './types';
|
7
7
|
|
8
|
-
const
|
8
|
+
const IconButton: React.FC<IconButtonProps> = ({
|
9
|
+
label,
|
10
|
+
iconName = 'plus_icon',
|
11
|
+
onClick,
|
12
|
+
}) => {
|
9
13
|
return (
|
10
14
|
<button onClick={onClick} className={classNames('ff-plus-icon')}>
|
11
15
|
<Icon
|
12
16
|
height={20}
|
13
17
|
width={20}
|
14
|
-
name={
|
15
|
-
color=''
|
18
|
+
name={iconName}
|
16
19
|
className={'ff-icon-color'}
|
17
20
|
/>
|
18
21
|
<Typography as="div" textAlign="center" className="icon-name">
|
19
|
-
{
|
22
|
+
{label}
|
20
23
|
</Typography>
|
21
24
|
</button>
|
22
25
|
);
|
23
26
|
};
|
24
27
|
|
25
|
-
export default
|
28
|
+
export default IconButton;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from './IconButton';
|