@artemy-tech/datepicker 0.3.0 → 0.4.1

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
@@ -6,10 +6,12 @@ React DatePicker с опциональной поддержкой react-hook-for
6
6
 
7
7
  - Выбор одиночной даты и диапазона дат
8
8
  - Контролируемый и неконтролируемый режимы
9
+ - Выбор времени (`showTime`)
10
+ - Кастомный триггер через `customInput` — любой элемент (кнопка, chip) открывает попап, `forwardRef` не нужен
11
+ - Кастомный инпут через `renderInput` — интеграция с любой UI-библиотекой (Ant Design, MUI, shadcn и др.)
9
12
  - Интеграция с react-hook-form (нулевые издержки если не используется)
10
13
  - Стилизация через CSS-переменные (`--datepicker-*`)
11
14
  - Полная поддержка TypeScript
12
- - Доступность (через react-day-picker)
13
15
 
14
16
  ## Установка
15
17
 
@@ -25,7 +27,7 @@ npm install @artemy-tech/datepicker react-hook-form
25
27
 
26
28
  ## Peer-зависимости
27
29
 
28
- ```
30
+ ```text
29
31
  react >= 17.0.0
30
32
  react-dom >= 17.0.0
31
33
  react-hook-form >= 7.0.0 # опционально
@@ -33,43 +35,171 @@ react-hook-form >= 7.0.0 # опционально
33
35
 
34
36
  ## Использование
35
37
 
38
+ ### Подключение стилей
39
+
40
+ ```tsx
41
+ import '@artemy-tech/datepicker/styles';
42
+ ```
43
+
36
44
  ### DatePicker
37
45
 
38
46
  ```tsx
39
47
  import { DatePicker } from '@artemy-tech/datepicker'
40
- import '@artemy-tech/datepicker/styles'
41
48
 
42
49
  // Неконтролируемый
43
- <DatePicker />
50
+ <DatePicker label="Дата рождения" />
44
51
 
45
52
  // Контролируемый
46
- const [date, setDate] = useState<Date>()
47
- <DatePicker value={date} onChange={setDate} />
53
+ const [date, setDate] = useState<Date | undefined>()
54
+ <DatePicker label="Дата" value={date} onChange={setDate} />
55
+
56
+ // С выбором времени
57
+ <DatePicker label="Дата и время" showTime={{ format: 'HH:mm' }} />
58
+
59
+ // Ограничение диапазона
60
+ <DatePicker label="Дата заезда" fromDate={new Date()} />
48
61
  ```
49
62
 
50
63
  ### DateRangePicker
51
64
 
52
65
  ```tsx
53
66
  import { DateRangePicker } from '@artemy-tech/datepicker'
67
+ import type { DateRange } from '@artemy-tech/datepicker'
68
+
69
+ const [range, setRange] = useState<DateRange | undefined>()
70
+
71
+ <DateRangePicker
72
+ label="Период проживания"
73
+ value={range}
74
+ onChange={setRange}
75
+ calendarLayout="horizontal"
76
+ />
77
+ ```
78
+
79
+ ### Кастомный триггер (`customInput`)
80
+
81
+ Через `customInput` можно передать любой элемент-триггер — кнопку, chip и т.д. `DatePicker` инжектит в него `value` (отформатированная дата) и `onClick` (открыть/закрыть календарь). `forwardRef` не нужен.
82
+
83
+ ```tsx
84
+ import { DatePicker } from '@artemy-tech/datepicker';
85
+
86
+ <DatePicker
87
+ customInput={<button type="button">Выбрать дату</button>}
88
+ />
89
+ ```
90
+
91
+ ### Кастомный инпут (`renderInput`)
54
92
 
55
- const [range, setRange] = useState<{ from: Date; to?: Date }>()
56
- <DateRangePicker value={range} onChange={setRange} />
93
+ Через `renderInput` можно заменить встроенный `<input>` на компонент из любой UI-библиотеки. Вся логика маски, валидации и попапа остаётся внутри `DatePicker`.
94
+
95
+ ```tsx
96
+ import { Input } from 'antd';
97
+ import type { InputRef } from 'antd';
98
+ import { DatePicker } from '@artemy-tech/datepicker';
99
+
100
+ <DatePicker
101
+ renderInput={({ ref, className, ...props }) => (
102
+ <Input ref={ref as React.Ref<InputRef>} {...props} />
103
+ )}
104
+ />;
57
105
  ```
