Skip to content

Commit

Permalink
[EuiAccordion] Added isDisabled to disable interaction and subdue t…
Browse files Browse the repository at this point in the history
…rigger (#6095)

* Updated docs
* Fixed playground
  • Loading branch information
cchaos committed Aug 10, 2022
1 parent 13dec37 commit e455552
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 11 deletions.
41 changes: 41 additions & 0 deletions src-docs/src/views/accordion/accordion_disabled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from 'react';

import {
EuiAccordion,
EuiFieldPassword,
EuiFormRow,
EuiPanel,
useGeneratedHtmlId,
} from '../../../../src';

export default () => {
const [passwordValue, setPasswordValue] = useState('');
const disabledAccordionId = useGeneratedHtmlId({
prefix: 'disabledAccordion',
});

const isInvalid = passwordValue === '';

return (
<EuiAccordion
id={disabledAccordionId}
buttonContent="Security settings"
isDisabled={isInvalid}
initialIsOpen={true}
>
<EuiPanel color="subdued">
<EuiFormRow
label="Password"
isInvalid={isInvalid}
error={['You must enter your password to save these changes.']}
>
<EuiFieldPassword
isInvalid={isInvalid}
defaultValue={passwordValue}
onChange={(v) => setPasswordValue(v.currentTarget.value)}
/>
</EuiFormRow>
</EuiPanel>
</EuiAccordion>
);
};
50 changes: 50 additions & 0 deletions src-docs/src/views/accordion/accordion_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ const accordionIsLoadingSnippet = [
import AccordionButtonElement from './accordion_buttonElement';
const accordionButtonElementSource = require('!!raw-loader!./accordion_buttonElement');

import AccordionDisabled from './accordion_disabled';
const accordionDisabledSource = require('!!raw-loader!./accordion_disabled');

export const AccordionExample = {
title: 'Accordion',
intro: (
Expand Down Expand Up @@ -314,6 +317,53 @@ export const AccordionExample = {
snippet: accordionIsLoadingSnippet,
demo: <AccordionIsLoading />,
},
{
title: 'Disabled state',
source: [
{
type: GuideSectionTypes.JS,
code: accordionDisabledSource,
},
],
text: (
<>
<p>
In some cases you might want to prevent the user from closing the{' '}
<strong>EuiAccordion</strong>. For example, if a form field is
displaying an error, opening the accordion and preventing its
closure until the error has been addressed will help the user find
and fix the error.
</p>
<p>
The <EuiCode>isDisabled</EuiCode> prop will disable interaction on
the button and the arrow. Use it in conjunction with{' '}
<EuiCode>initialIsOpen</EuiCode> to achieve the desired effect.
</p>
<EuiCallOut
color="warning"
iconType="accessibility"
title={
<>
When disabling the interaction of accordions based on user
input, it&apos;s advisable to ensure there is further
explanation through the use of help or error text.
</>
}
/>
</>
),
demo: <AccordionDisabled />,
props: { EuiAccordion },
snippet: `<EuiAccordion
id={accordionId5}
buttonContent="Clickable title"
isDisabled={true}
initialIsOpen={true}
>
<!-- Content to show when expanded -->
</EuiAccordion>
`,
},
{
title: 'When content changes dynamically',
source: [
Expand Down
5 changes: 5 additions & 0 deletions src-docs/src/views/accordion/playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const accordionConfig = () => {
type: PropTypes.String,
};

propsToUse.buttonElement = {
...propsToUse.buttonElement,
defaultValue: 'button',
};

propsToUse.id = {
...propsToUse.id,
value: htmlIdGenerator('generated')(),
Expand Down
126 changes: 117 additions & 9 deletions src/components/accordion/__snapshots__/accordion.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = `
class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper"
>
<button
aria-controls="18"
aria-controls="20"
aria-expanded="false"
aria-labelledby="generated-id"
class="euiButtonIcon euiButtonIcon--text euiButtonIcon--empty euiButtonIcon--xSmall euiAccordion__iconButton emotion-euiAccordion__iconButton"
Expand All @@ -23,7 +23,7 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = `
/>
</button>
<button
aria-controls="18"
aria-controls="20"
aria-expanded="false"
class="euiAccordion__button emotion-euiAccordion__button"
id="generated-id"
Expand All @@ -37,7 +37,7 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = `
<div
aria-labelledby="generated-id"
class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper"
id="18"
id="20"
role="region"
tabindex="-1"
>
Expand All @@ -54,6 +54,62 @@ exports[`EuiAccordion behavior closes when clicked twice 1`] = `
</div>
`;

exports[`EuiAccordion behavior does not open when isDisabled 1`] = `
<div
class="euiAccordion"
>
<div
class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper"
>
<button
aria-controls="18"
aria-expanded="false"
aria-labelledby="generated-id"
class="euiButtonIcon euiButtonIcon-isDisabled euiButtonIcon--text euiButtonIcon--empty euiButtonIcon--xSmall euiAccordion__iconButton emotion-euiAccordion__iconButton"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-hidden="true"
class="euiButtonIcon__icon"
color="inherit"
data-euiicon-type="arrowRight"
/>
</button>
<button
aria-controls="18"
aria-expanded="false"
class="euiAccordion__button emotion-euiAccordion__button-disabled"
disabled=""
id="generated-id"
type="button"
>
<span
class="euiAccordion__buttonContent"
/>
</button>
</div>
<div
aria-labelledby="generated-id"
class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper"
id="18"
role="region"
tabindex="-1"
>
<div>
<div
class=" emotion-euiAccordion__children"
>
<p>
You cannot see me.
</p>
</div>
</div>
</div>
</div>
`;

exports[`EuiAccordion behavior opens when clicked once 1`] = `
<div
class="euiAccordion euiAccordion-isOpen"
Expand All @@ -62,7 +118,7 @@ exports[`EuiAccordion behavior opens when clicked once 1`] = `
class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper"
>
<button
aria-controls="16"
aria-controls="17"
aria-expanded="true"
aria-labelledby="generated-id"
class="euiButtonIcon euiButtonIcon--text euiButtonIcon--empty euiButtonIcon--xSmall euiAccordion__iconButton euiAccordion__iconButton-isOpen emotion-euiAccordion__iconButton-isOpen"
Expand All @@ -77,7 +133,7 @@ exports[`EuiAccordion behavior opens when clicked once 1`] = `
/>
</button>
<button
aria-controls="16"
aria-controls="17"
aria-expanded="true"
class="euiAccordion__button emotion-euiAccordion__button"
id="generated-id"
Expand All @@ -91,7 +147,7 @@ exports[`EuiAccordion behavior opens when clicked once 1`] = `
<div
aria-labelledby="generated-id"
class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen"
id="16"
id="17"
role="region"
tabindex="-1"
>
Expand All @@ -116,7 +172,7 @@ exports[`EuiAccordion behavior opens when div is clicked if element is a div 1`]
class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper"
>
<button
aria-controls="17"
aria-controls="19"
aria-expanded="true"
aria-labelledby="generated-id"
class="euiButtonIcon euiButtonIcon--text euiButtonIcon--empty euiButtonIcon--xSmall euiAccordion__iconButton euiAccordion__iconButton-isOpen emotion-euiAccordion__iconButton-isOpen"
Expand All @@ -131,7 +187,7 @@ exports[`EuiAccordion behavior opens when div is clicked if element is a div 1`]
/>
</button>
<button
aria-controls="17"
aria-controls="19"
aria-expanded="true"
class="euiAccordion__button emotion-euiAccordion__button"
id="generated-id"
Expand All @@ -145,7 +201,7 @@ exports[`EuiAccordion behavior opens when div is clicked if element is a div 1`]
<div
aria-labelledby="generated-id"
class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen"
id="17"
id="19"
role="region"
tabindex="-1"
>
Expand Down Expand Up @@ -214,6 +270,58 @@ exports[`EuiAccordion is rendered 1`] = `
</div>
`;

exports[`EuiAccordion isDisabled is rendered 1`] = `
<div
class="euiAccordion"
>
<div
class="euiAccordion__triggerWrapper emotion-euiAccordion__triggerWrapper"
>
<button
aria-controls="16"
aria-expanded="false"
aria-labelledby="generated-id"
class="euiButtonIcon euiButtonIcon-isDisabled euiButtonIcon--text euiButtonIcon--empty euiButtonIcon--xSmall euiAccordion__iconButton emotion-euiAccordion__iconButton"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-hidden="true"
class="euiButtonIcon__icon"
color="inherit"
data-euiicon-type="arrowRight"
/>
</button>
<button
aria-controls="16"
aria-expanded="false"
class="euiAccordion__button emotion-euiAccordion__button-disabled"
disabled=""
id="generated-id"
type="button"
>
<span
class="euiAccordion__buttonContent"
/>
</button>
</div>
<div
aria-labelledby="generated-id"
class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper"
id="16"
role="region"
tabindex="-1"
>
<div>
<div
class=" emotion-euiAccordion__children"
/>
</div>
</div>
</div>
`;

exports[`EuiAccordion props arrowDisplay none is rendered 1`] = `
<div
class="euiAccordion"
Expand Down
11 changes: 11 additions & 0 deletions src/components/accordion/accordion.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ export const euiAccordionButtonStyles = (euiThemeContext: UseEuiTheme) => {
text-decoration: underline;
}
`,

// Triggering button needs separate `disabled` key because the element that renders may not support `:disabled`;
// Hover pseudo selector for specificity
disabled: css`
&,
&:hover {
cursor: not-allowed;
color: ${euiTheme.colors.disabledText};
text-decoration: none;
}
`,
};
};

Expand Down
20 changes: 20 additions & 0 deletions src/components/accordion/accordion.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ describe('EuiAccordion', () => {
});
});

describe('isDisabled', () => {
it('is rendered', () => {
const component = render(<EuiAccordion id={getId()} isDisabled />);

expect(component).toMatchSnapshot();
});
});

describe('behavior', () => {
it('opens when clicked once', () => {
const component = mount(
Expand All @@ -201,6 +209,18 @@ describe('EuiAccordion', () => {
expect(component.render()).toMatchSnapshot();
});

it('does not open when isDisabled', () => {
const component = mount(
<EuiAccordion id={getId()} isDisabled>
<p>You cannot see me.</p>
</EuiAccordion>
);

component.find('button').at(0).simulate('click');

expect(component.render()).toMatchSnapshot();
});

it('opens when div is clicked if element is a div', () => {
const component = mount(
<EuiAccordion id={getId()} element="div">
Expand Down
Loading

0 comments on commit e455552

Please sign in to comment.