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
5 changes: 5 additions & 0 deletions .changeset/spotty-colts-hear.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
'@primer/react': major
---

Remove the `sx` prop from `Announce`, `AriaAlert`, and `AriaStatus`
82 changes: 44 additions & 38 deletions packages/react/src/live-region/Announce.tsx
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,56 @@
import {announceFromElement} from '@primer/live-region-element'
import type React from 'react'
import {useEffect, useRef, useState, type ElementRef} from 'react'
import Box from '../Box'
import {useEffectOnce} from '../internal/hooks/useEffectOnce'
import {useEffectCallback} from '../internal/hooks/useEffectCallback'

export type AnnounceProps = React.ComponentPropsWithoutRef<typeof Box> & {
/**
* Specify if the content of the element should be announced when this
* component is rendered and is not hidden
* @default false
*/
announceOnShow?: boolean

/**
* Specify if the element is hidden
* @default false
*/
hidden?: boolean

/**
* Provide a delay in milliseconds before the announcement is made. This will
* only work with `polite` announcements
*/
delayMs?: number

/**
* The politeness level to use for the announcement
* @default 'polite'
*/
politeness?: 'assertive' | 'polite'
}
import type {PolymorphicProps} from '../utils/polymorphic2'

export type AnnounceProps<As extends React.ElementType> = PolymorphicProps<
'div',
As,
{
/**
* Specify if the content of the element should be announced when this
* component is rendered and is not hidden
* @default false
*/
announceOnShow?: boolean

/**
* Specify if the element is hidden
* @default false
*/
hidden?: boolean

/**
* Provide a delay in milliseconds before the announcement is made. This will
* only work with `polite` announcements
*/
delayMs?: number

/**
* The politeness level to use for the announcement
* @default 'polite'
*/
politeness?: 'assertive' | 'polite'
}
>

/**
* `Announce` is a component that will announce the text content of the
* `children` passed in to screen readers using the given politeness level. It
* will also announce any changes to the text content of `children`
*/
export function Announce({
announceOnShow = true,
children,
delayMs,
hidden = false,
politeness = 'polite',
...rest
}: AnnounceProps) {
export function Announce<As extends React.ElementType = 'div'>(props: AnnounceProps<As>) {
const {
as: BaseComponent = 'div',
announceOnShow = true,
children,
delayMs,
hidden = false,
politeness = 'polite',
...rest
} = props
const ref = useRef<ElementRef<'div'>>(null)
const [previousAnnouncementText, setPreviousAnnouncementText] = useState<string | null>(null)
const savedAnnouncement = useRef<ReturnType<typeof announceFromElement> | null>(null)
Expand DownExpand Up@@ -127,9 +133,9 @@ export function Announce({
}, [])

return (
<Box {...rest} ref={ref}>
<BaseComponent {...rest} ref={ref}>
{children}
</Box>
</BaseComponent>
)
}

Expand Down
17 changes: 7 additions & 10 deletions packages/react/src/live-region/AriaAlert.tsx
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
import type React from 'react'
import {type ElementType} from 'react'
import {Announce} from './Announce'
import type {SxProp} from '../sx'
import type {PolymorphicProps} from '../utils/polymorphic2'

export type AriaAlertProps<As extends ElementType> = React.PropsWithChildren<
export type AriaAlertProps<As extends ElementType> = PolymorphicProps<
'div',
As,
{
/**
* Customize the element type of the rendered container
*/
as?: As

/**
* Specify if the content of the element should be announced when this
* component is rendered and is not hidden
Expand All@@ -22,14 +19,14 @@ export type AriaAlertProps<As extends ElementType> = React.PropsWithChildren<
* @default false
*/
hidden?: boolean
} & SxProp
}
>

