@transferwise/components 0.0.0-experimental-fa3aa98 → 0.0.0-experimental-f4a328f
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/build/Calendar/Calendar.js +16 -94
- package/build/Calendar/Calendar.js.map +1 -1
- package/build/Calendar/Calendar.messages.js +0 -12
- package/build/Calendar/Calendar.messages.js.map +1 -1
- package/build/Calendar/Calendar.messages.mjs +0 -12
- package/build/Calendar/Calendar.messages.mjs.map +1 -1
- package/build/Calendar/Calendar.mjs +17 -95
- package/build/Calendar/Calendar.mjs.map +1 -1
- package/build/Calendar/DateHeader/DateHeader.js +1 -5
- package/build/Calendar/DateHeader/DateHeader.js.map +1 -1
- package/build/Calendar/DateHeader/DateHeader.mjs +1 -5
- package/build/Calendar/DateHeader/DateHeader.mjs.map +1 -1
- package/build/Calendar/DayCalendar/DayCalendar.js +0 -14
- package/build/Calendar/DayCalendar/DayCalendar.js.map +1 -1
- package/build/Calendar/DayCalendar/DayCalendar.mjs +0 -14
- package/build/Calendar/DayCalendar/DayCalendar.mjs.map +1 -1
- package/build/Calendar/DayCalendar/Table/DayCalendarTable.js +19 -53
- package/build/Calendar/DayCalendar/Table/DayCalendarTable.js.map +1 -1
- package/build/Calendar/DayCalendar/Table/DayCalendarTable.mjs +19 -53
- package/build/Calendar/DayCalendar/Table/DayCalendarTable.mjs.map +1 -1
- package/build/Calendar/MonthCalendar/MonthCalendar.js +0 -6
- package/build/Calendar/MonthCalendar/MonthCalendar.js.map +1 -1
- package/build/Calendar/MonthCalendar/MonthCalendar.mjs +0 -6
- package/build/Calendar/MonthCalendar/MonthCalendar.mjs.map +1 -1
- package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.js +3 -8
- package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.js.map +1 -1
- package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.mjs +3 -8
- package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.mjs.map +1 -1
- package/build/Calendar/YearCalendar/Table/YearCalendarTable.js +3 -8
- package/build/Calendar/YearCalendar/Table/YearCalendarTable.js.map +1 -1
- package/build/Calendar/YearCalendar/Table/YearCalendarTable.mjs +3 -8
- package/build/Calendar/YearCalendar/Table/YearCalendarTable.mjs.map +1 -1
- package/build/Calendar/YearCalendar/YearCalendar.js +0 -7
- package/build/Calendar/YearCalendar/YearCalendar.js.map +1 -1
- package/build/Calendar/YearCalendar/YearCalendar.mjs +0 -7
- package/build/Calendar/YearCalendar/YearCalendar.mjs.map +1 -1
- package/build/Calendar/{TableLink → tableLink}/TableLink.js +11 -26
- package/build/Calendar/tableLink/TableLink.js.map +1 -0
- package/build/Calendar/{TableLink → tableLink}/TableLink.mjs +11 -26
- package/build/Calendar/tableLink/TableLink.mjs.map +1 -0
- package/build/DateLookup/DateLookup.js +9 -20
- package/build/DateLookup/DateLookup.js.map +1 -1
- package/build/DateLookup/DateLookup.mjs +9 -20
- package/build/DateLookup/DateLookup.mjs.map +1 -1
- package/build/Markup/Markup.js +137 -0
- package/build/Markup/Markup.js.map +1 -0
- package/build/Markup/Markup.mjs +132 -0
- package/build/Markup/Markup.mjs.map +1 -0
- package/build/Markup/constants.js +36 -0
- package/build/Markup/constants.js.map +1 -0
- package/build/Markup/constants.mjs +29 -0
- package/build/Markup/constants.mjs.map +1 -0
- package/build/Markup/utils/parseMarkup.js +236 -0
- package/build/Markup/utils/parseMarkup.js.map +1 -0
- package/build/Markup/utils/parseMarkup.mjs +231 -0
- package/build/Markup/utils/parseMarkup.mjs.map +1 -0
- package/build/Markup/utils/sanitise.js +114 -0
- package/build/Markup/utils/sanitise.js.map +1 -0
- package/build/Markup/utils/sanitise.mjs +111 -0
- package/build/Markup/utils/sanitise.mjs.map +1 -0
- package/build/i18n/en.json +0 -4
- package/build/i18n/en.json.js +0 -4
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +0 -4
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/index.mjs +2 -1
- package/build/index.mjs.map +1 -1
- package/build/main.css +78 -123
- package/build/styles/Calendar/Calendar.css +37 -112
- package/build/styles/Markup/Markup.css +28 -0
- package/build/styles/Markup/_stories/Vulnerability/Vulnerability.css +69 -0
- package/build/styles/main.css +78 -123
- package/build/types/Body/Body.d.ts +2 -2
- package/build/types/Calendar/Calendar.d.ts +3 -16
- package/build/types/Calendar/Calendar.d.ts.map +1 -1
- package/build/types/Calendar/Calendar.messages.d.ts +0 -20
- package/build/types/Calendar/Calendar.messages.d.ts.map +1 -1
- package/build/types/Calendar/DateHeader/DateHeader.d.ts +0 -2
- package/build/types/Calendar/DateHeader/DateHeader.d.ts.map +1 -1
- package/build/types/Calendar/DayCalendar/DayCalendar.d.ts +1 -5
- package/build/types/Calendar/DayCalendar/DayCalendar.d.ts.map +1 -1
- package/build/types/Calendar/DayCalendar/Table/DayCalendarTable.d.ts +0 -4
- package/build/types/Calendar/DayCalendar/Table/DayCalendarTable.d.ts.map +1 -1
- package/build/types/Calendar/MonthCalendar/MonthCalendar.d.ts +0 -1
- package/build/types/Calendar/MonthCalendar/MonthCalendar.d.ts.map +1 -1
- package/build/types/Calendar/MonthCalendar/Table/MonthCalendarTable.d.ts +1 -2
- package/build/types/Calendar/MonthCalendar/Table/MonthCalendarTable.d.ts.map +1 -1
- package/build/types/Calendar/YearCalendar/Table/YearCalendarTable.d.ts +1 -2
- package/build/types/Calendar/YearCalendar/Table/YearCalendarTable.d.ts.map +1 -1
- package/build/types/Calendar/YearCalendar/YearCalendar.d.ts +0 -1
- package/build/types/Calendar/YearCalendar/YearCalendar.d.ts.map +1 -1
- package/build/types/Calendar/index.d.ts +0 -1
- package/build/types/Calendar/index.d.ts.map +1 -1
- package/build/types/Calendar/{TableLink → tableLink}/TableLink.d.ts +1 -3
- package/build/types/Calendar/tableLink/TableLink.d.ts.map +1 -0
- package/build/types/Calendar/tableLink/index.d.ts.map +1 -0
- package/build/types/DateLookup/DateLookup.d.ts +5 -24
- package/build/types/DateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/DateLookup/index.d.ts +0 -1
- package/build/types/DateLookup/index.d.ts.map +1 -1
- package/build/types/IconButton/IconButton.d.ts +1 -1
- package/build/types/Markup/Markup.d.ts +18 -0
- package/build/types/Markup/Markup.d.ts.map +1 -0
- package/build/types/Markup/Markup.types.d.ts +77 -0
- package/build/types/Markup/Markup.types.d.ts.map +1 -0
- package/build/types/Markup/_stories/Vulnerability/Vulnerability.d.ts +12 -0
- package/build/types/Markup/_stories/Vulnerability/Vulnerability.d.ts.map +1 -0
- package/build/types/Markup/constants.d.ts +20 -0
- package/build/types/Markup/constants.d.ts.map +1 -0
- package/build/types/Markup/index.d.ts +3 -0
- package/build/types/Markup/index.d.ts.map +1 -0
- package/build/types/Markup/utils/parseMarkup.d.ts +8 -0
- package/build/types/Markup/utils/parseMarkup.d.ts.map +1 -0
- package/build/types/Markup/utils/sanitise.d.ts +4 -0
- package/build/types/Markup/utils/sanitise.d.ts.map +1 -0
- package/build/types/Title/Title.d.ts +2 -2
- package/build/types/Upload/Steps/UploadImageStep/UploadImageStep.d.ts +1 -1
- package/build/types/UploadInput/UploadItem/UploadItemLink.d.ts +1 -1
- package/build/types/common/DateUtils/index.d.ts +0 -2
- package/build/types/common/DateUtils/index.d.ts.map +1 -1
- package/build/types/index.d.ts +4 -3
- package/build/types/index.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +0 -8
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Calendar/Calendar.css +37 -112
- package/src/Calendar/Calendar.less +35 -5
- package/src/Calendar/Calendar.messages.ts +0 -21
- package/src/Calendar/Calendar.test.tsx +27 -288
- package/src/Calendar/Calendar.tsx +19 -136
- package/src/Calendar/DateHeader/DateHeader.tsx +0 -6
- package/src/Calendar/DayCalendar/DayCalendar.tsx +1 -33
- package/src/Calendar/DayCalendar/Table/DayCalendarTable.tsx +28 -62
- package/src/Calendar/MonthCalendar/MonthCalendar.tsx +0 -8
- package/src/Calendar/MonthCalendar/Table/MonthCalendarTable.tsx +3 -15
- package/src/Calendar/YearCalendar/Table/YearCalendarTable.tsx +3 -15
- package/src/Calendar/YearCalendar/YearCalendar.tsx +0 -9
- package/src/Calendar/_stories/Calendar.story.tsx +4 -138
- package/src/Calendar/index.ts +0 -7
- package/src/Calendar/{TableLink → tableLink}/TableLink.tsx +14 -29
- package/src/DateLookup/DateLookup.test.tsx +37 -34
- package/src/DateLookup/DateLookup.tsx +13 -37
- package/src/DateLookup/_stories/DateLookup.story.tsx +2 -124
- package/src/DateLookup/index.ts +0 -6
- package/src/Markup/Markup.css +28 -0
- package/src/Markup/Markup.injection.test.tsx +163 -0
- package/src/Markup/Markup.less +29 -0
- package/src/Markup/Markup.test.tsx +463 -0
- package/src/Markup/Markup.tsx +169 -0
- package/src/Markup/Markup.types.ts +62 -0
- package/src/Markup/_stories/Markup.docs.mdx +75 -0
- package/src/Markup/_stories/Markup.security.docs.mdx +343 -0
- package/src/Markup/_stories/Markup.story.tsx +266 -0
- package/src/Markup/_stories/Vulnerability/Vulnerability.css +69 -0
- package/src/Markup/_stories/Vulnerability/Vulnerability.tsx +30 -0
- package/src/Markup/constants.ts +41 -0
- package/src/Markup/index.ts +2 -0
- package/src/Markup/utils/parseMarkup.test.ts +706 -0
- package/src/Markup/utils/parseMarkup.ts +234 -0
- package/src/Markup/utils/sanitise.test.ts +497 -0
- package/src/Markup/utils/sanitise.ts +133 -0
- package/src/common/DateUtils/index.ts +0 -2
- package/src/i18n/en.json +0 -4
- package/src/index.ts +4 -3
- package/src/main.css +78 -123
- package/src/main.less +1 -0
- package/build/Calendar/TableLink/TableLink.js.map +0 -1
- package/build/Calendar/TableLink/TableLink.mjs.map +0 -1
- package/build/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.js +0 -33
- package/build/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.js.map +0 -1
- package/build/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.mjs +0 -31
- package/build/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.mjs.map +0 -1
- package/build/common/DateUtils/isDateDisabled/isDateDisabled.js +0 -40
- package/build/common/DateUtils/isDateDisabled/isDateDisabled.js.map +0 -1
- package/build/common/DateUtils/isDateDisabled/isDateDisabled.mjs +0 -38
- package/build/common/DateUtils/isDateDisabled/isDateDisabled.mjs.map +0 -1
- package/build/styles/Calendar/TableLink/TableLink.css +0 -115
- package/build/types/Calendar/Calendar.types.d.ts +0 -32
- package/build/types/Calendar/Calendar.types.d.ts.map +0 -1
- package/build/types/Calendar/TableLink/TableLink.d.ts.map +0 -1
- package/build/types/Calendar/TableLink/index.d.ts.map +0 -1
- package/build/types/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.d.ts +0 -3
- package/build/types/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.d.ts.map +0 -1
- package/build/types/common/DateUtils/isDateDisabled/isDateDisabled.d.ts +0 -3
- package/build/types/common/DateUtils/isDateDisabled/isDateDisabled.d.ts.map +0 -1
- package/src/Calendar/Calendar.disabledDates.test.tsx +0 -518
- package/src/Calendar/Calendar.types.ts +0 -35
- package/src/Calendar/TableLink/TableLink.css +0 -115
- package/src/Calendar/TableLink/TableLink.less +0 -68
- package/src/Calendar/_stories/Calendar.accessibility.docs.mdx +0 -118
- package/src/Calendar/_stories/Calendar.test.story.tsx +0 -74
- package/src/DateLookup/DateLookup.disabledDates.test.tsx +0 -293
- package/src/DateLookup/_stories/DateLookup.accessibility.docs.mdx +0 -108
- package/src/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.test.ts +0 -98
- package/src/common/DateUtils/hasDisabledDatesInMonth/hasDisabledDatesInMonth.ts +0 -45
- package/src/common/DateUtils/isDateDisabled/isDateDisabled.test.ts +0 -169
- package/src/common/DateUtils/isDateDisabled/isDateDisabled.ts +0 -59
- /package/build/types/Calendar/{TableLink → tableLink}/index.d.ts +0 -0
- /package/src/Calendar/{TableLink → tableLink}/index.ts +0 -0
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
@import (reference) "./../../styles/variables/neptune-tokens.less";
|
|
2
|
-
|
|
3
|
-
.wds-Calendar__option--day,
|
|
4
|
-
.wds-Calendar__option--month,
|
|
5
|
-
.wds-Calendar__option--year {
|
|
6
|
-
width: 100%;
|
|
7
|
-
padding: var(--size-4) 0;
|
|
8
|
-
@media (--screen-400-zoom) {
|
|
9
|
-
padding: 0;
|
|
10
|
-
}
|
|
11
|
-
border: transparent;
|
|
12
|
-
border-radius: var(--radius-small);
|
|
13
|
-
background-color: transparent;
|
|
14
|
-
font-weight: var(--font-weight-semi-bold);
|
|
15
|
-
color: var(--color-content-primary);
|
|
16
|
-
|
|
17
|
-
&:focus {
|
|
18
|
-
background-color: var(--color-background-screen-hover);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
&.disabled,
|
|
22
|
-
&[aria-disabled="true"] {
|
|
23
|
-
--ring-outline-color: var(--color-sentiment-content-primary);
|
|
24
|
-
color: var(--color-content-tertiary);
|
|
25
|
-
cursor: not-allowed;
|
|
26
|
-
|
|
27
|
-
&:hover,
|
|
28
|
-
&:focus {
|
|
29
|
-
filter: unset;
|
|
30
|
-
opacity: unset;
|
|
31
|
-
background-color: var(--color-sentiment-background-surface);
|
|
32
|
-
color: var(--color-sentiment-content-primary);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
&.active {
|
|
36
|
-
&,
|
|
37
|
-
&:hover,
|
|
38
|
-
&:active,
|
|
39
|
-
&:focus {
|
|
40
|
-
filter: unset;
|
|
41
|
-
opacity: unset;
|
|
42
|
-
background-color: var(--color-sentiment-interactive-primary);
|
|
43
|
-
color: var(--color-sentiment-interactive-secondary);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
&.today {
|
|
48
|
-
text-decoration-color: var(--color-content-tertiary);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.wds-Calendar__option--day {
|
|
54
|
-
height: var(--size-40);
|
|
55
|
-
border-radius: var(--radius-full);
|
|
56
|
-
line-height: var(--size-40);
|
|
57
|
-
width: var(--size-40);
|
|
58
|
-
padding: 0;
|
|
59
|
-
display: inline-flex;
|
|
60
|
-
align-items: center;
|
|
61
|
-
justify-content: center;
|
|
62
|
-
|
|
63
|
-
&.today {
|
|
64
|
-
text-decoration: underline;
|
|
65
|
-
text-decoration-thickness: 2px;
|
|
66
|
-
text-underline-offset: 4px;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
-
|
|
3
|
-
<Meta title="Forms/Calendar/Accessibility" />
|
|
4
|
-
|
|
5
|
-
# Accessibility
|
|
6
|
-
|
|
7
|
-
Calendar is a fully keyboard-accessible date picker grid. All dates — including disabled ones — are reachable via keyboard so that screen reader users can discover which dates are unavailable and why.
|
|
8
|
-
|
|
9
|
-
## Keyboard Support
|
|
10
|
-
|
|
11
|
-
<table>
|
|
12
|
-
<thead>
|
|
13
|
-
<tr>
|
|
14
|
-
<th>Key</th>
|
|
15
|
-
<th>Action</th>
|
|
16
|
-
</tr>
|
|
17
|
-
</thead>
|
|
18
|
-
<tbody>
|
|
19
|
-
<tr>
|
|
20
|
-
<td>
|
|
21
|
-
<code>ArrowLeft</code>
|
|
22
|
-
</td>
|
|
23
|
-
<td>Move focus to previous day / month / year</td>
|
|
24
|
-
</tr>
|
|
25
|
-
<tr>
|
|
26
|
-
<td>
|
|
27
|
-
<code>ArrowRight</code>
|
|
28
|
-
</td>
|
|
29
|
-
<td>Move focus to next day / month / year</td>
|
|
30
|
-
</tr>
|
|
31
|
-
<tr>
|
|
32
|
-
<td>
|
|
33
|
-
<code>ArrowUp</code>
|
|
34
|
-
</td>
|
|
35
|
-
<td>Move focus up by one week (7 days) / 4 months / 4 years</td>
|
|
36
|
-
</tr>
|
|
37
|
-
<tr>
|
|
38
|
-
<td>
|
|
39
|
-
<code>ArrowDown</code>
|
|
40
|
-
</td>
|
|
41
|
-
<td>Move focus down by one week (7 days) / 4 months / 4 years</td>
|
|
42
|
-
</tr>
|
|
43
|
-
<tr>
|
|
44
|
-
<td>
|
|
45
|
-
<code>Enter</code> / <code>Space</code>
|
|
46
|
-
</td>
|
|
47
|
-
<td>Select the focused date (if enabled)</td>
|
|
48
|
-
</tr>
|
|
49
|
-
</tbody>
|
|
50
|
-
</table>
|
|
51
|
-
|
|
52
|
-
<br /> Navigation **does not skip** disabled dates. Users can arrow through every date in the grid
|
|
53
|
-
regardless of its enabled state.
|
|
54
|
-
|
|
55
|
-
## Screen Reader Announcements
|
|
56
|
-
|
|
57
|
-
Each date cell is a `<button>` with an `aria-label` in a human-readable long format (e.g. "6 July 2024") constructed via `Intl.DateTimeFormat` for full locale support.
|
|
58
|
-
|
|
59
|
-
### Active (Selected) Date
|
|
60
|
-
|
|
61
|
-
The currently selected date includes "selected day" in its aria-label:
|
|
62
|
-
|
|
63
|
-
> "6 July 2024, selected day"
|
|
64
|
-
|
|
65
|
-
### Disabled Dates (via `disabledRules`)
|
|
66
|
-
|
|
67
|
-
Dates disabled via `disabledRules` remain focusable and keyboard-navigable. They are announced with additional context:
|
|
68
|
-
|
|
69
|
-
- `aria-disabled="true"` signals the date is not selectable
|
|
70
|
-
- The aria-label appends "not available" (e.g. "6 July 2024, not available")
|
|
71
|
-
- `aria-describedby` links to the InlinePrompt element containing the reason text
|
|
72
|
-
|
|
73
|
-
This means a screen reader will announce something like:
|
|
74
|
-
|
|
75
|
-
> "6 July 2024, not available — We are closed on weekends. button, dimmed."
|
|
76
|
-
|
|
77
|
-
### Disabled + Selected
|
|
78
|
-
|
|
79
|
-
If the focused date is both active and disabled:
|
|
80
|
-
|
|
81
|
-
> "6 July 2024, selected day, not available"
|
|
82
|
-
|
|
83
|
-
### Out-of-Range Dates (via `min`/`max`)
|
|
84
|
-
|
|
85
|
-
Dates outside `min`/`max` boundaries use `aria-disabled="true"` (not the native HTML `disabled` attribute). They are rendered as interactive buttons in the grid: they can be clicked and the `aria-label` appends "not available". Arrow key navigation clamps at the boundary, so keyboard users cannot navigate into out-of-range cells — but they remain visible and clickable for pointer users.
|
|
86
|
-
|
|
87
|
-
This distinction is intentional: `min`/`max` defines a hard boundary (the calendar simply doesn't extend beyond it), while `disabledRules` marks dates that exist but are unavailable (users should be able to discover them and understand why).
|
|
88
|
-
|
|
89
|
-
## InlinePrompt Behaviour
|
|
90
|
-
|
|
91
|
-
An `InlinePrompt` renders below the day grid when the current month contains disabled dates. It displays the `disabledRules.reason` text.
|
|
92
|
-
|
|
93
|
-
### When It Appears
|
|
94
|
-
|
|
95
|
-
The prompt is visible when **all** of the following are true:
|
|
96
|
-
|
|
97
|
-
1. The Calendar is in day view
|
|
98
|
-
2. `disabledRules.reason` is provided
|
|
99
|
-
3. The currently displayed month contains at least one disabled date
|
|
100
|
-
|
|
101
|
-
### How It's Announced
|
|
102
|
-
|
|
103
|
-
The prompt is linked to disabled date cells via `aria-describedby`. This means the reason text is read as a description when a disabled cell receives focus — screen readers announce it after the label and role.
|
|
104
|
-
|
|
105
|
-
The prompt element has an `id` that matches the `aria-describedby` on each disabled cell. It is **not** a live region (`role="alert"` or `role="status"`) because:
|
|
106
|
-
|
|
107
|
-
- It does not change dynamically while focus is on a disabled cell
|
|
108
|
-
- Announcing it on every arrow key press would be disruptive
|
|
109
|
-
- The `aria-describedby` relationship already ensures it's read on focus
|
|
110
|
-
|
|
111
|
-
### Sentiment
|
|
112
|
-
|
|
113
|
-
The prompt's visual sentiment changes based on the currently focused date:
|
|
114
|
-
|
|
115
|
-
- **Negative** (red) — when the focused date is disabled
|
|
116
|
-
- **Neutral** — when the focused date is enabled
|
|
117
|
-
|
|
118
|
-
This is a visual-only change and does not affect screen reader output.
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
-
import { expect, within , userEvent } from 'storybook/test';
|
|
3
|
-
|
|
4
|
-
import Calendar from '../Calendar';
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
component: Calendar,
|
|
8
|
-
title: 'Forms/Calendar/Tests',
|
|
9
|
-
tags: ['!autodocs', '!manifest'],
|
|
10
|
-
} satisfies Meta<typeof Calendar>;
|
|
11
|
-
|
|
12
|
-
type Story = StoryObj<typeof Calendar>;
|
|
13
|
-
|
|
14
|
-
// min: March 2024, max: October 2024
|
|
15
|
-
const min = new Date(2024, 2, 1);
|
|
16
|
-
const max = new Date(2024, 9, 31);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Year view: years within min/max are enabled, years outside are disabled (aria-disabled),
|
|
20
|
-
* and both navigation arrows are disabled because min and max fall within the same 2020–2039 block.
|
|
21
|
-
*/
|
|
22
|
-
export const YearViewBoundaries: Story = {
|
|
23
|
-
render: () => <Calendar value={new Date(2024, 5, 15)} min={min} max={max} />,
|
|
24
|
-
play: async ({ canvasElement }) => {
|
|
25
|
-
const canvas = within(canvasElement);
|
|
26
|
-
|
|
27
|
-
await userEvent.click(canvas.getByRole('button', { name: /year view/iu }));
|
|
28
|
-
|
|
29
|
-
// Selected year (within range) is enabled
|
|
30
|
-
await expect(canvas.getByRole('button', { name: /2024.*selected year/iu })).not.toBeDisabled();
|
|
31
|
-
|
|
32
|
-
// Adjacent years outside range are disabled
|
|
33
|
-
await expect(canvas.getByRole('button', { name: /^2023.*not available/iu })).toBeDisabled();
|
|
34
|
-
await expect(canvas.getByRole('button', { name: /^2025.*not available/iu })).toBeDisabled();
|
|
35
|
-
|
|
36
|
-
// Both nav arrows disabled — min and max are both in the 2020–2039 block
|
|
37
|
-
await expect(canvas.getByRole('button', { name: /previous 20 years/iu })).toBeDisabled();
|
|
38
|
-
await expect(canvas.getByRole('button', { name: /next 20 years/iu })).toBeDisabled();
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Month view: months within min/max are enabled, months outside are disabled (aria-disabled),
|
|
44
|
-
* and both navigation arrows are disabled because min and max are both in 2024.
|
|
45
|
-
*/
|
|
46
|
-
export const MonthViewBoundaries: Story = {
|
|
47
|
-
render: () => <Calendar value={new Date(2024, 5, 15)} min={min} max={max} />,
|
|
48
|
-
play: async ({ canvasElement }) => {
|
|
49
|
-
const canvas = within(canvasElement);
|
|
50
|
-
|
|
51
|
-
// Navigate: year view → click 2024 → month view
|
|
52
|
-
await userEvent.click(canvas.getByRole('button', { name: /year view/iu }));
|
|
53
|
-
await userEvent.click(canvas.getByRole('button', { name: /2024.*selected year/iu }));
|
|
54
|
-
|
|
55
|
-
// Selected month (within range) is enabled
|
|
56
|
-
await expect(canvas.getByRole('button', { name: /^Jun.*selected month/iu })).not.toBeDisabled();
|
|
57
|
-
|
|
58
|
-
// Boundary months (min=Mar, max=Oct) are enabled
|
|
59
|
-
await expect(
|
|
60
|
-
canvas.getByRole('button', { name: /^Mar(?!.*not available)/iu }),
|
|
61
|
-
).not.toBeDisabled();
|
|
62
|
-
await expect(
|
|
63
|
-
canvas.getByRole('button', { name: /^Oct(?!.*not available)/iu }),
|
|
64
|
-
).not.toBeDisabled();
|
|
65
|
-
|
|
66
|
-
// Months outside range are disabled
|
|
67
|
-
await expect(canvas.getByRole('button', { name: /^Feb.*not available/iu })).toBeDisabled();
|
|
68
|
-
await expect(canvas.getByRole('button', { name: /^Nov.*not available/iu })).toBeDisabled();
|
|
69
|
-
|
|
70
|
-
// Both nav arrows disabled — min and max are both in 2024
|
|
71
|
-
await expect(canvas.getByRole('button', { name: /previous year/iu })).toBeDisabled();
|
|
72
|
-
await expect(canvas.getByRole('button', { name: /next year/iu })).toBeDisabled();
|
|
73
|
-
},
|
|
74
|
-
};
|
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
import { mockMatchMedia, mockResizeObserver, render, screen, userEvent } from '../test-utils';
|
|
2
|
-
import DateLookup from './DateLookup';
|
|
3
|
-
import type { DisabledRules } from '../Calendar/Calendar.types';
|
|
4
|
-
|
|
5
|
-
import { act } from 'react';
|
|
6
|
-
|
|
7
|
-
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTimeAsync });
|
|
8
|
-
|
|
9
|
-
mockMatchMedia();
|
|
10
|
-
mockResizeObserver();
|
|
11
|
-
|
|
12
|
-
const initialValue = new Date(2024, 6, 1);
|
|
13
|
-
|
|
14
|
-
const weekendRules: DisabledRules = {
|
|
15
|
-
weekdays: ['sat', 'sun'],
|
|
16
|
-
reason: 'We are closed on weekends.',
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const bankHolidayRules: DisabledRules = {
|
|
20
|
-
dates: [new Date(2024, 6, 4)],
|
|
21
|
-
reason: 'Bank holiday.',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
describe('DateLookup - disabled dates', () => {
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
jest.useFakeTimers();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(async () => {
|
|
30
|
-
await jest.runOnlyPendingTimersAsync();
|
|
31
|
-
jest.useRealTimers();
|
|
32
|
-
jest.clearAllMocks();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const openDateLookup = async () => {
|
|
36
|
-
await user.click(screen.getByRole('button'));
|
|
37
|
-
await act(async () => {
|
|
38
|
-
await jest.runOnlyPendingTimersAsync();
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
describe('panel behavior with rule-disabled dates', () => {
|
|
43
|
-
it('does NOT close when a rule-disabled date is clicked', async () => {
|
|
44
|
-
render(
|
|
45
|
-
<DateLookup value={initialValue} disabledRules={bankHolidayRules} onChange={jest.fn()} />,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
await openDateLookup();
|
|
49
|
-
const holiday = screen.getByLabelText(/^4 July 2024/u);
|
|
50
|
-
await user.click(holiday);
|
|
51
|
-
|
|
52
|
-
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('closes when an enabled date is clicked', async () => {
|
|
56
|
-
const handleChange = jest.fn();
|
|
57
|
-
render(
|
|
58
|
-
<DateLookup
|
|
59
|
-
value={initialValue}
|
|
60
|
-
disabledRules={bankHolidayRules}
|
|
61
|
-
onChange={handleChange}
|
|
62
|
-
/>,
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
await openDateLookup();
|
|
66
|
-
const enabledDate = screen.getByLabelText(/^3 July 2024/u);
|
|
67
|
-
await user.click(enabledDate);
|
|
68
|
-
|
|
69
|
-
await act(async () => {
|
|
70
|
-
await jest.runOnlyPendingTimersAsync();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
74
|
-
expect(handleChange).toHaveBeenCalledWith(new Date(2024, 6, 3));
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('panel behavior with out-of-range dates', () => {
|
|
79
|
-
const minDate = new Date(2024, 6, 3);
|
|
80
|
-
const maxDate = new Date(2024, 6, 25);
|
|
81
|
-
|
|
82
|
-
it('does NOT close when an out-of-range date is clicked', async () => {
|
|
83
|
-
render(
|
|
84
|
-
<DateLookup
|
|
85
|
-
value={new Date(2024, 6, 5)}
|
|
86
|
-
min={minDate}
|
|
87
|
-
max={maxDate}
|
|
88
|
-
onChange={jest.fn()}
|
|
89
|
-
/>,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
await openDateLookup();
|
|
93
|
-
await user.click(screen.getByRole('button', { name: /^1 July 2024/u }));
|
|
94
|
-
|
|
95
|
-
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('does NOT call onChange when an out-of-range date is clicked', async () => {
|
|
99
|
-
const handleChange = jest.fn();
|
|
100
|
-
render(
|
|
101
|
-
<DateLookup
|
|
102
|
-
value={new Date(2024, 6, 5)}
|
|
103
|
-
min={minDate}
|
|
104
|
-
max={maxDate}
|
|
105
|
-
onChange={handleChange}
|
|
106
|
-
/>,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
await openDateLookup();
|
|
110
|
-
await user.click(screen.getByRole('button', { name: /^1 July 2024/u }));
|
|
111
|
-
|
|
112
|
-
expect(handleChange).not.toHaveBeenCalled();
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('prop threading', () => {
|
|
117
|
-
it('renders rule-disabled dates with aria-disabled in the calendar', async () => {
|
|
118
|
-
render(<DateLookup value={initialValue} disabledRules={weekendRules} onChange={jest.fn()} />);
|
|
119
|
-
|
|
120
|
-
await openDateLookup();
|
|
121
|
-
|
|
122
|
-
const saturday = screen.getByLabelText(/^6 July 2024/u);
|
|
123
|
-
expect(saturday).toHaveAttribute('aria-disabled', 'true');
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('renders out-of-range dates with aria-disabled in the calendar', async () => {
|
|
127
|
-
render(
|
|
128
|
-
<DateLookup
|
|
129
|
-
value={new Date(2024, 6, 5)}
|
|
130
|
-
min={new Date(2024, 6, 3)}
|
|
131
|
-
max={new Date(2024, 6, 25)}
|
|
132
|
-
onChange={jest.fn()}
|
|
133
|
-
/>,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
await openDateLookup();
|
|
137
|
-
|
|
138
|
-
const outOfRangeDate = screen.getByRole('button', { name: /^1 July 2024/u });
|
|
139
|
-
expect(outOfRangeDate).toHaveAttribute('aria-disabled', 'true');
|
|
140
|
-
expect(outOfRangeDate).toBeEnabled();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('renders InlinePrompt with disabledRules reason text', async () => {
|
|
144
|
-
render(<DateLookup value={initialValue} disabledRules={weekendRules} onChange={jest.fn()} />);
|
|
145
|
-
|
|
146
|
-
await openDateLookup();
|
|
147
|
-
|
|
148
|
-
expect(screen.getByText('We are closed on weekends.')).toBeInTheDocument();
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('renders previous month button as disabled when min is in the current month', async () => {
|
|
152
|
-
render(
|
|
153
|
-
<DateLookup value={new Date(2024, 6, 5)} min={new Date(2024, 6, 1)} onChange={jest.fn()} />,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
await openDateLookup();
|
|
157
|
-
|
|
158
|
-
expect(screen.getByRole('button', { name: /previous month/iu })).toBeDisabled();
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('renders next month button as disabled when max is in the current month', async () => {
|
|
162
|
-
render(
|
|
163
|
-
<DateLookup
|
|
164
|
-
value={new Date(2024, 6, 5)}
|
|
165
|
-
max={new Date(2024, 6, 31)}
|
|
166
|
-
onChange={jest.fn()}
|
|
167
|
-
/>,
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
await openDateLookup();
|
|
171
|
-
|
|
172
|
-
expect(screen.getByRole('button', { name: /next month/iu })).toBeDisabled();
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
describe('InlinePrompt for out-of-range dates', () => {
|
|
177
|
-
const minDate = new Date(2024, 6, 3);
|
|
178
|
-
const maxDate = new Date(2024, 6, 25);
|
|
179
|
-
|
|
180
|
-
it('shows negative prompt with boundary dates when out-of-range date is clicked', async () => {
|
|
181
|
-
render(
|
|
182
|
-
<DateLookup
|
|
183
|
-
value={new Date(2024, 6, 5)}
|
|
184
|
-
min={minDate}
|
|
185
|
-
max={maxDate}
|
|
186
|
-
onChange={jest.fn()}
|
|
187
|
-
/>,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
await openDateLookup();
|
|
191
|
-
await user.click(screen.getByRole('button', { name: /^1 July 2024/u }));
|
|
192
|
-
|
|
193
|
-
// The prompt renders inside a portal so query from document
|
|
194
|
-
const prompt = document.querySelector('.wds-inline-prompt');
|
|
195
|
-
expect(prompt).toBeInTheDocument();
|
|
196
|
-
expect(prompt).toHaveClass('wds-prompt--negative');
|
|
197
|
-
expect(prompt).toHaveTextContent(
|
|
198
|
-
'Please select a date between 3 July 2024 and 25 July 2024.',
|
|
199
|
-
);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('shows boundary message (not disabledRules reason) when out-of-range date is clicked', async () => {
|
|
203
|
-
render(
|
|
204
|
-
<DateLookup
|
|
205
|
-
value={new Date(2024, 6, 5)}
|
|
206
|
-
min={minDate}
|
|
207
|
-
max={maxDate}
|
|
208
|
-
disabledRules={weekendRules}
|
|
209
|
-
onChange={jest.fn()}
|
|
210
|
-
/>,
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
await openDateLookup();
|
|
214
|
-
// July 27 is beyond max
|
|
215
|
-
await user.click(screen.getByRole('button', { name: /^27 July 2024/u }));
|
|
216
|
-
|
|
217
|
-
const prompt = document.querySelector('.wds-inline-prompt');
|
|
218
|
-
expect(prompt).toHaveTextContent(
|
|
219
|
-
'Please select a date between 3 July 2024 and 25 July 2024.',
|
|
220
|
-
);
|
|
221
|
-
expect(prompt).not.toHaveTextContent('We are closed on weekends.');
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe('onDateSelect', () => {
|
|
226
|
-
it('fires with isEnabled: false when navigating to a rule-disabled date', async () => {
|
|
227
|
-
const handleDateSelect = jest.fn();
|
|
228
|
-
render(
|
|
229
|
-
<DateLookup
|
|
230
|
-
value={new Date(2024, 6, 5)}
|
|
231
|
-
disabledRules={weekendRules}
|
|
232
|
-
onChange={jest.fn()}
|
|
233
|
-
onDateSelect={handleDateSelect}
|
|
234
|
-
/>,
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
await openDateLookup();
|
|
238
|
-
await user.keyboard('{ArrowRight}');
|
|
239
|
-
|
|
240
|
-
expect(handleDateSelect).toHaveBeenCalledWith(
|
|
241
|
-
expect.objectContaining({
|
|
242
|
-
date: new Date(2024, 6, 6),
|
|
243
|
-
isEnabled: false,
|
|
244
|
-
}),
|
|
245
|
-
);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('fires with isEnabled: false when clicking an out-of-range date', async () => {
|
|
249
|
-
const handleDateSelect = jest.fn();
|
|
250
|
-
render(
|
|
251
|
-
<DateLookup
|
|
252
|
-
value={new Date(2024, 6, 5)}
|
|
253
|
-
min={new Date(2024, 6, 3)}
|
|
254
|
-
max={new Date(2024, 6, 25)}
|
|
255
|
-
onChange={jest.fn()}
|
|
256
|
-
onDateSelect={handleDateSelect}
|
|
257
|
-
/>,
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
await openDateLookup();
|
|
261
|
-
await user.click(screen.getByRole('button', { name: /^1 July 2024/u }));
|
|
262
|
-
|
|
263
|
-
expect(handleDateSelect).toHaveBeenCalledWith(
|
|
264
|
-
expect.objectContaining({
|
|
265
|
-
date: new Date(2024, 6, 1),
|
|
266
|
-
isEnabled: false,
|
|
267
|
-
}),
|
|
268
|
-
);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it('fires with isEnabled: true when clicking an enabled date', async () => {
|
|
272
|
-
const handleDateSelect = jest.fn();
|
|
273
|
-
render(
|
|
274
|
-
<DateLookup
|
|
275
|
-
value={new Date(2024, 6, 5)}
|
|
276
|
-
disabledRules={weekendRules}
|
|
277
|
-
onChange={jest.fn()}
|
|
278
|
-
onDateSelect={handleDateSelect}
|
|
279
|
-
/>,
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
await openDateLookup();
|
|
283
|
-
await user.click(screen.getByLabelText(/^3 July 2024/u));
|
|
284
|
-
|
|
285
|
-
expect(handleDateSelect).toHaveBeenCalledWith(
|
|
286
|
-
expect.objectContaining({
|
|
287
|
-
date: new Date(2024, 6, 3),
|
|
288
|
-
isEnabled: true,
|
|
289
|
-
}),
|
|
290
|
-
);
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
});
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
-
|
|
3
|
-
<Meta title="Forms/DateLookup/Accessibility" />
|
|
4
|
-
|
|
5
|
-
# Accessibility
|
|
6
|
-
|
|
7
|
-
DateLookup wraps the Calendar component inside a dropdown panel. It provides full keyboard accessibility for opening, navigating, selecting, and dismissing dates.
|
|
8
|
-
|
|
9
|
-
## Keyboard Support
|
|
10
|
-
|
|
11
|
-
<table>
|
|
12
|
-
<thead>
|
|
13
|
-
<tr>
|
|
14
|
-
<th>Key</th>
|
|
15
|
-
<th>Context</th>
|
|
16
|
-
<th>Action</th>
|
|
17
|
-
</tr>
|
|
18
|
-
</thead>
|
|
19
|
-
<tbody>
|
|
20
|
-
<tr>
|
|
21
|
-
<td>
|
|
22
|
-
<code>ArrowLeft/Right/Up/Down</code>
|
|
23
|
-
</td>
|
|
24
|
-
<td>Trigger focused, panel closed</td>
|
|
25
|
-
<td>Opens the panel</td>
|
|
26
|
-
</tr>
|
|
27
|
-
<tr>
|
|
28
|
-
<td>
|
|
29
|
-
<code>ArrowLeft/Right/Up/Down</code>
|
|
30
|
-
</td>
|
|
31
|
-
<td>Panel open</td>
|
|
32
|
-
<td>Navigates between dates (see Calendar)</td>
|
|
33
|
-
</tr>
|
|
34
|
-
<tr>
|
|
35
|
-
<td>
|
|
36
|
-
<code>Enter</code> / <code>Space</code>
|
|
37
|
-
</td>
|
|
38
|
-
<td>Panel open, enabled date focused</td>
|
|
39
|
-
<td>Selects date, closes panel</td>
|
|
40
|
-
</tr>
|
|
41
|
-
<tr>
|
|
42
|
-
<td>
|
|
43
|
-
<code>Enter</code> / <code>Space</code>
|
|
44
|
-
</td>
|
|
45
|
-
<td>Panel open, disabled date focused</td>
|
|
46
|
-
<td>No action (panel stays open)</td>
|
|
47
|
-
</tr>
|
|
48
|
-
<tr>
|
|
49
|
-
<td>
|
|
50
|
-
<code>Escape</code>
|
|
51
|
-
</td>
|
|
52
|
-
<td>Panel open</td>
|
|
53
|
-
<td>Reverts to original value, closes panel</td>
|
|
54
|
-
</tr>
|
|
55
|
-
</tbody>
|
|
56
|
-
</table>
|
|
57
|
-
|
|
58
|
-
<br />
|
|
59
|
-
|
|
60
|
-
### Click Behaviour
|
|
61
|
-
|
|
62
|
-
- **Clicking an enabled date**: selects it, closes the panel, fires `onChange`
|
|
63
|
-
- **Clicking a disabled date**: does not select, panel stays open, focus remains in the calendar grid
|
|
64
|
-
|
|
65
|
-
## Screen Reader Announcements
|
|
66
|
-
|
|
67
|
-
DateLookup relies on the Calendar's built-in accessibility features for date announcements. See [Calendar
|
|
68
|
-
Accessibility](?path=/docs/forms-calendar-accessibility--docs) for details on how dates are labelled and described.
|
|
69
|
-
|
|
70
|
-
### Trigger Button
|
|
71
|
-
|
|
72
|
-
The trigger button announces the currently selected date (or placeholder text when no date is selected). It uses `aria-controls` to associate with the panel.
|
|
73
|
-
|
|
74
|
-
### Panel
|
|
75
|
-
|
|
76
|
-
The dropdown panel is rendered with `role="dialog"` and is connected to the trigger via `aria-controls`. When opened, focus moves into the calendar grid.
|
|
77
|
-
|
|
78
|
-
## Disabled Dates (via `disabledRules`)
|
|
79
|
-
|
|
80
|
-
When `disabledRules` is provided, disabled dates remain focusable and keyboard-navigable:
|
|
81
|
-
|
|
82
|
-
- `aria-disabled="true"` marks the cell as unavailable
|
|
83
|
-
- "not available" is appended to the aria-label
|
|
84
|
-
- `aria-describedby` links to the InlinePrompt reason text
|
|
85
|
-
- Keyboard navigation reaches disabled dates (they are not skipped)
|
|
86
|
-
- Clicking or pressing Enter on a disabled date does **not** close the panel
|
|
87
|
-
|
|
88
|
-
## Out-of-Range Dates (via `min`/`max`)
|
|
89
|
-
|
|
90
|
-
Dates outside `min`/`max` boundaries use `aria-disabled="true"` (not the native HTML `disabled` attribute). They are rendered as interactive buttons in the grid and can be clicked; the `aria-label` appends "not available". Arrow key navigation clamps at the boundary, so keyboard users cannot navigate into out-of-range cells.
|
|
91
|
-
|
|
92
|
-
This distinction is intentional: `min`/`max` defines a hard boundary, while `disabledRules` marks dates that exist but are unavailable (users can discover them and understand why via the InlinePrompt).
|
|
93
|
-
|
|
94
|
-
### InlinePrompt
|
|
95
|
-
|
|
96
|
-
An InlinePrompt renders below the day grid inside the panel when the visible month contains disabled dates. It displays the configured `disabledRules.reason` text.
|
|
97
|
-
|
|
98
|
-
The prompt is linked to disabled cells via `aria-describedby`, so screen readers announce the reason when a disabled
|
|
99
|
-
date receives focus. See [Calendar Accessibility](?path=/docs/forms-calendar-accessibility--docs) for full details on
|
|
100
|
-
the prompt's announcement behaviour.
|
|
101
|
-
|
|
102
|
-
## Consumer Callbacks
|
|
103
|
-
|
|
104
|
-
The `onDateSelect` callback fires with `{ date, isEnabled }` whenever the user navigates to or clicks on any date. Consumers can use this to:
|
|
105
|
-
|
|
106
|
-
- Display a custom message explaining why a specific date is disabled
|
|
107
|
-
- Track which dates users attempt to select
|
|
108
|
-
- Provide alternative actions for disabled dates
|