Skip to content

Commit 3d7950e

Browse files
authored
Merge pull request #160 from springload/feature/allow-zero-expanded
Feature/allow zero expanded
2 parents 41bfab5 + 6303e17 commit 3d7950e

File tree

7 files changed

+476
-63
lines changed

7 files changed

+476
-63
lines changed

demo/js/demo.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ const Example = (): JSX.Element => (
6767
</AccordionItem>
6868
</Accordion>
6969

70-
<h2 className="u-margin-top">Allow multiple</h2>
70+
<h2 className="u-margin-top">Allow multiple/zero</h2>
7171

72-
<Accordion allowMultipleExpanded={true}>
72+
<Accordion allowMultipleExpanded={true} allowZeroExpanded={true}>
7373
<AccordionItem>
7474
<AccordionItemHeading>
7575
<h3 className="u-position-relative">
@@ -97,6 +97,15 @@ const Example = (): JSX.Element => (
9797
AccordionItem
9898
</td>
9999
</tr>
100+
<tr>
101+
<td>allowZeroExpanded</td>
102+
<td>Boolean</td>
103+
<td>false</td>
104+
<td>
105+
Close an AccordionItem when it's the only
106+
one expanded
107+
</td>
108+
</tr>
100109
<tr>
101110
<td>onChange</td>
102111
<td>Function(keys)</td>

src/Accordion/Accordion.spec.tsx

Lines changed: 97 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe('Accordion', () => {
2323

2424
function mountAccordion(): ReactWrapper {
2525
return mount(
26-
<Accordion allowMultipleExpanded={false}>
26+
<Accordion>
2727
<AccordionItem>
2828
<FooTitle />
2929
</AccordionItem>
@@ -62,21 +62,60 @@ describe('Accordion', () => {
6262
).toEqual(1);
6363
});
6464

65-
it('collapses an expanded item when its title is clicked', () => {
66-
const wrapper = mountAccordion();
67-
68-
const fooTitle = wrapper.find(FooTitle);
69-
70-
fooTitle.simulate('click'); // open
71-
fooTitle.simulate('click'); // close
65+
it('pre expanded accordion', () => {
66+
const wrapper = mount(
67+
<Accordion>
68+
<AccordionItem expanded={true}>Fake Child</AccordionItem>
69+
<AccordionItem>Fake Child</AccordionItem>
70+
</Accordion>,
71+
);
7272

7373
const instance = wrapper.find(Provider).instance() as Provider;
7474

7575
expect(
7676
instance.state.items.filter(
7777
(item: Item) => item.expanded === true,
7878
).length,
79-
).toEqual(0);
79+
).toEqual(1);
80+
});
81+
82+
it('works with multiple pre expanded accordion. Extra expands are just ignored.', () => {
83+
const hideBodyClassName = 'HIDE';
84+
const wrapper = mount(
85+
<Accordion allowMultipleExpanded={false}>
86+
<AccordionItem
87+
expanded={true}
88+
hideBodyClassName={hideBodyClassName}
89+
>
90+
Fake Child
91+
</AccordionItem>
92+
<AccordionItem
93+
expanded={true}
94+
hideBodyClassName={hideBodyClassName}
95+
>
96+
Fake Child
97+
</AccordionItem>
98+
</Accordion>,
99+
);
100+
101+
const instance = wrapper.find(Provider).instance() as Provider;
102+
103+
expect(
104+
instance.state.items.filter((item: Item) => item.expanded)
105+
.length,
106+
).toEqual(1);
107+
expect(
108+
wrapper.findWhere((item: ReactWrapper) =>
109+
item.hasClass(hideBodyClassName),
110+
).length,
111+
).toEqual(1);
112+
});
113+
114+
it('respects arbitrary user-defined props', () => {
115+
const wrapper = mount(<Accordion lang="en" />);
116+
const div = wrapper.find('div').getDOMNode();
117+
118+
expect(div.getAttribute('lang')).toEqual('en');
80119
});
81120
});
82121

@@ -128,10 +167,11 @@ describe('Accordion', () => {
128167
).toEqual(2);
129168
});
130169

131-
it('collapses an expanded item when its title is clicked', () => {
170+
it('collapses an expanded item when its title is clicked and there is more than one item expanded', () => {
132171
const wrapper = mountMultipleExpanded();
133172

134173
wrapper.find(FooTitle).simulate('click'); // open
174+
wrapper.find(BarTitle).simulate('click'); // open
135175
wrapper.find(FooTitle).simulate('click'); // close
136176

137177
const instance = wrapper.find(Provider).instance() as Provider;
@@ -140,7 +180,7 @@ describe('Accordion', () => {
140180
instance.state.items.filter(
141181
(item: Item) => item.expanded === true,
142182
).length,
143-
).toEqual(0);
183+
).toEqual(1);
144184
});
145185
});
146186

@@ -167,11 +207,11 @@ describe('Accordion', () => {
167207
).toEqual(0);
168208
});
169209

170-
it('pre expanded accordion', () => {
210+
it('pre expanded accordion when allowMultipleExpanded is true', () => {
171211
const wrapper = mount(
172-
<Accordion>
212+
<Accordion allowMultipleExpanded={true}>
213+
<AccordionItem expanded={true}>Fake Child</AccordionItem>
173214
<AccordionItem expanded={true}>Fake Child</AccordionItem>
174-
<AccordionItem>Fake Child</AccordionItem>
175215
</Accordion>,
176216
);
177217

@@ -180,60 +220,66 @@ describe('Accordion', () => {
180220
expect(
181221
instance.state.items.filter((item: Item) => item.expanded === true)
182222
.length,
183-
).toEqual(1);
223+
).toEqual(2);
184224
});
225+
});
185226

186-
it('works with multiple pre expanded accordion. Extra expands are just ignored.', () => {
187-
const hideBodyClassName = 'HIDE';
188-
const wrapper = mount(
189-
<Accordion allowMultipleExpanded={false}>
190-
<AccordionItem
191-
expanded={true}
192-
hideBodyClassName={hideBodyClassName}
193-
>
194-
Fake Child
195-
</AccordionItem>
196-
<AccordionItem
197-
expanded={true}
198-
hideBodyClassName={hideBodyClassName}
199-
>
200-
Fake Child
227+
describe('<Accordion allowZeroExpanded="false" />', () => {
228+
const [FooTitle] = [
229+
(): JSX.Element => <AccordionItemHeading>Foo</AccordionItemHeading>,
230+
];
231+
232+
function mountAccordion(): ReactWrapper {
233+
return mount(
234+
<Accordion>
235+
<AccordionItem>
236+
<FooTitle />
201237
</AccordionItem>
202238
</Accordion>,
203239
);
240+
}
241+
242+
it("doesn't collapse an expanded item when it's the only item expanded", () => {
243+
const wrapper = mountAccordion();
244+
245+
wrapper.find(FooTitle).simulate('click'); // open
246+
wrapper.find(FooTitle).simulate('click'); // close
204247

205248
const instance = wrapper.find(Provider).instance() as Provider;
206249

207250
expect(
208-
instance.state.items.filter((item: Item) => item.expanded).length,
209-
).toEqual(1);
210-
expect(
211-
wrapper.findWhere((item: ReactWrapper) =>
212-
item.hasClass(hideBodyClassName),
213-
).length,
251+
instance.state.items.filter((item: Item) => item.expanded === true)
252+
.length,
214253
).toEqual(1);
215254
});
255+
});
216256

217-
it('pre expanded accordion when allowMultipleExpanded is true', () => {
218-
const wrapper = mount(
219-
<Accordion allowMultipleExpanded={true}>
220-
<AccordionItem expanded={true}>Fake Child</AccordionItem>
221-
<AccordionItem expanded={true}>Fake Child</AccordionItem>
257+
describe('<Accordion allowZeroExpanded="true" />', () => {
258+
const [FooTitle] = [
259+
(): JSX.Element => <AccordionItemHeading>Foo</AccordionItemHeading>,
260+
];
261+
262+
function mountZeroExpanded(): ReactWrapper {
263+
return mount(
264+
<Accordion allowZeroExpanded={true}>
265+
<AccordionItem>
266+
<FooTitle />
267+
</AccordionItem>
222268
</Accordion>,
223269
);
270+
}
224271

225-
const instance = wrapper.find(Provider).instance() as Provider;
272+
it("collapses an expanded item when its title is clicked and it's the only item open", () => {
273+
const wrapper = mountZeroExpanded();
226274

227-
expect(
228-
instance.state.items.filter((item: Item) => item.expanded === true)
229-
.length,
230-
).toEqual(2);
231-
});
275+
wrapper.find(FooTitle).simulate('click'); // open
276+
wrapper.find(FooTitle).simulate('click'); // close
232277

233-
it('respects arbitrary user-defined props', () => {
234-
const wrapper = mount(<Accordion lang="en" />);
235-
const div = wrapper.find('div').getDOMNode();
278+
const provider = wrapper.find(Provider).instance() as Provider;
236279

237-
expect(div.getAttribute('lang')).toEqual('en');
280+
expect(
281+
provider.state.items.filter((item: Item) => item.expanded === true)
282+
.length,
283+
).toEqual(0);
238284
});
239285
});

src/Accordion/Accordion.wrapper.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type AccordionWrapperProps = Omit<
1515
'onChange'
1616
> & {
1717
allowMultipleExpanded?: boolean;
18+
allowZeroExpanded?: boolean;
1819
onChange(args: UUID[]): void;
1920
};
2021

@@ -23,6 +24,7 @@ export default class AccordionWrapper extends React.Component<
2324
> {
2425
static defaultProps: AccordionWrapperProps = {
2526
allowMultipleExpanded: false,
27+
allowZeroExpanded: false,
2628
onChange: (): void => {
2729
//
2830
},
@@ -31,7 +33,12 @@ export default class AccordionWrapper extends React.Component<
3133
};
3234

3335
renderAccordion = (accordionStore: AccordionContainer): JSX.Element => {
34-
const { allowMultipleExpanded, onChange, ...rest } = this.props;
36+
const {
37+
allowMultipleExpanded,
38+
allowZeroExpanded,
39+
onChange,
40+
...rest
41+
} = this.props;
3542

3643
return <Accordion {...rest} />;
3744
};
@@ -40,6 +47,7 @@ export default class AccordionWrapper extends React.Component<
4047
return (
4148
<Provider
4249
allowMultipleExpanded={this.props.allowMultipleExpanded}
50+
allowZeroExpanded={this.props.allowZeroExpanded}
4351
onChange={this.props.onChange}
4452
>
4553
<Consumer>{this.renderAccordion}</Consumer>

0 commit comments

Comments
 (0)