Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiAccordion] Added isDisabled to disable interaction and subdue trigger #6095

Merged
merged 7 commits into from
Aug 10, 2022
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
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