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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agroptima-design-system",
3
- "version": "0.31.10",
3
+ "version": "0.31.11",
4
4
  "scripts": {
5
5
  "dev": "npm run storybook",
6
6
  "storybook": "storybook dev -p 6006 --ci",
@@ -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/breakpoints';
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 cssClasses = classNames('date-picker', variant, className)
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
- <DayPicker
61
- className={cssClasses}
62
- locale={availableLocales[lng]}
63
- mode="range"
64
- min={1}
65
- selected={selected}
66
- onSelect={selectDate}
67
- footer={<Footer lng={lng} selected={selected} />}
68
- defaultMonth={selected?.from}
69
- required={required}
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 cssClasses = classNames('date-picker', variant, className)
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
- <DayPicker
45
- className={cssClasses}
46
- locale={availableLocales[lng]}
47
- mode="single"
48
- selected={selected}
49
- onSelect={selectDate}
50
- footer={<Footer lng={lng} selected={selected} />}
51
- required={required}
52
- defaultMonth={selected}
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({ lng, selected }: { selected?: Date; lng: Locale }): string {
57
- if (!selected) return translations[lng].pickDate
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
  }
@@ -151,5 +151,8 @@
151
151
  }
152
152
  }
153
153
  }
154
+ &.hidden {
155
+ display: none;
156
+ }
154
157
 
155
158
  }
@@ -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
 
@@ -1,3 +1,5 @@
1
+ import type { DateRange } from 'react-day-picker'
2
+
1
3
  export function formatDate(date: string, lng: string) {
2
4
  if (!date) return ''
3
5
  return new Date(date).toLocaleDateString(lng)
@@ -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
  })