-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Carousel: Disabled focus handling and CarouselAnnouncer (#32844)
- Loading branch information
1 parent
603fe59
commit fc04799
Showing
26 changed files
with
390 additions
and
59 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
change/@fluentui-react-carousel-preview-37035160-0805-40b3-a10a-0d7e332c3442.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "minor", | ||
"comment": "feat: Handle nav disabled behavior and provide index based aria labels for next/prev buttons", | ||
"packageName": "@fluentui/react-carousel-preview", | ||
"email": "mifraser@microsoft.com", | ||
"dependentChangeType": "patch" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages/react-components/react-carousel-preview/library/src/CarouselAnnouncer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './components/CarouselAnnouncer/index'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...eact-carousel-preview/library/src/components/CarouselAnnouncer/CarouselAnnouncer.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import { isConformant } from '../../testing/isConformant'; | ||
import { CarouselAnnouncer } from './CarouselAnnouncer'; | ||
|
||
const renderFunc = (index: number, totalSlides: number, groupList: number[][]) => `Slide ${index} of ${totalSlides}`; | ||
|
||
describe('CarouselAnnouncer', () => { | ||
isConformant({ | ||
Component: CarouselAnnouncer, | ||
displayName: 'CarouselAnnouncer', | ||
requiredProps: { | ||
children: renderFunc, | ||
}, | ||
}); | ||
|
||
// TODO add more tests here, and create visual regression tests in /apps/vr-tests | ||
|
||
it('renders a default state', () => { | ||
const result = render(<CarouselAnnouncer>{renderFunc}</CarouselAnnouncer>); | ||
expect(result.container).toMatchSnapshot(); | ||
}); | ||
}); |
33 changes: 33 additions & 0 deletions
33
...nts/react-carousel-preview/library/src/components/CarouselAnnouncer/CarouselAnnouncer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as React from 'react'; | ||
import type { ForwardRefComponent } from '@fluentui/react-utilities'; | ||
import { useCarouselAnnouncer_unstable } from './useCarouselAnnouncer'; | ||
import { renderCarouselAnnouncer_unstable } from './renderCarouselAnnouncer'; | ||
import { useCarouselAnnouncerStyles_unstable } from './useCarouselAnnouncerStyles.styles'; | ||
import type { CarouselAnnouncerProps } from './CarouselAnnouncer.types'; | ||
|
||
/** | ||
* CarouselAnnouncer component - This component will enable context for announcements of carousel page changes. | ||
* | ||
* It is recommended to provide a simple current out of total page index string. | ||
* | ||
* Slide group lists are also provided when multiple cards are present in a single slide. | ||
*/ | ||
export const CarouselAnnouncer: ForwardRefComponent<CarouselAnnouncerProps> = React.forwardRef((props, ref) => { | ||
const state = useCarouselAnnouncer_unstable(props, ref); | ||
|
||
useCarouselAnnouncerStyles_unstable(state); | ||
|
||
/** | ||
* @see https://github.com/microsoft/fluentui/blob/master/docs/react-v9/contributing/rfcs/react-components/convergence/custom-styling.md | ||
* | ||
* TODO: 💡 once package will become stable (PR which will be part of promoting PREVIEW package to STABLE), | ||
* - uncomment this line | ||
* - update types {@link file://./../../../../../../../packages/react-components/react-shared-contexts/library/src/CustomStyleHooksContext/CustomStyleHooksContext.ts#CustomStyleHooksContextValue} | ||
* - verify that custom global style override works for your component | ||
*/ | ||
// useCustomStyleHook_unstable('useCarouselAnnouncerStyles_unstable')(state); | ||
|
||
return renderCarouselAnnouncer_unstable(state); | ||
}); | ||
|
||
CarouselAnnouncer.displayName = 'CarouselAnnouncer'; |
38 changes: 38 additions & 0 deletions
38
...eact-carousel-preview/library/src/components/CarouselAnnouncer/CarouselAnnouncer.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; | ||
|
||
export type CarouselAnnouncerSlots = { | ||
root: Slot<'div'>; | ||
}; | ||
|
||
export type AnnouncerIndexRenderFunction = (index: number, totalSlides: number, slideGroupList: number[][]) => string; | ||
/** | ||
* CarouselAnnouncer Props | ||
*/ | ||
export type CarouselAnnouncerProps = Omit<ComponentProps<Partial<CarouselAnnouncerSlots>>, 'children'> & { | ||
children: AnnouncerIndexRenderFunction; | ||
}; | ||
|
||
/** | ||
* State used in rendering CarouselAnnouncer | ||
*/ | ||
export type CarouselAnnouncerState = ComponentState<CarouselAnnouncerSlots> & { | ||
/** | ||
* The function that will render nav items based on total slides and their index. | ||
*/ | ||
renderAnnouncerChild: AnnouncerIndexRenderFunction; | ||
|
||
/** | ||
* The total number of slides passed in from carousel context. | ||
*/ | ||
totalSlides: number; | ||
|
||
/** | ||
* The current index passed in from carousel context. | ||
*/ | ||
currentIndex: number; | ||
|
||
/** | ||
* The list of cards in each slide based on index. | ||
*/ | ||
slideGroupList: number[][]; | ||
}; |
12 changes: 12 additions & 0 deletions
12
...ew/library/src/components/CarouselAnnouncer/__snapshots__/CarouselAnnouncer.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`CarouselAnnouncer renders a default state 1`] = ` | ||
<div> | ||
<div | ||
aria-live="polite" | ||
class="fui-CarouselAnnouncer" | ||
> | ||
Slide 0 of 0 | ||
</div> | ||
</div> | ||
`; |
5 changes: 5 additions & 0 deletions
5
...react-components/react-carousel-preview/library/src/components/CarouselAnnouncer/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './CarouselAnnouncer'; | ||
export * from './CarouselAnnouncer.types'; | ||
export * from './renderCarouselAnnouncer'; | ||
export * from './useCarouselAnnouncer'; | ||
export * from './useCarouselAnnouncerStyles.styles'; |
15 changes: 15 additions & 0 deletions
15
...act-carousel-preview/library/src/components/CarouselAnnouncer/renderCarouselAnnouncer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** @jsxRuntime automatic */ | ||
/** @jsxImportSource @fluentui/react-jsx-runtime */ | ||
|
||
import { assertSlots } from '@fluentui/react-utilities'; | ||
import type { CarouselAnnouncerState, CarouselAnnouncerSlots } from './CarouselAnnouncer.types'; | ||
|
||
/** | ||
* Render the final JSX of CarouselAnnouncer | ||
*/ | ||
export const renderCarouselAnnouncer_unstable = (state: CarouselAnnouncerState) => { | ||
const { renderAnnouncerChild, currentIndex, totalSlides, slideGroupList } = state; | ||
assertSlots<CarouselAnnouncerSlots>(state); | ||
|
||
return <state.root>{renderAnnouncerChild(currentIndex, totalSlides, slideGroupList)}</state.root>; | ||
}; |
57 changes: 57 additions & 0 deletions
57
...s/react-carousel-preview/library/src/components/CarouselAnnouncer/useCarouselAnnouncer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import * as React from 'react'; | ||
import { getIntrinsicElementProps, slot, useIsomorphicLayoutEffect } from '@fluentui/react-utilities'; | ||
import type { CarouselAnnouncerProps, CarouselAnnouncerState } from './CarouselAnnouncer.types'; | ||
import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext'; | ||
|
||
/** | ||
* Create the state required to render CarouselAnnouncer. | ||
* | ||
* The returned state can be modified with hooks such as useCarouselAnnouncerStyles_unstable, | ||
* before being passed to renderCarouselAnnouncer_unstable. | ||
* | ||
* @param props - props from this instance of CarouselAnnouncer | ||
* @param ref - reference to root HTMLDivElement of CarouselAnnouncer | ||
*/ | ||
export const useCarouselAnnouncer_unstable = ( | ||
props: CarouselAnnouncerProps, | ||
ref: React.Ref<HTMLDivElement>, | ||
): CarouselAnnouncerState => { | ||
const [totalSlides, setTotalSlides] = React.useState(0); | ||
const [slideGroupList, setSlideGroupList] = React.useState([[0]]); | ||
const subscribeForValues = useCarouselContext(ctx => ctx.subscribeForValues); | ||
const currentIndex = useCarouselContext(ctx => ctx.activeIndex); | ||
|
||
useIsomorphicLayoutEffect(() => { | ||
return subscribeForValues(data => { | ||
setTotalSlides(data.navItemsCount); | ||
setSlideGroupList(data.groupIndexList); | ||
}); | ||
}, [subscribeForValues]); | ||
|
||
return { | ||
totalSlides, | ||
currentIndex, | ||
slideGroupList, | ||
renderAnnouncerChild: props.children, | ||
// TODO add appropriate props/defaults | ||
components: { | ||
// TODO add each slot's element type or component | ||
root: 'div', | ||
}, | ||
// TODO add appropriate slots, for example: | ||
// mySlot: resolveShorthand(props.mySlot), | ||
root: slot.always( | ||
getIntrinsicElementProps('div', { | ||
ref, | ||
...props, | ||
children: null, | ||
}), | ||
{ | ||
elementType: 'div', | ||
defaultProps: { | ||
'aria-live': 'polite', | ||
}, | ||
}, | ||
), | ||
}; | ||
}; |
35 changes: 35 additions & 0 deletions
35
...sel-preview/library/src/components/CarouselAnnouncer/useCarouselAnnouncerStyles.styles.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { makeStyles, mergeClasses } from '@griffel/react'; | ||
import type { SlotClassNames } from '@fluentui/react-utilities'; | ||
import type { CarouselAnnouncerSlots, CarouselAnnouncerState } from './CarouselAnnouncer.types'; | ||
|
||
export const carouselAnnouncerClassNames: SlotClassNames<CarouselAnnouncerSlots> = { | ||
root: 'fui-CarouselAnnouncer', | ||
}; | ||
|
||
/** | ||
* Styles for the root slot | ||
* Hidden according to A11Y compatibility: https://www.a11yproject.com/posts/how-to-hide-content/ | ||
*/ | ||
const useStyles = makeStyles({ | ||
root: { | ||
clip: 'rect(0 0 0 0)', | ||
height: '0px', | ||
overflow: 'hidden', | ||
position: 'absolute', | ||
width: '0px', | ||
clipPath: 'inset(50%)', | ||
whiteSpace: 'nowrap', | ||
}, | ||
}); | ||
|
||
/** | ||
* Apply styling to the CarouselAnnouncer slots based on the state | ||
*/ | ||
export const useCarouselAnnouncerStyles_unstable = (state: CarouselAnnouncerState): CarouselAnnouncerState => { | ||
'use no memo'; | ||
|
||
const styles = useStyles(); | ||
state.root.className = mergeClasses(carouselAnnouncerClassNames.root, styles.root, state.root.className); | ||
|
||
return state; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.