58
106
 
59
107
  ### С react-hook-form
60
108
 
61
109
  ```tsx
62
- import { useForm } from 'react-hook-form'
63
- import { RHFDatePicker } from '@artemy-tech/datepicker/rhf'
110
+ import { FormProvider, useForm } from 'react-hook-form';
111
+ import { RHFDatePicker, RHFDateRangePicker } from '@artemy-tech/datepicker/rhf';
112
+ import type { DateRange } from '@artemy-tech/datepicker';
64
113
 
65
- const { control } = useForm()
114
+ interface FormValues {
115
+ checkIn: Date | undefined;
116
+ period: DateRange | undefined;
117
+ }
66
118
 
67
- <RHFDatePicker name="date" control={control} />
119
+ function BookingForm() {
120
+ const methods = useForm<FormValues>({
121
+ defaultValues: { checkIn: undefined, period: undefined },
122
+ });
123
+
124
+ return (
125
+ <FormProvider {...methods}>
126
+ <form onSubmit={methods.handleSubmit(console.log)}>
127
+ <RHFDatePicker
128
+ name="checkIn"
129
+ label="Дата заезда"
130
+ rules={{ validate: (v) => v !== undefined || 'Выберите дату' }}
131
+ />
132
+ <RHFDateRangePicker
133
+ name="period"
134
+ label="Период"
135
+ rules={{
136
+ validate: (v) => v?.from !== undefined || 'Выберите период',
137
+ }}
138
+ />
139
+ <button type="submit">Отправить</button>
140
+ </form>
141
+ </FormProvider>
142
+ );
143
+ }
68
144
  ```
69
145
 
146
+ ## Props
147
+
148
+ ### DatePicker — пропсы
149
+
150
+ | Prop | Тип | По умолчанию | Описание |
151
+ | -------------- | ----------------------------------------------- | ------------------ | --------------------------------------------------- |
152
+ | `value` | `Date` | — | Контролируемое значение |
153
+ | `defaultValue` | `Date` | — | Значение по умолчанию (неконтролируемый режим) |
154
+ | `onChange` | `(date: Date \| undefined) => void` | — | Callback при изменении |
155
+ | `label` | `string` | — | Плавающий лейбл |
156
+ | `placeholder` | `string` | `дд.мм.гггг` | Плейсхолдер |
157
+ | `fromDate` | `Date` | — | Минимально допустимая дата |
158
+ | `toDate` | `Date` | — | Максимально допустимая дата |
159
+ | `showTime` | `boolean \| { format: 'HH:mm' \| 'HH:mm:ss' }` | — | Включить выбор времени |
160
+ | `noCalendar` | `boolean` | `false` | Только ввод, без попапа |
161
+ | `size` | `'s' \| 'm' \| 'l'` | `'m'` | Размер |
162
+ | `disabled` | `boolean` | `false` | |
163
+ | `failed` | `boolean` | `false` | Состояние ошибки |
164
+ | `loading` | `boolean` | `false` | Состояние загрузки |
165
+ | `icon` | `ReactNode \| false` | `<CalendarIcon />` | Иконка (`false` — скрыть) |
166
+ | `iconPosition` | `'start' \| 'end'` | `'end'` | Позиция иконки |
167
+ | `renderInput` | `(props: DatePickerInputProps) => ReactNode` | — | Кастомный `<input>`; маска и попап сохраняются |
168
+ | `customInput` | `ReactElement` | — | Триггер-элемент; получает `value` и `onClick` |
169
+ | `className` | `string` | — | CSS-класс на корневом элементе |
170
+
171
+ ### DateRangePicker — пропсы
172
+
173
+ | Prop | Тип | По умолчанию | Описание |
174
+ | ---------------- | ---------------------------------------------- | ------------------ | --------------------------- |
175
+ | `value` | `DateRange` | — | Контролируемое значение |
176
+ | `defaultValue` | `DateRange` | — | Значение по умолчанию |
177
+ | `onChange` | `(range: DateRange \| undefined) => void` | — | Callback при изменении |
178
+ | `label` | `string` | — | Плавающий лейбл |
179
+ | `fromDate` | `Date` | — | Минимально допустимая дата |
180
+ | `toDate` | `Date` | — | Максимально допустимая дата |
181
+ | `calendarLayout` | `'vertical' \| 'horizontal'` | `'horizontal'` | Расположение двух месяцев |
182
+ | `showTime` | `boolean \| { format: 'HH:mm' \| 'HH:mm:ss' }` | — | Включить выбор времени |
183
+ | `size` | `'s' \| 'm' \| 'l'` | `'m'` | Размер |
184
+ | `disabled` | `boolean` | `false` | |
185
+ | `failed` | `boolean` | `false` | |
186
+ | `loading` | `boolean` | `false` | |
187
+ | `icon` | `ReactNode \| false` | `<CalendarIcon />` | Иконка |
188
+ | `iconPosition` | `'start' \| 'end'` | `'end'` | |
189
+ | `className` | `string` | — | |
190
+
191
+ ### RHFDatePicker / RHFDateRangePicker — пропсы
192
+
193
+ Принимают все пропсы соответствующего компонента, плюс:
194
+
195
+ | Prop | Тип | Описание |
196
+ | ------- | ----------------- | --------------------------------- |
197
+ | `name` | `string` | Имя поля в форме |
198
+ | `rules` | `RegisterOptions` | Правила валидации react-hook-form |
199
+
70
200
  ## Стилизация
