Skip to content

Commit 3fcad10

Browse files
Change divs to headings
1 parent d70b844 commit 3fcad10

File tree

7 files changed

+77
-69
lines changed

7 files changed

+77
-69
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ Enables external control of the expansion.
138138
139139
Class(es) to apply to the 'heading' element.
140140
141-
#### aria-level : `number` [*optional*, default: `3`]
141+
#### headingLevel : `number` [*optional*, default: `3`]
142142
143-
Semantics to apply to the 'heading' element. A value of `1` would make your
144-
heading element hierarchically equivalent to an `<h1>` tag, and likewise a value
145-
of `6` would make it equivalent to an `<h6>` tag.
143+
Will determine which 'heading' element is used in the markup. A value of `1`
144+
would make your element an `<h1>` tag, and likewise a value of `6` would make it
145+
an `<h6>` tag.
146146
147147
### AccordionItemButton
148148

src/components/AccordionContext.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import * as React from 'react';
44
import AccordionStore, {
55
InjectedButtonAttributes,
6-
InjectedHeadingAttributes,
76
InjectedPanelAttributes,
87
} from '../helpers/AccordionStore';
98
import { ID } from './ItemContext';
@@ -28,7 +27,6 @@ export interface AccordionContext {
2827
uuid: ID,
2928
dangerouslySetExpanded?: boolean,
3029
): InjectedPanelAttributes;
31-
getHeadingAttributes(uuid: ID): InjectedHeadingAttributes;
3230
getButtonAttributes(
3331
uuid: ID,
3432
dangerouslySetExpanded?: boolean,
@@ -78,11 +76,6 @@ export class Provider extends React.PureComponent<
7876
return this.state.getPanelAttributes(key, dangerouslySetExpanded);
7977
};
8078

81-
getHeadingAttributes = (): InjectedHeadingAttributes => {
82-
// uuid: UUID
83-
return this.state.getHeadingAttributes();
84-
};
85-
8679
getButtonAttributes = (
8780
key: ID,
8881
dangerouslySetExpanded?: boolean,
@@ -102,7 +95,6 @@ export class Provider extends React.PureComponent<
10295
isItemDisabled: this.isItemDisabled,
10396
isItemExpanded: this.isItemExpanded,
10497
getPanelAttributes: this.getPanelAttributes,
105-
getHeadingAttributes: this.getHeadingAttributes,
10698
getButtonAttributes: this.getButtonAttributes,
10799
}}
108100
>

src/components/AccordionItemHeading.spec.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,39 @@ describe('AccordionItem', () => {
5959
});
6060
});
6161