export function AriaAlert<As extends ElementType>({
export function AriaAlert<As extends ElementType = 'div'>({
announceOnShow = true,
children,
...rest
}: AriaAlertProps<As> & React.ComponentPropsWithoutRef<ElementType extends As ? As : 'div'>) {
}: AriaAlertProps<As>) {
return (
<Announce {...rest} announceOnShow={announceOnShow} politeness="assertive">
{children}
Expand Down
17 changes: 7 additions & 10 deletions packages/react/src/live-region/AriaStatus.tsx
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
import type React from 'react'
import {type ElementType} from 'react'
import {Announce} from './Announce'
import type {SxProp} from '../sx'
import type {PolymorphicProps} from '../utils/polymorphic2'

export type AriaStatusProps<As extends ElementType> = React.PropsWithChildren<
export type AriaStatusProps<As extends ElementType> = PolymorphicProps<
'div',
As,
{
/**
* Customize the element type of the rendered container
*/
as?: As

/**
* Specify if the content of the element should be announced when this
* component is rendered and is not hidden
Expand All@@ -27,14 +24,14 @@ export type AriaStatusProps<As extends ElementType> = React.PropsWithChildren<
* Provide a delay in milliseconds before the announcement is made
*/
delayMs?: number
} & SxProp
}
>

export function AriaStatus<As extends ElementType>({
export function AriaStatus<As extends ElementType = 'div'>({
announceOnShow = false,
children,
...rest
}: AriaStatusProps<As> & React.ComponentPropsWithoutRef<ElementType extends As ? As : 'div'>) {
}: AriaStatusProps<As>) {
return (
<Announce {...rest} announceOnShow={announceOnShow} politeness="polite">
{children}
Expand Down
9 changes: 0 additions & 9 deletions packages/react/src/live-region/__tests__/Announce.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,15 +37,6 @@ describe('Announce', () => {
expect(container.firstChild).toHaveAttribute('data-testid', 'container')
})

it('should support styling via the `sx` prop', () => {
render(
<Announce data-testid="container" sx={{color: 'blue'}}>
test
</Announce>,
)
expect(screen.getByTestId('container')).toHaveStyle('color: rgb(0, 0, 255)')
})

it('should support customizing the container element with `as`', () => {
render(
<Announce as="span" data-testid="container">
Expand Down
9 changes: 0 additions & 9 deletions packages/react/src/live-region/__tests__/AriaAlert.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,15 +31,6 @@ describe('AriaAlert', () => {
expect(container.firstChild).toHaveAttribute('data-testid', 'container')
})

it('should support styling via the `sx` prop', () => {
render(
<AriaAlert data-testid="container" sx={{color: 'blue'}}>
test
</AriaAlert>,
)
expect(screen.getByTestId('container')).toHaveStyle('color: rgb(0, 0, 255)')
})

it('should support customizing the container element with `as`', () => {
render(
<AriaAlert as="span" data-testid="container">
Expand Down
9 changes: 0 additions & 9 deletions packages/react/src/live-region/__tests__/AriaStatus.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,15 +67,6 @@ describe('AriaStatus', () => {
expect(container.firstChild).toHaveAttribute('data-testid', 'container')
})

it('should support styling via the `sx` prop', () => {
render(
<AriaStatus data-testid="container" sx={{color: 'blue'}}>
test
</AriaStatus>,
)
expect(screen.getByTestId('container')).toHaveStyle('color: rgb(0, 0, 255)')
})

it('should support customizing the container element with `as`', () => {
render(
<AriaStatus as="span" data-testid="container">
Expand Down
23 changes: 23 additions & 0 deletions packages/react/src/utils/polymorphic2.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
/**
* This file is an alternative to polymorphic.ts that hopes to support
* polyrmophic components in React. It explicitly hopes to make it easy to
* type the props of components and allow for explicitly setting the type of a
* component
*/

import type {ElementType} from 'react'

type AsProp<As extends ElementType> = {
/**
* Customize the element type of the container element for the component
*/
as?: As
}

type PolymorphicProps<DefaultAs extends ElementType, As extends ElementType, Props> = Props &
AsProp<As> &
(As extends React.ElementType
? Omit<React.ComponentPropsWithoutRef<As>, keyof Props>
: Omit<React.ComponentPropsWithoutRef<DefaultAs>, keyof Props>)

export type {PolymorphicProps}
Loading