71
201
 
72
- Подключите базовые стили и переопределите через CSS-переменные:
202
+ Подключите базовые стили и переопределите нужные токены:
73
203
 
74
204
  ```css
75
205
  @import '@artemy-tech/datepicker/styles';
@@ -78,6 +208,28 @@ const { control } = useForm()
78
208
  --datepicker-color-accent: #6366f1;
79
209
  --datepicker-radius: 8px;
80
210
  --datepicker-font-size: 14px;
211
+ --datepicker-border-color: #e0e0e0;
212
+ --datepicker-border-color-focus: #6366f1;
213
+ --datepicker-bg: #ffffff;
214
+ --datepicker-color-text: #1a1a1a;
215
+ --datepicker-color-placeholder: #9e9e9e;
216
+ }
217
+ ```
218
+
219
+ Состояния задаются через `data-*`-атрибуты на корневом элементе, что позволяет стилизовать их без JS:
220
+
221
+ ```css
222
+ .datepicker[data-focused] {
223
+ ...;
224
+ }
225
+ .datepicker[data-filled] {
226
+ ...;
227
+ }
228
+ .datepicker[data-failed] {
229
+ ...;
230
+ }
231
+ .datepicker[data-disabled] {
232
+ ...;
81
233
  }
82
234
  ```
83
235
 
@@ -1,11 +1,29 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, ReactElement } from 'react';
3
3
  import { DateRange } from 'react-day-picker';
4
4
 
5
5
  type DatePickerSize = 's' | 'm' | 'l';
6
6
  type DatePickerShowTime = boolean | {
7
7
  format: 'HH:mm' | 'HH:mm:ss';
8
8
  };