62+
describe('headingLevel prop', () => {
63+
it('is h3 by default', () => {
64+
const { getByTestId } = render(
65+
<Accordion>
66+
<AccordionItem>
67+
<AccordionItemHeading data-testid={UUIDS.FOO}>
68+
<AccordionItemButton />
69+
</AccordionItemHeading>
70+
</AccordionItem>
71+
</Accordion>,
72+
);
73+
74+
expect(getByTestId(UUIDS.FOO).tagName).toEqual('H3');
75+
});
76+
77+
it('can be overridden', () => {
78+
const { getByTestId } = render(
79+
<Accordion>
80+
<AccordionItem>
81+
<AccordionItemHeading
82+
data-testid={UUIDS.FOO}
83+
headingLevel={4}
84+
>
85+
<AccordionItemButton />
86+
</AccordionItemHeading>
87+
</AccordionItem>
88+
</Accordion>,
89+
);
90+
91+
expect(getByTestId(UUIDS.FOO).tagName).toEqual('H4');
92+
});
93+
});
94+
6295
describe('children prop', () => {
6396
it('is respected', () => {
6497
const { getByText } = render(

src/components/AccordionItemHeading.tsx

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
import * as React from 'react';
2-
import { InjectedHeadingAttributes } from '../helpers/AccordionStore';
32
import DisplayName from '../helpers/DisplayName';
4-
import { DivAttributes } from '../helpers/types';
53
import { assertValidHtmlId } from '../helpers/id';
4+
import { HeadingAttributes } from '../helpers/types';
65

7-
import { Consumer as ItemConsumer, ItemContext } from './ItemContext';
8-
9-
type Props = DivAttributes;
10-
11-
const defaultProps = {
12-
className: 'accordion__heading',
13-
'aria-level': 3,
14-
};
6+
interface AccordianItemHeadingProps extends HeadingAttributes {
7+
className?: string;
8+
headingLevel?: number;
9+
}
1510

1611
export const SPEC_ERROR = `AccordionItemButton may contain only one child element, which must be an instance of AccordionItemButton.
1712
@@ -21,12 +16,31 @@ From the WAI-ARIA spec (https://www.w3.org/TR/wai-aria-practices-1.1/#accordion)
2116
2217
`;
2318

24-
export class AccordionItemHeading extends React.PureComponent<Props> {
25-
static defaultProps: typeof defaultProps = defaultProps;
19+
const Heading = React.forwardRef<HTMLHeadingElement, AccordianItemHeadingProps>(
20+
(
21+
{
22+
headingLevel = 3,
23+
className = 'accordion__heading',
24+
...props
25+
}: AccordianItemHeadingProps,
26+
ref,
27+
) => {
28+
const HeadingTag = `h${headingLevel}`;
29+
return React.createElement(HeadingTag, {
30+
className,
31+
...props,
32+
ref,
33+
'data-accordion-component': 'AccordionItemHeading',
34+
});
35+
},
36+
);
37+
38+
Heading.displayName = 'Heading';
2639

27-
ref: HTMLDivElement | undefined;
40+
export class AccordionItemHeading extends React.PureComponent<AccordianItemHeadingProps> {
41+
ref: HTMLHeadingElement | undefined;
2842

29-
static VALIDATE(ref: HTMLDivElement | undefined): void | never {
43+
static VALIDATE(ref: HTMLHeadingElement | undefined): void | never {
3044
if (ref === undefined) {
3145
throw new Error('ref is undefined');
3246
}
@@ -43,7 +57,7 @@ export class AccordionItemHeading extends React.PureComponent<Props> {
4357
}
4458
}
4559

46-
setRef = (ref: HTMLDivElement): void => {
60+
setRef = (ref: HTMLHeadingElement): void => {
4761
this.ref = ref;
4862
};
4963

@@ -56,36 +70,19 @@ export class AccordionItemHeading extends React.PureComponent<Props> {
5670
}
5771

5872
render(): JSX.Element {
59-
return (
60-
<div
61-
data-accordion-component="AccordionItemHeading"
62-
{...this.props}
63-
ref={this.setRef}
64-
/>
65-
);
73+
return <Heading ref={this.setRef} {...this.props} />;
6674
}
6775
}
6876

69-
type WrapperProps = Pick<
70-
DivAttributes,
71-
Exclude<keyof DivAttributes, keyof InjectedHeadingAttributes>
72-
>;
73-
74-
const AccordionItemHeadingWrapper: React.SFC<DivAttributes> = (
75-
props: WrapperProps,
76-
): JSX.Element => (
77-
<ItemConsumer>
78-
{(itemContext: ItemContext): JSX.Element => {
79-
const { headingAttributes } = itemContext;
80-
81-
if (props.id) {
82-
assertValidHtmlId(props.id);
83-
}
84-
85-
return <AccordionItemHeading {...props} {...headingAttributes} />;
86-
}}
87-
</ItemConsumer>
88-
);
77+
const AccordionItemHeadingWrapper: React.FC<AccordianItemHeadingProps> = (
78+
props: AccordianItemHeadingProps,
79+
): JSX.Element => {
80+
if (props.id) {
81+
assertValidHtmlId(props.id);
82+
}
83+
84+
return <AccordionItemHeading {...props} />;
85+
};
8986

9087
AccordionItemHeadingWrapper.displayName = DisplayName.AccordionItemHeading;
9188

src/components/ItemContext.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import * as React from 'react';
44
import {
55
InjectedButtonAttributes,
6-
InjectedHeadingAttributes,
76
InjectedPanelAttributes,
87
} from '../helpers/AccordionStore';
98
import {
@@ -30,7 +29,6 @@ export type ItemContext = {
3029
expanded: boolean;
3130
disabled: boolean;
3231
panelAttributes: InjectedPanelAttributes;
33-
headingAttributes: InjectedHeadingAttributes;
3432
buttonAttributes: InjectedButtonAttributes;
3533
toggleExpanded(): void;
3634
};
@@ -57,7 +55,6 @@ const Provider = ({
5755
uuid,
5856
dangerouslySetExpanded,
5957
);
60-
const headingAttributes = accordionContext.getHeadingAttributes(uuid);
6158
const buttonAttributes = accordionContext.getButtonAttributes(
6259
uuid,
6360
dangerouslySetExpanded,
@@ -71,7 +68,6 @@ const Provider = ({
7168
disabled,
7269
toggleExpanded: toggleExpanded,
7370
panelAttributes,
74-
headingAttributes,
7571
buttonAttributes,
7672
}}
7773
>

src/helpers/AccordionStore.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ export interface InjectedPanelAttributes {
88
hidden: boolean | undefined;
99
}
1010

11-
export interface InjectedHeadingAttributes {
12-
role: string;
13-
}
14-
1511
export interface InjectedButtonAttributes {
1612
id: string;
1713
'aria-controls': string;
@@ -95,13 +91,6 @@ export default class AccordionStore {
9591
};
9692
};
9793

98-
public readonly getHeadingAttributes = (): // uuid: UUID,
99-
InjectedHeadingAttributes => {
100-
return {
101-
role: 'heading',
102-
};
103-
};
104-
10594
public readonly getButtonAttributes = (
10695
uuid: ID,
10796
dangerouslySetExpanded?: boolean,

src/helpers/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ import * as React from 'react';
22

33
export type DivAttributes = React.HTMLAttributes<HTMLDivElement>;
44
export type ButtonAttributes = React.HTMLAttributes<HTMLButtonElement>;
5+
export type HeadingAttributes = React.HTMLAttributes<HTMLHeadingElement>;

0 commit comments

Comments
 (0)