Skip to content
Open
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/pretty-coats-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Add data-component attributes and associated tests for PageHeader, PageLayout, Pagehead, Popover, Portal, and ProgressBar
49 changes: 49 additions & 0 deletions packages/react/src/PageHeader/PageHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,49 @@ describe('PageHeader', () => {
implementsClassName(PageHeader.Actions, classes.Actions)
implementsClassName(PageHeader.Description, classes.Description)
implementsClassName(PageHeader.Navigation, classes.Navigation)

it('renders data-component attributes for PageHeader and exported subcomponents', () => {
const {container} = render(
<PageHeader aria-label="Title" role="banner">
<PageHeader.ContextArea>ContextArea</PageHeader.ContextArea>
<PageHeader.ParentLink href="#">ParentLink</PageHeader.ParentLink>
<PageHeader.ContextBar>ContextBar</PageHeader.ContextBar>
<PageHeader.TitleArea>
<PageHeader.LeadingAction>LeadingAction</PageHeader.LeadingAction>
<PageHeader.Breadcrumbs>Breadcrumbs</PageHeader.Breadcrumbs>
<PageHeader.LeadingVisual>LeadingVisual</PageHeader.LeadingVisual>
<PageHeader.Title>Title</PageHeader.Title>
<PageHeader.TrailingVisual>TrailingVisual</PageHeader.TrailingVisual>
<PageHeader.TrailingAction>TrailingAction</PageHeader.TrailingAction>
<PageHeader.Actions>Actions</PageHeader.Actions>
</PageHeader.TitleArea>
<PageHeader.ContextAreaActions>ContextAreaActions</PageHeader.ContextAreaActions>
<PageHeader.Description>Description</PageHeader.Description>
<PageHeader.Navigation>Navigation</PageHeader.Navigation>
</PageHeader>,
)

expect(container.firstChild).toHaveAttribute('data-component', 'PageHeader')
expect(container.querySelector('[data-component="PageHeader.ContextArea"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageHeader.ParentLink"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageHeader.ContextBar"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageHeader.ContextAreaActions"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageHeader.Description"]')).toBeInTheDocument()

// New tests, but we need to update this to data-component="PageHeader.TitleArea later
expect(container.querySelector('[data-component="TitleArea"]')).toBeInTheDocument()

// New tests, but we need to update these from PH_ to PageHeader. later
expect(container.querySelector('[data-component="PH_LeadingAction"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_Breadcrumbs"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_LeadingVisual"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_Title"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_TrailingVisual"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_TrailingAction"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_Actions"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PH_Navigation"]')).toBeInTheDocument()
})

it('respects the title variant prop', () => {
const {getByText} = render(
<PageHeader role="banner" aria-label="Title">
Expand All @@ -31,6 +74,7 @@ describe('PageHeader', () => {
)
expect(getByText('Title')).toHaveStyle('font-size: 32px')
})

it('renders "aria-label" prop when Navigation is rendered as "nav" landmark', () => {
const {getByLabelText, getByText} = render(
<PageHeader role="banner" aria-label="Title">
Expand All @@ -45,6 +89,7 @@ describe('PageHeader', () => {
expect(getByLabelText('Custom')).toBeInTheDocument()
expect(getByText('Navigation')).toHaveAttribute('aria-label', 'Custom')
})

it('does not render "aria-label" prop when Navigation is rendered as "div"', () => {
const {getByText} = render(
<PageHeader role="banner" aria-label="Title">
Expand All @@ -71,6 +116,7 @@ describe('PageHeader', () => {

consoleSpy.mockRestore()
})

it('does not render "role" attribute when not explicitly specified', () => {
const {container} = render(
<PageHeader>
Expand All @@ -81,6 +127,7 @@ describe('PageHeader', () => {
)
expect(container.firstChild).not.toHaveAttribute('role')
})

it('renders "role" attribute when explicitly specified', () => {
const {container} = render(
<PageHeader role="banner">
Expand All @@ -91,6 +138,7 @@ describe('PageHeader', () => {
)
expect(container.firstChild).toHaveAttribute('role', 'banner')
})

it('does not render "aria-label" attribute when not explicitly specified', () => {
const {container} = render(
<PageHeader role="banner">
Expand All @@ -101,6 +149,7 @@ describe('PageHeader', () => {
)
expect(container.firstChild).not.toHaveAttribute('aria-label')
})

it('renders custom "aria-label" attribute when explicitly specified', () => {
const {container} = render(
<PageHeader aria-label="Custom aria-label" role="banner">
Expand Down
26 changes: 22 additions & 4 deletions packages/react/src/PageHeader/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const Root = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageHeader
<BaseComponent
ref={rootRef}
className={clsx(classes.PageHeader, className)}
data-component="PageHeader"
data-has-border={hasBorder ? 'true' : undefined}
aria-label={ariaLabel}
role={role}
Expand All @@ -127,7 +128,11 @@ const ContextArea: FCWithSlotMarker<React.PropsWithChildren<ChildrenPropTypes>>
hidden = hiddenOnRegularAndWide,
}) => {
return (
<div className={clsx(classes.ContextArea, className)} {...getHiddenDataAttributes(hidden)}>
<div
className={clsx(classes.ContextArea, className)}
data-component="PageHeader.ContextArea"
{...getHiddenDataAttributes(hidden)}
>
{children}
</div>
)
Expand All @@ -154,6 +159,7 @@ const ParentLink = React.forwardRef<HTMLAnchorElement, ParentLinkProps>(
aria-label={ariaLabel}
muted
className={clsx(classes.ParentLink, className)}
data-component="PageHeader.ParentLink"
{...getHiddenDataAttributes(hidden)}
href={href}
>
Expand All @@ -176,7 +182,11 @@ const ContextBar: React.FC<React.PropsWithChildren<ChildrenPropTypes>> = ({
hidden = hiddenOnRegularAndWide,
}) => {
return (
<div className={clsx(classes.ContextBar, className)} {...getHiddenDataAttributes(hidden)}>
<div
className={clsx(classes.ContextBar, className)}
data-component="PageHeader.ContextBar"
{...getHiddenDataAttributes(hidden)}
>
{children}
</div>
)
Expand All @@ -190,7 +200,11 @@ const ContextAreaActions: React.FC<React.PropsWithChildren<ChildrenPropTypes>> =
hidden = hiddenOnRegularAndWide,
}) => {
return (
<div className={clsx(classes.ContextAreaActions, className)} {...getHiddenDataAttributes(hidden)}>
<div
className={clsx(classes.ContextAreaActions, className)}
data-component="PageHeader.ContextAreaActions"
{...getHiddenDataAttributes(hidden)}
>
{children}
</div>
)
Expand Down Expand Up @@ -332,7 +346,11 @@ const Actions = ({children, className, hidden = false}: ActionsProps) => {
// PageHeader.Description: The description area of the header. Visible on all viewports
const Description: React.FC<React.PropsWithChildren<ChildrenPropTypes>> = ({children, className, hidden = false}) => {
return (
<div className={clsx(classes.Description, className)} {...getHiddenDataAttributes(hidden)}>
<div
className={clsx(classes.Description, className)}
data-component="PageHeader.Description"
{...getHiddenDataAttributes(hidden)}
>
{children}
</div>
)
Expand Down
19 changes: 19 additions & 0 deletions packages/react/src/PageLayout/PageLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ describe('PageLayout', async () => {
expect(getByText('Pane')).toBeVisible()
})

it('renders data-component attributes for PageLayout and exported subcomponents', () => {
const {container} = render(
<PageLayout>
<PageLayout.Header>Header</PageLayout.Header>
<PageLayout.Content>Content</PageLayout.Content>
<PageLayout.Pane>Pane</PageLayout.Pane>
<PageLayout.Sidebar>Sidebar</PageLayout.Sidebar>
<PageLayout.Footer>Footer</PageLayout.Footer>
</PageLayout>,
)

expect(container.querySelector('[data-component="PageLayout"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.Header"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.Content"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.Pane"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.Sidebar"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.Footer"]')).toBeInTheDocument()
})

it('should support labeling landmarks through `aria-label`', () => {
render(
<PageLayout>
Expand Down
6 changes: 6 additions & 0 deletions packages/react/src/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const RootWrapper = memo(
} as React.CSSProperties
}
className={clsx(classes.PageLayoutRoot, className)}
data-component="PageLayout"
data-has-sidebar={hasSidebar || undefined}
>
{children}
Expand Down Expand Up @@ -570,6 +571,7 @@ const Header: FCWithSlotMarker<React.PropsWithChildren<PageLayoutHeaderProps>> =
<header
aria-label={label}
aria-labelledby={labelledBy}
data-component="PageLayout.Header"
{...getResponsiveAttributes('hidden', hidden)}
className={clsx(classes.Header, className)}
style={
Expand Down Expand Up @@ -649,6 +651,7 @@ const Content: FCWithSlotMarker<React.PropsWithChildren<PageLayoutContentProps>>
ref={contentWrapperRef}
aria-label={label}
aria-labelledby={labelledBy}
data-component="PageLayout.Content"
style={style}
className={clsx(classes.ContentWrapper, className)}
{...getResponsiveAttributes('is-hidden', hidden)}
Expand Down Expand Up @@ -896,6 +899,7 @@ const Pane = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageLayout
{...labelProp}
{...(id && {id: paneId})}
className={classes.Pane}
data-component="PageLayout.Pane"
data-resizable={resizable || undefined}
style={
{
Expand Down Expand Up @@ -1230,6 +1234,7 @@ const Sidebar = React.forwardRef<HTMLDivElement, React.PropsWithChildren<PageLay
{...labelProp}
{...(id && {id: sidebarId})}
className={classes.Sidebar}
data-component="PageLayout.Sidebar"
data-resizable={resizable || undefined}
style={
{
Expand Down Expand Up @@ -1330,6 +1335,7 @@ const Footer: FCWithSlotMarker<React.PropsWithChildren<PageLayoutFooterProps>> =
<footer
aria-label={label}
aria-labelledby={labelledBy}
data-component="PageLayout.Footer"
{...getResponsiveAttributes('hidden', hidden)}
className={clsx(classes.FooterWrapper, className)}
style={
Expand Down
Loading
Loading