Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions cypress/component/DateTimeInput.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Choose date',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
dateRenderLabel="date-input label"
timeRenderLabel="time-input label"
Expand Down Expand Up @@ -106,7 +108,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
Expand Down Expand Up @@ -134,7 +138,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
dateRenderLabel="date-input"
timeRenderLabel="time-input"
Expand Down Expand Up @@ -169,7 +175,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
dateRenderLabel="date-input"
timeRenderLabel="time-input"
Expand Down Expand Up @@ -199,7 +207,9 @@ describe('<DateInput/>', () => {
screenReaderLabels: {
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
},
timeRenderLabel: 'time-input',
invalidDateTimeMessage: 'whoops',
Expand Down Expand Up @@ -249,7 +259,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
Expand Down Expand Up @@ -286,7 +298,9 @@ describe('<DateInput/>', () => {
screenReaderLabels={{
calendarIcon: 'Open calendar',
prevMonthButton: 'Previous month',
nextMonthButton: 'Next month'
nextMonthButton: 'Next month',
datePickerDialog: 'Date picker',
selectedLabel: 'selected'
}}
timeRenderLabel="time-input"
invalidDateTimeMessage="whoops"
Expand Down
5 changes: 2 additions & 3 deletions packages/__docs__/src/Nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,8 @@ class Nav extends Component<NavProps, NavState> {
themeSelected = themeSelected || isSelected

const renderThemeName = (rawName: string) => {
if (rawName !== 'canvas' && rawName !== 'canvas-high-contrast') {
return `${rawName} (beta)`
}
if (rawName === 'canvas') return 'legacy-canvas'
if (rawName === 'canvas-high-contrast') return 'legacy-canvas-high-contrast'
return rawName
}

Expand Down
56 changes: 54 additions & 2 deletions packages/ui-calendar/src/Calendar/__tests__/Calendar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,12 @@ describe('<Calendar />', () => {
{generateDays()}
</Calendar>
)
const defaultPrevButton = screen.getByText('Previous month')
const defaultNextButton = screen.getByText('Next month')
const defaultPrevButton = screen.getByRole('button', {
name: /^Previous month/
})
const defaultNextButton = screen.getByRole('button', {
name: /^Next month/
})

expect(defaultPrevButton).toBeInTheDocument()
expect(defaultNextButton).toBeInTheDocument()
Expand Down Expand Up @@ -536,4 +540,52 @@ describe('<Calendar />', () => {
expect(calendar.tagName).toBe('UL')
expect(calendar).toHaveTextContent(weekdayLabels.join(''))
})

describe('navigation button targetMonthSrLabel', () => {
it('should include the target month in the default button screen reader labels', () => {
render(
<Calendar
renderWeekdayLabels={weekdayLabels}
visibleMonth="2023-12-01"
locale="en"
selectedLabel="Selected"
>
{generateDays()}
</Calendar>
)

expect(
screen.getByRole('button', { name: 'Previous month, November 2023' })
).toBeInTheDocument()
expect(
screen.getByRole('button', { name: 'Next month, January 2024' })
).toBeInTheDocument()
})

it('should pass targetMonthSrLabel to function render props', () => {
render(
<Calendar
renderWeekdayLabels={weekdayLabels}
visibleMonth="2023-12-01"
locale="en"
selectedLabel="Selected"
renderPrevMonthButton={({ targetMonthSrLabel }) => (
<button aria-label={`Go to ${targetMonthSrLabel}`}>prev</button>
)}
renderNextMonthButton={({ targetMonthSrLabel }) => (
<button aria-label={`Go to ${targetMonthSrLabel}`}>next</button>
)}
>
{generateDays()}
</Calendar>
)

expect(
screen.getByRole('button', { name: 'Go to November 2023' })
).toBeInTheDocument()
expect(
screen.getByRole('button', { name: 'Go to January 2024' })
).toBeInTheDocument()
})
})
})
25 changes: 19 additions & 6 deletions packages/ui-calendar/src/Calendar/v1/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,28 +175,41 @@ class Calendar extends Component<CalendarProps, CalendarState> {

renderMonthNavigationButtons = () => {
const { renderNextMonthButton, renderPrevMonthButton } = this.props
const { visibleMonth } = this.state
const prevMonthName = visibleMonth
.clone()
.subtract({ months: 1 })
.format('MMMM YYYY')
const nextMonthName = visibleMonth
.clone()
.add({ months: 1 })
.format('MMMM YYYY')

return {
prevButton: renderPrevMonthButton ? (
callRenderProp(renderPrevMonthButton)
callRenderProp(renderPrevMonthButton, {
targetMonthSrLabel: prevMonthName
})
) : (
<IconButton
size="small"
withBackground={false}
withBorder={false}
renderIcon={<IconArrowOpenStartSolid color="primary" />}
screenReaderLabel="Previous month"
screenReaderLabel={`Previous month, ${prevMonthName}`}
/>
),
nextButton: renderNextMonthButton ? (
callRenderProp(renderNextMonthButton)
callRenderProp(renderNextMonthButton, {
targetMonthSrLabel: nextMonthName
})
) : (
<IconButton
size="small"
withBackground={false}
withBorder={false}
renderIcon={<IconArrowOpenEndSolid color="primary" />}
screenReaderLabel="Next month"
screenReaderLabel={`Next month, ${nextMonthName}`}
/>
)
}
Expand Down Expand Up @@ -299,12 +312,12 @@ class Calendar extends Component<CalendarProps, CalendarState> {
{renderNavigationLabel ? (
callRenderProp(renderNavigationLabel)
) : (
<span>
<div aria-live="polite" aria-atomic="true">
<div>{visibleMonth.format('MMMM')}</div>
{!withYearPicker ? (
<div>{visibleMonth.format('YYYY')}</div>
) : null}
</span>
</div>
)}
{nextButton &&
cloneButton(nextButton, this.handleMonthChange('next'))}
Expand Down
30 changes: 17 additions & 13 deletions packages/ui-calendar/src/Calendar/v1/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,23 @@ type CalendarOwnProps = {
*/
renderNavigationLabel?: Renderable
/**
* A button to render in the navigation header. The recommendation is to
* compose it with the [IconButton](IconButton) component by setting the `size`
* prop to `small`, `withBorder` and `withBackground` to `false`, and setting
* `renderIcon` to [IconArrowOpenEnd](icons).
*/
renderNextMonthButton?: Renderable
/**
* A button to render in the navigation header. The recommendation is to
* compose it with the [IconButton](Button) component by setting the `size`
* prop to `small`, `withBorder` and `withBackground` to `false`, and setting
* `renderIcon` to [IconArrowOpenStart](icons).
*/
renderPrevMonthButton?: Renderable
* A button to render in the navigation header.
* When passed as a function, receives `{ targetMonthSrLabel }` —
* a pre-formatted screen reader label for the target month (e.g. "November 2023").
* The recommendation is to compose it with the [IconButton](Button) component
* by setting the `size` prop to `small`, `withBorder` and `withBackground` to `false`,
* and setting `renderIcon` to [IconArrowOpenStart](icons).
*/
renderNextMonthButton?: Renderable<{ targetMonthSrLabel: string }>
/**
* A button to render in the navigation header.
* When passed as a function, receives `{ targetMonthSrLabel }` —
* a pre-formatted screen reader label for the target month (e.g. "November 2023").
* The recommendation is to compose it with the [IconButton](Button) component
* by setting the `size` prop to `small`, `withBorder` and `withBackground` to `false`,
* and setting `renderIcon` to [IconArrowOpenStart](icons).
*/
renderPrevMonthButton?: Renderable<{ targetMonthSrLabel: string }>
/**
* An array of labels containing the name of each day of the week. The visible
* portion of the label should be abbreviated (no longer than three characters).
Expand Down
36 changes: 18 additions & 18 deletions packages/ui-calendar/src/Calendar/v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,23 +174,26 @@ type: example

const date = parseDate(renderedDate)

const buttonProps = (type = 'prev') => ({
size: 'small',
withBackground: false,
withBorder: false,
renderIcon:
type === 'prev' ? (
<ChevronLeftInstUIIcon color="baseColor" />
) : (
<ChevronRightInstUIIcon color="baseColor" />
),
screenReaderLabel: type === 'prev' ? 'Previous month' : 'Next month'
})
const renderMonthButton = (type = 'prev') => ({ targetMonthSrLabel }) => (
<IconButton
size="small"
withBackground={false}
withBorder={false}
renderIcon={
type === 'prev' ? (
<ChevronLeftInstUIIcon color="baseColor" />
) : (
<ChevronRightInstUIIcon color="baseColor" />
)
}
screenReaderLabel={`${type === 'prev' ? 'Previous month' : 'Next month'}, ${targetMonthSrLabel}`}
/>
)

return (
<Calendar
renderPrevMonthButton={<IconButton {...buttonProps('prev')} />}
renderNextMonthButton={<IconButton {...buttonProps('next')} />}
renderPrevMonthButton={renderMonthButton('prev')}
renderNextMonthButton={renderMonthButton('next')}
renderNavigationLabel={
<span>
<div>{date.format('MMMM')}</div>
Expand Down Expand Up @@ -251,7 +254,4 @@ the abbreviation. ex. `[<AccessibleContent alt="Sunday">Sun</AccessibleContent>,

#### Rendering next and previous month buttons

The `renderNextMonthButton` and `renderPrevMonthButton` can be supplied using the
[IconButton](IconButton) component with the `size` prop set to
`small`, the `withBackground` and `withBorder` props both set to `false`, and the `renderIcon` prop set to `ChevronLeftInstUIIcon` or
`ChevronRightInstUIIcon`.
The `renderNextMonthButton` and `renderPrevMonthButton` can be supplied as a function that receives `{ targetMonthSrLabel }` — a pre-formatted screen reader label for the target month (e.g. "November 2023"). Use this to compose an [IconButton](IconButton) component with the `size` prop set to `small`, the `withBackground` and `withBorder` props both set to `false`, and the `renderIcon` prop set to `ChevronLeftInstUIIcon` or `ChevronRightInstUIIcon`. The `screenReaderLabel` should include the target month for better accessibility: e.g. "Previous month, November 2023".
35 changes: 26 additions & 9 deletions packages/ui-calendar/src/Calendar/v2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,28 +174,41 @@ class Calendar extends Component<CalendarProps, CalendarState> {

renderMonthNavigationButtons = () => {
const { renderNextMonthButton, renderPrevMonthButton } = this.props
const { visibleMonth } = this.state
const prevMonthName = visibleMonth
.clone()
.subtract({ months: 1 })
.format('MMMM YYYY')
const nextMonthName = visibleMonth
.clone()
.add({ months: 1 })
.format('MMMM YYYY')

return {
prevButton: renderPrevMonthButton ? (
callRenderProp(renderPrevMonthButton)
callRenderProp(renderPrevMonthButton, {
targetMonthSrLabel: prevMonthName
})
) : (
<IconButton
size="small"
withBackground={false}
withBorder={false}
renderIcon={<ChevronLeftInstUIIcon color="baseColor" />}
screenReaderLabel="Previous month"
screenReaderLabel={`Previous month, ${prevMonthName}`}
/>
),
nextButton: renderNextMonthButton ? (
callRenderProp(renderNextMonthButton)
callRenderProp(renderNextMonthButton, {
targetMonthSrLabel: nextMonthName
})
) : (
<IconButton
size="small"
withBackground={false}
withBorder={false}
renderIcon={<ChevronRightInstUIIcon color="baseColor" />}
screenReaderLabel="Next month"
screenReaderLabel={`Next month, ${nextMonthName}`}
/>
)
}
Expand Down Expand Up @@ -298,12 +311,16 @@ class Calendar extends Component<CalendarProps, CalendarState> {
{renderNavigationLabel ? (
callRenderProp(renderNavigationLabel)
) : (
<span>
<div>{visibleMonth.format('MMMM')}</div>
<h2
aria-live="polite"
aria-atomic="true"
css={styles?.navigationLabel}
>
<span>{visibleMonth.format('MMMM')}</span>
{!withYearPicker ? (
<div>{visibleMonth.format('YYYY')}</div>
<span>{visibleMonth.format('YYYY')}</span>
) : null}
</span>
</h2>
)}
{nextButton &&
cloneButton(nextButton, this.handleMonthChange('next'))}
Expand All @@ -312,7 +329,7 @@ class Calendar extends Component<CalendarProps, CalendarState> {
{withYearPicker ? (
<div css={styles?.yearPicker}>
<SimpleSelect
width="90px"
width="95px"
renderLabel=""
placeholder="--"
assistiveText={withYearPicker.screenReaderLabel}
Expand Down
Loading
Loading