agroptima-design-system 0.31.10 → 0.31.11
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/package.json +1 -1
- package/src/atoms/DatePicker/DatePicker.scss +28 -2
- package/src/atoms/DatePicker/DateRangePicker.tsx +43 -12
- package/src/atoms/DatePicker/DateSinglePicker.tsx +50 -13
- package/src/atoms/DatePicker/translations.ts +4 -0
- package/src/atoms/Input.scss +3 -0
- package/src/atoms/Input.tsx +6 -0
- package/src/stories/Changelog.mdx +6 -0
- package/src/stories/DateRangePicker.stories.ts +25 -0
- package/src/stories/DateSinglePicker.stories.ts +25 -0
- package/src/stories/Input.stories.ts +4 -0
- package/src/utils/dateHelpers.ts +2 -0
- package/tests/DateRangePicker.spec.tsx +13 -0
- package/tests/DateSinglePicker.spec.tsx +12 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
@use '../../settings/typography/content' as typography;
|
|
3
3
|
@use '../../settings/config';
|
|
4
4
|
@use '../../settings/depth';
|
|
5
|
-
@use '../../settings/
|
|
5
|
+
@use '../../settings/mixins';
|
|
6
6
|
|
|
7
7
|
// Interpolation applied: https://sass-lang.com/documentation/breaking-changes/css-vars/
|
|
8
8
|
.rdp-root {
|
|
@@ -12,13 +12,16 @@
|
|
|
12
12
|
--rdp-range_middle-background-color: #{color_alias.$primary-color-50};
|
|
13
13
|
--rdp-range_start-date-background-color: #{color_alias.$primary-color-600};
|
|
14
14
|
--rdp-range_end-date-background-color: #{color_alias.$primary-color-600};
|
|
15
|
-
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
.rdp-caption_label {
|
|
19
18
|
text-transform: capitalize;
|
|
19
|
+
padding-left: config.$space-3x;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
.rdp-footer {
|
|
23
|
+
padding-left: config.$space-3x;
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
.rdp-selected .rdp-day_button {
|
|
24
27
|
background-color: #{color_alias.$primary-color-600};
|
|
@@ -30,5 +33,28 @@
|
|
|
30
33
|
background-color: var(--rdp-range_middle-background-color);
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
.toggle {
|
|
37
|
+
.input-group.primary .input-container {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: config.$space-1x;
|
|
41
|
+
padding: 8px 6px 8px;
|
|
42
|
+
|
|
43
|
+
.icon {
|
|
44
|
+
@include mixins.svg-color(color_alias.$primary-color-600);
|
|
45
|
+
@include mixins.size(config.$icon-size-3x);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
.calendar {
|
|
49
|
+
display: flex;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
border-radius: config.$corner-radius-xxs;
|
|
52
|
+
z-index: depth.$z-dropdown-options;
|
|
53
|
+
padding-left: config.$space-3x;
|
|
54
|
+
width: 20rem;
|
|
55
|
+
position: absolute;
|
|
56
|
+
box-shadow: 0px 9px 28px 8px rgba(0, 0, 0, 0.05), 0px 6px 16px 0px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
33
59
|
|
|
34
60
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
fromDateToISOString,
|
|
12
12
|
fromISOToDate,
|
|
13
13
|
} from '../../utils/dateHelpers'
|
|
14
|
+
import { Input } from '../Input'
|
|
14
15
|
import { availableLocales, type Locale, translations } from './translations'
|
|
15
16
|
|
|
16
17
|
export type Variant = 'primary'
|
|
@@ -22,6 +23,8 @@ export type DateRangePickerProps = {
|
|
|
22
23
|
className?: string
|
|
23
24
|
defaultValue?: DateRange
|
|
24
25
|
onSelect?: (date: DateRange) => void
|
|
26
|
+
withInput?: boolean
|
|
27
|
+
label?: string
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export type DateRange = {
|
|
@@ -36,13 +39,20 @@ export function DateRangePicker({
|
|
|
36
39
|
className,
|
|
37
40
|
required = false,
|
|
38
41
|
variant,
|
|
42
|
+
withInput = false,
|
|
43
|
+
label = 'Date',
|
|
39
44
|
}: DateRangePickerProps): React.JSX.Element {
|
|
40
|
-
const
|
|
45
|
+
const inputType = withInput ? 'text' : 'hidden'
|
|
46
|
+
const cssClasses = classNames('date-picker', variant, className, {
|
|
47
|
+
toggle: withInput,
|
|
48
|
+
})
|
|
41
49
|
|
|
42
50
|
const [selected, setSelected] = useState<DateRangeReactDayPicker>(
|
|
43
51
|
toDateRange(defaultValue),
|
|
44
52
|
)
|
|
45
53
|
|
|
54
|
+
const [isOpen, setIsOpen] = useState<boolean>(!withInput)
|
|
55
|
+
|
|
46
56
|
function selectDate(dateRange: DateRangeReactDayPicker | undefined) {
|
|
47
57
|
const selectedDateRange = {
|
|
48
58
|
from: dateRange?.from,
|
|
@@ -57,26 +67,47 @@ export function DateRangePicker({
|
|
|
57
67
|
}, [defaultValue])
|
|
58
68
|
|
|
59
69
|
return (
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
<div className={cssClasses}>
|
|
71
|
+
<div onClick={() => setIsOpen(!isOpen)}>
|
|
72
|
+
<Input
|
|
73
|
+
type={inputType}
|
|
74
|
+
label={label}
|
|
75
|
+
datePickerIcon={isOpen ? 'AngleUp' : 'AngleDown'}
|
|
76
|
+
value={`${formatDatePickerFooterDate(selected.from, lng as string)} - ${formatDatePickerFooterDate(selected.to, lng as string)}`}
|
|
77
|
+
icon="Calendar"
|
|
78
|
+
name="date"
|
|
79
|
+
placeholder={translations[lng].rangePlaceholder}
|
|
80
|
+
readOnly
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
{isOpen && (
|
|
84
|
+
<DayPicker
|
|
85
|
+
locale={availableLocales[lng]}
|
|
86
|
+
mode="range"
|
|
87
|
+
min={1}
|
|
88
|
+
selected={selected}
|
|
89
|
+
onSelect={selectDate}
|
|
90
|
+
footer={
|
|
91
|
+
<Footer lng={lng} selected={selected} withInput={withInput} />
|
|
92
|
+
}
|
|
93
|
+
defaultMonth={selected?.from}
|
|
94
|
+
required={required}
|
|
95
|
+
className="calendar"
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
71
99
|
)
|
|
72
100
|
}
|
|
73
101
|
function Footer({
|
|
74
102
|
lng,
|
|
75
103
|
selected,
|
|
104
|
+
withInput,
|
|
76
105
|
}: {
|
|
77
106
|
lng: Locale
|
|
78
107
|
selected: DateRangeReactDayPicker | undefined
|
|
108
|
+
withInput: boolean
|
|
79
109
|
}): string {
|
|
110
|
+
if (withInput) return ''
|
|
80
111
|
if (!selected?.from && !selected?.to) {
|
|
81
112
|
return translations[lng].pickDate
|
|
82
113
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
fromDateToISOString,
|
|
9
9
|
fromISOToDate,
|
|
10
10
|
} from '../../utils/dateHelpers'
|
|
11
|
+
import { Input } from '../Input'
|
|
11
12
|
import { availableLocales, type Locale, translations } from './translations'
|
|
12
13
|
|
|
13
14
|
export type Variant = 'primary'
|
|
@@ -19,6 +20,8 @@ export type DateSinglePickerProps = {
|
|
|
19
20
|
className?: string
|
|
20
21
|
defaultValue?: string
|
|
21
22
|
onSelect?: (date: string) => void
|
|
23
|
+
withInput?: boolean
|
|
24
|
+
label?: string
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export function DateSinglePicker({
|
|
@@ -28,12 +31,19 @@ export function DateSinglePicker({
|
|
|
28
31
|
className,
|
|
29
32
|
required = false,
|
|
30
33
|
variant,
|
|
34
|
+
withInput = false,
|
|
35
|
+
label = 'Date',
|
|
31
36
|
}: DateSinglePickerProps): React.JSX.Element {
|
|
32
|
-
const
|
|
37
|
+
const inputType = withInput ? 'text' : 'hidden'
|
|
38
|
+
|
|
39
|
+
const cssClasses = classNames('date-picker', variant, className, {
|
|
40
|
+
toggle: withInput,
|
|
41
|
+
})
|
|
33
42
|
|
|
34
43
|
const [selected, setSelected] = useState<Date | undefined>(
|
|
35
44
|
fromISOToDate(defaultValue),
|
|
36
45
|
)
|
|
46
|
+
const [isOpen, setIsOpen] = useState<boolean>(!withInput)
|
|
37
47
|
|
|
38
48
|
function selectDate(date: Date | undefined) {
|
|
39
49
|
setSelected(date)
|
|
@@ -41,20 +51,47 @@ export function DateSinglePicker({
|
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
return (
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
<div className={cssClasses}>
|
|
55
|
+
<div onClick={() => setIsOpen(!isOpen)}>
|
|
56
|
+
<Input
|
|
57
|
+
type={inputType}
|
|
58
|
+
label={label}
|
|
59
|
+
datePickerIcon={isOpen ? 'AngleUp' : 'AngleDown'}
|
|
60
|
+
value={formatDatePickerFooterDate(selected, lng as string)}
|
|
61
|
+
icon="Calendar"
|
|
62
|
+
name="date"
|
|
63
|
+
placeholder={translations[lng].singlePlaceholder}
|
|
64
|
+
readOnly
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
{isOpen && (
|
|
68
|
+
<DayPicker
|
|
69
|
+
locale={availableLocales[lng]}
|
|
70
|
+
mode="single"
|
|
71
|
+
selected={selected}
|
|
72
|
+
onSelect={selectDate}
|
|
73
|
+
footer={
|
|
74
|
+
<Footer lng={lng} selected={selected} withInput={withInput} />
|
|
75
|
+
}
|
|
76
|
+
required={required}
|
|
77
|
+
defaultMonth={selected}
|
|
78
|
+
className="calendar"
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
54
82
|
)
|
|
55
83
|
}
|
|
56
|
-
function Footer({
|
|
57
|
-
|
|
84
|
+
function Footer({
|
|
85
|
+
lng,
|
|
86
|
+
selected,
|
|
87
|
+
withInput,
|
|
88
|
+
}: {
|
|
89
|
+
selected?: Date
|
|
90
|
+
lng: Locale
|
|
91
|
+
withInput: boolean
|
|
92
|
+
}): string {
|
|
93
|
+
if (withInput) return ''
|
|
94
|
+
if (!selected) return translations[lng].pickSingleDate
|
|
58
95
|
|
|
59
96
|
return translations[lng].selectedDate.replace(
|
|
60
97
|
'${date}',
|
|
@@ -21,10 +21,14 @@ export const translations: Translation = {
|
|
|
21
21
|
pickDate: 'Pick a date or a range of dates',
|
|
22
22
|
selectedDate: 'Selected date: ${date}',
|
|
23
23
|
selectedRangeOfDates: 'Selected dates range: from ${from} to ${to}',
|
|
24
|
+
singlePlaceholder: 'mm/dd/yyyy',
|
|
25
|
+
rangePlaceholder: 'mm/dd/yyyy - mm/dd/yyyy',
|
|
24
26
|
},
|
|
25
27
|
es: {
|
|
26
28
|
pickDate: 'Selecciona una fecha o un rango de fechas',
|
|
27
29
|
selectedDate: 'Fecha seleccionada: ${date}',
|
|
28
30
|
selectedRangeOfDates: 'Rango de fechas seleccionado: desde ${from} a ${to}',
|
|
31
|
+
singlePlaceholder: 'dd/mm/yyyy',
|
|
32
|
+
rangePlaceholder: 'dd/mm/yyyy - dd/mm/yyyy',
|
|
29
33
|
},
|
|
30
34
|
}
|
package/src/atoms/Input.scss
CHANGED
package/src/atoms/Input.tsx
CHANGED
|
@@ -19,6 +19,7 @@ export interface InputProps extends React.ComponentPropsWithRef<'input'> {
|
|
|
19
19
|
suffix?: string
|
|
20
20
|
errors?: string[]
|
|
21
21
|
required?: boolean
|
|
22
|
+
datePickerIcon?: IconType
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function Input({
|
|
@@ -36,6 +37,7 @@ export function Input({
|
|
|
36
37
|
id,
|
|
37
38
|
errors,
|
|
38
39
|
required = false,
|
|
40
|
+
datePickerIcon,
|
|
39
41
|
...props
|
|
40
42
|
}: InputProps): React.JSX.Element {
|
|
41
43
|
const identifier = id || name
|
|
@@ -61,6 +63,7 @@ export function Input({
|
|
|
61
63
|
className={classNames('input-group', variant, className, {
|
|
62
64
|
file: type === 'file',
|
|
63
65
|
invalid: errors?.length,
|
|
66
|
+
hidden: type === 'hidden',
|
|
64
67
|
})}
|
|
65
68
|
>
|
|
66
69
|
{!hideLabel && (
|
|
@@ -88,6 +91,9 @@ export function Input({
|
|
|
88
91
|
})}
|
|
89
92
|
{...props}
|
|
90
93
|
/>
|
|
94
|
+
{datePickerIcon && (
|
|
95
|
+
<Icon className="right-icon" name={datePickerIcon} />
|
|
96
|
+
)}
|
|
91
97
|
{suffix && <span className="input-suffix">{suffix}</span>}
|
|
92
98
|
{type === 'password' && (
|
|
93
99
|
<IconButton
|
|
@@ -4,6 +4,12 @@ import { Meta } from "@storybook/blocks";
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
## 0.31.11
|
|
8
|
+
|
|
9
|
+
* On DateSinglePicker component, Input component shows the selected date with the optional property withInput.
|
|
10
|
+
* On DateRangePicker component, Input component shows the selected date with the optional property withInput.
|
|
11
|
+
* Add datePickerIcon optional property for DatePicker components to Icon component
|
|
12
|
+
|
|
7
13
|
## 0.31.10
|
|
8
14
|
|
|
9
15
|
* Change footer text for DateRangePicker only one selected day
|
|
@@ -32,6 +32,20 @@ const meta = {
|
|
|
32
32
|
className: {
|
|
33
33
|
description: 'Optional parametre for add styles by className',
|
|
34
34
|
},
|
|
35
|
+
withInput: {
|
|
36
|
+
description: 'Optional input to read and select the date',
|
|
37
|
+
control: {
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
default: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
label: {
|
|
43
|
+
description: 'Optional label for input',
|
|
44
|
+
control: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
default: 'Date',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
35
49
|
},
|
|
36
50
|
}
|
|
37
51
|
|
|
@@ -63,3 +77,14 @@ export const WithRangeDateSelected: Story = {
|
|
|
63
77
|
},
|
|
64
78
|
parameters: figmaPrimaryDesign,
|
|
65
79
|
}
|
|
80
|
+
|
|
81
|
+
export const RangeDatePickerWithInput: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
variant: 'primary',
|
|
84
|
+
onSelect: (date) => console.log('onSelect date:', date),
|
|
85
|
+
defaultValue: { from: '2024-01-02', to: '2024-01-12' },
|
|
86
|
+
lng: 'en',
|
|
87
|
+
withInput: true,
|
|
88
|
+
},
|
|
89
|
+
parameters: figmaPrimaryDesign,
|
|
90
|
+
}
|
|
@@ -32,6 +32,20 @@ const meta = {
|
|
|
32
32
|
className: {
|
|
33
33
|
description: 'Optional parametre for add styles by className',
|
|
34
34
|
},
|
|
35
|
+
withInput: {
|
|
36
|
+
description: 'Optional input to read and select the date',
|
|
37
|
+
control: {
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
default: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
label: {
|
|
43
|
+
description: 'Optional label for input',
|
|
44
|
+
control: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
default: 'Date',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
35
49
|
},
|
|
36
50
|
}
|
|
37
51
|
|
|
@@ -62,3 +76,14 @@ export const WithSingleDaySelected: Story = {
|
|
|
62
76
|
},
|
|
63
77
|
parameters: figmaPrimaryDesign,
|
|
64
78
|
}
|
|
79
|
+
|
|
80
|
+
export const SingleDatePickerWithInput: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
variant: 'primary',
|
|
83
|
+
onSelect: (date) => console.log('onSelect date:', date),
|
|
84
|
+
defaultValue: '2024-01-20',
|
|
85
|
+
lng: 'en',
|
|
86
|
+
withInput: true,
|
|
87
|
+
},
|
|
88
|
+
parameters: figmaPrimaryDesign,
|
|
89
|
+
}
|
|
@@ -52,6 +52,10 @@ const meta = {
|
|
|
52
52
|
description:
|
|
53
53
|
'Optional array of errors. If passed, the errors are listed and invalid style is applied.',
|
|
54
54
|
},
|
|
55
|
+
datePickerIcon: {
|
|
56
|
+
description:
|
|
57
|
+
'Optional icon added to input when input is applied to the date picker component selection',
|
|
58
|
+
},
|
|
55
59
|
},
|
|
56
60
|
}
|
|
57
61
|
|
package/src/utils/dateHelpers.ts
CHANGED
|
@@ -24,4 +24,17 @@ describe('DateRangePicker', () => {
|
|
|
24
24
|
getByText('Rango de fechas seleccionado: desde 12/1/2025 a 20/1/2025'),
|
|
25
25
|
).toBeInTheDocument()
|
|
26
26
|
})
|
|
27
|
+
|
|
28
|
+
it('renders with input that shows date picker value', () => {
|
|
29
|
+
const { getByRole } = render(
|
|
30
|
+
<DateRangePicker
|
|
31
|
+
defaultValue={{ from: '2025-01-12', to: '2025-01-20' }}
|
|
32
|
+
onSelect={() => jest.fn()}
|
|
33
|
+
lng={'es'}
|
|
34
|
+
withInput
|
|
35
|
+
/>,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
expect(getByRole('textbox')).toHaveValue('12/1/2025 - 20/1/2025')
|
|
39
|
+
})
|
|
27
40
|
})
|
|
@@ -22,4 +22,16 @@ describe('DateSinglePicker', () => {
|
|
|
22
22
|
expect(getByText('do')).toBeInTheDocument()
|
|
23
23
|
expect(getByText('Fecha seleccionada: 23/1/2025')).toBeInTheDocument()
|
|
24
24
|
})
|
|
25
|
+
it('renders with input that show date picker value', () => {
|
|
26
|
+
const { getByRole } = render(
|
|
27
|
+
<DateSinglePicker
|
|
28
|
+
defaultValue={'2025-01-23'}
|
|
29
|
+
onSelect={() => jest.fn()}
|
|
30
|
+
withInput
|
|
31
|
+
lng={'es'}
|
|
32
|
+
/>,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
expect(getByRole('textbox')).toHaveValue('23/1/2025')
|
|
36
|
+
})
|
|
25
37
|
})
|