agroptima-design-system 0.29.3-beta.4 → 0.30.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/DateRangePicker.tsx +40 -5
- package/src/atoms/DatePicker/translations.ts +0 -2
- package/src/atoms/Input.scss +0 -5
- package/src/atoms/Switch.scss +98 -0
- package/src/atoms/Switch.tsx +51 -0
- package/src/stories/Changelog.mdx +2 -6
- package/src/stories/DatePicker.stories.ts +11 -23
- package/src/stories/Input.stories.ts +0 -9
- package/src/stories/Switch.stories.ts +93 -0
- package/tests/DateRangePicker.spec.tsx +26 -0
- package/tests/Switch.spec.tsx +35 -0
- package/src/atoms/DatePicker/DatePicker.tsx +0 -75
- package/src/atoms/DatePicker/DateSinglePicker.tsx +0 -75
- package/tests/DatePicker.spec.tsx +0 -48
- /package/src/atoms/DatePicker/{DatePicker.scss → DateRangePicker.scss} +0 -0
package/package.json
CHANGED
|
@@ -1,32 +1,60 @@
|
|
|
1
1
|
import 'react-day-picker/style.css'
|
|
2
|
+
import './DateRangePicker.scss'
|
|
2
3
|
import { useEffect, useState } from 'react'
|
|
3
4
|
import { type DateRange, DayPicker, type Locale } from 'react-day-picker'
|
|
4
5
|
import { enGB, es } from 'react-day-picker/locale'
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
6
|
+
import { classNames } from '../../utils/classNames'
|
|
7
|
+
import {
|
|
8
|
+
formatDatePickerFooterDate,
|
|
9
|
+
formatDatePickerParamsDate,
|
|
10
|
+
} from '../../utils/dateHelpers'
|
|
7
11
|
import { translations } from './translations'
|
|
8
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
|
+
|
|
9
24
|
const availableLocales: AvailableLocale = {
|
|
10
25
|
es: es,
|
|
11
26
|
en: enGB,
|
|
12
27
|
}
|
|
13
28
|
|
|
14
|
-
export interface DateRangePickerProps {
|
|
29
|
+
export interface DateRangePickerProps extends DivPropsWithoutOnSelect {
|
|
30
|
+
variant?: Variant
|
|
15
31
|
onSelect: (dateRange: DateRange | undefined) => void
|
|
16
32
|
selected?: DateRange
|
|
17
33
|
lng: keyof typeof availableLocales
|
|
18
34
|
}
|
|
19
35
|
|
|
20
36
|
export function DateRangePicker({
|
|
37
|
+
className,
|
|
38
|
+
variant = 'primary',
|
|
21
39
|
onSelect = () => {},
|
|
22
40
|
selected: preselected,
|
|
23
41
|
lng,
|
|
24
42
|
}: DateRangePickerProps): React.JSX.Element {
|
|
25
43
|
const manageFooterText = (): string => {
|
|
26
44
|
const hasDatesFilter = selected && selected.from && selected.to
|
|
45
|
+
const isExactDate =
|
|
46
|
+
formatDatePickerParamsDate(selected?.from) ===
|
|
47
|
+
formatDatePickerParamsDate(selected?.to)
|
|
27
48
|
|
|
28
49
|
if (!hasDatesFilter) return translations[lng].pickDate
|
|
29
50
|
|
|
51
|
+
if (isExactDate) {
|
|
52
|
+
return translations[lng].selectedDate.replace(
|
|
53
|
+
'${date}',
|
|
54
|
+
formatDatePickerFooterDate(selected.from, lng as string),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
30
58
|
return translations[lng].selectedRangeOfDates
|
|
31
59
|
.replace(
|
|
32
60
|
'${from}',
|
|
@@ -39,6 +67,7 @@ export function DateRangePicker({
|
|
|
39
67
|
const [footer, setFooter] = useState<string>(() => {
|
|
40
68
|
return manageFooterText()
|
|
41
69
|
})
|
|
70
|
+
const cssClasses = classNames('date-picker', variant, className)
|
|
42
71
|
|
|
43
72
|
useEffect(() => {
|
|
44
73
|
setSelected(preselected)
|
|
@@ -47,12 +76,18 @@ export function DateRangePicker({
|
|
|
47
76
|
}, [preselected])
|
|
48
77
|
|
|
49
78
|
function selectDate(dateRange: DateRange | undefined) {
|
|
79
|
+
const isSingleDaySelection = dateRange && !dateRange.to
|
|
80
|
+
|
|
81
|
+
if (isSingleDaySelection) {
|
|
82
|
+
dateRange.to = dateRange.from
|
|
83
|
+
}
|
|
84
|
+
|
|
50
85
|
setSelected(dateRange)
|
|
51
86
|
onSelect(dateRange)
|
|
52
87
|
}
|
|
53
88
|
|
|
54
89
|
return (
|
|
55
|
-
|
|
90
|
+
<div className={cssClasses}>
|
|
56
91
|
<DayPicker
|
|
57
92
|
locale={availableLocales[lng]}
|
|
58
93
|
mode="range"
|
|
@@ -62,6 +97,6 @@ export function DateRangePicker({
|
|
|
62
97
|
footer={footer}
|
|
63
98
|
defaultMonth={selected?.from}
|
|
64
99
|
/>
|
|
65
|
-
|
|
100
|
+
</div>
|
|
66
101
|
)
|
|
67
102
|
}
|
|
@@ -5,13 +5,11 @@ interface Translation {
|
|
|
5
5
|
export const translations: Translation = {
|
|
6
6
|
en: {
|
|
7
7
|
pickDate: 'Pick a day or a range of dates',
|
|
8
|
-
pickSingleDate: 'Pick a date',
|
|
9
8
|
selectedDate: 'Selected date: ${date}',
|
|
10
9
|
selectedRangeOfDates: 'Selected dates range: from ${from} to ${to}',
|
|
11
10
|
},
|
|
12
11
|
es: {
|
|
13
12
|
pickDate: 'Selecciona un día o un rango de fechas',
|
|
14
|
-
pickSingleDate: 'Selecciona una fecha',
|
|
15
13
|
selectedDate: 'Fecha seleccionada: ${date}',
|
|
16
14
|
selectedRangeOfDates: 'Rango de fechas seleccionado: desde ${from} a ${to}',
|
|
17
15
|
},
|
package/src/atoms/Input.scss
CHANGED
|
@@ -36,12 +36,7 @@
|
|
|
36
36
|
padding: config.$space-2x config.$space-3x config.$space-2x;
|
|
37
37
|
input[type='date'] {
|
|
38
38
|
min-width: -webkit-fill-available;
|
|
39
|
-
|
|
40
39
|
}
|
|
41
|
-
input[type='date']::-webkit-calendar-picker-indicator {
|
|
42
|
-
display: none;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
40
|
input[type='number'] {
|
|
46
41
|
text-align: right;
|
|
47
42
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
@use '../settings/color_alias';
|
|
2
|
+
@use '../settings/typography/form' as typography;
|
|
3
|
+
@use '../settings/config';
|
|
4
|
+
|
|
5
|
+
.switch-group {
|
|
6
|
+
@include typography.checkbox-label;
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: space-between;
|
|
9
|
+
align-items: center;
|
|
10
|
+
width: 100%;
|
|
11
|
+
gap: config.$space-1x;
|
|
12
|
+
|
|
13
|
+
.switch {
|
|
14
|
+
-webkit-appearance: none;
|
|
15
|
+
-moz-appearance: none;
|
|
16
|
+
appearance: none;
|
|
17
|
+
position: relative;
|
|
18
|
+
font-size: inherit;
|
|
19
|
+
box-sizing: content-box;
|
|
20
|
+
border-radius: 1em;
|
|
21
|
+
vertical-align: text-bottom;
|
|
22
|
+
color: inherit;
|
|
23
|
+
|
|
24
|
+
&::before {
|
|
25
|
+
content: '';
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: 50%;
|
|
28
|
+
left: 0;
|
|
29
|
+
transform: translate(0, -50%);
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
border-radius: 50%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&.primary {
|
|
35
|
+
border: 1px solid color_alias.$neutral-color-800;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&.primary::before {
|
|
39
|
+
background-color: color_alias.$neutral-color-800;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&.primary:checked {
|
|
43
|
+
border: 1px solid color_alias.$primary-color-600;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&.primary:checked::before {
|
|
47
|
+
background-color: color_alias.$primary-color-600;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&.primary:disabled {
|
|
51
|
+
background-color: color_alias.$neutral-color-50;
|
|
52
|
+
border: 1px solid color_alias.$neutral-color-400;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&.primary:checked:disabled {
|
|
56
|
+
background-color: color_alias.$primary-color-50;
|
|
57
|
+
border: 1px solid color_alias.$primary-color-400;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&.primary:disabled::before {
|
|
61
|
+
background-color: color_alias.$neutral-color-400;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&.primary:checked:disabled::before {
|
|
65
|
+
background-color: color_alias.$primary-color-400;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&.medium {
|
|
69
|
+
width: 2.75em;
|
|
70
|
+
height: 1.375em;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&.medium::before {
|
|
74
|
+
width: 1.1em;
|
|
75
|
+
height: 1.1em;
|
|
76
|
+
margin: 0 0.15em;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.medium:checked::before {
|
|
80
|
+
left: 1.375em;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.small {
|
|
84
|
+
width: 1.75em;
|
|
85
|
+
height: 1em;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&.small::before {
|
|
89
|
+
width: 0.75em;
|
|
90
|
+
height: 0.75em;
|
|
91
|
+
margin: 0 0.15em;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&.small:checked::before {
|
|
95
|
+
left: 0.75em;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import './Switch.scss'
|
|
2
|
+
import { classNames } from '../utils/classNames'
|
|
3
|
+
|
|
4
|
+
export type Variant = 'primary'
|
|
5
|
+
export type Size = 'small' | 'medium'
|
|
6
|
+
|
|
7
|
+
type InputPropsWithoutSize = Omit<
|
|
8
|
+
React.ComponentPropsWithoutRef<'input'>,
|
|
9
|
+
'size'
|
|
10
|
+
>
|
|
11
|
+
|
|
12
|
+
export interface SwitchProps extends InputPropsWithoutSize {
|
|
13
|
+
label: string
|
|
14
|
+
accessibilityLabel?: string
|
|
15
|
+
hideLabel?: boolean
|
|
16
|
+
variant?: Variant
|
|
17
|
+
id?: string
|
|
18
|
+
size?: Size
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function Switch({
|
|
22
|
+
label,
|
|
23
|
+
accessibilityLabel,
|
|
24
|
+
hideLabel = false,
|
|
25
|
+
disabled,
|
|
26
|
+
variant = 'primary',
|
|
27
|
+
size = 'medium',
|
|
28
|
+
id,
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}: SwitchProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div className={classNames('switch-group', className)}>
|
|
34
|
+
<label
|
|
35
|
+
htmlFor={id}
|
|
36
|
+
className={classNames({ 'visually-hidden': hideLabel })}
|
|
37
|
+
>
|
|
38
|
+
{label}
|
|
39
|
+
</label>
|
|
40
|
+
<input
|
|
41
|
+
id={id}
|
|
42
|
+
type="checkbox"
|
|
43
|
+
className={classNames('switch', variant, size)}
|
|
44
|
+
disabled={disabled}
|
|
45
|
+
aria-label={accessibilityLabel || label}
|
|
46
|
+
role="switch"
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -4,13 +4,9 @@ import { Meta } from "@storybook/blocks";
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
-
## 0.
|
|
7
|
+
## 0.30.0
|
|
8
8
|
|
|
9
|
-
*
|
|
10
|
-
* Updated the footer message for a single day date picker.
|
|
11
|
-
* DatePicker component now is a wrapper for the single and range options to select.
|
|
12
|
-
* DateRangePicker component refactored to DatePicker.
|
|
13
|
-
* Change input component style for deleting calendar icon if is date type.
|
|
9
|
+
* Add Switch component
|
|
14
10
|
|
|
15
11
|
## 0.29.2
|
|
16
12
|
|
|
@@ -1,11 +1,14 @@
|
|
|
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
|
+
footer: {
|
|
10
|
+
description: 'Text for the footer',
|
|
11
|
+
},
|
|
9
12
|
variant: {
|
|
10
13
|
description: 'Component variant used',
|
|
11
14
|
},
|
|
@@ -18,9 +21,6 @@ const meta = {
|
|
|
18
21
|
lng: {
|
|
19
22
|
description: 'String with the locale to be used on the translations',
|
|
20
23
|
},
|
|
21
|
-
type: {
|
|
22
|
-
description: 'Type of date that could be range or single',
|
|
23
|
-
},
|
|
24
24
|
},
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -34,43 +34,31 @@ 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
40
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
41
41
|
lng: 'en',
|
|
42
|
-
type: 'single',
|
|
43
|
-
},
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const RangeDatePicker: Story = {
|
|
47
|
-
args: {
|
|
48
|
-
variant: 'primary',
|
|
49
|
-
onSelect: (date) => console.log('onSelect date:', date),
|
|
50
|
-
lng: 'en',
|
|
51
|
-
type: 'range',
|
|
52
42
|
},
|
|
53
43
|
parameters: figmaPrimaryDesign,
|
|
54
44
|
}
|
|
55
45
|
|
|
56
|
-
export const
|
|
46
|
+
export const WithDateRangeSelected: Story = {
|
|
57
47
|
args: {
|
|
58
48
|
variant: 'primary',
|
|
59
49
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
60
|
-
selected: new Date(2024, 1, 2),
|
|
50
|
+
selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 15) },
|
|
61
51
|
lng: 'en',
|
|
62
|
-
type: 'single',
|
|
63
52
|
},
|
|
64
53
|
parameters: figmaPrimaryDesign,
|
|
65
54
|
}
|
|
66
55
|
|
|
67
|
-
export const
|
|
56
|
+
export const WithSingleDaySelected: Story = {
|
|
68
57
|
args: {
|
|
69
58
|
variant: 'primary',
|
|
70
59
|
onSelect: (date) => console.log('onSelect date:', date),
|
|
71
|
-
selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1,
|
|
60
|
+
selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 2) },
|
|
72
61
|
lng: 'en',
|
|
73
|
-
type: 'range',
|
|
74
62
|
},
|
|
75
63
|
parameters: figmaPrimaryDesign,
|
|
76
64
|
}
|
|
@@ -124,12 +124,3 @@ export const WithSuffix: Story = {
|
|
|
124
124
|
},
|
|
125
125
|
parameters: figmaPrimaryDesign,
|
|
126
126
|
}
|
|
127
|
-
export const Date: Story = {
|
|
128
|
-
args: {
|
|
129
|
-
label: 'Input with date',
|
|
130
|
-
helpText: 'This text can help you',
|
|
131
|
-
name: 'price',
|
|
132
|
-
type: 'date',
|
|
133
|
-
},
|
|
134
|
-
parameters: figmaPrimaryDesign,
|
|
135
|
-
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/react'
|
|
2
|
+
import { Switch } from '../atoms/Switch'
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Atoms/Switch',
|
|
6
|
+
component: Switch,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
argTypes: {
|
|
9
|
+
accessibilityLabel: {
|
|
10
|
+
description: 'Accessible name & description of the element',
|
|
11
|
+
},
|
|
12
|
+
variant: {
|
|
13
|
+
description: 'Variant used from a list of values',
|
|
14
|
+
},
|
|
15
|
+
disabled: {
|
|
16
|
+
description: 'Is the component in disabled state?',
|
|
17
|
+
},
|
|
18
|
+
label: {
|
|
19
|
+
description: 'Label for the component',
|
|
20
|
+
},
|
|
21
|
+
id: {
|
|
22
|
+
description: 'Value needed for the label relation',
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
description: 'Medium or small sizes available',
|
|
26
|
+
},
|
|
27
|
+
hideLabel: {
|
|
28
|
+
description: 'Show or hide label?',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const figmaPrimaryDesign = {
|
|
34
|
+
design: {
|
|
35
|
+
type: 'figma',
|
|
36
|
+
url: 'https://www.figma.com/design/DN2ova21vWqCRvPspBXgI1/Design-System?node-id=3854-81&t=Hb5zHVDMclLNXeS6-4',
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default meta
|
|
41
|
+
type Story = StoryObj<typeof meta>
|
|
42
|
+
|
|
43
|
+
export const Primary: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
accessibilityLabel: 'Marks if the user likes videogames',
|
|
46
|
+
variant: 'primary',
|
|
47
|
+
disabled: false,
|
|
48
|
+
label: 'Do you like videogames?',
|
|
49
|
+
id: 'switch-videogames-preference',
|
|
50
|
+
onClick: (e) =>
|
|
51
|
+
console.log('onClick: ', (e.target as HTMLInputElement).checked),
|
|
52
|
+
},
|
|
53
|
+
parameters: figmaPrimaryDesign,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const PrimaryWithoutLabel: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
accessibilityLabel: 'Marks if the user likes videogames',
|
|
59
|
+
variant: 'primary',
|
|
60
|
+
disabled: false,
|
|
61
|
+
label: 'Do you like videogames?',
|
|
62
|
+
id: 'switch-videogames-preference',
|
|
63
|
+
hideLabel: true,
|
|
64
|
+
onClick: (e) =>
|
|
65
|
+
console.log('onClick: ', (e.target as HTMLInputElement).checked),
|
|
66
|
+
},
|
|
67
|
+
parameters: figmaPrimaryDesign,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const Disabled: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
accessibilityLabel: 'Marks if the user likes videogames',
|
|
73
|
+
variant: 'primary',
|
|
74
|
+
disabled: true,
|
|
75
|
+
label: 'Do you like videogames?',
|
|
76
|
+
id: 'switch-videogames-preference',
|
|
77
|
+
},
|
|
78
|
+
parameters: figmaPrimaryDesign,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const Small: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
accessibilityLabel: 'Marks if the user likes videogames',
|
|
84
|
+
variant: 'primary',
|
|
85
|
+
disabled: false,
|
|
86
|
+
label: 'Do you like videogames?',
|
|
87
|
+
id: 'switch-videogames-preference',
|
|
88
|
+
onClick: (e) =>
|
|
89
|
+
console.log('onClick: ', (e.target as HTMLInputElement).checked),
|
|
90
|
+
size: 'small',
|
|
91
|
+
},
|
|
92
|
+
parameters: figmaPrimaryDesign,
|
|
93
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getAllByRole, render } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { DateRangePicker } from '../src/atoms/DatePicker/DateRangePicker'
|
|
4
|
+
|
|
5
|
+
describe('DateRangePicker', () => {
|
|
6
|
+
it('renders with expected footer, language and month', () => {
|
|
7
|
+
const { getByText } = render(
|
|
8
|
+
<DateRangePicker
|
|
9
|
+
selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
|
|
10
|
+
onSelect={() => jest.fn()}
|
|
11
|
+
lng={'es'}
|
|
12
|
+
/>,
|
|
13
|
+
)
|
|
14
|
+
expect(getByText('enero 2025')).toBeInTheDocument()
|
|
15
|
+
expect(getByText('lu')).toBeInTheDocument()
|
|
16
|
+
expect(getByText('ma')).toBeInTheDocument()
|
|
17
|
+
expect(getByText('mi')).toBeInTheDocument()
|
|
18
|
+
expect(getByText('ju')).toBeInTheDocument()
|
|
19
|
+
expect(getByText('vi')).toBeInTheDocument()
|
|
20
|
+
expect(getByText('sá')).toBeInTheDocument()
|
|
21
|
+
expect(getByText('do')).toBeInTheDocument()
|
|
22
|
+
expect(
|
|
23
|
+
getByText('Rango de fechas seleccionado: desde 1/1/2025 a 15/1/2025'),
|
|
24
|
+
).toBeInTheDocument()
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Switch } from '../src/atoms/Switch'
|
|
4
|
+
|
|
5
|
+
describe('Switch', () => {
|
|
6
|
+
it('renders medium size', () => {
|
|
7
|
+
const { getByRole, getByText } = render(
|
|
8
|
+
<Switch
|
|
9
|
+
accessibilityLabel="Marks if the user likes videogames"
|
|
10
|
+
id="switch-videogames-preference"
|
|
11
|
+
label="Do you like videogames?"
|
|
12
|
+
onClick={() => {}}
|
|
13
|
+
variant="primary"
|
|
14
|
+
/>,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
expect(getByText(/Do you like videogames/i)).toBeInTheDocument()
|
|
18
|
+
expect(getByRole('switch')).toHaveClass(`switch primary medium`)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('renders small size', () => {
|
|
22
|
+
const { getByRole } = render(
|
|
23
|
+
<Switch
|
|
24
|
+
accessibilityLabel="Marks if the user likes videogames"
|
|
25
|
+
id="switch-videogames-preference"
|
|
26
|
+
label="Do you like videogames?"
|
|
27
|
+
onClick={() => {}}
|
|
28
|
+
variant="primary"
|
|
29
|
+
size="small"
|
|
30
|
+
/>,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
expect(getByRole('switch')).toHaveClass(`switch primary small`)
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import 'react-day-picker/style.css'
|
|
2
|
-
import './DatePicker.scss'
|
|
3
|
-
import { type DateRange, type Locale } from 'react-day-picker'
|
|
4
|
-
import { classNames } from '../../utils/classNames'
|
|
5
|
-
import { DateRangePicker } from './DateRangePicker'
|
|
6
|
-
import { DateSinglePicker } from './DateSinglePicker'
|
|
7
|
-
|
|
8
|
-
export type Variant = 'primary'
|
|
9
|
-
export type DatePickerType = 'single' | 'range'
|
|
10
|
-
|
|
11
|
-
type DivPropsWithoutOnSelect = Omit<
|
|
12
|
-
React.ComponentPropsWithoutRef<'div'>,
|
|
13
|
-
'onSelect'
|
|
14
|
-
>
|
|
15
|
-
|
|
16
|
-
export interface AvailableLocale {
|
|
17
|
-
[index: string]: Locale
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface DatePickerBaseProps extends DivPropsWithoutOnSelect {
|
|
21
|
-
variant?: Variant
|
|
22
|
-
lng: keyof AvailableLocale
|
|
23
|
-
type: DatePickerType
|
|
24
|
-
month?: Date
|
|
25
|
-
onMonthChange?: (date: Date | undefined) => void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface DateSinglePickerProps {
|
|
29
|
-
type: 'single'
|
|
30
|
-
selected?: Date | undefined
|
|
31
|
-
onSelect: (date: Date | undefined) => void
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface DateRangePickerProps {
|
|
35
|
-
type: 'range'
|
|
36
|
-
selected?: DateRange | undefined
|
|
37
|
-
onSelect: (date: DateRange | undefined) => void
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
type DatePickerProps = (DateSinglePickerProps | DateRangePickerProps) &
|
|
41
|
-
DatePickerBaseProps
|
|
42
|
-
|
|
43
|
-
export function DatePicker(props: DatePickerProps): React.JSX.Element {
|
|
44
|
-
const {
|
|
45
|
-
variant,
|
|
46
|
-
className,
|
|
47
|
-
type,
|
|
48
|
-
lng,
|
|
49
|
-
onSelect,
|
|
50
|
-
selected,
|
|
51
|
-
month,
|
|
52
|
-
onMonthChange,
|
|
53
|
-
} = props
|
|
54
|
-
|
|
55
|
-
const cssClasses = classNames('date-picker', variant, className)
|
|
56
|
-
|
|
57
|
-
if (type === 'single') {
|
|
58
|
-
return (
|
|
59
|
-
<div className={cssClasses}>
|
|
60
|
-
<DateSinglePicker
|
|
61
|
-
lng={lng}
|
|
62
|
-
selected={selected}
|
|
63
|
-
onSelect={onSelect}
|
|
64
|
-
month={month}
|
|
65
|
-
onMonthChange={onMonthChange}
|
|
66
|
-
/>
|
|
67
|
-
</div>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
return (
|
|
71
|
-
<div className={cssClasses}>
|
|
72
|
-
<DateRangePicker lng={lng} selected={selected} onSelect={onSelect} />
|
|
73
|
-
</div>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import 'react-day-picker/style.css'
|
|
2
|
-
import { useEffect, useState } from 'react'
|
|
3
|
-
import { DayPicker, type Locale } from 'react-day-picker'
|
|
4
|
-
import { enGB, es } from 'react-day-picker/locale'
|
|
5
|
-
import {
|
|
6
|
-
formatDatePickerFooterDate,
|
|
7
|
-
formatDatePickerParamsDate,
|
|
8
|
-
} from '../../utils/dateHelpers'
|
|
9
|
-
import { Input } from '../Input'
|
|
10
|
-
import type { AvailableLocale } from './DatePicker'
|
|
11
|
-
import { translations } from './translations'
|
|
12
|
-
|
|
13
|
-
const availableLocales: AvailableLocale = {
|
|
14
|
-
es: es,
|
|
15
|
-
en: enGB,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface DateSinglePickerProps {
|
|
19
|
-
onSelect: (date: Date | undefined) => void
|
|
20
|
-
selected?: Date
|
|
21
|
-
lng: keyof typeof availableLocales
|
|
22
|
-
month?: Date
|
|
23
|
-
onMonthChange?: (date: Date | undefined) => void
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function DateSinglePicker({
|
|
27
|
-
onSelect = () => {},
|
|
28
|
-
selected: preselected,
|
|
29
|
-
lng,
|
|
30
|
-
month: selectedMonth,
|
|
31
|
-
onMonthChange = () => {},
|
|
32
|
-
}: DateSinglePickerProps): React.JSX.Element {
|
|
33
|
-
const manageFooterText = (): string => {
|
|
34
|
-
if (!selected) return translations[lng].pickSingleDate
|
|
35
|
-
|
|
36
|
-
return translations[lng].selectedDate.replace(
|
|
37
|
-
'${date}',
|
|
38
|
-
formatDatePickerFooterDate(selected, lng as string),
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const [selected, setSelected] = useState<Date | undefined>(preselected)
|
|
43
|
-
const [month, setMonth] = useState<Date | undefined>(selectedMonth)
|
|
44
|
-
const [footer, setFooter] = useState<string>(() => {
|
|
45
|
-
return manageFooterText()
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
setSelected(preselected)
|
|
50
|
-
setFooter(manageFooterText())
|
|
51
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
|
-
}, [preselected])
|
|
53
|
-
|
|
54
|
-
function selectDate(date: Date | undefined) {
|
|
55
|
-
setSelected(date)
|
|
56
|
-
setMonth(date)
|
|
57
|
-
onSelect(date)
|
|
58
|
-
onMonthChange(date)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<>
|
|
63
|
-
<DayPicker
|
|
64
|
-
locale={availableLocales[lng]}
|
|
65
|
-
mode="single"
|
|
66
|
-
selected={selected}
|
|
67
|
-
onSelect={(date) => selectDate(date)}
|
|
68
|
-
footer={footer}
|
|
69
|
-
required
|
|
70
|
-
month={month}
|
|
71
|
-
onMonthChange={(date) => setMonth(date)}
|
|
72
|
-
/>
|
|
73
|
-
</>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/react'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import { DatePicker } from '../src/atoms/DatePicker/DatePicker'
|
|
4
|
-
|
|
5
|
-
describe('DatePicker', () => {
|
|
6
|
-
it('renders with expected footer, language and month for a range type', () => {
|
|
7
|
-
const { getByText } = render(
|
|
8
|
-
<DatePicker
|
|
9
|
-
selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
|
|
10
|
-
onSelect={() => jest.fn()}
|
|
11
|
-
lng={'es'}
|
|
12
|
-
type="range"
|
|
13
|
-
/>,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
expect(getByText('enero 2025')).toBeInTheDocument()
|
|
17
|
-
expect(getByText('lu')).toBeInTheDocument()
|
|
18
|
-
expect(getByText('ma')).toBeInTheDocument()
|
|
19
|
-
expect(getByText('mi')).toBeInTheDocument()
|
|
20
|
-
expect(getByText('ju')).toBeInTheDocument()
|
|
21
|
-
expect(getByText('vi')).toBeInTheDocument()
|
|
22
|
-
expect(getByText('sá')).toBeInTheDocument()
|
|
23
|
-
expect(getByText('do')).toBeInTheDocument()
|
|
24
|
-
expect(
|
|
25
|
-
getByText('Rango de fechas seleccionado: desde 1/1/2025 a 15/1/2025'),
|
|
26
|
-
).toBeInTheDocument()
|
|
27
|
-
})
|
|
28
|
-
it('renders with expected footer, language and month for a single type', () => {
|
|
29
|
-
const { getByText } = render(
|
|
30
|
-
<DatePicker
|
|
31
|
-
selected={new Date(2025, 1, 15)}
|
|
32
|
-
onSelect={() => jest.fn()}
|
|
33
|
-
lng={'es'}
|
|
34
|
-
type="single"
|
|
35
|
-
/>,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
expect(getByText('febrero 2025')).toBeInTheDocument()
|
|
39
|
-
expect(getByText('lu')).toBeInTheDocument()
|
|
40
|
-
expect(getByText('ma')).toBeInTheDocument()
|
|
41
|
-
expect(getByText('mi')).toBeInTheDocument()
|
|
42
|
-
expect(getByText('ju')).toBeInTheDocument()
|
|
43
|
-
expect(getByText('vi')).toBeInTheDocument()
|
|
44
|
-
expect(getByText('sá')).toBeInTheDocument()
|
|
45
|
-
expect(getByText('do')).toBeInTheDocument()
|
|
46
|
-
expect(getByText('Fecha seleccionada: 15/2/2025')).toBeInTheDocument()
|
|
47
|
-
})
|
|
48
|
-
})
|
|
File without changes
|