agroptima-design-system 0.31.7-beta.2 → 0.31.8
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/DateRangePicker.tsx +84 -41
- package/src/atoms/DatePicker/DateSinglePicker.tsx +40 -46
- package/src/atoms/DatePicker/index.tsx +7 -0
- package/src/atoms/DatePicker/translations.ts +17 -1
- package/src/stories/Changelog.mdx +13 -0
- package/src/stories/{DatePicker.stories.ts → DateRangePicker.stories.ts} +9 -28
- package/src/stories/DateSinglePicker.stories.ts +64 -0
- package/src/stories/Drawer.stories.js +2 -3
- package/src/stories/Modal.stories.js +327 -212
- package/src/utils/dateHelpers.ts +8 -2
- package/tests/DateRangePicker.spec.tsx +27 -0
- package/tests/DateSinglePicker.spec.tsx +25 -0
- package/tests/Modal.spec.tsx +24 -8
- package/tests/a11y.spec.tsx +5 -0
- package/src/atoms/DatePicker/DatePicker.tsx +0 -70
- package/tests/DatePicker.spec.tsx +0 -48
package/package.json
CHANGED
|
@@ -1,68 +1,111 @@
|
|
|
1
1
|
import 'react-day-picker/style.css'
|
|
2
|
+
import './DatePicker.scss'
|
|
2
3
|
import { useEffect, useState } from 'react'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type DateRange as DateRangeReactDayPicker,
|
|
6
|
+
DayPicker,
|
|
7
|
+
} from 'react-day-picker'
|
|
8
|
+
import { classNames } from '../../utils/classNames'
|
|
9
|
+
import {
|
|
10
|
+
formatDatePickerFooterDate,
|
|
11
|
+
fromDateToISOString,
|
|
12
|
+
fromISOToDate,
|
|
13
|
+
} from '../../utils/dateHelpers'
|
|
14
|
+
import { availableLocales, type Locale, translations } from './translations'
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
export type Variant = 'primary'
|
|
17
|
+
|
|
18
|
+
export type DateRangePickerProps = {
|
|
19
|
+
variant?: Variant
|
|
20
|
+
lng: Locale
|
|
21
|
+
required?: boolean
|
|
22
|
+
className?: string
|
|
23
|
+
defaultValue?: DateRange
|
|
24
|
+
onSelect?: (date: DateRange) => void
|
|
12
25
|
}
|
|
13
26
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
lng: keyof typeof availableLocales
|
|
18
|
-
className: string
|
|
27
|
+
export type DateRange = {
|
|
28
|
+
from: string | undefined
|
|
29
|
+
to: string | undefined
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
export function DateRangePicker({
|
|
22
|
-
onSelect
|
|
23
|
-
|
|
33
|
+
onSelect,
|
|
34
|
+
defaultValue,
|
|
24
35
|
lng,
|
|
25
36
|
className,
|
|
37
|
+
required = false,
|
|
38
|
+
variant,
|
|
26
39
|
}: DateRangePickerProps): React.JSX.Element {
|
|
27
|
-
const
|
|
28
|
-
const hasDatesFilter = selected && selected.from && selected.to
|
|
40
|
+
const cssClasses = classNames('date-picker', variant, className)
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
const [selected, setSelected] = useState<DateRangeReactDayPicker>(
|
|
43
|
+
toDateRange(defaultValue),
|
|
44
|
+
)
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
function selectDate(dateRange: DateRangeReactDayPicker | undefined) {
|
|
47
|
+
const selectedDateRange = {
|
|
48
|
+
from: dateRange?.from,
|
|
49
|
+
to: dateRange?.to,
|
|
50
|
+
}
|
|
51
|
+
setSelected(selectedDateRange)
|
|
52
|
+
onSelect?.(toDateRangeISO(selectedDateRange))
|
|
38
53
|
}
|
|
39
54
|
|
|
40
|
-
const [selected, setSelected] = useState<DateRange | undefined>(preselected)
|
|
41
|
-
const [footer, setFooter] = useState<string>(() => {
|
|
42
|
-
return manageFooterText()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
55
|
useEffect(() => {
|
|
46
|
-
setSelected(
|
|
47
|
-
|
|
48
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
}, [preselected])
|
|
50
|
-
|
|
51
|
-
function selectDate(dateRange: DateRange | undefined) {
|
|
52
|
-
setSelected(dateRange)
|
|
53
|
-
onSelect(dateRange)
|
|
54
|
-
}
|
|
56
|
+
setSelected(toDateRange(defaultValue))
|
|
57
|
+
}, [defaultValue])
|
|
55
58
|
|
|
56
59
|
return (
|
|
57
60
|
<DayPicker
|
|
58
|
-
className={
|
|
61
|
+
className={cssClasses}
|
|
59
62
|
locale={availableLocales[lng]}
|
|
60
63
|
mode="range"
|
|
61
64
|
min={1}
|
|
62
65
|
selected={selected}
|
|
63
|
-
onSelect={
|
|
64
|
-
footer={
|
|
66
|
+
onSelect={selectDate}
|
|
67
|
+
footer={<Footer lng={lng} selected={selected} />}
|
|
65
68
|
defaultMonth={selected?.from}
|
|
69
|
+
required={required}
|
|
66
70
|
/>
|
|
67
71
|
)
|
|
68
72
|
}
|
|
73
|
+
function Footer({
|
|
74
|
+
lng,
|
|
75
|
+
selected,
|
|
76
|
+
}: {
|
|
77
|
+
lng: Locale
|
|
78
|
+
selected: DateRangeReactDayPicker | undefined
|
|
79
|
+
}): string {
|
|
80
|
+
if (!selected?.from && !selected?.to) {
|
|
81
|
+
return translations[lng].pickDate
|
|
82
|
+
}
|
|
83
|
+
if (selected?.to && selected?.from?.getTime() !== selected?.to?.getTime()) {
|
|
84
|
+
return translations[lng].selectedRangeOfDates
|
|
85
|
+
.replace(
|
|
86
|
+
'${from}',
|
|
87
|
+
formatDatePickerFooterDate(selected?.from, lng as string),
|
|
88
|
+
)
|
|
89
|
+
.replace('${to}', formatDatePickerFooterDate(selected?.to, lng as string))
|
|
90
|
+
}
|
|
91
|
+
return translations[lng].selectedOnlyFrom.replace(
|
|
92
|
+
'${from}',
|
|
93
|
+
formatDatePickerFooterDate(selected?.from, lng as string),
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function toDateRange(
|
|
98
|
+
dateRange: DateRange | undefined,
|
|
99
|
+
): DateRangeReactDayPicker {
|
|
100
|
+
return {
|
|
101
|
+
from: fromISOToDate(dateRange?.from),
|
|
102
|
+
to: fromISOToDate(dateRange?.to),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function toDateRangeISO(dateRange: DateRangeReactDayPicker): DateRange {
|
|
107
|
+
return {
|
|
108
|
+
from: fromDateToISOString(dateRange?.from),
|
|
109
|
+
to: fromDateToISOString(dateRange?.to),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -1,69 +1,63 @@
|
|
|
1
1
|
import 'react-day-picker/style.css'
|
|
2
|
-
import
|
|
2
|
+
import './DatePicker.scss'
|
|
3
|
+
import { useState } from 'react'
|
|
3
4
|
import { DayPicker } from 'react-day-picker'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
className
|
|
5
|
+
import { classNames } from '../../utils/classNames'
|
|
6
|
+
import {
|
|
7
|
+
formatDatePickerFooterDate,
|
|
8
|
+
fromDateToISOString,
|
|
9
|
+
fromISOToDate,
|
|
10
|
+
} from '../../utils/dateHelpers'
|
|
11
|
+
import { availableLocales, type Locale, translations } from './translations'
|
|
12
|
+
|
|
13
|
+
export type Variant = 'primary'
|
|
14
|
+
|
|
15
|
+
export type DateSinglePickerProps = {
|
|
16
|
+
variant?: Variant
|
|
17
|
+
lng: Locale
|
|
18
|
+
required?: boolean
|
|
19
|
+
className?: string
|
|
20
|
+
defaultValue?: string
|
|
21
|
+
onSelect?: (date: string) => void
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
export function DateSinglePicker({
|
|
22
|
-
onSelect
|
|
23
|
-
|
|
25
|
+
onSelect,
|
|
26
|
+
defaultValue,
|
|
24
27
|
lng,
|
|
25
28
|
className,
|
|
29
|
+
required = false,
|
|
30
|
+
variant,
|
|
26
31
|
}: DateSinglePickerProps): React.JSX.Element {
|
|
27
|
-
const
|
|
28
|
-
if (!selected) return translations[lng].pickSingleDate
|
|
29
|
-
|
|
30
|
-
return translations[lng].selectedDate.replace(
|
|
31
|
-
'${date}',
|
|
32
|
-
formatDatePickerFooterDate(selected, lng as string),
|
|
33
|
-
)
|
|
34
|
-
}
|
|
32
|
+
const cssClasses = classNames('date-picker', variant, className)
|
|
35
33
|
|
|
36
|
-
const [selected, setSelected] = useState<Date | undefined>(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return manageFooterText()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
setSelected(preselected)
|
|
44
|
-
setMonth(preselected)
|
|
45
|
-
setFooter(manageFooterText())
|
|
46
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
47
|
-
}, [preselected])
|
|
34
|
+
const [selected, setSelected] = useState<Date | undefined>(
|
|
35
|
+
fromISOToDate(defaultValue),
|
|
36
|
+
)
|
|
48
37
|
|
|
49
38
|
function selectDate(date: Date | undefined) {
|
|
50
39
|
setSelected(date)
|
|
51
|
-
|
|
52
|
-
onSelect(date)
|
|
40
|
+
onSelect?.(fromDateToISOString(date))
|
|
53
41
|
}
|
|
54
42
|
|
|
55
43
|
return (
|
|
56
44
|
<DayPicker
|
|
57
|
-
className={
|
|
45
|
+
className={cssClasses}
|
|
58
46
|
locale={availableLocales[lng]}
|
|
59
47
|
mode="single"
|
|
60
48
|
selected={selected}
|
|
61
|
-
onSelect={
|
|
62
|
-
footer={
|
|
63
|
-
required
|
|
64
|
-
month={month}
|
|
65
|
-
onMonthChange={(date) => setMonth(date)}
|
|
49
|
+
onSelect={selectDate}
|
|
50
|
+
footer={<Footer lng={lng} selected={selected} />}
|
|
51
|
+
required={required}
|
|
66
52
|
defaultMonth={selected}
|
|
67
53
|
/>
|
|
68
54
|
)
|
|
69
55
|
}
|
|
56
|
+
function Footer({ lng, selected }: { selected?: Date; lng: Locale }): string {
|
|
57
|
+
if (!selected) return translations[lng].pickSingleDate
|
|
58
|
+
|
|
59
|
+
return translations[lng].selectedDate.replace(
|
|
60
|
+
'${date}',
|
|
61
|
+
formatDatePickerFooterDate(selected, lng as string),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { DateRange, DateRangePickerProps } from './DateRangePicker'
|
|
2
|
+
export type { DateSinglePickerProps } from './DateSinglePicker'
|
|
3
|
+
|
|
4
|
+
import { DateRangePicker } from './DateRangePicker'
|
|
5
|
+
import { DateSinglePicker } from './DateSinglePicker'
|
|
6
|
+
|
|
7
|
+
export { DateRangePicker, DateSinglePicker }
|
|
@@ -1,18 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { type Locale as LocaleReactDayPicker } from 'react-day-picker'
|
|
2
|
+
import { enGB, es } from 'react-day-picker/locale'
|
|
3
|
+
|
|
4
|
+
export interface Translation {
|
|
2
5
|
[index: string]: { [index: string]: string }
|
|
3
6
|
}
|
|
4
7
|
|
|
8
|
+
export interface AvailableLocale {
|
|
9
|
+
[index: string]: LocaleReactDayPicker
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const availableLocales: AvailableLocale = {
|
|
13
|
+
es: es,
|
|
14
|
+
en: enGB,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Locale = keyof typeof availableLocales
|
|
18
|
+
|
|
5
19
|
export const translations: Translation = {
|
|
6
20
|
en: {
|
|
7
21
|
pickDate: 'Pick a day or a range of dates',
|
|
8
22
|
pickSingleDate: 'Pick a date',
|
|
9
23
|
selectedDate: 'Selected date: ${date}',
|
|
10
24
|
selectedRangeOfDates: 'Selected dates range: from ${from} to ${to}',
|
|
25
|
+
selectedOnlyFrom: 'Selected dates range: from ${from}',
|
|
11
26
|
},
|
|
12
27
|
es: {
|
|
13
28
|
pickDate: 'Selecciona un día o un rango de fechas',
|
|
14
29
|
pickSingleDate: 'Selecciona una fecha',
|
|
15
30
|
selectedDate: 'Fecha seleccionada: ${date}',
|
|
16
31
|
selectedRangeOfDates: 'Rango de fechas seleccionado: desde ${from} a ${to}',
|
|
32
|
+
selectedOnlyFrom: 'Rango de fechas seleccionado: desde ${from}',
|
|
17
33
|
},
|
|
18
34
|
}
|
|
@@ -4,6 +4,19 @@ import { Meta } from "@storybook/blocks";
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
## 0.31.8
|
|
8
|
+
|
|
9
|
+
* Refactor Modal component to use HTML dialog
|
|
10
|
+
|
|
11
|
+
## 0.31.7
|
|
12
|
+
|
|
13
|
+
* Fixed date clearing event in range and added a new translation to the footer for the first day of the selected range.
|
|
14
|
+
* Refactoring of types and translations and reduction of state logic in components
|
|
15
|
+
* Refactoring dateHelpers functions for convert dates to ISO format and ISO format to dates
|
|
16
|
+
* DateRangePicker and DateSinglePicker separation in two different components.
|
|
17
|
+
* Updating stories for DateRangePicker and DateSinglePicker
|
|
18
|
+
* Updating test for DateRangePicker and DateSinglePicker
|
|
19
|
+
|
|
7
20
|
## 0.31.6
|
|
8
21
|
|
|
9
22
|
* Refactor styles and fix range day selection
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { StoryObj } from '@storybook/react'
|
|
2
|
-
import {
|
|
2
|
+
import { DateRangePicker } from '../atoms/DatePicker/DateRangePicker'
|
|
3
3
|
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Atoms/
|
|
6
|
-
component:
|
|
5
|
+
title: 'Design System/Atoms/DateRangePicker',
|
|
6
|
+
component: DateRangePicker,
|
|
7
7
|
parameters: {
|
|
8
8
|
docs: {
|
|
9
9
|
description: {
|
|
@@ -26,8 +26,11 @@ const meta = {
|
|
|
26
26
|
lng: {
|
|
27
27
|
description: 'String with the locale to be used on the translations',
|
|
28
28
|
},
|
|
29
|
-
|
|
30
|
-
description: '
|
|
29
|
+
required: {
|
|
30
|
+
description: 'Optional parametre for required pick date',
|
|
31
|
+
},
|
|
32
|
+
className: {
|
|
33
|
+
description: 'Optional parametre for add styles by className',
|
|
31
34
|
},
|
|
32
35
|
},
|
|
33
36
|
}
|
|
@@ -42,32 +45,11 @@ const figmaPrimaryDesign = {
|
|
|
42
45
|
export default meta
|
|
43
46
|
type Story = StoryObj<typeof meta>
|
|
44
47
|
|
|
45
|
-
export const SingleDatePicker: Story = {
|
|
46
|
-
args: {
|
|
47
|
-
variant: 'primary',
|
|
48
|
-
onSelect: (date) => console.log('onSelect date:', date),
|
|
49
|
-
lng: 'en',
|
|
50
|
-
type: 'single',
|
|
51
|
-
},
|
|
52
|
-
}
|
|
53
|
-
|
|
54
48
|
export const RangeDatePicker: Story = {
|
|
55
49
|
args: {
|
|
56
50
|
variant: 'primary',
|
|
57
51
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
58
52
|
lng: 'en',
|
|
59
|
-
type: 'range',
|
|
60
|
-
},
|
|
61
|
-
parameters: figmaPrimaryDesign,
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const WithSingleDaySelected: Story = {
|
|
65
|
-
args: {
|
|
66
|
-
variant: 'primary',
|
|
67
|
-
onSelect: (date) => console.log('onSelect date:', date),
|
|
68
|
-
selected: new Date(2024, 1, 2),
|
|
69
|
-
lng: 'en',
|
|
70
|
-
type: 'single',
|
|
71
53
|
},
|
|
72
54
|
parameters: figmaPrimaryDesign,
|
|
73
55
|
}
|
|
@@ -76,9 +58,8 @@ export const WithRangeDateSelected: Story = {
|
|
|
76
58
|
args: {
|
|
77
59
|
variant: 'primary',
|
|
78
60
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
79
|
-
|
|
61
|
+
defaultValue: { from: '2024-01-02', to: '2024-01-12' },
|
|
80
62
|
lng: 'en',
|
|
81
|
-
type: 'range',
|
|
82
63
|
},
|
|
83
64
|
parameters: figmaPrimaryDesign,
|
|
84
65
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/react'
|
|
2
|
+
import { DateSinglePicker } from '../atoms/DatePicker/DateSinglePicker'
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Atoms/DateSinglePicker',
|
|
6
|
+
component: DateSinglePicker,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'<h2>Usage guidelines</h2><p>DateRangePicker component allows users to select past, present, or future dates in a visual way in range or single format.</p>',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
tags: ['autodocs'],
|
|
16
|
+
argTypes: {
|
|
17
|
+
variant: {
|
|
18
|
+
description: 'Component variant used',
|
|
19
|
+
},
|
|
20
|
+
onSelect: {
|
|
21
|
+
description: 'Component onSelect callback',
|
|
22
|
+
},
|
|
23
|
+
selected: {
|
|
24
|
+
description: 'Selected date or date range',
|
|
25
|
+
},
|
|
26
|
+
lng: {
|
|
27
|
+
description: 'String with the locale to be used on the translations',
|
|
28
|
+
},
|
|
29
|
+
required: {
|
|
30
|
+
description: 'Optional parametre for required pick date',
|
|
31
|
+
},
|
|
32
|
+
className: {
|
|
33
|
+
description: 'Optional parametre for add styles by className',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const figmaPrimaryDesign = {
|
|
39
|
+
design: {
|
|
40
|
+
type: 'figma',
|
|
41
|
+
url: 'https://www.figma.com/design/DN2ova21vWqCRvPspBXgI1/Design-System?node-id=3665-571&m=dev',
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default meta
|
|
46
|
+
type Story = StoryObj<typeof meta>
|
|
47
|
+
|
|
48
|
+
export const SingleDatePicker: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
variant: 'primary',
|
|
51
|
+
onSelect: (date) => console.log('onSelect date:', date),
|
|
52
|
+
lng: 'en',
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const WithSingleDaySelected: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
variant: 'primary',
|
|
59
|
+
onSelect: (date) => console.log('onSelect date:', date),
|
|
60
|
+
defaultValue: '2024-01-20',
|
|
61
|
+
lng: 'en',
|
|
62
|
+
},
|
|
63
|
+
parameters: figmaPrimaryDesign,
|
|
64
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { CheckableTag, CheckableTagGroup } from '../atoms/CheckableTag'
|
|
3
3
|
import { Collapsible } from '../atoms/Collapsible'
|
|
4
|
-
import {
|
|
4
|
+
import { DateRangePicker } from '../atoms/DatePicker/DateRangePicker'
|
|
5
5
|
import { Drawer } from '../atoms/Drawer'
|
|
6
6
|
|
|
7
7
|
const figmaPrimaryDesign = {
|
|
@@ -130,10 +130,9 @@ export const Filters = {
|
|
|
130
130
|
</Collapsible>
|
|
131
131
|
<Collapsible noHorizontalPadding open title="Date">
|
|
132
132
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
|
133
|
-
<
|
|
133
|
+
<DateRangePicker
|
|
134
134
|
selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
|
|
135
135
|
onSelect={(date) => console.log('date: ', date)}
|
|
136
|
-
type="range"
|
|
137
136
|
lng="en"
|
|
138
137
|
/>
|
|
139
138
|
</div>
|