@artemy-tech/datepicker 0.6.0 → 0.7.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/README.md CHANGED
@@ -4,21 +4,23 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@artemy-tech/datepicker?color=green)](https://www.npmjs.com/package/@artemy-tech/datepicker)
5
5
  [![CI](https://github.com/artemydottech/datepicker/actions/workflows/ci.yml/badge.svg)](https://github.com/artemydottech/datepicker/actions/workflows/ci.yml)
6
6
  [![codecov](https://codecov.io/gh/artemydottech/datepicker/branch/main/graph/badge.svg)](https://codecov.io/gh/artemydottech/datepicker)
7
- [![bundle size](https://deno.bundlejs.com/badge?q=@artemy-tech/datepicker)](https://bundlejs.com/?q=@artemy-tech/datepicker)
8
- [![license](https://img.shields.io/npm/l/@artemy-tech/datepicker)](https://github.com/artemydottech/datepicker/blob/main/LICENSE)
7
+ [![publish size](https://badgen.net/packagephobia/publish/@artemy-tech/datepicker)](https://packagephobia.com/result?p=@artemy-tech/datepicker)
9
8
 
10
- React DatePicker с опциональной поддержкой react-hook-form. Построен на базе [react-day-picker v9](https://daypicker.dev/) (headless) и [date-fns v4](https://date-fns.org/).
9
+ React DatePicker с маской ввода, поддержкой произвольных локалей и форматов даты, выбором диапазона и времени, опциональной интеграцией с react-hook-form. Построен на [react-day-picker v9](https://daypicker.dev/) и [date-fns v4](https://date-fns.org/).
10
+
11
+ **📚 [Документация и примеры →](https://artemydottech.github.io/datepicker)**
11
12
 
12
13
  ## Возможности
13
14
 
14
- - Выбор одиночной даты и диапазона дат
15
+ - Одиночная дата и диапазон
15
16
  - Контролируемый и неконтролируемый режимы
16
17
  - Выбор времени (`showTime`)
17
- - Кастомный триггер через `customTrigger` render-функция, получает текущее значение и `onClick`
18
- - Кастомный инпут через `renderInput` интеграция с любой UI-библиотекой (Ant Design, MUI, shadcn и др.)
18
+ - **Произвольная локаль** через проп `locale` (любая локаль `date-fns`)
19
+ - **Произвольный формат даты** через проп `dateFormat` (`dd.MM.yyyy`, `MM/dd/yyyy`, `yyyy-MM-dd`, …) маска ввода генерится автоматически
20
+ - Кастомный триггер (`customTrigger`) и кастомный инпут (`renderInput`) — интеграция с Ant Design, MUI, shadcn/ui и др.
19
21
  - Интеграция с react-hook-form (нулевые издержки если не используется)
20
- - Стилизация через CSS-переменные (`--datepicker-*`)
21
- - Полная поддержка TypeScript
22
+ - Стилизация через CSS-переменные `--datepicker-*`
23
+ - Полная поддержка TypeScript, в т.ч. дженерики для RHF-компонентов
22
24
 
23
25
  ## Установка
24
26
 
@@ -26,37 +28,34 @@ React DatePicker с опциональной поддержкой react-hook-for
26
28
  npm install @artemy-tech/datepicker
27
29
  ```
28
30
 
29
- Для интеграции с react-hook-form:
31
+ Для интеграции с react-hook-form установите его как peer-зависимость:
30
32
 
31
33
  ```bash
32
- npm install @artemy-tech/datepicker react-hook-form
34
+ npm install react-hook-form
33
35
  ```
34
36
 
35
- ## Peer-зависимости
36
-
37
- ```text
38
- react >= 17.0.0
39
- react-hook-form >= 7.0.0 # опционально
40
- ```
41
-
42
- ## Использование
43
-
44
- ### Подключение стилей
37
+ ## Quick start
45
38
 
46
39
  ```tsx
47
40
  import '@artemy-tech/datepicker/styles';
41
+ import { DatePicker } from '@artemy-tech/datepicker';
42
+
43
+ export const Example = () => <DatePicker label="Дата рождения" />;
48
44
  ```
49
45
 
46
+ ## Примеры
47
+
50
48
  ### DatePicker
51
49
 
52
50
  ```tsx
53
- import { DatePicker } from '@artemy-tech/datepicker'
51
+ import { useState } from 'react';
52
+ import { DatePicker } from '@artemy-tech/datepicker';
54
53
 
55
54
  // Неконтролируемый
56
55
  <DatePicker label="Дата рождения" />
57
56
 
58
57
  // Контролируемый
59
- const [date, setDate] = useState<Date | undefined>()
58
+ const [date, setDate] = useState<Date | undefined>();
60
59
  <DatePicker label="Дата" value={date} onChange={setDate} />
61
60
 
62
61
  // С выбором времени
@@ -69,147 +68,92 @@ const [date, setDate] = useState<Date | undefined>()
69
68
  ### DateRangePicker
70
69
 
71
70
  ```tsx
72
- import { DateRangePicker } from '@artemy-tech/datepicker'
73
- import type { DateRange } from '@artemy-tech/datepicker'
71
+ import { useState } from 'react';
72
+ import { DateRangePicker, type DateRange } from '@artemy-tech/datepicker';
74
73
 
75
- const [range, setRange] = useState<DateRange | undefined>()
74
+ const [range, setRange] = useState<DateRange | undefined>();
76
75
 
77
76
  <DateRangePicker
78
77
  label="Период проживания"
79
78
  value={range}
80
79
  onChange={setRange}
81
80
  calendarLayout="horizontal"
82
- />
81
+ />;
83
82
  ```
84
83
 
85
- ### Кастомный триггер (`customTrigger`)
84
+ ### Локали и форматы
86
85
 
87
- Через `customTrigger` можно передать render-функцию, которая получает отформатированное значение и обработчик клика.
86
+ По умолчанию: `locale = ru`, `dateFormat = 'dd.MM.yyyy'`. Любую локаль `date-fns` можно подключить точечно — маска и плейсхолдер пересчитаются автоматически.
88
87
 
89
88
  ```tsx
90
- import { DatePicker } from '@artemy-tech/datepicker';
89
+ import { enUS, de } from 'date-fns/locale';
90
+ import { DatePicker, DateRangePicker } from '@artemy-tech/datepicker';
91
91
 
92
92
  <DatePicker
93
- customTrigger={(value, onClick) => (
94
- <button type="button" onClick={onClick}>
95
- {value || 'Выбрать дату'}
96
- </button>
97
- )}
93
+ locale={enUS}
94
+ dateFormat="MM/dd/yyyy"
95
+ label="Birth date"
98
96
  />
99
- ```
100
-
101
- ### Кастомный инпут (`renderInput`)
102
-
103
- Через `renderInput` можно заменить встроенный `<input>` на компонент из любой UI-библиотеки. Вся логика маски, валидации и попапа остаётся внутри `DatePicker`.
104
-
105
- ```tsx
106
- import { Input } from 'antd';
107
- import type { InputRef } from 'antd';
108
- import { DatePicker } from '@artemy-tech/datepicker';
109
97
 
110
98
  <DatePicker
111
- renderInput={({ ref, className, ...props }) => (
112
- <Input ref={ref as React.Ref<InputRef>} {...props} />
113
- )}
114
- />;
99
+ locale={enUS}
100
+ dateFormat="yyyy-MM-dd"
101
+ label="ISO date"
102
+ />
103
+
104
+ <DateRangePicker
105
+ locale={de}
106
+ dateFormat="dd.MM.yyyy"
107
+ label="Zeitraum"
108
+ />
115
109
  ```
116
110
 
111
+ Поддерживаемые токены в `dateFormat`: `dd`, `MM`, `yyyy`. Разделители — любые одиночные символы (`.`, `/`, `-`, ` `). Время добавляется через проп `showTime`, а не через `dateFormat`.
112
+
117
113
  ### С react-hook-form
118
114
 
115
+ `RHFDatePicker` и `RHFDateRangePicker` принимают дженерик-параметр — тип значений формы. Это даёт автокомплит и типобезопасность для `name`:
116
+
119
117
  ```tsx
120
118
  import { FormProvider, useForm } from 'react-hook-form';
121
119
  import { RHFDatePicker, RHFDateRangePicker } from '@artemy-tech/datepicker/rhf';
122
120
  import type { DateRange } from '@artemy-tech/datepicker';
123
121
 
124
- interface FormValues {
122
+ interface BookingFormValues {
125
123
  checkIn: Date | undefined;
126
124
  period: DateRange | undefined;
127
125
  }
128
126
 
129
- function BookingForm() {
130
- const methods = useForm<FormValues>({
127
+ const BookingForm = () => {
128
+ const methods = useForm<BookingFormValues>({
131
129
  defaultValues: { checkIn: undefined, period: undefined },
132
130
  });
133
131
 
134
132
  return (
135
133
  <FormProvider {...methods}>
136
134
  <form onSubmit={methods.handleSubmit(console.log)}>
137
- <RHFDatePicker
135
+ <RHFDatePicker<BookingFormValues>
138
136
  name="checkIn"
139
137
  label="Дата заезда"
140
138
  rules={{ validate: (v) => v !== undefined || 'Выберите дату' }}
141
139
  />
142
- <RHFDateRangePicker
140
+ <RHFDateRangePicker<BookingFormValues>
143
141
  name="period"
144
142
  label="Период"
145
- rules={{
146
- validate: (v) => v?.from !== undefined || 'Выберите период',
147
- }}
143
+ rules={{ validate: (v) => v?.from !== undefined || 'Выберите период' }}
148
144
  />
149
145
  <button type="submit">Отправить</button>
150
146
  </form>
151
147
  </FormProvider>
152
148
  );
153
- }
149
+ };
154
150
  ```
155
151
 
156
- ## Props
157
-
158
- ### DatePicker — пропсы
159
-
160
- | Prop | Тип | По умолчанию | Описание |
161
- | -------------- | ----------------------------------------------- | ------------------ | --------------------------------------------------- |
162
- | `value` | `Date` | — | Контролируемое значение |
163
- | `defaultValue` | `Date` | — | Значение по умолчанию (неконтролируемый режим) |
164
- | `onChange` | `(date: Date \| undefined) => void` | — | Callback при изменении |
165
- | `label` | `string` | — | Плавающий лейбл |
166
- | `placeholder` | `string` | `дд.мм.гггг` | Плейсхолдер |
167
- | `fromDate` | `Date` | — | Минимально допустимая дата |
168
- | `toDate` | `Date` | — | Максимально допустимая дата |
169
- | `showTime` | `boolean \| { format: 'HH:mm' \| 'HH:mm:ss' }` | — | Включить выбор времени |
170
- | `noCalendar` | `boolean` | `false` | Только ввод, без попапа |
171
- | `size` | `'s' \| 'm' \| 'l'` | `'m'` | Размер |
172
- | `disabled` | `boolean` | `false` | |
173
- | `failed` | `boolean` | `false` | Состояние ошибки |
174
- | `loading` | `boolean` | `false` | Состояние загрузки |
175
- | `icon` | `ReactNode \| false` | `<CalendarIcon />` | Иконка (`false` — скрыть) |
176
- | `iconPosition` | `'start' \| 'end'` | `'end'` | Позиция иконки |
177
- | `renderInput` | `(props: DatePickerInputProps) => ReactNode` | — | Кастомный `<input>`; маска и попап сохраняются |
178
- | `customTrigger` | `(value: string, onClick: () => void) => ReactNode` | — | Render-функция для произвольного триггера |
179
- | `className` | `string` | — | CSS-класс на корневом элементе |
180
-
181
- ### DateRangePicker — пропсы
182
-
183
- | Prop | Тип | По умолчанию | Описание |
184
- | ---------------- | ---------------------------------------------- | ------------------ | --------------------------- |
185
- | `value` | `DateRange` | — | Контролируемое значение |
186
- | `defaultValue` | `DateRange` | — | Значение по умолчанию |
187
- | `onChange` | `(range: DateRange \| undefined) => void` | — | Callback при изменении |
188
- | `label` | `string` | — | Плавающий лейбл |
189
- | `fromDate` | `Date` | — | Минимально допустимая дата |
190
- | `toDate` | `Date` | — | Максимально допустимая дата |
191
- | `calendarLayout` | `'vertical' \| 'horizontal'` | `'horizontal'` | Расположение двух месяцев |
192
- | `showTime` | `boolean \| { format: 'HH:mm' \| 'HH:mm:ss' }` | — | Включить выбор времени |
193
- | `size` | `'s' \| 'm' \| 'l'` | `'m'` | Размер |
194
- | `disabled` | `boolean` | `false` | |
195
- | `failed` | `boolean` | `false` | |
196
- | `loading` | `boolean` | `false` | |
197
- | `icon` | `ReactNode \| false` | `<CalendarIcon />` | Иконка |
198
- | `iconPosition` | `'start' \| 'end'` | `'end'` | |
199
- | `className` | `string` | — | |
200
-
201
- ### RHFDatePicker / RHFDateRangePicker — пропсы
202
-
203
- Принимают все пропсы соответствующего компонента, плюс:
204
-
205
- | Prop | Тип | Описание |
206
- | ------- | ----------------- | --------------------------------- |
207
- | `name` | `string` | Имя поля в форме |
208
- | `rules` | `RegisterOptions` | Правила валидации react-hook-form |
152
+ > Полные рецепты для **Zod**, **Joi** и **shadcn/ui Form** — на [странице документации](https://artemydottech.github.io/datepicker/recipes).
209
153
 
210
154
  ## Стилизация
211
155
 
212
- Подключите базовые стили и переопределите нужные токены:
156
+ Подключите базовые стили и переопределите нужные CSS-переменные:
213
157
 
214
158
  ```css
215
159
  @import '@artemy-tech/datepicker/styles';
@@ -217,31 +161,17 @@ function BookingForm() {
217
161
  :root {
218
162
  --datepicker-color-accent: #6366f1;
219
163
  --datepicker-radius: 8px;
220
- --datepicker-font-size: 14px;
221
- --datepicker-border-color: #e0e0e0;
222
164
  --datepicker-border-color-focus: #6366f1;
223
- --datepicker-bg: #ffffff;
224
- --datepicker-color-text: #1a1a1a;
225
- --datepicker-color-placeholder: #9e9e9e;
226
165
  }
227
166
  ```
228
167
 
229
- Состояния задаются через `data-*`-атрибуты на корневом элементе, что позволяет стилизовать их без JS:
168
+ Состояния задаются через `data-*`-атрибуты на корневом элементе (`data-focused`, `data-filled`, `data-failed`, `data-disabled`) — стилизуются без JS.
230
169
 
231
- ```css
232
- .datepicker[data-focused] {
233
- ...;
234
- }
235
- .datepicker[data-filled] {
236
- ...;
237
- }
238
- .datepicker[data-failed] {
239
- ...;
240
- }
241
- .datepicker[data-disabled] {
242
- ...;
243
- }
244
- ```
170
+ Полный список токенов и data-атрибутов — в [разделе Theming](https://artemydottech.github.io/datepicker/theming).
171
+
172
+ ## API
173
+
174
+ Подробная справка по пропсам, типам и edge-cases — в [документации](https://artemydottech.github.io/datepicker).
245
175
 
246
176
  ## Лицензия
247
177
 
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
+ import { Locale } from 'date-fns/locale';
3
4
  import { DateRange } from 'react-day-picker';
4
5
 
5
6
  type DatePickerSize = 's' | 'm' | 'l';
@@ -43,8 +44,10 @@ interface DatePickerProps {
43
44
  className?: string;
44
45
  renderInput?: (props: DatePickerInputProps) => ReactNode;
45
46
  customTrigger?: (value: string, onClick: () => void) => ReactNode;
47
+ locale?: Locale;
48
+ dateFormat?: string;
46
49
  }
47
- declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, renderInput, customTrigger, }: DatePickerProps): react_jsx_runtime.JSX.Element;
50
+ declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, renderInput, customTrigger, locale, dateFormat: dateFormatProp, }: DatePickerProps): react_jsx_runtime.JSX.Element;
48
51
 
49
52
  type DateRangePickerSize = 's' | 'm' | 'l';
50
53
  type DateRangePickerCalendarLayout = 'vertical' | 'horizontal';
@@ -64,7 +67,9 @@ interface DateRangePickerProps {
64
67
  icon?: ReactNode | false;
65
68
  iconPosition?: 'start' | 'end';
66
69
  className?: string;
70
+ locale?: Locale;
71
+ dateFormat?: string;
67
72
  }
68
- declare function DateRangePicker({ value, defaultValue, onChange, label, fromDate: fromConstraint, toDate: toConstraint, disabled, failed, loading, size, calendarLayout, showTime, icon, iconPosition, className, }: DateRangePickerProps): react_jsx_runtime.JSX.Element;
73
+ declare function DateRangePicker({ value, defaultValue, onChange, label, fromDate: fromConstraint, toDate: toConstraint, disabled, failed, loading, size, calendarLayout, showTime, icon, iconPosition, className, locale, dateFormat: dateFormatProp, }: DateRangePickerProps): react_jsx_runtime.JSX.Element;
69
74
 
70
75
  export { DatePicker as D, type DatePickerInputProps as a, type DatePickerProps as b, type DatePickerShowTime as c, DateRangePicker as d, type DateRangePickerProps as e };
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
+ import { Locale } from 'date-fns/locale';
3
4
  import { DateRange } from 'react-day-picker';
4
5
 
5
6
  type DatePickerSize = 's' | 'm' | 'l';
@@ -43,8 +44,10 @@ interface DatePickerProps {
43
44
  className?: string;
44
45
  renderInput?: (props: DatePickerInputProps) => ReactNode;
45
46
  customTrigger?: (value: string, onClick: () => void) => ReactNode;
47
+ locale?: Locale;
48
+ dateFormat?: string;
46
49
  }
47
- declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, renderInput, customTrigger, }: DatePickerProps): react_jsx_runtime.JSX.Element;
50
+ declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, renderInput, customTrigger, locale, dateFormat: dateFormatProp, }: DatePickerProps): react_jsx_runtime.JSX.Element;
48
51
 
49
52
  type DateRangePickerSize = 's' | 'm' | 'l';
50
53
  type DateRangePickerCalendarLayout = 'vertical' | 'horizontal';
@@ -64,7 +67,9 @@ interface DateRangePickerProps {
64
67
  icon?: ReactNode | false;
65
68
  iconPosition?: 'start' | 'end';
66
69
  className?: string;
70
+ locale?: Locale;
71
+ dateFormat?: string;
67
72
  }
68
- declare function DateRangePicker({ value, defaultValue, onChange, label, fromDate: fromConstraint, toDate: toConstraint, disabled, failed, loading, size, calendarLayout, showTime, icon, iconPosition, className, }: DateRangePickerProps): react_jsx_runtime.JSX.Element;
73
+ declare function DateRangePicker({ value, defaultValue, onChange, label, fromDate: fromConstraint, toDate: toConstraint, disabled, failed, loading, size, calendarLayout, showTime, icon, iconPosition, className, locale, dateFormat: dateFormatProp, }: DateRangePickerProps): react_jsx_runtime.JSX.Element;
69
74
 
70
75
  export { DatePicker as D, type DatePickerInputProps as a, type DatePickerProps as b, type DatePickerShowTime as c, DateRangePicker as d, type DateRangePickerProps as e };