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.
Files changed (57) hide show
  1. package/lib/assets/utils/functionUtils.d.ts +3 -0
  2. package/lib/components/DatePicker/DatePicker.d.ts +5 -0
  3. package/lib/components/DatePicker/DatePicker.stories.d.ts +9 -0
  4. package/lib/components/DatePicker/Timepicker.d.ts +4 -0
  5. package/lib/components/DatePicker/index.d.ts +1 -0
  6. package/lib/components/DatePicker/types.d.ts +81 -0
  7. package/lib/components/IconButton/IconButton.d.ts +5 -0
  8. package/lib/components/IconButton/IconButton.stories.d.ts +6 -0
  9. package/lib/components/IconButton/index.d.ts +1 -0
  10. package/lib/components/IconButton/types.d.ts +5 -0
  11. package/lib/components/InputWithDropdown/InputWithDropdown.d.ts +1 -1
  12. package/lib/components/InputWithDropdown/types.d.ts +3 -7
  13. package/lib/components/TableTree/TableTree.d.ts +1 -1
  14. package/lib/index.d.ts +68 -10
  15. package/lib/index.esm.js +8556 -224
  16. package/lib/index.esm.js.map +1 -1
  17. package/lib/index.js +8558 -224
  18. package/lib/index.js.map +1 -1
  19. package/lib/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +3 -1
  21. package/src/assets/Themes/BaseTheme.scss +7 -0
  22. package/src/assets/Themes/DarkTheme.scss +7 -1
  23. package/src/assets/icons/add_variable_icon.svg +5 -0
  24. package/src/assets/icons/calendar_icon.svg +9 -0
  25. package/src/assets/icons/clock_icon.svg +11 -0
  26. package/src/assets/icons/info_icon.svg +4 -0
  27. package/src/assets/icons/left_arrow_icon.svg +3 -0
  28. package/src/assets/icons/right_arrow_icon.svg +4 -0
  29. package/src/assets/styles/_mixins.scss +1 -0
  30. package/src/assets/utils/functionUtils.ts +37 -0
  31. package/src/components/DatePicker/DatePicker.scss +387 -0
  32. package/src/components/DatePicker/DatePicker.stories.tsx +161 -0
  33. package/src/components/DatePicker/DatePicker.tsx +438 -0
  34. package/src/components/DatePicker/Timepicker.tsx +372 -0
  35. package/src/components/DatePicker/index.ts +1 -0
  36. package/src/components/DatePicker/types.ts +100 -0
  37. package/src/components/Drawer/Drawer.scss +0 -1
  38. package/src/components/Drawer/Drawer.tsx +10 -14
  39. package/src/components/Icon/iconList.ts +17 -9
  40. package/src/components/{AddButton/AddButton.scss → IconButton/IconButton.scss} +6 -2
  41. package/src/components/IconButton/IconButton.stories.tsx +25 -0
  42. package/src/components/{AddButton/AddButton.tsx → IconButton/IconButton.tsx} +10 -7
  43. package/src/components/IconButton/index.ts +1 -0
  44. package/src/components/{AddButton → IconButton}/types.ts +3 -2
  45. package/src/components/InputWithDropdown/InputWithDropdown.scss +1 -1
  46. package/src/components/InputWithDropdown/InputWithDropdown.stories.tsx +10 -13
  47. package/src/components/InputWithDropdown/InputWithDropdown.tsx +10 -8
  48. package/src/components/InputWithDropdown/types.ts +4 -7
  49. package/src/components/RadioButton/RadioButton.scss +3 -3
  50. package/src/components/Select/Select.scss +1 -1
  51. package/src/components/StateDropdown/StateDropdown.tsx +10 -15
  52. package/src/components/TableTree/TableTree.tsx +4 -0
  53. package/src/index.ts +5 -0
  54. package/src/assets/icons/expired_license_icon.svg +0 -3
  55. package/src/assets/icons/expiringSoon_license_icon.svg +0 -3
  56. package/src/components/AddButton/AddButton.stories.tsx +0 -24
  57. package/src/components/AddButton/index.ts +0 -1
