Skip to content

Commit

Permalink
STCOM-1188 Accordion Bugfix post react18 updates. (#2105)
Browse files Browse the repository at this point in the history
* use flushSync on default accordion toggle

* Accordion-set - compare the correct value in componentDidUpdate for updating the internal AccordionStatus

* whitespace

* Update CHANGELOG.md
  • Loading branch information
JohnC-80 committed Jul 25, 2023
1 parent 497388d commit 51dfbf8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* Provide the `getFieldUniqueKey` prop to define a `key` for the list items in the `<RepeatableField>` component. Refs STCOM-1186.
* Bugfix for `<MultiSelection>` - onRemove should support remove button clicks and list de-selection as it does backspace. Refs STCOM-1106.
* Add `graph` icon. Refs STCOM-1187.
* `<AccordionSet/>` bugfix - fix for Accordions reverting to their initial open/close state when outer component is updated. Fixes STCOM-1188.

## [11.0.0](https://github.com/folio-org/stripes-components/tree/v11.0.0) (2023-01-30)
[Full Changelog](https://github.com/folio-org/stripes-components/compare/v10.3.0...v11.0.0)
Expand Down
2 changes: 1 addition & 1 deletion lib/Accordion/AccordionSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AccordionSet extends React.Component {

componentDidUpdate(prevProps, prevState) {
if (
Object.keys(prevState).length !== Object.keys(this.state.status).length) {
Object.keys(prevState.status).length !== Object.keys(this.state.status).length) {
if (this.innerStatus.current) this.innerStatus.current.setStatus(this.state.status);
}
}
Expand Down
33 changes: 22 additions & 11 deletions lib/Accordion/stories/BasicUsage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,51 @@

/* eslint-disable max-len */

import React from 'react';
import React, {useState, useRef} from 'react';
import faker from 'faker';
import { AccordionSet, Accordion } from '..';
import Button from '../../Button';

const BasicUsage = () => (
const BasicUsage = () => {
const [textValue, updateTextValue] = useState();
const paragraphs = useRef([
faker.lorem.paragraph(),
faker.lorem.paragraph(),
faker.lorem.paragraph(),
faker.lorem.paragraph(),
faker.lorem.paragraph(),
faker.lorem.paragraph(),
faker.lorem.paragraph()
]).current;
return(
<AccordionSet>
<Accordion label="Information" displayWhenOpen={<Button icon="plus-sign">Add</Button>} headerProps={{ headingLevel: 2 }}>
This is an example of an AccordionSet. The 2nd of these accordions is closed by default using the &quot;closedByDefault&quot; prop.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas vitae fringilla felis, sed commodo tellus. Sed bibendum mi id lorem sagittis sodales. Quisque ac lectus gravida, viverra ante et, iaculis sapien. Praesent eget ligula tortor. Praesent vitae ipsum placerat, blandit quam quis, tempus tortor. Aliquam erat volutpat. Fusce hendrerit lectus sed ex dictum, in pretium eros vestibulum. Nulla semper vehicula leo at varius. Quisque bibendum mauris sit amet tellus lobortis ultricies. Mauris eleifend sapien vel est posuere tincidunt. Proin ut nunc ut enim rhoncus elementum vitae in mauris. Nullam ultrices dictum nulla in commodo. Suspendisse potenti. Donec et velit ac quam consequat cursus. Pellentesque quis elit magna. Fusce velit libero, mattis ac placerat eget, aliquam a ante.
<br />
<br />
<input aria-label="I'm hidden! when closed!" type="text" />
{faker.lorem.paragraph()}
<input aria-label="I'm hidden! when closed!" type="text" id="testTextField" value={textValue} onChange={(e) => updateTextValue(e.target.value)} />
{paragraphs[0]}
</Accordion>
<Accordion label="Extended Information" closedByDefault>
{faker.lorem.paragraph()}
{paragraphs[1]}
<br />
<br />
{faker.lorem.paragraph()}
{paragraphs[2]}
</Accordion>
<Accordion label="Proxy">
{faker.lorem.paragraph()}
{paragraphs[3]}
<br />
<br />
{faker.lorem.paragraph()}
{paragraphs[4]}
</Accordion>
<Accordion label="Loans">
{faker.lorem.paragraph()}
{paragraphs[5]}
<br />
<br />
{faker.lorem.paragraph()}
{paragraphs[6]}
</Accordion>
</AccordionSet>
);
)};

export default BasicUsage;
4 changes: 3 additions & 1 deletion lib/Accordion/stories/Status.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import React, {useState} from 'react';
import Accordion from '../Accordion';
import AccordionSet from '../AccordionSet';
import AccordionStatus from '../AccordionStatus';
import ExpandAllButton from '../ExpandAllButton';

export default () => {
const [textValue, updateTextValue] = useState('')
return (
<div>
<h2>AccordionStatus with AccordionSet (uncontrolled - State managed by AccordionStatus)</h2>
Expand All @@ -13,6 +14,7 @@ export default () => {
<AccordionSet>
<Accordion label="AccordionStatus_one">
<p>first content</p>
<input type="text" value={textValue} onChange={(e) => updateTextValue(e.target.value)} />
</Accordion>
<Accordion label="AccordionStatus_two">
<p>second content</p>
Expand Down
51 changes: 48 additions & 3 deletions lib/Accordion/tests/Accordion-test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { describe, beforeEach, it } from 'mocha';
import { expect } from 'chai';
import { Accordion as Interactor, Keyboard, runAxeTest, Button } from '@folio/stripes-testing';
import { Accordion as Interactor, Keyboard, Bigtest, runAxeTest, Button } from '@folio/stripes-testing';
import sinon from 'sinon';
import { mountWithContext } from '../../../tests/helpers';
import UsageWithAccordionSet from '../stories/BasicUsage';

import Accordion from '../Accordion';
import AccordionSet from '../AccordionSet';
Expand Down Expand Up @@ -205,9 +206,14 @@ describe('Accordion', () => {

beforeEach(async () => {
await mountWithContext(
<AccordionSet>
<AccordionSet initialStatus={{
test1: false,
test2: true,
test3: true,
test4: true,
}}>
<Accordion label="test1" id="test1">
<input aria-label="test1" />
<input aria-label="test1" type="text" id="testControl1" />
</Accordion>
<Accordion label="test2" id="test2">
<input aria-label="test2" />
Expand All @@ -226,6 +232,15 @@ describe('Accordion', () => {

it('has a button', () => Button('test1').exists());

describe('contents ready for interaction following open', () => {
beforeEach(async () => {
await first.clickHeader();
await Bigtest.TextField({id: 'testControl1', }).fillIn("test");
});

it('Child element was filled out successfully', () => Bigtest.TextField({id: 'testControl1'}).has({ value: "test" }));
});

describe('keyboard navigation: next accordion', () => {
beforeEach(async () => {
await first.focus();
Expand Down Expand Up @@ -262,3 +277,33 @@ describe('Accordion', () => {
it('First accordion is in focus', async () => await first.is({ focused: true }));
});
});

describe('Accordion - updating state of parent component', () => {
const first = Interactor({ index: 0 });
const second = Interactor({ index: 1 });
const last = Interactor({ index: 3 });
const textField = Bigtest.TextField({ id: 'testTextField' });
beforeEach(async () => {
await mountWithContext(<UsageWithAccordionSet/>)
});

it('renders second accordion as closed', () => second.is({ open: false }));
it('renders a blank textfield', () => textField.has({ value: ''}));

describe('opening the closed accordion', () => {
beforeEach(async () => {
await second.clickHeader();
});

it('renders second accordion as open', () => second.is({ open: true }));

describe('changing the text value/parent state', () => {
beforeEach(async () => {
await textField.fillIn('test');
});

it('renders state value in textField', () => textField.has({ value: 'test' }));
it('renders second accordion as open', () => second.is({ open: true }));
});
});
});

0 comments on commit 51dfbf8

Please sign in to comment.