9
+ interface DatePickerInputProps {
10
+ ref: React.Ref<HTMLInputElement>;
11
+ type: 'text';
12
+ inputMode: 'numeric';
13
+ className: string;
14
+ value: string;
15
+ placeholder: string | undefined;
16
+ disabled: boolean;
17
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
18
+ onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
19
+ onPaste: React.ClipboardEventHandler<HTMLInputElement>;
20
+ onFocus: React.FocusEventHandler<HTMLInputElement>;
21
+ onBlur: React.FocusEventHandler<HTMLInputElement>;
22
+ 'aria-label': string;
23
+ 'aria-expanded': boolean | undefined;
24
+ 'aria-haspopup': 'dialog' | undefined;
25
+ 'aria-invalid': true | undefined;
26
+ }
9
27
  interface DatePickerProps {
10
28
  value?: Date;
11
29
  defaultValue?: Date;
@@ -23,8 +41,13 @@ interface DatePickerProps {
23
41
  icon?: ReactNode | false;
24
42
  iconPosition?: 'start' | 'end';
25
43
  className?: string;
44
+ renderInput?: (props: DatePickerInputProps) => ReactNode;
45
+ customInput?: ReactElement<{
46
+ value?: string;
47
+ onClick?: () => void;
48
+ }>;
26
49
  }
27
- declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, }: 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, customInput, }: DatePickerProps): react_jsx_runtime.JSX.Element;
28
51
 
29
52
  type DateRangePickerSize = 's' | 'm' | 'l';
30
53
  type DateRangePickerCalendarLayout = 'vertical' | 'horizontal';
@@ -47,4 +70,4 @@ interface DateRangePickerProps {
47
70
  }
48
71
  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;
49
72
 
50
- export { DatePicker as D, type DatePickerProps as a, type DatePickerShowTime as b, DateRangePicker as c, type DateRangePickerProps as d };
73
+ export { DatePicker as D, type DatePickerInputProps as a, type DatePickerProps as b, type DatePickerShowTime as c, DateRangePicker as d, type DateRangePickerProps as e };
@@ -1,11 +1,29 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, ReactElement } from 'react';
3
3
  import { DateRange } from 'react-day-picker';
4
4
 
5
5
  type DatePickerSize = 's' | 'm' | 'l';
6
6
  type DatePickerShowTime = boolean | {
7
7
  format: 'HH:mm' | 'HH:mm:ss';
8
8
  };
9
+ interface DatePickerInputProps {
10
+ ref: React.Ref<HTMLInputElement>;
11
+ type: 'text';
12
+ inputMode: 'numeric';
13
+ className: string;
14
+ value: string;
15
+ placeholder: string | undefined;
16
+ disabled: boolean;
17
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
18
+ onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
19
+ onPaste: React.ClipboardEventHandler<HTMLInputElement>;
20
+ onFocus: React.FocusEventHandler<HTMLInputElement>;
21
+ onBlur: React.FocusEventHandler<HTMLInputElement>;
22
+ 'aria-label': string;
23
+ 'aria-expanded': boolean | undefined;
24
+ 'aria-haspopup': 'dialog' | undefined;
25
+ 'aria-invalid': true | undefined;
26
+ }
9
27
  interface DatePickerProps {
10
28
  value?: Date;
11
29
  defaultValue?: Date;
@@ -23,8 +41,13 @@ interface DatePickerProps {
23
41
  icon?: ReactNode | false;
24
42
  iconPosition?: 'start' | 'end';
25
43
  className?: string;
44
+ renderInput?: (props: DatePickerInputProps) => ReactNode;
45
+ customInput?: ReactElement<{
46
+ value?: string;
47
+ onClick?: () => void;
48
+ }>;
26
49
  }
27
- declare function DatePicker({ value, defaultValue, onChange, label, placeholder, fromDate, toDate, disabled, failed, loading, size, noCalendar, showTime, icon, iconPosition, className, }: 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, customInput, }: DatePickerProps): react_jsx_runtime.JSX.Element;
28
51
 
29
52
  type DateRangePickerSize = 's' | 'm' | 'l';
30
53
  type DateRangePickerCalendarLayout = 'vertical' | 'horizontal';
@@ -47,4 +70,4 @@ interface DateRangePickerProps {
47
70
  }
48
71
  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;
49
72
 
50
- export { DatePicker as D, type DatePickerProps as a, type DatePickerShowTime as b, DateRangePicker as c, type DateRangePickerProps as d };
73
+ export { DatePicker as D, type DatePickerInputProps as a, type DatePickerProps as b, type DatePickerShowTime as c, DateRangePicker as d, type DateRangePickerProps as e };