@@ -0,0 +1,161 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import CustomDatePicker from './DatePicker';
3
+ import { useState } from 'react';
4
+
5
+ const meta: Meta<typeof CustomDatePicker> = {
6
+ title: 'Components/DatePicker',
7
+ component: CustomDatePicker,
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'A custom date picker component with built-in calendar and input field.',
14
+ },
15
+ },
16
+ },
17
+ tags: ['autodocs'],
18
+ argTypes: {
19
+ minDate: {
20
+ description: 'The minimum selectable date',
21
+ control: {
22
+ type: 'date',
23
+ },
24
+ },
25
+ maxDate: {
26
+ description: 'The maximum selectable date',
27
+ control: {
28
+ type: 'date',
29
+ },
30
+ },
31
+ value: {
32
+ description: 'Selected date value',
33
+ control: {
34
+ type: 'date',
35
+ },
36
+ },
37
+ onChange: {
38
+ description: 'Function to handle date selection',
39
+ action: 'changed',
40
+ },
41
+ placeholder: {
42
+ description: 'Placeholder text for the input field',
43
+ control: 'text',
44
+ },
45
+ disabled: {
46
+ description: 'Disables the date picker',
47
+ control: 'boolean',
48
+ },
49
+ dateFormat: {
50
+ description: 'Date format to display',
51
+ control: 'text',
52
+ },
53
+ timeFormat: {
54
+ description: 'time format to display',
55
+ control: 'text',
56
+ },
57
+ timezone: {
58
+ description: 'Timezone for date formatting',
59
+ control: 'text',
60
+ },
61
+ calendarWidth: {
62
+ description: 'Custom width for the calendar in pixel',
63
+ control: "number"
64
+ },
65
+ error: {
66
+ description: 'Displays the input field in an error state',
67
+ control: 'boolean',
68
+ },
69
+ helperText: {
70
+ description: 'Helper text to show below the input, often used for error messages',
71
+ control: 'text',
72
+ },
73
+ },
74
+ };
75
+
76
+ export default meta;
77
+
78
+ type Story = StoryObj<typeof CustomDatePicker>;
79
+
80
+ // Default story for DatePicker
81
+ export const Default: Story = {
82
+ render: (args) => {
83
+ const [date, setDate] = useState<Date | undefined>();
84
+
85
+ return(
86
+ <CustomDatePicker
87
+ {...args}
88
+ value={date}
89
+ onChange={setDate}
90
+ />
91
+ )
92
+ }
93
+ };
94
+
95
+ // Start Date Filter story
96
+ export const StartDateFilter: Story = {
97
+ render: (args) => {
98
+ const [startDate, setStartDate] = useState<Date | undefined>();
99
+
100
+ return (
101
+ <CustomDatePicker
102
+ {...args}
103
+ value={startDate}
104
+ onChange={setStartDate}
105
+ calendarWidth = {240}
106
+ maxDate={new Date()} // Disable future dates for start date picker
107
+ />
108
+ );
109
+ },
110
+ };
111
+
112
+ // End Date Input story
113
+ export const EndDateInput: Story = {
114
+ render: (args) => {
115
+ const [startDate, setStartDate] = useState<Date | undefined>();
116
+ const [endDate, setEndDate] = useState<Date | undefined>();
117
+
118
+ return (
119
+ <>
120
+ <p>Select Start Date:</p>
121
+ <CustomDatePicker
122
+ {...args}
123
+ value={startDate}
124
+ onChange={setStartDate}
125
+ maxDate={new Date()} // Disable future dates for start date picker
126
+ />
127
+
128
+ <p>Select End Date:</p>
129
+ <CustomDatePicker
130
+ {...args}
131
+ value={endDate}
132
+ onChange={setEndDate}
133
+ disabled={!startDate}
134
+ minDate={startDate || undefined} // Restrict the end date based on selected start date
135
+ maxDate={new Date()} // Disable future dates for end date picker
136
+ />
137
+ </>
138
+ );
139
+ },
140
+ };
141
+
142
+ // Schedule Date Input story
143
+ export const ScheduleDateInput: Story = {
144
+ args: {
145
+ error: false,
146
+ helperText: "Error"
147
+ },
148
+
149
+ render: (args) => {
150
+ const [selectDate, setSelectDate] = useState<Date | undefined>(new Date());
151
+
152
+ return (
153
+ <CustomDatePicker
154
+ {...args}
155
+ value={selectDate}
156
+ onChange={setSelectDate}
157
+ minDate={new Date()} // Set minimum date to today
158
+ />
159
+ );
160
+ }
161
+ };
@@ -0,0 +1,438 @@
1
+ import React, { useEffect, useState, useRef } from 'react';
2
+ import { DayPicker } from 'react-day-picker';
3
+ import { formatInTimeZone } from 'date-fns-tz';
4
+ import TimePicker from './Timepicker';
5
+ import Icon from '../Icon';
6
+ import './DatePicker.scss';
7
+ import {
8
+ DatePickerProps,
9
+ CustomCaptionProps,
10
+ CustomCalenderButtonProps,
11
+ } from './types';
12
+ import Button from '../Button';
13
+ import Typography from '../Typography';
14
+ import classNames from 'classnames';
15
+
16
+ const CustomDatePicker: React.FC<DatePickerProps> = ({
17
+ minDate,
18
+ maxDate,
19
+ value,
20
+ onChange,
21
+ placeholder = 'Select a date',
22
+ disabled = false,
23
+ dateFormat = 'EEEE, dd MMM yyyy',
24
+ calendarWidth,
25
+ timezone = 'Asia/Kolkata',
26
+ timeFormat = 'hh:mm a',
27
+ error,
28
+ helperText = '',
29
+ }) => {
30
+ const [timeValue, setTimeValue] = useState<string>('');
31
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>();
32
+ const [isPickerOpen, setIsPickerOpen] = useState<boolean>(false);
33
+ const [timeError, setTimeError] = useState<boolean>(false);
34
+ const [selectedMonth, setSelectedMonth] = useState<Date | undefined>(
35
+ new Date()
36
+ );
37
+ const [view, setView] = useState<string>('days');
38
+ const [startYear, setStartYear] = useState(() => {
39
+ const currentYear =
40
+ selectedMonth?.getFullYear() ?? new Date().getFullYear();
41
+ return currentYear - (currentYear % 12); // Set to the first year in the 12-year range
42
+ });
43
+ const [datePickerPosition, setDatePickerPosition] = useState<
44
+ 'top' | 'bottom'
45
+ >('bottom');
46
+ const pickerRef = useRef<HTMLDivElement>(null); // Ref to track the picker
47
+ const containerRef = useRef<HTMLDivElement>(null);
48
+
49
+ useEffect(() => {
50
+ if (value) {
51
+ setTimeValue(formatTimeStr(value));
52
+ setSelectedDate(value);
53
+ }
54
+ }, [value, isPickerOpen]);
55
+
56
+ const formatTimeStr = (date: Date): string => {
57
+ const hours = date.getHours().toString().padStart(2, '0');
58
+ const minutes = date.getMinutes().toString().padStart(2, '0');
59
+ return `${hours}:${minutes}`;
60
+ };
61
+
62
+ // Convert minDate and maxDate to "hh:mm" for the TimePicker if the dates match
63
+ const minTime =
64
+ selectedDate &&
65
+ minDate &&
66
+ selectedDate.toDateString() === minDate.toDateString()
67
+ ? formatTimeStr(minDate)
68
+ : undefined;
69
+
70
+ const maxTime =
71
+ selectedDate &&
72
+ maxDate &&
73
+ selectedDate.toDateString() === maxDate.toDateString()
74
+ ? formatTimeStr(maxDate)
75
+ : undefined;
76
+
77
+ useEffect(() => {
78
+ const adjustPosition = () => {
79
+ if (containerRef.current && pickerRef.current) {
80
+ const relativeRect = containerRef.current.getBoundingClientRect();
81
+ const absoluteRect = pickerRef.current.getBoundingClientRect();
82
+
83
+ const spaceBelow = window.innerHeight - relativeRect.bottom;
84
+ const spaceAbove = relativeRect.top;
85
+
86
+ // Check if there is more space above than below
87
+ if (
88
+ spaceBelow < absoluteRect.height &&
89
+ spaceAbove >= absoluteRect.height
90
+ ) {
91
+ setDatePickerPosition('top');
92
+ } else {
93
+ setDatePickerPosition('bottom');
94
+ }
95
+ }
96
+ };
97
+
98
+ // Initial check
99
+ adjustPosition();
100
+
101
+ // Adjust position on window resize
102
+ window.addEventListener('resize', adjustPosition);
103
+ return () => window.removeEventListener('resize', adjustPosition);
104
+ }, []);
105
+
106
+ const calendarStyle = {
107
+ '--rdp-day-width': calendarWidth ? `${calendarWidth / 7 - 4}px` : undefined,
108
+ } as React.CSSProperties;
109
+
110
+ const handleTimeChange = (time: string) => {
111
+ setTimeValue(time);
112
+ if (selectedDate) {
113
+ const [hoursStr, minutesStr] = time.split(':');
114
+ const newSelectedDate = new Date(selectedDate);
115
+ newSelectedDate.setHours(parseInt(hoursStr ? hoursStr : '0', 10));
116
+ newSelectedDate.setMinutes(
117
+ parseInt(minutesStr ? minutesStr : '0', 10) || 0
118
+ );
119
+ setSelectedDate(newSelectedDate);
120
+ }
121
+ };
122
+
123
+ const handleDaySelect = (date: Date | undefined) => {
124
+ if (!timeValue || !date) {
125
+ // if need to set time to current time in case no time selected
126
+ const now = new Date();
127
+ date?.setHours(now.getHours(), now.getMinutes(), now.getSeconds());
128
+
129
+ setSelectedDate(date);
130
+ } else {
131
+ const [hoursStr, minutesStr] = timeValue.split(':');
132
+ date.setHours(parseInt(hoursStr ? hoursStr : '0', 10) || 0);
133
+ date.setMinutes(parseInt(minutesStr ? minutesStr : '0', 10) || 0);
134
+ setSelectedDate(date);
135
+ }
136
+ };
137
+
138
+ const handleSave = () => {
139
+ onChange(selectedDate);
140
+ resetAndCloseDatePicker();
141
+ };
142
+
143
+ const handleDateInputClick = () => {
144
+ setIsPickerOpen((prev) => !prev);
145
+ setView('days');
146
+ setSelectedMonth(value ?? new Date());
147
+ };
148
+
149
+ const handleClickOutside = (event: MouseEvent) => {
150
+ if (
151
+ pickerRef.current &&
152
+ !pickerRef.current.contains(event.target as Node)
153
+ ) {
154
+ resetAndCloseDatePicker();
155
+ }
156
+ };
157
+
158
+ const handleCancel = () => {
159
+ resetAndCloseDatePicker();
160
+ };
161
+
162
+ const resetAndCloseDatePicker = () => {
163
+ setIsPickerOpen(false); // Close the picker if the click was outside
164
+ setView('days'); // Return to default day view on close of day picker
165
+ setSelectedMonth(value ?? new Date());
166
+ };
167
+
168
+ useEffect(() => {
169
+ if (isPickerOpen) {
170
+ document.addEventListener('mousedown', handleClickOutside);
171
+ } else {
172
+ document.removeEventListener('mousedown', handleClickOutside);
173
+ }
174
+ return () => {
175
+ document.removeEventListener('mousedown', handleClickOutside); // Clean up the event listener
176
+ };
177
+ }, [isPickerOpen]);
178
+
179
+ const months = Array.from({ length: 12 }, (_, i) =>
180
+ new Date(0, i).toLocaleString('default', { month: 'long' })
181
+ );
182
+ const years = Array.from({ length: 12 }, (_, i) => startYear + i);
183
+
184
+ const handleMonthClick = () => setView('months');
185
+ const handleYearClick = () => setView('years');
186
+
187
+ const handleMonthSelect = (monthIndex: number) => {
188
+ const newDate = new Date(selectedMonth || '');
189
+ newDate.setMonth(monthIndex);
190
+ setSelectedMonth(newDate);
191
+ setView('days');
192
+ };
193
+
194
+ const handleYearSelect = (year: number) => {
195
+ const newDate = new Date(selectedMonth || '');
196
+ newDate.setFullYear(year);
197
+ setSelectedMonth(newDate);
198
+ setView('days');
199
+ };
200
+
201
+ const handleNextClick = () => {
202
+ if (view === 'years') {
203
+ setStartYear((prev) => prev + 12);
204
+ }
205
+ };
206
+
207
+ const handlePrevClick = () => {
208
+ if (view === 'years') {
209
+ setStartYear((prev) => prev - 12);
210
+ }
211
+ };
212
+
213
+ useEffect(() => {
214
+ if (isPickerOpen && view === 'years') {
215
+ const currentYear =
216
+ selectedMonth?.getFullYear() ?? new Date().getFullYear();
217
+ setStartYear(currentYear - (currentYear % 12)); // Reset to the first year in the range that contains the selected year
218
+ }
219
+ }, [isPickerOpen, selectedMonth, view]);
220
+
221
+ // Custom Caption Component
222
+ const CustomCaption: React.FC<CustomCaptionProps> = ({ children }) => {
223
+ // If children is a React node (like an element), render it directly
224
+ if (React.isValidElement(children)) {
225
+ return <div>{children}</div>;
226
+ }
227
+
228
+ const [month = '', year = ''] = String(children).split(' ');
229
+
230
+ return (
231
+ <Typography
232
+ as="div"
233
+ fontWeight="medium"
234
+ lineHeight="16.8px"
235
+ className="ff-calendar-haeder"
236
+ >
237
+ <span onClick={handleMonthClick} className="ff-cursor-pointer">
238
+ {month}
239
+ </span>
240
+ <span onClick={handleYearClick} className="ff-cursor-pointer">
241
+ {year}
242
+ </span>
243
+ </Typography>
244
+ );
245
+ };
246
+
247
+ // Custom MonthGrid Component
248
+ const CustomMonthGrid: React.FC = () => {
249
+ return (
250
+ <div className="ff-custom-month_grid">
251
+ {months.map((month: string, index: number) => (
252
+ <div
253
+ key={index}
254
+ onClick={() => handleMonthSelect(index)}
255
+ className={classNames('ff-custom-month', {
256
+ 'ff-custom-month--selected': index === selectedMonth?.getMonth(),
257
+ })}
258
+ >
259
+ <Typography>{month}</Typography>
260
+ </div>
261
+ ))}
262
+ </div>
263
+ );
264
+ };
265
+
266
+ const CustomPrevButton: React.FC<CustomCalenderButtonProps> = ({
267
+ disabled,
268
+ onClick,
269
+ }) => {
270
+ return (
271
+ <button
272
+ className="ff-calendar-nav-button"
273
+ onClick={onClick}
274
+ disabled={disabled}
275
+ >
276
+ <Icon name="left_arrow_icon" height={12} width={12} />
277
+ </button>
278
+ );
279
+ };
280
+ const CustomNextButton: React.FC<CustomCalenderButtonProps> = ({
281
+ disabled,
282
+ onClick,
283
+ }) => {
284
+ return (
285
+ <button
286
+ className="ff-calendar-nav-button"
287
+ onClick={onClick}
288
+ disabled={disabled}
289
+ >
290
+ <Icon name="right_arrow_icon" height={12} width={12} />
291
+ </button>
292
+ );
293
+ };
294
+
295
+ // Custom YearGrid Component
296
+ const CustomYearGrid: React.FC = () => {
297
+ return (
298
+ <div className="ff-custom-year_grid">
299
+ {years.map((year: number) => (
300
+ <div
301
+ key={year}
302
+ onClick={() => handleYearSelect(year)}
303
+ className={classNames('ff-custom-year', {
304
+ 'ff-custom-year--selected': year === selectedMonth?.getFullYear(),
305
+ })}
306
+ >
307
+ <Typography>{year}</Typography>
308
+ </div>
309
+ ))}
310
+ </div>
311
+ );
312
+ };
313
+
314
+ return (
315
+ <div className="ff-date-picker" ref={containerRef}>
316
+ <div className="ff-datepicker-input-container">
317
+ <div className="ff-input-with-icon ff-date-input-field">
318
+ <Icon
319
+ name={'calendar_icon'}
320
+ hoverEffect={false}
321
+ className="ff-calendar-icon"
322
+ />
323
+ <input
324
+ type="text"
325
+ value={value ? formatInTimeZone(value, timezone, dateFormat) : ''}
326
+ readOnly
327
+ placeholder={placeholder}
328
+ className="ff-date-input"
329
+ disabled={disabled}
330
+ onClick={handleDateInputClick}
331
+ />
332
+ {helperText && error && (
333
+ <span
334
+ className={classNames('ff-date-input-message', {
335
+ 'ff-date-input-message--danger': !!error,
336
+ })}
337
+ >
338
+ {helperText}
339
+ </span>
340
+ )}
341
+ </div>
342
+
343
+ <div className="ff-input-with-icon ff-time-input-field">
344
+ <Icon
345
+ name={'clock_icon'}
346
+ hoverEffect={false}
347
+ className="ff-clock-icon"
348
+ />
349
+ <input
350
+ type="text"
351
+ placeholder="Select time"
352
+ className="ff-time-input"
353
+ value={value ? formatInTimeZone(value, timezone, timeFormat) : ''}
354
+ disabled={disabled}
355
+ onClick={handleDateInputClick}
356
+ readOnly
357
+ />
358
+ </div>
359
+ </div>
360
+
361
+ {isPickerOpen && (
362
+ <div
363
+ className="ff-date-picker-container"
364
+ ref={pickerRef}
365
+ style={{
366
+ top: datePickerPosition === 'top' ? 'auto' : '110%',
367
+ bottom: datePickerPosition === 'top' ? '110%' : 'auto',
368
+ }}
369
+ >
370
+ <div className="ff-calendar-container">
371
+ <DayPicker
372
+ style={calendarStyle}
373
+ className="ff-calendar"
374
+ mode="single"
375
+ selected={selectedDate}
376
+ onSelect={handleDaySelect}
377
+ month={selectedMonth}
378
+ onMonthChange={(month) => {
379
+ if (view === 'days') {
380
+ setSelectedMonth(month);
381
+ }
382
+ }}
383
+ onNextClick={handleNextClick}
384
+ onPrevClick={handlePrevClick}
385
+ disableNavigation={view === 'months'}
386
+ disabled={[
387
+ {
388
+ before: new Date(minDate ? minDate : ''),
389
+ after: new Date(maxDate ? maxDate : ''),
390
+ },
391
+ ]}
392
+ timeZone={timezone}
393
+ components={{
394
+ CaptionLabel: (props) => <CustomCaption {...props} />,
395
+ PreviousMonthButton: (props) => <CustomPrevButton {...props} />,
396
+ NextMonthButton: (props) => <CustomNextButton {...props} />,
397
+ ...(view === 'months'
398
+ ? {
399
+ MonthGrid: () => <CustomMonthGrid />,
400
+ }
401
+ : {}),
402
+ ...(view === 'years'
403
+ ? {
404
+ MonthGrid: () => <CustomYearGrid />,
405
+ }
406
+ : {}),
407
+ }}
408
+ />
409
+ <TimePicker
410
+ value={timeValue}
411
+ onChange={handleTimeChange}
412
+ minTime={minTime}
413
+ maxTime={maxTime}
414
+ onErrorChange={setTimeError}
415
+ />
416
+ </div>
417
+ <div className="ff-date-picker-controls">
418
+ <Button
419
+ className="ff-date-picker-button"
420
+ variant="secondary"
421
+ onClick={handleCancel}
422
+ label="Cancel"
423
+ />
424
+ <Button
425
+ className="ff-date-picker-button"
426
+ variant="primary"
427
+ onClick={handleSave}
428
+ label="Save"
429
+ disabled={timeError}
430
+ />
431
+ </div>
432
+ </div>
433
+ )}
434
+ </div>
435
+ );
436
+ };
437
+
438
+ export default CustomDatePicker;