@povio/ui 2.3.2 → 2.3.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.
@@ -22,9 +22,9 @@ var translation_default = {
22
22
  "thisAndLastWeek": "Ta in prejšnji teden",
23
23
  "thisMonth": "Ta mesec",
24
24
  "thisAndLastMonth": "Ta in prejšnji mesec",
25
- "thisYear": "Ta leto",
25
+ "thisYear": "To leto",
26
26
  "lastYear": "Prejšnje leto",
27
- "thisAndLastYear": "Ta in prejšnje leto",
27
+ "thisAndLastYear": "To in prejšnje leto",
28
28
  "soFar": "Od začetka"
29
29
  },
30
30
  "navigation": {
@@ -23,7 +23,7 @@ import { useDateRangePickerState, useRangeCalendarState } from "react-stately";
23
23
  var DateRangePickerBase = (props) => {
24
24
  const ui = UIConfig.useConfig();
25
25
  const { t } = useTranslation();
26
- const { ref, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, onChange, value, disableDropdown, className, hideSidebar, placeholder, inputClassName, hideLabel = ui.input.hideLabel, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, isClearable = ui.input.isClearable, todayIcon = ui.dateInput.todayIcon, shouldForceLeadingZeros = ui.dateInput.shouldForceLeadingZeros, disableManualEntry = ui.dateInput.disableManualEntry, autoFixYear = ui.dateInput.autoFixYear, ...rest } = props;
26
+ const { ref, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, onChange, value, disableDropdown, className, hideSidebar, placeholder, inputClassName, hideLabel = ui.input.hideLabel, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, isClearable = ui.input.isClearable, todayIcon = ui.dateInput.todayIcon, shouldForceLeadingZeros = ui.dateInput.shouldForceLeadingZeros, disableManualEntry = ui.dateInput.disableManualEntry, autoFixYear = ui.dateInput.autoFixYear, minValue, maxValue, ...rest } = props;
27
27
  const [validationRangeError, setValidationRangeError] = useState();
28
28
  const datePickerInputRef = useRef(null);
29
29
  const dateRangePickerRef = useMemo(() => ({ get current() {
@@ -33,12 +33,16 @@ var DateRangePickerBase = (props) => {
33
33
  ...rest,
34
34
  value,
35
35
  shouldCloseOnSelect: false,
36
- shouldForceLeadingZeros
36
+ shouldForceLeadingZeros,
37
+ minValue,
38
+ maxValue
37
39
  });
38
40
  const state = useDateRangePickerState({
39
41
  ...rest,
40
42
  shouldForceLeadingZeros,
41
43
  value,
44
+ minValue,
45
+ maxValue,
42
46
  onChange: (newValue) => {
43
47
  if (isValidRange(newValue)) return;
44
48
  onChange?.(newValue);
@@ -49,12 +53,16 @@ var DateRangePickerBase = (props) => {
49
53
  const { groupProps, labelProps, startFieldProps, endFieldProps, buttonProps, dialogProps } = useDateRangePicker({
50
54
  ...rest,
51
55
  label,
52
- shouldForceLeadingZeros
56
+ shouldForceLeadingZeros,
57
+ minValue,
58
+ maxValue
53
59
  }, state, dateRangePickerRef);
54
60
  const { calendarProps } = useDateRangePicker({
55
61
  ...rest,
56
62
  label,
57
- shouldForceLeadingZeros
63
+ shouldForceLeadingZeros,
64
+ minValue,
65
+ maxValue
58
66
  }, dialogState, dateRangePickerRef);
59
67
  const { locale } = useLocale$1();
60
68
  useImperativeHandle(ref, () => ({ clear: () => {
@@ -79,8 +87,8 @@ var DateRangePickerBase = (props) => {
79
87
  createCalendar,
80
88
  pageBehavior: "single",
81
89
  visibleDuration: { months: 1 },
82
- minValue: void 0,
83
- maxValue: void 0
90
+ minValue,
91
+ maxValue
84
92
  });
85
93
  const rightCalendarState = useRangeCalendarState({
86
94
  ...calendarProps,
@@ -89,8 +97,8 @@ var DateRangePickerBase = (props) => {
89
97
  pageBehavior: "single",
90
98
  visibleDuration: { months: 1 },
91
99
  defaultFocusedValue: today(getLocalTimeZone()).add({ months: 1 }),
92
- minValue: void 0,
93
- maxValue: void 0
100
+ minValue,
101
+ maxValue
94
102
  });
95
103
  const [activePreset, setActivePreset] = useState(null);
96
104
  const [rangeSelection, setRangeSelection] = useState({
@@ -110,6 +118,32 @@ var DateRangePickerBase = (props) => {
110
118
  className: headerClassName,
111
119
  labelProps
112
120
  };
121
+ const isDateOutsideBounds = useCallback((date) => {
122
+ if (minValue && date.compare(minValue) < 0) return true;
123
+ if (maxValue && date.compare(maxValue) > 0) return true;
124
+ return false;
125
+ }, [minValue, maxValue]);
126
+ const clampRangeToBounds = useCallback((range) => {
127
+ if (range === null) return null;
128
+ if (minValue && maxValue && minValue.compare(maxValue) > 0) return null;
129
+ let startDate = range.start;
130
+ let endDate = range.end;
131
+ if (minValue && endDate.compare(minValue) < 0 || maxValue && startDate.compare(maxValue) > 0) return null;
132
+ if (minValue && startDate.compare(minValue) < 0) startDate = minValue;
133
+ if (maxValue && startDate.compare(maxValue) > 0) startDate = maxValue;
134
+ if (minValue && endDate.compare(minValue) < 0) endDate = minValue;
135
+ if (maxValue && endDate.compare(maxValue) > 0) endDate = maxValue;
136
+ if (startDate.compare(endDate) > 0) return null;
137
+ return {
138
+ start: startDate,
139
+ end: endDate
140
+ };
141
+ }, [minValue, maxValue]);
142
+ const isRangeWithinBounds = useCallback((range) => {
143
+ if (minValue && range.start.compare(minValue) < 0) return false;
144
+ if (maxValue && range.end.compare(maxValue) > 0) return false;
145
+ return true;
146
+ }, [minValue, maxValue]);
113
147
  const isValidRange = useCallback((newValue) => {
114
148
  if (newValue?.start && newValue?.end) {
115
149
  const startDate = newValue.start;
@@ -123,18 +157,20 @@ var DateRangePickerBase = (props) => {
123
157
  }, [t]);
124
158
  const handleCalendarStatesChange = (newValue) => {
125
159
  if (newValue) {
126
- if (isValidRange(newValue)) return;
127
- dialogState.setValue(newValue);
128
- const startDate = newValue.start;
129
- const endDate = newValue.end;
160
+ const clampedValue = clampRangeToBounds(newValue);
161
+ if (!clampedValue) return;
162
+ if (isValidRange(clampedValue)) return;
163
+ dialogState.setValue(clampedValue);
164
+ const startDate = clampedValue.start;
165
+ const endDate = clampedValue.end;
130
166
  leftCalendarState.setFocusedDate(startDate);
131
167
  if (startDate.year === endDate.year && startDate.month === endDate.month) rightCalendarState.setFocusedDate(startDate.add({ months: 1 }));
132
168
  else rightCalendarState.setFocusedDate(endDate);
133
- leftCalendarState.setValue(newValue);
134
- rightCalendarState.setValue(newValue);
169
+ leftCalendarState.setValue(clampedValue);
170
+ rightCalendarState.setValue(clampedValue);
135
171
  setRangeSelection({
136
- start: newValue.start,
137
- end: newValue.end,
172
+ start: clampedValue.start,
173
+ end: clampedValue.end,
138
174
  isSelecting: false
139
175
  });
140
176
  setHoverDate(null);
@@ -176,6 +212,7 @@ var DateRangePickerBase = (props) => {
176
212
  leftCalendarState.setFocusedDate(date.subtract({ months: 1 }));
177
213
  }
178
214
  }
215
+ if (isDateOutsideBounds(date)) return;
179
216
  if (!rangeSelection.isSelecting || !rangeSelection.start) {
180
217
  setRangeSelection({
181
218
  start: date,
@@ -188,18 +225,17 @@ var DateRangePickerBase = (props) => {
188
225
  } else {
189
226
  const { start } = rangeSelection;
190
227
  const end = date;
191
- const finalStart = start.compare(end) <= 0 ? start : end;
192
- const finalEnd = start.compare(end) <= 0 ? end : start;
193
- const newRange = {
194
- start: finalStart,
195
- end: finalEnd
196
- };
197
- leftCalendarState.setValue(newRange);
198
- rightCalendarState.setValue(newRange);
199
- dialogState.setValue(newRange);
228
+ const clampedRange = clampRangeToBounds({
229
+ start: start.compare(end) <= 0 ? start : end,
230
+ end: start.compare(end) <= 0 ? end : start
231
+ });
232
+ if (!clampedRange) return;
233
+ leftCalendarState.setValue(clampedRange);
234
+ rightCalendarState.setValue(clampedRange);
235
+ dialogState.setValue(clampedRange);
200
236
  setRangeSelection({
201
- start: finalStart,
202
- end: finalEnd,
237
+ start: clampedRange.start,
238
+ end: clampedRange.end,
203
239
  isSelecting: false
204
240
  });
205
241
  setHoverDate(null);
@@ -209,7 +245,9 @@ var DateRangePickerBase = (props) => {
209
245
  rangeSelection,
210
246
  leftCalendarState,
211
247
  rightCalendarState,
212
- dialogState
248
+ dialogState,
249
+ isDateOutsideBounds,
250
+ clampRangeToBounds
213
251
  ]);
214
252
  const handleKeyboardNavigation = useCallback((event, date, calendarSide) => {
215
253
  const currentState = calendarSide === "left" ? leftCalendarState : rightCalendarState;
@@ -295,18 +333,28 @@ var DateRangePickerBase = (props) => {
295
333
  handleDateSelection
296
334
  ]);
297
335
  const syncCalendarStates = useCallback((newValue) => {
298
- if (isValidRange(newValue)) return;
299
- leftCalendarState.setValue(newValue);
300
- rightCalendarState.setValue(newValue);
301
- dialogState.setValue(newValue);
302
- if (newValue) setRangeSelection({
303
- start: newValue.start,
304
- end: newValue.end,
305
- isSelecting: false
306
- });
307
- else setRangeSelection({
308
- start: null,
309
- end: null,
336
+ if (newValue === null) {
337
+ setValidationRangeError(void 0);
338
+ leftCalendarState.setValue(null);
339
+ rightCalendarState.setValue(null);
340
+ dialogState.setValue(null);
341
+ setRangeSelection({
342
+ start: null,
343
+ end: null,
344
+ isSelecting: false
345
+ });
346
+ setHoverDate(null);
347
+ return;
348
+ }
349
+ const clampedValue = clampRangeToBounds(newValue);
350
+ if (!clampedValue) return;
351
+ if (isValidRange(clampedValue)) return;
352
+ leftCalendarState.setValue(clampedValue);
353
+ rightCalendarState.setValue(clampedValue);
354
+ dialogState.setValue(clampedValue);
355
+ setRangeSelection({
356
+ start: clampedValue.start,
357
+ end: clampedValue.end,
310
358
  isSelecting: false
311
359
  });
312
360
  setHoverDate(null);
@@ -314,24 +362,32 @@ var DateRangePickerBase = (props) => {
314
362
  isValidRange,
315
363
  leftCalendarState,
316
364
  rightCalendarState,
317
- dialogState
365
+ dialogState,
366
+ clampRangeToBounds
318
367
  ]);
319
368
  const onApply = () => {
320
- const valueToApply = rangeSelection.start && rangeSelection.end ? {
369
+ let valueToApply = dialogState.value;
370
+ if (rangeSelection.start && rangeSelection.end) valueToApply = {
321
371
  start: rangeSelection.start,
322
372
  end: rangeSelection.end
323
- } : dialogState.value;
324
- if (valueToApply) state.setValue(valueToApply);
373
+ };
374
+ const clampedValue = clampRangeToBounds(valueToApply);
375
+ if (clampedValue) state.setValue(clampedValue);
325
376
  state.toggle();
326
377
  };
327
378
  const onTodayPress = () => {
328
379
  const todayDate = today(getLocalTimeZone());
329
- leftCalendarState.setFocusedDate(todayDate);
330
- rightCalendarState.setFocusedDate(todayDate.add({ months: 1 }));
331
- syncCalendarStates({
380
+ const clampedTodayRange = clampRangeToBounds({
332
381
  start: todayDate,
333
382
  end: todayDate
334
383
  });
384
+ if (!clampedTodayRange) return;
385
+ const startDate = clampedTodayRange.start;
386
+ const endDate = clampedTodayRange.end;
387
+ leftCalendarState.setFocusedDate(startDate);
388
+ if (startDate.year === endDate.year && startDate.month === endDate.month) rightCalendarState.setFocusedDate(startDate.add({ months: 1 }));
389
+ else rightCalendarState.setFocusedDate(endDate);
390
+ syncCalendarStates(clampedTodayRange);
335
391
  };
336
392
  const onOpenChange = (isOpen) => {
337
393
  state.toggle();
@@ -387,59 +443,84 @@ var DateRangePickerBase = (props) => {
387
443
  end: thisMonthEnd
388
444
  };
389
445
  };
446
+ const createPreset = (params) => {
447
+ let clampedValue = clampRangeToBounds(params.getValue());
448
+ let isDisabled = false;
449
+ if (params.keepEnabledUnlessFutureMin) {
450
+ let minDateIsInFuture = false;
451
+ if (minValue && minValue.compare(todayDate) > 0) minDateIsInFuture = true;
452
+ if (minDateIsInFuture) {
453
+ isDisabled = true;
454
+ clampedValue = null;
455
+ } else if (!clampedValue && maxValue) clampedValue = {
456
+ start: maxValue,
457
+ end: maxValue
458
+ };
459
+ }
460
+ if (!clampedValue) isDisabled = true;
461
+ if (clampedValue && !isRangeWithinBounds(clampedValue)) isDisabled = true;
462
+ return {
463
+ label: params.label,
464
+ getValue: params.getValue,
465
+ clampedValue,
466
+ isDisabled
467
+ };
468
+ };
390
469
  const presets = [
391
- {
470
+ createPreset({
392
471
  label: t(($) => $.ui.datePicker.presets.thisWeek, { ns: "ui" }),
393
472
  getValue: getThisWeekRange
394
- },
395
- {
473
+ }),
474
+ createPreset({
396
475
  label: t(($) => $.ui.datePicker.presets.lastWeek, { ns: "ui" }),
397
476
  getValue: getLastWeekRange
398
- },
399
- {
477
+ }),
478
+ createPreset({
400
479
  label: t(($) => $.ui.datePicker.presets.thisAndLastWeek, { ns: "ui" }),
401
480
  getValue: getThisAndLastWeekRange
402
- },
403
- {
481
+ }),
482
+ createPreset({
404
483
  label: t(($) => $.ui.datePicker.presets.thisMonth, { ns: "ui" }),
405
484
  getValue: getThisMonthRange
406
- },
407
- {
485
+ }),
486
+ createPreset({
408
487
  label: t(($) => $.ui.datePicker.presets.thisAndLastMonth, { ns: "ui" }),
409
488
  getValue: getThisAndLastMonthRange
410
- },
411
- {
489
+ }),
490
+ createPreset({
412
491
  label: t(($) => $.ui.datePicker.presets.thisYear, { ns: "ui" }),
413
492
  getValue: () => ({
414
493
  start: startOfYear(todayDate),
415
494
  end: todayDate
416
495
  })
417
- },
418
- {
496
+ }),
497
+ createPreset({
419
498
  label: t(($) => $.ui.datePicker.presets.lastYear, { ns: "ui" }),
420
499
  getValue: () => ({
421
500
  start: startOfYear(todayDate.subtract({ years: 1 })),
422
501
  end: endOfYear(todayDate.subtract({ years: 1 }))
423
502
  })
424
- },
425
- {
503
+ }),
504
+ createPreset({
426
505
  label: t(($) => $.ui.datePicker.presets.thisAndLastYear, { ns: "ui" }),
427
506
  getValue: () => ({
428
507
  start: startOfYear(todayDate.subtract({ years: 1 })),
429
508
  end: todayDate
430
509
  })
431
- },
432
- {
510
+ }),
511
+ createPreset({
433
512
  label: t(($) => $.ui.datePicker.presets.soFar, { ns: "ui" }),
434
513
  getValue: () => ({
435
514
  start: startOfYear(todayDate),
436
515
  end: todayDate
437
- })
438
- }
516
+ }),
517
+ keepEnabledUnlessFutureMin: true
518
+ })
439
519
  ];
440
520
  const selectPreset = (preset) => {
521
+ if (preset.isDisabled || !preset.clampedValue) return;
441
522
  setActivePreset(preset.label);
442
- const presetValue = preset.getValue();
523
+ const presetValue = preset.clampedValue;
443
524
  syncCalendarStates(presetValue);
444
525
  const startDate = presetValue.start;
445
526
  leftCalendarState.setFocusedDate(startDate);
@@ -486,8 +567,9 @@ var DateRangePickerBase = (props) => {
486
567
  sidebar: /* @__PURE__ */ jsx("div", {
487
568
  className: "flex w-full flex-row overflow-auto border-elevation-outline-default-1 border-solid [-ms-overflow-style:none] [scrollbar-width:none] md:w-[156px] md:flex-col md:border-r [&::-webkit-scrollbar]:hidden",
488
569
  children: presets.map((preset) => /* @__PURE__ */ jsx(Button, {
570
+ isDisabled: preset.isDisabled,
489
571
  onClick: () => selectPreset(preset),
490
- className: clsx("w-full px-2 py-1 text-left md:px-list-side-item-left md:py-list-height-item", activePreset !== preset.label && "text-interactive-text-secondary-idle hover:text-interactive-text-secondary-hover", activePreset === preset.label && "bg-interactive-contained-primary-idle text-interactive-text-secondary-idle-inverted"),
572
+ className: clsx("w-full px-2 py-1 text-left md:px-list-side-item-left md:py-list-height-item disabled:text-interactive-text-secondary-disabled!", activePreset !== preset.label && "text-interactive-text-secondary-idle hover:text-interactive-text-secondary-hover", activePreset === preset.label && "bg-interactive-contained-primary-idle text-interactive-text-secondary-idle-inverted"),
491
573
  children: /* @__PURE__ */ jsx(Typography, {
492
574
  size: "label-2",
493
575
  sizeMobile: "label-3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@povio/ui",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "type": "module",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",