@stenajs-webui/calendar 24.0.0 → 25.0.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.
@@ -4,19 +4,10 @@ import { ValueAndOnValueChangeProps } from "@stenajs-webui/forms";
4
4
  import { TravelCalendarSizeVariant } from "../../../features/travel-calendar/components/TravelCalendar";
5
5
  import { DateTextInputVariant, RenderTravelDateContent } from "../../../features/travel-calendar/types";
6
6
  import { SupportedLocaleCode } from "../../../features/localize-date-format/LocaleMapper";
7
- export interface TravelDateCalendarProps extends ValueAndOnValueChangeProps<string> {
7
+ import { VisibleMonthState } from "../../../features/travel-calendar/hooks/UseVisibleMonthState";
8
+ export interface TravelDateCalendarProps extends ValueAndOnValueChangeProps<string>, VisibleMonthState {
8
9
  localeCode?: SupportedLocaleCode;
9
10
  languageLocaleCode?: SupportedLocaleCode;
10
- /**
11
- * The month the calendar shows. Only its year and month are read, so any
12
- * day of the month will do. The calendar never changes it by itself; see
13
- * onVisibleMonthChange.
14
- *
15
- * It is not taken from the value. To open on the month of a value, pass
16
- * that month, for example with
17
- * useVisibleMonthState(parseLocalizedDateString(value, localeCode)).
18
- */
19
- visibleMonth: Date;
20
11
  label?: string;
21
12
  previousMonthButtonAriaLabel?: string;
22
13
  nextMonthButtonAriaLabel?: string;
@@ -31,23 +22,6 @@ export interface TravelDateCalendarProps extends ValueAndOnValueChangeProps<stri
31
22
  * navigation, stays the calendar's. See RenderTravelDateContent.
32
23
  */
33
24
  renderDateContent?: RenderTravelDateContent;
34
- /**
35
- * Called when the calendar should show another month: from the month
36
- * buttons, the month picker, the arrow keys, or a value in another month.
37
- * It gets the first day of that month, and the calendar moves once
38
- * visibleMonth is set to it. It is not called for the month already shown.
39
- *
40
- * When it follows a value, it never asks for a month before the current
41
- * one: a value in the past asks for the current month. The month buttons
42
- * and the arrow keys are not limited that way. To keep the user out of
43
- * past months, set prevMonthDisabled and isDateDisabled, for example with
44
- * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
45
- * month picker starts at firstMonthInMonthPicker, the current month by
46
- * default.
47
- *
48
- * useVisibleMonthState() keeps this state, for when nothing else needs it.
49
- */
50
- onVisibleMonthChange: (visibleMonth: Date) => void;
51
25
  prevMonthDisabled?: (visibleMonth: Date) => boolean;
52
26
  nextMonthDisabled?: (visibleMonth: Date) => boolean;
53
27
  size?: TravelCalendarSizeVariant;
@@ -3,19 +3,10 @@ import { ValueAndOnValueChangeProps } from "@stenajs-webui/forms";
3
3
  import { TravelCalendarSizeVariant } from "../../../features/travel-calendar/components/TravelCalendar";
4
4
  import { SupportedLocaleCode } from "../../../features/localize-date-format/LocaleMapper";
5
5
  import { RenderTravelDateContent } from "../../../features/travel-calendar/types";
6
- export interface TravelDateCalendarPanelProps extends ValueAndOnValueChangeProps<string> {
6
+ import { VisibleMonthState } from "../../../features/travel-calendar/hooks/UseVisibleMonthState";
7
+ export interface TravelDateCalendarPanelProps extends ValueAndOnValueChangeProps<string>, VisibleMonthState {
7
8
  localeCode?: SupportedLocaleCode;
8
9
  languageLocaleCode?: SupportedLocaleCode;
9
- /**
10
- * The month the calendar shows. Only its year and month are read, so any
11
- * day of the month will do. The calendar never changes it by itself; see
12
- * onVisibleMonthChange.
13
- *
14
- * It is not taken from the value. To open on the month of a value, pass
15
- * that month, for example with
16
- * useVisibleMonthState(parseLocalizedDateString(value, localeCode)).
17
- */
18
- visibleMonth: Date;
19
10
  previousMonthButtonAriaLabel?: string;
20
11
  nextMonthButtonAriaLabel?: string;
21
12
  firstMonthInMonthPicker?: Date;
@@ -27,23 +18,6 @@ export interface TravelDateCalendarPanelProps extends ValueAndOnValueChangeProps
27
18
  * navigation, stays the calendar's. See RenderTravelDateContent.
28
19
  */
29
20
  renderDateContent?: RenderTravelDateContent;
30
- /**
31
- * Called when the calendar should show another month: from the month
32
- * buttons, the month picker, the arrow keys, or a value in another month.
33
- * It gets the first day of that month, and the calendar moves once
34
- * visibleMonth is set to it. It is not called for the month already shown.
35
- *
36
- * When it follows a value, it never asks for a month before the current
37
- * one: a value in the past asks for the current month. The month buttons
38
- * and the arrow keys are not limited that way. To keep the user out of
39
- * past months, set prevMonthDisabled and isDateDisabled, for example with
40
- * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
41
- * month picker starts at firstMonthInMonthPicker, the current month by
42
- * default.
43
- *
44
- * useVisibleMonthState() keeps this state, for when nothing else needs it.
45
- */
46
- onVisibleMonthChange: (visibleMonth: Date) => void;
47
21
  prevMonthDisabled?: (visibleMonth: Date) => boolean;
48
22
  nextMonthDisabled?: (visibleMonth: Date) => boolean;
49
23
  size?: TravelCalendarSizeVariant;
@@ -4,19 +4,10 @@ import { ValueAndOnValueChangeProps } from "@stenajs-webui/forms";
4
4
  import { TravelCalendarSizeVariant } from "../../../features/travel-calendar/components/TravelCalendar";
5
5
  import { DateTextInputVariant, TravelDateRangeInputValue, RenderTravelDateContent } from "../../../features/travel-calendar/types";
6
6
  import { SupportedLocaleCode } from "../../../features/localize-date-format/LocaleMapper";
7
- export interface TravelDateRangeCalendarProps extends ValueAndOnValueChangeProps<TravelDateRangeInputValue> {
7
+ import { VisibleMonthState } from "../../../features/travel-calendar/hooks/UseVisibleMonthState";
8
+ export interface TravelDateRangeCalendarProps extends ValueAndOnValueChangeProps<TravelDateRangeInputValue>, VisibleMonthState {
8
9
  localeCode?: SupportedLocaleCode;
9
10
  languageLocaleCode?: SupportedLocaleCode;
10
- /**
11
- * The month the calendar shows. Only its year and month are read, so any
12
- * day of the month will do. The calendar never changes it by itself; see
13
- * onVisibleMonthChange.
14
- *
15
- * It is not taken from the value. To open on the month of a value, pass
16
- * that month, for example with
17
- * useVisibleMonthState(parseLocalizedDateString(value, localeCode)).
18
- */
19
- visibleMonth: Date;
20
11
  startDateLabel?: string;
21
12
  endDateLabel?: string;
22
13
  previousMonthButtonAriaLabel?: string;
@@ -32,23 +23,6 @@ export interface TravelDateRangeCalendarProps extends ValueAndOnValueChangeProps
32
23
  * navigation, stays the calendar's. See RenderTravelDateContent.
33
24
  */
34
25
  renderDateContent?: RenderTravelDateContent;
35
- /**
36
- * Called when the calendar should show another month: from the month
37
- * buttons, the month picker, the arrow keys, or a value in another month.
38
- * It gets the first day of that month, and the calendar moves once
39
- * visibleMonth is set to it. It is not called for the month already shown.
40
- *
41
- * When it follows a value, it never asks for a month before the current
42
- * one: a value in the past asks for the current month. The month buttons
43
- * and the arrow keys are not limited that way. To keep the user out of
44
- * past months, set prevMonthDisabled and isDateDisabled, for example with
45
- * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
46
- * month picker starts at firstMonthInMonthPicker, the current month by
47
- * default.
48
- *
49
- * useVisibleMonthState() keeps this state, for when nothing else needs it.
50
- */
51
- onVisibleMonthChange: (visibleMonth: Date) => void;
52
26
  prevMonthDisabled?: (visibleMonth: Date) => boolean;
53
27
  nextMonthDisabled?: (visibleMonth: Date) => boolean;
54
28
  size?: TravelCalendarSizeVariant;
@@ -5,22 +5,13 @@ import { ValueAndOnValueChangeProps } from "@stenajs-webui/forms";
5
5
  import { TravelCalendarSizeVariant } from "../../../features/travel-calendar/components/TravelCalendar";
6
6
  import { DateTextInputVariant, RenderTravelDateContent } from "../../../features/travel-calendar/types";
7
7
  import { SupportedLocaleCode } from "../../../features/localize-date-format/LocaleMapper";
8
+ import { VisibleMonthState } from "../../../features/travel-calendar/hooks/UseVisibleMonthState";
8
9
  export interface RenderBelowSingleDateCalendarArgs {
9
10
  hideCalendar: () => void;
10
11
  }
11
- export interface TravelDateInputProps extends ValueAndOnValueChangeProps<string> {
12
+ export interface TravelDateInputProps extends ValueAndOnValueChangeProps<string>, VisibleMonthState {
12
13
  localeCode?: SupportedLocaleCode;
13
14
  languageLocaleCode?: SupportedLocaleCode;
14
- /**
15
- * The month the calendar shows. Only its year and month are read, so any
16
- * day of the month will do. The calendar never changes it by itself; see
17
- * onVisibleMonthChange.
18
- *
19
- * It is not taken from the value. To open on the month of a value, pass
20
- * that month, for example with
21
- * useVisibleMonthState(parseLocalizedDateString(value, localeCode)).
22
- */
23
- visibleMonth: Date;
24
15
  label?: string;
25
16
  previousMonthButtonAriaLabel?: string;
26
17
  nextMonthButtonAriaLabel?: string;
@@ -35,23 +26,6 @@ export interface TravelDateInputProps extends ValueAndOnValueChangeProps<string>
35
26
  * navigation, stays the calendar's. See RenderTravelDateContent.
36
27
  */
37
28
  renderDateContent?: RenderTravelDateContent;
38
- /**
39
- * Called when the calendar should show another month: from the month
40
- * buttons, the month picker, the arrow keys, or a value in another month.
41
- * It gets the first day of that month, and the calendar moves once
42
- * visibleMonth is set to it. It is not called for the month already shown.
43
- *
44
- * When it follows a value, it never asks for a month before the current
45
- * one: a value in the past asks for the current month. The month buttons
46
- * and the arrow keys are not limited that way. To keep the user out of
47
- * past months, set prevMonthDisabled and isDateDisabled, for example with
48
- * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
49
- * month picker starts at firstMonthInMonthPicker, the current month by
50
- * default.
51
- *
52
- * useVisibleMonthState() keeps this state, for when nothing else needs it.
53
- */
54
- onVisibleMonthChange: (visibleMonth: Date) => void;
55
29
  prevMonthDisabled?: (visibleMonth: Date) => boolean;
56
30
  nextMonthDisabled?: (visibleMonth: Date) => boolean;
57
31
  zIndex?: number;
@@ -5,22 +5,13 @@ import { ValueAndOnValueChangeProps } from "@stenajs-webui/forms";
5
5
  import { TravelCalendarSizeVariant } from "../../../features/travel-calendar/components/TravelCalendar";
6
6
  import { DateTextInputVariant, TravelDateRangeInputValue, RenderTravelDateContent } from "../../../features/travel-calendar/types";
7
7
  import { SupportedLocaleCode } from "../../../features/localize-date-format/LocaleMapper";
8
+ import { VisibleMonthState } from "../../../features/travel-calendar/hooks/UseVisibleMonthState";
8
9
  export interface RenderBelowCalendarArgs {
9
10
  hideCalendar: () => void;
10
11
  }
11
- export interface TravelDateRangeInputProps extends ValueAndOnValueChangeProps<TravelDateRangeInputValue> {
12
+ export interface TravelDateRangeInputProps extends ValueAndOnValueChangeProps<TravelDateRangeInputValue>, VisibleMonthState {
12
13
  localeCode?: SupportedLocaleCode;
13
14
  languageLocaleCode?: SupportedLocaleCode;
14
- /**
15
- * The month the calendar shows. Only its year and month are read, so any
16
- * day of the month will do. The calendar never changes it by itself; see
17
- * onVisibleMonthChange.
18
- *
19
- * It is not taken from the value. To open on the month of a value, pass
20
- * that month, for example with
21
- * useVisibleMonthState(parseLocalizedDateString(value, localeCode)).
22
- */
23
- visibleMonth: Date;
24
15
  startDateLabel?: string;
25
16
  endDateLabel?: string;
26
17
  previousMonthButtonAriaLabel?: string;
@@ -36,23 +27,6 @@ export interface TravelDateRangeInputProps extends ValueAndOnValueChangeProps<Tr
36
27
  * navigation, stays the calendar's. See RenderTravelDateContent.
37
28
  */
38
29
  renderDateContent?: RenderTravelDateContent;
39
- /**
40
- * Called when the calendar should show another month: from the month
41
- * buttons, the month picker, the arrow keys, or a value in another month.
42
- * It gets the first day of that month, and the calendar moves once
43
- * visibleMonth is set to it. It is not called for the month already shown.
44
- *
45
- * When it follows a value, it never asks for a month before the current
46
- * one: a value in the past asks for the current month. The month buttons
47
- * and the arrow keys are not limited that way. To keep the user out of
48
- * past months, set prevMonthDisabled and isDateDisabled, for example with
49
- * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
50
- * month picker starts at firstMonthInMonthPicker, the current month by
51
- * default.
52
- *
53
- * useVisibleMonthState() keeps this state, for when nothing else needs it.
54
- */
55
- onVisibleMonthChange: (visibleMonth: Date) => void;
56
30
  prevMonthDisabled?: (visibleMonth: Date) => boolean;
57
31
  nextMonthDisabled?: (visibleMonth: Date) => boolean;
58
32
  zIndex?: number;
@@ -9,8 +9,12 @@
9
9
  * month picker work with other days of the month, and the app should get the
10
10
  * same month in the same form whichever way it was reached.
11
11
  *
12
- * A request for the month that is already visible is not made at all, so the
13
- * app only hears about actual changes.
12
+ * A request for the month that is already visible is not made at all. The
13
+ * check is against the month of the last render, so two requests made before
14
+ * the app has passed a month back, such as two quick clicks while it loads,
15
+ * both reach it, the same way two quick edits reach any controlled input
16
+ * that updates later. The second request is left to the app rather than
17
+ * dropped here, since the app may not have taken the first.
14
18
  *
15
19
  * The month is kept by year and month, so an app that passes a new Date on
16
20
  * every render, such as new Date(), does not rebuild the calendar each time.
@@ -1,5 +1,39 @@
1
+ /**
2
+ * The visible month of a travel calendar, which the app keeps. All five
3
+ * travel calendars take these two props, and useVisibleMonthState returns
4
+ * them, ready to spread onto one.
5
+ */
1
6
  export interface VisibleMonthState {
7
+ /**
8
+ * The month the calendar shows. Only its year and month are read, so any
9
+ * day of the month will do. The calendar never changes it by itself; see
10
+ * onVisibleMonthChange.
11
+ *
12
+ * It is not taken from the value. To open on the month of the value, pass
13
+ * that month; useVisibleMonthState shows how.
14
+ */
2
15
  visibleMonth: Date;
16
+ /**
17
+ * Called when the calendar should show another month: from the month
18
+ * buttons, the month picker, the arrow keys, or a date in another month
19
+ * that the calendar follows. The single date calendars follow their value,
20
+ * typed or set from outside. The range calendars only follow a date typed
21
+ * into one of their fields.
22
+ *
23
+ * It gets the first day of that month, and the calendar moves once
24
+ * visibleMonth is set to it. It is not called for the month already shown.
25
+ *
26
+ * When it follows a date, it never asks for a month before the current
27
+ * one: a date in the past asks for the current month, unless it is in the
28
+ * month already shown. The month buttons and the arrow keys are not
29
+ * limited that way. To keep the user out of past months, set
30
+ * prevMonthDisabled and isDateDisabled, for example with
31
+ * usePrevMonthDisabledBeforeToday() and useDisabledBeforeToday(). The
32
+ * month picker starts at firstMonthInMonthPicker, the current month by
33
+ * default.
34
+ *
35
+ * useVisibleMonthState() keeps this state, for when nothing else needs it.
36
+ */
3
37
  onVisibleMonthChange: (visibleMonth: Date) => void;
4
38
  }
5
39
  /**
@@ -14,20 +48,34 @@ export interface VisibleMonthState {
14
48
  *
15
49
  * It starts at the current month, not at the month of a value. Before the
16
50
  * month was controlled, a calendar without initialMonthInFocus opened on the
17
- * month of its value. To keep that, start from the value's date:
51
+ * month of its value. To keep that, start from the value's date, with a
52
+ * function, the way useState takes one:
18
53
  *
19
- * const visibleMonthState = useVisibleMonthState(
20
- * parseLocalizedDateString(value, localeCode),
54
+ * const visibleMonthState = useVisibleMonthState(() =>
55
+ * value ? parseLocalizedDateString(value, localeCode) : undefined,
21
56
  * );
22
57
  *
23
- * parseLocalizedDateString returns undefined for an empty or incomplete
24
- * value, which falls back to the current month. Only the first render's
25
- * month is used, like any initial state.
58
+ * The function only runs on the first render, so the value is not parsed
59
+ * again on every render after it, and the check for a missing value keeps
60
+ * it type safe for an optional value. parseLocalizedDateString returns
61
+ * undefined for an incomplete value as well, and undefined falls back to
62
+ * the current month.
63
+ *
64
+ * The value of a range calendar is an object of two strings, so parse its
65
+ * start date instead:
66
+ *
67
+ * const visibleMonthState = useVisibleMonthState(() =>
68
+ * value?.startDate
69
+ * ? parseLocalizedDateString(value.startDate, localeCode)
70
+ * : undefined,
71
+ * );
26
72
  *
27
73
  * A calendar that had initialMonthInFocus passes that month instead:
28
74
  * useVisibleMonthState(initialMonthInFocus).
29
75
  *
30
- * @param initialMonth The month to show first. Defaults to the current month.
76
+ * @param initialMonth The month to show first, or a function that returns it,
77
+ * called once. Defaults to the current month, also when it is or returns
78
+ * undefined.
31
79
  *
32
80
  * @example
33
81
  * const visibleMonthState = useVisibleMonthState();
@@ -38,4 +86,4 @@ export interface VisibleMonthState {
38
86
  * {...visibleMonthState}
39
87
  * />
40
88
  */
41
- export declare const useVisibleMonthState: (initialMonth?: Date) => VisibleMonthState;
89
+ export declare const useVisibleMonthState: (initialMonth?: Date | (() => Date | undefined)) => VisibleMonthState;