@navikt/ds-react 1.4.2 → 1.4.3
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/_docs.json +120 -0
- package/cjs/date/hooks/useDatepicker.js +36 -11
- package/cjs/date/hooks/useMonthPicker.js +34 -10
- package/cjs/date/hooks/useRangeDatepicker.js +181 -65
- package/cjs/date/utils/format-date.js +3 -3
- package/cjs/date/utils/parse-date.js +14 -8
- package/esm/date/hooks/index.d.ts +3 -0
- package/esm/date/hooks/index.js.map +1 -1
- package/esm/date/hooks/useDatepicker.d.ts +18 -0
- package/esm/date/hooks/useDatepicker.js +36 -11
- package/esm/date/hooks/useDatepicker.js.map +1 -1
- package/esm/date/hooks/useMonthPicker.d.ts +17 -0
- package/esm/date/hooks/useMonthPicker.js +34 -10
- package/esm/date/hooks/useMonthPicker.js.map +1 -1
- package/esm/date/hooks/useRangeDatepicker.d.ts +12 -2
- package/esm/date/hooks/useRangeDatepicker.js +181 -65
- package/esm/date/hooks/useRangeDatepicker.js.map +1 -1
- package/esm/date/utils/format-date.d.ts +1 -1
- package/esm/date/utils/format-date.js +3 -3
- package/esm/date/utils/format-date.js.map +1 -1
- package/esm/date/utils/parse-date.d.ts +1 -1
- package/esm/date/utils/parse-date.js +14 -8
- package/esm/date/utils/parse-date.js.map +1 -1
- package/package.json +2 -2
- package/src/date/datepicker/datepicker.stories.tsx +30 -5
- package/src/date/hooks/index.ts +3 -0
- package/src/date/hooks/useDatepicker.tsx +73 -10
- package/src/date/hooks/useMonthPicker.tsx +68 -10
- package/src/date/hooks/useRangeDatepicker.test.tsx +59 -0
- package/src/date/hooks/useRangeDatepicker.tsx +285 -92
- package/src/date/monthpicker/monthpicker.stories.tsx +20 -0
- package/src/date/utils/__tests__/format-dates.test.ts +4 -4
- package/src/date/utils/__tests__/parse-dates.test.ts +0 -40
- package/src/date/utils/format-date.ts +5 -3
- package/src/date/utils/parse-date.ts +18 -9
|
@@ -10,10 +10,42 @@ import {
|
|
|
10
10
|
isValidDate,
|
|
11
11
|
parseDate,
|
|
12
12
|
} from "../utils";
|
|
13
|
-
import { UseDatepickerOptions } from "./useDatepicker";
|
|
13
|
+
import { DateValidationT, UseDatepickerOptions } from "./useDatepicker";
|
|
14
|
+
|
|
15
|
+
export type RangeValidationT = {
|
|
16
|
+
from: DateValidationT;
|
|
17
|
+
to: DateValidationT & { isBeforeFrom?: boolean };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getValidationMessage = (from = {}, to = {}): RangeValidationT => ({
|
|
21
|
+
from: {
|
|
22
|
+
isDisabled: false,
|
|
23
|
+
isWeekend: false,
|
|
24
|
+
isEmpty: false,
|
|
25
|
+
isInvalid: false,
|
|
26
|
+
isBefore: false,
|
|
27
|
+
isAfter: false,
|
|
28
|
+
isValidDate: true,
|
|
29
|
+
...from,
|
|
30
|
+
},
|
|
31
|
+
to: {
|
|
32
|
+
isDisabled: false,
|
|
33
|
+
isWeekend: false,
|
|
34
|
+
isEmpty: false,
|
|
35
|
+
isInvalid: false,
|
|
36
|
+
isBefore: false,
|
|
37
|
+
isAfter: false,
|
|
38
|
+
isBeforeFrom: false,
|
|
39
|
+
isValidDate: true,
|
|
40
|
+
...to,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
14
43
|
|
|
15
44
|
interface UseRangeDatepickerOptions
|
|
16
|
-
extends Omit<
|
|
45
|
+
extends Omit<
|
|
46
|
+
UseDatepickerOptions,
|
|
47
|
+
"defaultSelected" | "onDateChange" | "onValidate"
|
|
48
|
+
> {
|
|
17
49
|
/**
|
|
18
50
|
* The initially selected DateRange
|
|
19
51
|
*/
|
|
@@ -22,6 +54,10 @@ interface UseRangeDatepickerOptions
|
|
|
22
54
|
* Callback for changed state
|
|
23
55
|
*/
|
|
24
56
|
onRangeChange?: (val?: DateRange) => void;
|
|
57
|
+
/**
|
|
58
|
+
* validation-callback
|
|
59
|
+
*/
|
|
60
|
+
onValidate?: (val: RangeValidationT) => void;
|
|
25
61
|
}
|
|
26
62
|
|
|
27
63
|
interface UseRangeDatepickerValue {
|
|
@@ -65,6 +101,92 @@ const RANGE = {
|
|
|
65
101
|
|
|
66
102
|
type RangeT = typeof RANGE[keyof typeof RANGE];
|
|
67
103
|
|
|
104
|
+
const fromValidation = (day: Date, opt?: UseRangeDatepickerOptions) => {
|
|
105
|
+
const isBefore =
|
|
106
|
+
opt?.fromDate && day && differenceInCalendarDays(opt?.fromDate, day) > 0;
|
|
107
|
+
const isAfter =
|
|
108
|
+
opt?.toDate && day && differenceInCalendarDays(day, opt?.toDate) > 0;
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
isValidDate(day) &&
|
|
112
|
+
!(opt?.disableWeekends && isWeekend(day)) &&
|
|
113
|
+
!(opt?.disabled && isMatch(day, opt.disabled))
|
|
114
|
+
) {
|
|
115
|
+
return {
|
|
116
|
+
isValidDate: false,
|
|
117
|
+
isInvalid: !isValidDate(day),
|
|
118
|
+
isWeekend: opt?.disableWeekends && isWeekend(day),
|
|
119
|
+
isDisabled: opt?.disabled && isMatch(day, opt.disabled),
|
|
120
|
+
isBefore: isBefore,
|
|
121
|
+
isAfter: isAfter,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (isBefore || isAfter) {
|
|
125
|
+
return {
|
|
126
|
+
isValidDate: false,
|
|
127
|
+
isBefore: isBefore,
|
|
128
|
+
isAfter: isAfter,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const toValidation = (
|
|
134
|
+
day: Date,
|
|
135
|
+
from: Date,
|
|
136
|
+
opt?: UseRangeDatepickerOptions
|
|
137
|
+
) => {
|
|
138
|
+
const isBefore =
|
|
139
|
+
opt?.fromDate && day && differenceInCalendarDays(opt?.fromDate, day) > 0;
|
|
140
|
+
const isAfter =
|
|
141
|
+
opt?.toDate && day && differenceInCalendarDays(day, opt?.toDate) > 0;
|
|
142
|
+
|
|
143
|
+
const isBeforeFrom =
|
|
144
|
+
(from && differenceInCalendarDays(from, day) > 0) ?? false;
|
|
145
|
+
|
|
146
|
+
if (
|
|
147
|
+
isValidDate(day) &&
|
|
148
|
+
!(opt?.disableWeekends && isWeekend(day)) &&
|
|
149
|
+
!(opt?.disabled && isMatch(day, opt.disabled))
|
|
150
|
+
) {
|
|
151
|
+
return {
|
|
152
|
+
isValidDate: false,
|
|
153
|
+
isInvalid: !isValidDate(day),
|
|
154
|
+
isWeekend: opt?.disableWeekends && isWeekend(day),
|
|
155
|
+
isDisabled: opt?.disabled && isMatch(day, opt.disabled),
|
|
156
|
+
isBefore,
|
|
157
|
+
isAfter,
|
|
158
|
+
isBeforeFrom,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (isBefore || isAfter || isBeforeFrom) {
|
|
162
|
+
return {
|
|
163
|
+
isValidDate: false,
|
|
164
|
+
isBefore,
|
|
165
|
+
isAfter,
|
|
166
|
+
isBeforeFrom,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const initialValidation = (
|
|
172
|
+
range?: DateRange,
|
|
173
|
+
opt?: UseRangeDatepickerOptions
|
|
174
|
+
): RangeValidationT => {
|
|
175
|
+
if (!range || !range?.from) {
|
|
176
|
+
return getValidationMessage(
|
|
177
|
+
{ isEmpty: true, isValidDate: false },
|
|
178
|
+
{ isEmpty: true, isValidDate: false }
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const fromVal = fromValidation(range.from, opt);
|
|
183
|
+
const toVal = range.to
|
|
184
|
+
? toValidation(range.to, range.from, opt)
|
|
185
|
+
: { isEmpty: true, isValidDate: false };
|
|
186
|
+
|
|
187
|
+
return getValidationMessage({ ...fromVal }, { ...toVal });
|
|
188
|
+
};
|
|
189
|
+
|
|
68
190
|
export const useRangeDatepicker = (
|
|
69
191
|
opt: UseRangeDatepickerOptions = {}
|
|
70
192
|
): UseRangeDatepickerValue => {
|
|
@@ -77,6 +199,8 @@ export const useRangeDatepicker = (
|
|
|
77
199
|
disabled,
|
|
78
200
|
disableWeekends,
|
|
79
201
|
onRangeChange,
|
|
202
|
+
inputFormat,
|
|
203
|
+
onValidate,
|
|
80
204
|
} = opt;
|
|
81
205
|
|
|
82
206
|
const locale = getLocaleFromString(_locale);
|
|
@@ -97,15 +221,20 @@ export const useRangeDatepicker = (
|
|
|
97
221
|
|
|
98
222
|
const [fromInputValue, setFromInputValue] = useState(
|
|
99
223
|
defaultSelected?.from
|
|
100
|
-
? formatDateForInput(defaultSelected.from, locale, "date")
|
|
224
|
+
? formatDateForInput(defaultSelected.from, locale, "date", inputFormat)
|
|
101
225
|
: ""
|
|
102
226
|
);
|
|
103
227
|
|
|
104
228
|
const [toInputValue, setToInputValue] = useState(
|
|
105
229
|
defaultSelected?.to
|
|
106
|
-
? formatDateForInput(defaultSelected.to, locale, "date")
|
|
230
|
+
? formatDateForInput(defaultSelected.to, locale, "date", inputFormat)
|
|
107
231
|
: ""
|
|
108
232
|
);
|
|
233
|
+
|
|
234
|
+
const [validation, setValidation] = useState<RangeValidationT>(
|
|
235
|
+
initialValidation(selectedRange, opt)
|
|
236
|
+
);
|
|
237
|
+
|
|
109
238
|
const [open, setOpen] = useState(false);
|
|
110
239
|
|
|
111
240
|
const updateRange = (range?: DateRange) => {
|
|
@@ -113,6 +242,15 @@ export const useRangeDatepicker = (
|
|
|
113
242
|
setSelectedRange(range);
|
|
114
243
|
};
|
|
115
244
|
|
|
245
|
+
const updateValidation = (
|
|
246
|
+
from: Partial<RangeValidationT["from"]> = {},
|
|
247
|
+
to: Partial<RangeValidationT["to"]> = {}
|
|
248
|
+
) => {
|
|
249
|
+
const msg = getValidationMessage(from, to);
|
|
250
|
+
setValidation(msg);
|
|
251
|
+
onValidate?.(msg);
|
|
252
|
+
};
|
|
253
|
+
|
|
116
254
|
const handleFocusIn = useCallback(
|
|
117
255
|
(e) => {
|
|
118
256
|
if (!e?.target || !e?.target?.nodeType) {
|
|
@@ -143,14 +281,20 @@ export const useRangeDatepicker = (
|
|
|
143
281
|
const reset = () => {
|
|
144
282
|
updateRange(defaultSelected ?? { from: undefined, to: undefined });
|
|
145
283
|
setMonth(defaultSelected ? defaultSelected?.from : today);
|
|
284
|
+
setValidation(
|
|
285
|
+
initialValidation(
|
|
286
|
+
defaultSelected ?? { from: undefined, to: undefined },
|
|
287
|
+
opt
|
|
288
|
+
)
|
|
289
|
+
);
|
|
146
290
|
setFromInputValue(
|
|
147
291
|
defaultSelected?.from
|
|
148
|
-
? formatDateForInput(defaultSelected.from, locale, "date")
|
|
292
|
+
? formatDateForInput(defaultSelected.from, locale, "date", inputFormat)
|
|
149
293
|
: ""
|
|
150
294
|
);
|
|
151
295
|
setToInputValue(
|
|
152
296
|
defaultSelected?.to
|
|
153
|
-
? formatDateForInput(defaultSelected.to, locale, "date")
|
|
297
|
+
? formatDateForInput(defaultSelected.to, locale, "date", inputFormat)
|
|
154
298
|
: ""
|
|
155
299
|
);
|
|
156
300
|
setDefaultSelected(_defaultSelected);
|
|
@@ -159,11 +303,16 @@ export const useRangeDatepicker = (
|
|
|
159
303
|
const setSelected = (range?: DateRange) => {
|
|
160
304
|
updateRange(range);
|
|
161
305
|
setFromInputValue(
|
|
162
|
-
range?.from
|
|
306
|
+
range?.from
|
|
307
|
+
? formatDateForInput(range.from, locale, "date", inputFormat)
|
|
308
|
+
: ""
|
|
163
309
|
);
|
|
164
310
|
setToInputValue(
|
|
165
|
-
range?.to
|
|
311
|
+
range?.to
|
|
312
|
+
? formatDateForInput(range?.to, locale, "date", inputFormat)
|
|
313
|
+
: ""
|
|
166
314
|
);
|
|
315
|
+
setValidation(initialValidation(range, opt));
|
|
167
316
|
};
|
|
168
317
|
|
|
169
318
|
const handleFocus = (e, src: RangeT) => {
|
|
@@ -172,52 +321,10 @@ export const useRangeDatepicker = (
|
|
|
172
321
|
if (isValidDate(day)) {
|
|
173
322
|
setMonth(day);
|
|
174
323
|
src === RANGE.FROM
|
|
175
|
-
? setFromInputValue(
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const handleInputs = (day: Date, src: RangeT) => {
|
|
181
|
-
if (src === RANGE.FROM) {
|
|
182
|
-
const isAfter =
|
|
183
|
-
toInputValue &&
|
|
184
|
-
differenceInCalendarDays(
|
|
185
|
-
day,
|
|
186
|
-
parseDate(toInputValue, today, locale, "date")
|
|
187
|
-
) > 0;
|
|
188
|
-
|
|
189
|
-
if (isAfter) {
|
|
190
|
-
setFromInputValue(
|
|
191
|
-
formatDateForInput(
|
|
192
|
-
parseDate(toInputValue, today, locale, "date"),
|
|
193
|
-
locale,
|
|
194
|
-
"date"
|
|
195
|
-
)
|
|
196
|
-
);
|
|
197
|
-
setToInputValue(formatDateForInput(day, locale, "date"));
|
|
198
|
-
} else {
|
|
199
|
-
setFromInputValue(formatDateForInput(day, locale, "date"));
|
|
200
|
-
}
|
|
201
|
-
} else if (src === RANGE.TO) {
|
|
202
|
-
const isBefore =
|
|
203
|
-
fromInputValue &&
|
|
204
|
-
differenceInCalendarDays(
|
|
205
|
-
parseDate(fromInputValue, today, locale, "date"),
|
|
206
|
-
day
|
|
207
|
-
) > 0;
|
|
208
|
-
|
|
209
|
-
if (isBefore) {
|
|
210
|
-
setToInputValue(
|
|
211
|
-
formatDateForInput(
|
|
212
|
-
parseDate(fromInputValue, today, locale, "date"),
|
|
213
|
-
locale,
|
|
214
|
-
"date"
|
|
324
|
+
? setFromInputValue(
|
|
325
|
+
formatDateForInput(day, locale, "date", inputFormat)
|
|
215
326
|
)
|
|
216
|
-
);
|
|
217
|
-
setFromInputValue(formatDateForInput(day, locale, "date"));
|
|
218
|
-
} else {
|
|
219
|
-
setToInputValue(formatDateForInput(day, locale, "date"));
|
|
220
|
-
}
|
|
327
|
+
: setToInputValue(formatDateForInput(day, locale, "date", inputFormat));
|
|
221
328
|
}
|
|
222
329
|
};
|
|
223
330
|
|
|
@@ -227,7 +334,19 @@ export const useRangeDatepicker = (
|
|
|
227
334
|
return;
|
|
228
335
|
}
|
|
229
336
|
|
|
230
|
-
|
|
337
|
+
if (src === RANGE.FROM) {
|
|
338
|
+
setFromInputValue(formatDateForInput(day, locale, "date", inputFormat));
|
|
339
|
+
} else if (src === RANGE.TO) {
|
|
340
|
+
setToInputValue(formatDateForInput(day, locale, "date", inputFormat));
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const validateDay = (day: any) => {
|
|
345
|
+
return (
|
|
346
|
+
isValidDate(day) &&
|
|
347
|
+
!(disableWeekends && isWeekend(day)) &&
|
|
348
|
+
!(disabled && isMatch(day, disabled))
|
|
349
|
+
);
|
|
231
350
|
};
|
|
232
351
|
|
|
233
352
|
const handleSelect = (range) => {
|
|
@@ -238,70 +357,142 @@ export const useRangeDatepicker = (
|
|
|
238
357
|
!selectedRange?.from && selectedRange?.to ? selectedRange?.to : range?.to;
|
|
239
358
|
|
|
240
359
|
range?.from
|
|
241
|
-
? setFromInputValue(
|
|
360
|
+
? setFromInputValue(
|
|
361
|
+
formatDateForInput(range?.from, locale, "date", inputFormat)
|
|
362
|
+
)
|
|
242
363
|
: setFromInputValue("");
|
|
243
364
|
prevToRange
|
|
244
|
-
? setToInputValue(
|
|
365
|
+
? setToInputValue(
|
|
366
|
+
formatDateForInput(prevToRange, locale, "date", inputFormat)
|
|
367
|
+
)
|
|
245
368
|
: setToInputValue("");
|
|
369
|
+
updateValidation(
|
|
370
|
+
{ isValidDate: !!range?.from, isEmpty: !range?.from },
|
|
371
|
+
{ isValidDate: !!range?.to, isEmpty: !prevToRange }
|
|
372
|
+
);
|
|
246
373
|
updateRange({ from: range?.from, to: prevToRange });
|
|
247
374
|
};
|
|
248
375
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
:
|
|
376
|
+
const fromChange = (
|
|
377
|
+
val: string = "",
|
|
378
|
+
day: Date,
|
|
379
|
+
isBefore = false,
|
|
380
|
+
isAfter = false
|
|
381
|
+
) => {
|
|
382
|
+
setFromInputValue(val);
|
|
383
|
+
if (!validateDay(day)) {
|
|
384
|
+
updateRange({ ...selectedRange, from: undefined });
|
|
385
|
+
updateValidation(
|
|
386
|
+
{
|
|
387
|
+
isEmpty: !val,
|
|
388
|
+
isValidDate: false,
|
|
389
|
+
isInvalid: !isValidDate(day),
|
|
390
|
+
isWeekend: disableWeekends && isWeekend(day),
|
|
391
|
+
isDisabled: disabled && isMatch(day, disabled),
|
|
392
|
+
isBefore,
|
|
393
|
+
isAfter,
|
|
394
|
+
},
|
|
395
|
+
validation.to
|
|
265
396
|
);
|
|
266
397
|
return;
|
|
267
398
|
}
|
|
268
|
-
|
|
269
|
-
const isBefore = fromDate && differenceInCalendarDays(fromDate, day) > 0;
|
|
270
|
-
const isAfter = toDate && differenceInCalendarDays(day, toDate) > 0;
|
|
271
399
|
if (isBefore || isAfter) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
400
|
+
updateRange({ ...selectedRange, from: undefined });
|
|
401
|
+
updateValidation(
|
|
402
|
+
{
|
|
403
|
+
isValidDate: false,
|
|
404
|
+
isBefore,
|
|
405
|
+
isAfter,
|
|
406
|
+
},
|
|
407
|
+
validation.to
|
|
408
|
+
);
|
|
275
409
|
return;
|
|
276
410
|
}
|
|
277
411
|
|
|
278
|
-
/* If to-value < from-value, switch places in state */
|
|
279
412
|
if (
|
|
280
|
-
|
|
281
|
-
selectedRange?.
|
|
282
|
-
differenceInCalendarDays(selectedRange?.from, day) >= 0
|
|
413
|
+
selectedRange?.to &&
|
|
414
|
+
differenceInCalendarDays(day, selectedRange?.to) > 0
|
|
283
415
|
) {
|
|
284
|
-
updateRange({
|
|
416
|
+
updateRange({ to: day, from: day });
|
|
417
|
+
setToInputValue(formatDateForInput(day, locale, "date", inputFormat));
|
|
285
418
|
setMonth(day);
|
|
419
|
+
updateValidation();
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (toInputValue && !selectedRange?.to) {
|
|
424
|
+
const toDay = parseDate(toInputValue, today, locale, "date");
|
|
425
|
+
if (validateDay(toDay)) {
|
|
426
|
+
updateRange({ from: day, to: toDay });
|
|
427
|
+
setMonth(day);
|
|
428
|
+
updateValidation();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
updateRange({ ...selectedRange, from: day });
|
|
433
|
+
updateValidation({}, validation.to);
|
|
434
|
+
setMonth(day);
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const toChange = (
|
|
438
|
+
val: string = "",
|
|
439
|
+
day: Date,
|
|
440
|
+
isBefore = false,
|
|
441
|
+
isAfter = false
|
|
442
|
+
) => {
|
|
443
|
+
setToInputValue(val);
|
|
444
|
+
if (!validateDay(day)) {
|
|
445
|
+
updateRange({ from: selectedRange?.from, to: undefined });
|
|
446
|
+
updateValidation(validation.from, {
|
|
447
|
+
isEmpty: !val,
|
|
448
|
+
isValidDate: false,
|
|
449
|
+
isInvalid: !isValidDate(day),
|
|
450
|
+
isWeekend: disableWeekends && isWeekend(day),
|
|
451
|
+
isDisabled: disabled && isMatch(day, disabled),
|
|
452
|
+
isBefore,
|
|
453
|
+
isAfter,
|
|
454
|
+
});
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (isBefore || isAfter) {
|
|
459
|
+
updateRange({ from: selectedRange?.from, to: undefined });
|
|
460
|
+
updateValidation(validation.from, {
|
|
461
|
+
isValidDate: false,
|
|
462
|
+
isBefore,
|
|
463
|
+
isAfter,
|
|
464
|
+
});
|
|
286
465
|
return;
|
|
287
466
|
}
|
|
288
467
|
|
|
289
|
-
/* If
|
|
468
|
+
/* If to-value < from-value */
|
|
290
469
|
if (
|
|
291
|
-
|
|
292
|
-
selectedRange?.
|
|
293
|
-
differenceInCalendarDays(day, selectedRange?.to) >= 0
|
|
470
|
+
selectedRange?.from &&
|
|
471
|
+
differenceInCalendarDays(selectedRange?.from, day) > 0
|
|
294
472
|
) {
|
|
295
|
-
updateRange({
|
|
296
|
-
|
|
473
|
+
updateRange({ from: selectedRange?.from, to: undefined });
|
|
474
|
+
updateValidation(validation.from, {
|
|
475
|
+
isValidDate: false,
|
|
476
|
+
isBeforeFrom: true,
|
|
477
|
+
});
|
|
297
478
|
return;
|
|
298
479
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
src === RANGE.TO && updateRange({ from: selectedRange?.from, to: day });
|
|
480
|
+
updateRange({ from: selectedRange?.from, to: day });
|
|
481
|
+
updateValidation(validation.from, {});
|
|
302
482
|
setMonth(day);
|
|
303
483
|
};
|
|
304
484
|
|
|
485
|
+
/* live-update datepicker based on changes in inputfields */
|
|
486
|
+
const handleChange = (e, src: RangeT) => {
|
|
487
|
+
const day = parseDate(e.target.value, today, locale, "date");
|
|
488
|
+
const isBefore = fromDate && differenceInCalendarDays(fromDate, day) > 0;
|
|
489
|
+
const isAfter = toDate && differenceInCalendarDays(day, toDate) > 0;
|
|
490
|
+
|
|
491
|
+
return src === RANGE.FROM
|
|
492
|
+
? fromChange(e.target.value, day, isBefore, isAfter)
|
|
493
|
+
: toChange(e.target.value, day, isBefore, isAfter);
|
|
494
|
+
};
|
|
495
|
+
|
|
305
496
|
const handleClose = useCallback(() => {
|
|
306
497
|
setOpen(false);
|
|
307
498
|
if (selectedRange?.from && !selectedRange?.to) {
|
|
@@ -336,6 +527,8 @@ export const useRangeDatepicker = (
|
|
|
336
527
|
mode: "range" as const,
|
|
337
528
|
open,
|
|
338
529
|
onOpenToggle: () => setOpen((x) => !x),
|
|
530
|
+
disabled,
|
|
531
|
+
disableWeekends,
|
|
339
532
|
ref: datePickerRef,
|
|
340
533
|
};
|
|
341
534
|
|
|
@@ -90,6 +90,26 @@ export const UseMonthpicker = () => {
|
|
|
90
90
|
);
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
export const UseMonthpickerFormat = () => {
|
|
94
|
+
const { inputProps, monthpickerProps } = UNSAFE_useMonthpicker({
|
|
95
|
+
disabled: [new Date("Apr 1 2022")],
|
|
96
|
+
onMonthChange: console.log,
|
|
97
|
+
inputFormat: "MM.yyyy",
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div style={{ height: "20rem" }}>
|
|
102
|
+
<MonthPicker {...monthpickerProps}>
|
|
103
|
+
<MonthPicker.Input
|
|
104
|
+
{...inputProps}
|
|
105
|
+
label="Velg måned"
|
|
106
|
+
variant="monthpicker"
|
|
107
|
+
/>
|
|
108
|
+
</MonthPicker>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
93
113
|
export const Required = () => {
|
|
94
114
|
const { inputProps, monthpickerProps } = UNSAFE_useMonthpicker({
|
|
95
115
|
locale: "nb",
|
|
@@ -6,16 +6,16 @@ const parse = (inp: string) => parseDate(inp, new Date(), nb, "date");
|
|
|
6
6
|
|
|
7
7
|
describe("Format date to correct output", () => {
|
|
8
8
|
test("formatDateForInput", () => {
|
|
9
|
-
expect(formatDateForInput(parse("15/05/
|
|
9
|
+
expect(formatDateForInput(parse("15/05/2022"), nb, "date")).toEqual(
|
|
10
10
|
"15.05.2022"
|
|
11
11
|
);
|
|
12
|
-
expect(formatDateForInput(parse("1/5/
|
|
12
|
+
expect(formatDateForInput(parse("1/5/2022"), nb, "date")).toEqual(
|
|
13
13
|
"01.05.2022"
|
|
14
14
|
);
|
|
15
|
-
expect(formatDateForInput(parse("1/05/
|
|
15
|
+
expect(formatDateForInput(parse("1/05/2022"), nb, "date")).toEqual(
|
|
16
16
|
"01.05.2022"
|
|
17
17
|
);
|
|
18
|
-
expect(formatDateForInput(parse("15/5/
|
|
18
|
+
expect(formatDateForInput(parse("15/5/2022"), nb, "date")).toEqual(
|
|
19
19
|
"15.05.2022"
|
|
20
20
|
);
|
|
21
21
|
});
|
|
@@ -2,7 +2,6 @@ import { parseDate } from "..";
|
|
|
2
2
|
import { isValidDate } from "..";
|
|
3
3
|
import nb from "date-fns/locale/nb";
|
|
4
4
|
import getMonth from "date-fns/getMonth";
|
|
5
|
-
import getYear from "date-fns/getYear";
|
|
6
5
|
|
|
7
6
|
const check = (inp: string) =>
|
|
8
7
|
expect(isValidDate(parseDate(inp, new Date(), nb, "date")));
|
|
@@ -11,71 +10,32 @@ const parse = (inp: string) => parseDate(inp, new Date(), nb, "date");
|
|
|
11
10
|
|
|
12
11
|
describe("Parse date-inputs", () => {
|
|
13
12
|
test("No spaces", () => {
|
|
14
|
-
check("150522").toBeTruthy();
|
|
15
13
|
check("11052022").toBeTruthy();
|
|
16
14
|
check("15052022").toBeTruthy();
|
|
17
15
|
});
|
|
18
16
|
|
|
19
17
|
test(". divider", () => {
|
|
20
|
-
check("1.5.22").toBeTruthy();
|
|
21
18
|
check("1.5.2022").toBeTruthy();
|
|
22
|
-
check("11.05.22").toBeTruthy();
|
|
23
19
|
check("11.05.2022").toBeTruthy();
|
|
24
20
|
});
|
|
25
21
|
|
|
26
22
|
test("/ divider", () => {
|
|
27
|
-
check("1/5/22").toBeTruthy();
|
|
28
|
-
check("10/5/22").toBeTruthy();
|
|
29
23
|
check("1/5/2022").toBeTruthy();
|
|
30
24
|
check("10/5/2022").toBeTruthy();
|
|
31
|
-
check("1/05/22").toBeTruthy();
|
|
32
|
-
check("10/05/22").toBeTruthy();
|
|
33
25
|
check("1/05/2022").toBeTruthy();
|
|
34
26
|
check("10/05/2022").toBeTruthy();
|
|
35
27
|
});
|
|
36
28
|
|
|
37
29
|
test("- divider", () => {
|
|
38
|
-
check("1-5-22").toBeTruthy();
|
|
39
|
-
check("10-5-22").toBeTruthy();
|
|
40
30
|
check("1-5-2022").toBeTruthy();
|
|
41
31
|
check("10-5-2022").toBeTruthy();
|
|
42
|
-
check("1-05-22").toBeTruthy();
|
|
43
|
-
check("10-05-22").toBeTruthy();
|
|
44
32
|
check("1-05-2022").toBeTruthy();
|
|
45
33
|
check("10-05-2022").toBeTruthy();
|
|
46
34
|
});
|
|
47
35
|
});
|
|
48
36
|
|
|
49
|
-
describe("Parse date-inputs to correct year", () => {
|
|
50
|
-
test("No spaces", () => {
|
|
51
|
-
expect(getYear(parse("150522"))).toEqual(2022);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test(". divider", () => {
|
|
55
|
-
expect(getYear(parse("1.05.22"))).toEqual(2022);
|
|
56
|
-
expect(getYear(parse("11.05.22"))).toEqual(2022);
|
|
57
|
-
expect(getYear(parse("1.5.22"))).toEqual(2022);
|
|
58
|
-
expect(getYear(parse("11.5.22"))).toEqual(2022);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("/ divider", () => {
|
|
62
|
-
expect(getYear(parse("1/5/22"))).toEqual(2022);
|
|
63
|
-
expect(getYear(parse("10/5/22"))).toEqual(2022);
|
|
64
|
-
expect(getYear(parse("1/05/22"))).toEqual(2022);
|
|
65
|
-
expect(getYear(parse("10/05/22"))).toEqual(2022);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("- divider", () => {
|
|
69
|
-
expect(getYear(parse("1-5-22"))).toEqual(2022);
|
|
70
|
-
expect(getYear(parse("10-5-22"))).toEqual(2022);
|
|
71
|
-
expect(getYear(parse("1-05-22"))).toEqual(2022);
|
|
72
|
-
expect(getYear(parse("10-05-22"))).toEqual(2022);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
37
|
describe("Parse date-inputs to correct month", () => {
|
|
77
38
|
test("No spaces", () => {
|
|
78
|
-
expect(getMonth(parse("150522"))).toEqual(4);
|
|
79
39
|
expect(getMonth(parse("11052022"))).toEqual(4);
|
|
80
40
|
expect(getMonth(parse("15052022"))).toEqual(4);
|
|
81
41
|
});
|
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
export const formatDateForInput = (
|
|
8
8
|
date: Date,
|
|
9
9
|
locale: Locale,
|
|
10
|
-
type: "date" | "month"
|
|
10
|
+
type: "date" | "month",
|
|
11
|
+
inputFormat?: string
|
|
11
12
|
) => {
|
|
12
13
|
const INPUT_DATE_STRING_FORMAT =
|
|
13
|
-
|
|
14
|
+
inputFormat ??
|
|
15
|
+
(type === "date"
|
|
14
16
|
? INPUT_DATE_STRING_FORMAT_DATE
|
|
15
|
-
: INPUT_DATE_STRING_FORMAT_MONTH;
|
|
17
|
+
: INPUT_DATE_STRING_FORMAT_MONTH);
|
|
16
18
|
return format(date, INPUT_DATE_STRING_FORMAT, { locale });
|
|
17
19
|
};
|