agroptima-design-system 0.28.7 → 0.29.0
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.scss → DatePicker/DateRangePicker.scss} +5 -5
- package/src/atoms/DatePicker/DateRangePicker.tsx +102 -0
- package/src/atoms/DatePicker/translations.ts +16 -0
- package/src/stories/Changelog.mdx +5 -1
- package/src/stories/DatePicker.stories.ts +14 -6
- package/src/stories/Drawer.stories.js +3 -3
- package/src/utils/dateHelpers.ts +19 -0
- package/tests/{DatePicker.spec.tsx → DateRangePicker.spec.tsx} +7 -6
- package/src/atoms/DatePicker.tsx +0 -66
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
@use '
|
|
2
|
-
@use '
|
|
3
|
-
@use '
|
|
4
|
-
@use '
|
|
5
|
-
@use '
|
|
1
|
+
@use '../../settings/color_alias';
|
|
2
|
+
@use '../../settings/typography/content' as typography;
|
|
3
|
+
@use '../../settings/config';
|
|
4
|
+
@use '../../settings/depth';
|
|
5
|
+
@use '../../settings/breakpoints';
|
|
6
6
|
|
|
7
7
|
// Interpolation applied: https://sass-lang.com/documentation/breaking-changes/css-vars/
|
|
8
8
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import 'react-day-picker/style.css'
|
|
2
|
+
import './DateRangePicker.scss'
|
|
3
|
+
import { useEffect, useState } from 'react'
|
|
4
|
+
import { type DateRange, DayPicker, type Locale } from 'react-day-picker'
|
|
5
|
+
import { enGB, es } from 'react-day-picker/locale'
|
|
6
|
+
import { classNames } from '../../utils/classNames'
|
|
7
|
+
import {
|
|
8
|
+
formatDatePickerFooterDate,
|
|
9
|
+
formatDatePickerParamsDate,
|
|
10
|
+
} from '../../utils/dateHelpers'
|
|
11
|
+
import { translations } from './translations'
|
|
12
|
+
|
|
13
|
+
export type Variant = 'primary'
|
|
14
|
+
|
|
15
|
+
type DivPropsWithoutOnSelect = Omit<
|
|
16
|
+
React.ComponentPropsWithoutRef<'div'>,
|
|
17
|
+
'onSelect'
|
|
18
|
+
>
|
|
19
|
+
|
|
20
|
+
interface AvailableLocale {
|
|
21
|
+
[index: string]: Locale
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const availableLocales: AvailableLocale = {
|
|
25
|
+
es: es,
|
|
26
|
+
en: enGB,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DateRangePickerProps extends DivPropsWithoutOnSelect {
|
|
30
|
+
variant?: Variant
|
|
31
|
+
onSelect: (dateRange: DateRange | undefined) => void
|
|
32
|
+
selected?: DateRange
|
|
33
|
+
lng: keyof typeof availableLocales
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function DateRangePicker({
|
|
37
|
+
className,
|
|
38
|
+
variant = 'primary',
|
|
39
|
+
onSelect = () => {},
|
|
40
|
+
selected: preselected,
|
|
41
|
+
lng,
|
|
42
|
+
}: DateRangePickerProps): React.JSX.Element {
|
|
43
|
+
const manageFooterText = (): string => {
|
|
44
|
+
const hasDatesFilter = selected && selected.from && selected.to
|
|
45
|
+
const isExactDate =
|
|
46
|
+
formatDatePickerParamsDate(selected?.from) ===
|
|
47
|
+
formatDatePickerParamsDate(selected?.to)
|
|
48
|
+
|
|
49
|
+
if (!hasDatesFilter) return translations[lng].pickDate
|
|
50
|
+
|
|
51
|
+
if (isExactDate) {
|
|
52
|
+
return translations[lng].selectedDate.replace(
|
|
53
|
+
'${date}',
|
|
54
|
+
formatDatePickerFooterDate(selected.from, lng as string),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return translations[lng].selectedRangeOfDates
|
|
59
|
+
.replace(
|
|
60
|
+
'${from}',
|
|
61
|
+
formatDatePickerFooterDate(selected.from, lng as string),
|
|
62
|
+
)
|
|
63
|
+
.replace('${to}', formatDatePickerFooterDate(selected.to, lng as string))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const [selected, setSelected] = useState<DateRange | undefined>(preselected)
|
|
67
|
+
const [footer, setFooter] = useState<string>(() => {
|
|
68
|
+
return manageFooterText()
|
|
69
|
+
})
|
|
70
|
+
const cssClasses = classNames('date-picker', variant, className)
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
setSelected(preselected)
|
|
74
|
+
setFooter(manageFooterText())
|
|
75
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
76
|
+
}, [preselected])
|
|
77
|
+
|
|
78
|
+
function selectDate(dateRange: DateRange | undefined) {
|
|
79
|
+
const isSingleDaySelection = dateRange && !dateRange.to
|
|
80
|
+
|
|
81
|
+
if (isSingleDaySelection) {
|
|
82
|
+
dateRange.to = dateRange.from
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setSelected(dateRange)
|
|
86
|
+
onSelect(dateRange)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div className={cssClasses}>
|
|
91
|
+
<DayPicker
|
|
92
|
+
locale={availableLocales[lng]}
|
|
93
|
+
mode="range"
|
|
94
|
+
min={1}
|
|
95
|
+
selected={selected}
|
|
96
|
+
onSelect={(dateRange) => selectDate(dateRange)}
|
|
97
|
+
footer={footer}
|
|
98
|
+
defaultMonth={selected?.from}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface Translation {
|
|
2
|
+
[index: string]: { [index: string]: string }
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const translations: Translation = {
|
|
6
|
+
en: {
|
|
7
|
+
pickDate: 'Pick a day or a range of dates',
|
|
8
|
+
selectedDate: 'Selected date: ${date}',
|
|
9
|
+
selectedRangeOfDates: 'Selected dates range: from ${from} to ${to}',
|
|
10
|
+
},
|
|
11
|
+
es: {
|
|
12
|
+
pickDate: 'Selecciona un día o un rango de fechas',
|
|
13
|
+
selectedDate: 'Fecha seleccionada: ${date}',
|
|
14
|
+
selectedRangeOfDates: 'Rango de fechas seleccionado: desde ${from} a ${to}',
|
|
15
|
+
},
|
|
16
|
+
}
|
|
@@ -4,10 +4,14 @@ import { Meta } from "@storybook/blocks";
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
-
## 0.
|
|
7
|
+
## 0.29.0
|
|
8
8
|
|
|
9
9
|
* Add Divider component
|
|
10
10
|
|
|
11
|
+
## 0.28.7
|
|
12
|
+
|
|
13
|
+
* DateRangePicker component manages its footer text
|
|
14
|
+
|
|
11
15
|
## 0.28.6
|
|
12
16
|
|
|
13
17
|
* Remove overflow-x from html element for Modal component.
|
|
@@ -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
|
tags: ['autodocs'],
|
|
8
8
|
argTypes: {
|
|
9
9
|
footer: {
|
|
@@ -34,10 +34,9 @@ const figmaPrimaryDesign = {
|
|
|
34
34
|
export default meta
|
|
35
35
|
type Story = StoryObj<typeof meta>
|
|
36
36
|
|
|
37
|
-
export const
|
|
37
|
+
export const Primary: Story = {
|
|
38
38
|
args: {
|
|
39
39
|
variant: 'primary',
|
|
40
|
-
footer: 'Pick a day.',
|
|
41
40
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
42
41
|
lng: 'en',
|
|
43
42
|
},
|
|
@@ -47,10 +46,19 @@ export const PrimaryDateRange: Story = {
|
|
|
47
46
|
export const WithDateRangeSelected: Story = {
|
|
48
47
|
args: {
|
|
49
48
|
variant: 'primary',
|
|
50
|
-
footer: 'From 2024-02-02 to 2024-02-15',
|
|
51
49
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
52
50
|
selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 15) },
|
|
53
51
|
lng: 'en',
|
|
54
52
|
},
|
|
55
53
|
parameters: figmaPrimaryDesign,
|
|
56
54
|
}
|
|
55
|
+
|
|
56
|
+
export const WithSingleDaySelected: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
variant: 'primary',
|
|
59
|
+
onSelect: (date) => console.log('onSelect date:', date),
|
|
60
|
+
selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 2) },
|
|
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 = {
|
|
@@ -122,10 +122,10 @@ export const Filters = {
|
|
|
122
122
|
</Collapsible>
|
|
123
123
|
<Collapsible noHorizontalPadding open title="Date">
|
|
124
124
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
|
125
|
-
<
|
|
126
|
-
footer="From 2024-01-01 to 2024-01-15"
|
|
125
|
+
<DateRangePicker
|
|
127
126
|
selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
|
|
128
127
|
onSelect={(date) => console.log('date: ', date)}
|
|
128
|
+
lng="en"
|
|
129
129
|
/>
|
|
130
130
|
</div>
|
|
131
131
|
</Collapsible>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function formatDate(date: string, lng: string) {
|
|
2
|
+
if (!date) return ''
|
|
3
|
+
return new Date(date).toLocaleDateString(lng)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function formatDatePickerParamsDate(date: Date | undefined) {
|
|
7
|
+
if (!date) return ''
|
|
8
|
+
|
|
9
|
+
return date.toLocaleDateString('sv-SE')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function formatDatePickerFooterDate(
|
|
13
|
+
date: Date | undefined,
|
|
14
|
+
lng: string,
|
|
15
|
+
) {
|
|
16
|
+
if (!date) return ''
|
|
17
|
+
|
|
18
|
+
return formatDate(formatDatePickerParamsDate(date), lng)
|
|
19
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { render } from '@testing-library/react'
|
|
1
|
+
import { getAllByRole, render } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
|
-
import {
|
|
3
|
+
import { DateRangePicker } from '../src/atoms/DatePicker/DateRangePicker'
|
|
4
4
|
|
|
5
|
-
describe('
|
|
5
|
+
describe('DateRangePicker', () => {
|
|
6
6
|
it('renders with expected footer, language and month', () => {
|
|
7
7
|
const { getByText } = render(
|
|
8
|
-
<
|
|
9
|
-
footer="From 2024-01-01 to 2024-01-15"
|
|
8
|
+
<DateRangePicker
|
|
10
9
|
selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
|
|
11
10
|
onSelect={() => jest.fn()}
|
|
12
11
|
lng={'es'}
|
|
@@ -20,6 +19,8 @@ describe('DatePicker', () => {
|
|
|
20
19
|
expect(getByText('vi')).toBeInTheDocument()
|
|
21
20
|
expect(getByText('sá')).toBeInTheDocument()
|
|
22
21
|
expect(getByText('do')).toBeInTheDocument()
|
|
23
|
-
expect(
|
|
22
|
+
expect(
|
|
23
|
+
getByText('Rango de fechas seleccionado: desde 1/1/2025 a 15/1/2025'),
|
|
24
|
+
).toBeInTheDocument()
|
|
24
25
|
})
|
|
25
26
|
})
|
package/src/atoms/DatePicker.tsx
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import 'react-day-picker/style.css'
|
|
2
|
-
import './DatePicker.scss'
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
-
import { type DateRange, DayPicker, type Locale } from 'react-day-picker'
|
|
5
|
-
import { enGB, es } from 'react-day-picker/locale'
|
|
6
|
-
import { classNames } from '../utils/classNames'
|
|
7
|
-
|
|
8
|
-
export type Variant = 'primary'
|
|
9
|
-
|
|
10
|
-
type DivPropsWithoutOnSelect = Omit<
|
|
11
|
-
React.ComponentPropsWithoutRef<'div'>,
|
|
12
|
-
'onSelect'
|
|
13
|
-
>
|
|
14
|
-
|
|
15
|
-
interface AvailableLocale {
|
|
16
|
-
[index: string]: Locale
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const availableLocales: AvailableLocale = {
|
|
20
|
-
es: es,
|
|
21
|
-
en: enGB,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface DatePickerProps extends DivPropsWithoutOnSelect {
|
|
25
|
-
variant?: Variant
|
|
26
|
-
onSelect: (dateRange: DateRange | undefined) => void
|
|
27
|
-
footer: string
|
|
28
|
-
selected?: DateRange
|
|
29
|
-
lng: keyof typeof availableLocales
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function DatePicker({
|
|
33
|
-
className,
|
|
34
|
-
variant = 'primary',
|
|
35
|
-
onSelect = () => {},
|
|
36
|
-
footer = 'Pick a day',
|
|
37
|
-
selected: preselected,
|
|
38
|
-
lng,
|
|
39
|
-
}: DatePickerProps): React.JSX.Element {
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
setSelected(preselected)
|
|
42
|
-
}, [preselected])
|
|
43
|
-
|
|
44
|
-
const cssClasses = classNames('date-picker', variant, className)
|
|
45
|
-
|
|
46
|
-
const [selected, setSelected] = useState<DateRange | undefined>(preselected)
|
|
47
|
-
|
|
48
|
-
function selectDate(dateRange: DateRange | undefined) {
|
|
49
|
-
setSelected(dateRange)
|
|
50
|
-
onSelect(dateRange)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<div className={cssClasses}>
|
|
55
|
-
<DayPicker
|
|
56
|
-
locale={availableLocales[lng]}
|
|
57
|
-
mode="range"
|
|
58
|
-
min={1}
|
|
59
|
-
selected={selected}
|
|
60
|
-
onSelect={(dateRange) => selectDate(dateRange)}
|
|
61
|
-
footer={footer}
|
|
62
|
-
defaultMonth={selected?.from}
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
65
|
-
)
|
|
66
|
-
}
|