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/pretty-coats-sell.md
Original file line numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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
32 changes: 32 additions & 0 deletions packages/react/src/PageLayout/PageLayout.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,6 +103,38 @@ 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()
expect(container.querySelector('[data-component="PageLayout.HorizontalDivider"]')).toBeInTheDocument()
expect(container.querySelector('[data-component="PageLayout.VerticalDivider"]')).toBeInTheDocument()
})

it('renders data-component for DragHandle when pane is resizable', () => {
const {container} = render(
<PageLayout>
<PageLayout.Content>Content</PageLayout.Content>
<PageLayout.Pane resizable>Pane</PageLayout.Pane>
</PageLayout>,
)

expect(container.querySelector('[data-component="PageLayout.DragHandle"]')).toBeInTheDocument()
})

it('should support labeling landmarks through `aria-label`', () => {
render(
<PageLayout>
Expand Down
9 changes: 9 additions & 0 deletions packages/react/src/PageLayout/PageLayout.tsx
Original file line numberDiff line numberDiff 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 DownExpand Up@@ -157,6 +158,7 @@ const HorizontalDivider = memo<React.PropsWithChildren<DividerProps>>(
return (
<div
className={clsx(classes.HorizontalDivider, className)}
data-component="PageLayout.HorizontalDivider"
{...getResponsiveAttributes('variant', variant)}
{...getResponsiveAttributes('position', position)}
style={
Expand All@@ -181,6 +183,7 @@ const VerticalDivider = memo<React.PropsWithChildren<VerticalDividerProps>>(
return (
<div
className={clsx(classes.VerticalDivider, className)}
data-component="PageLayout.VerticalDivider"
{...getResponsiveAttributes('variant', variant)}
{...getResponsiveAttributes('position', position)}
style={style}
Expand DownExpand Up@@ -493,6 +496,7 @@ const DragHandle = memo<DragHandleProps>(function DragHandle({
<div
ref={handleRef}
className={classes.DraggableHandle}
data-component="PageLayout.DragHandle"
role="slider"
aria-label="Draggable pane splitter"
aria-valuemin={ariaValueMin}
Expand DownExpand Up@@ -570,6 +574,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 DownExpand Up@@ -649,6 +654,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 DownExpand Up@@ -896,6 +902,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 DownExpand Up@@ -1230,6 +1237,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 DownExpand Up@@ -1330,6 +1338,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