Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
Popup in compact interactive list (#2149)
Browse files Browse the repository at this point in the history
  • Loading branch information
adoroshk authored May 1, 2024
1 parent 7399b61 commit bbc7c11
Show file tree
Hide file tree
Showing 50 changed files with 201 additions and 12 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,49 @@ Terra.describeViewports('CompactInteractiveList', ['medium'], () => {
Terra.validates.element('focus-on-submenu-first-item', { selector: '#compact-interactive-list-cell-content' });
});
});

describe('cell with popup, keyboard navigation', () => {
it('should focus on popup buton', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/compact-interactive-list/cell-content');
browser.keys(['Tab', 'End', 'ArrowLeft']);
Terra.validates.element('popup-closed-focus-on-cell-button', { selector: '#compact-interactive-list-cell-content' });
});

it('should open popup on Enter', () => {
browser.keys(['Enter']);
Terra.validates.element('popup-open-no-visible-focus', { selector: '#compact-interactive-list-cell-content' });
});

it('should move to the first interactive element on tab', () => {
browser.keys(['Tab']);
Terra.validates.element('popup-open-focus-on-first-checkbox-unselected', { selector: '#compact-interactive-list-cell-content' });
});

it('should close on Esc button, should not shift from the cell if arrow keys were pressed when open', () => {
browser.keys(['ArrowLeft', 'Escape']);
Terra.validates.element('popup-closed-focus-on-cell-button', { selector: '#compact-interactive-list-cell-content' });
});
});

describe('cell with popup, mouse interactions', () => {
it('should open popup on click', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/compact-interactive-list/cell-content');
$('#popup-button').click();
Terra.validates.element('popup-open-no-visible-focus', { selector: '#compact-interactive-list-cell-content' });
});

it('should select interactive item on click', () => {
$('[class*="label-text"]').click();
Terra.validates.element('popup-open-focus-on-first-checkbox-selected', { selector: '#compact-interactive-list-cell-content' });
});

it('should close popup on click outside', () => {
// current test closes popup but does not add focus outline to the button (as it should), probably due to the issue in terra-button.
// if terra-button outline starts showing after update in terra-button, the screenshot update will be needed.
$('[class*="popup-overlay"]').click();
Terra.validates.element('popup-closed-per-click-on-overlay', { selector: '#compact-interactive-list-cell-content' });
});
});
});

Terra.describeViewports('CompactInteractiveList', ['medium'], () => {
Expand Down
1 change: 1 addition & 0 deletions packages/terra-framework-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Changed
* Updated `terra-navigation-side-menu` example styles.
* Updated `terra-compact-interactive-list` keyboard interactions descriptions for the left and right arrow keys.
* Updated `terra-compact-interactive-list` documentation for `terra-popup` supported in a cell.

* Added
* Added a note about accessibility requirements for sorting or another action to the Multiple Row Selection example in `terra-table`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import CellContent from './CellContent?dev-site-examples';
<Notice variant="important" ariaLevel="3">

* Only one interactive element per cell is allowed. Because the Compact Intercative List component is one tab stop and the arrow keys are used to move between cells, these keys are not available to move to multiple interactive elements in a cell.
* Interactive elements are limited to [terra-button](https://engineering.cerner.com/terra-ui/components/cerner-terra-core-docs/button/about), [terra-hyperlink](https://engineering.cerner.com/terra-ui/components/cerner-terra-core-docs/hyperlink/about), and [terra-menu](https://engineering.cerner.com/terra-ui/components/cerner-terra-framework-docs/menu/menu). Currently, the cell does not restrict interaction when active,
and all interactive elements keep their native arrow key interactions. If you place a text input, a text area, or select elements in a cell, you are unable to move away from the cell with the arrow keys.
* Interactive elements are limited to [terra-button](https://engineering.cerner.com/terra-ui/components/cerner-terra-core-docs/button/about), [terra-hyperlink](https://engineering.cerner.com/terra-ui/components/cerner-terra-core-docs/hyperlink/about), [terra-menu](https://engineering.cerner.com/terra-ui/components/cerner-terra-framework-docs/menu/menu), and [terra-popup](https://engineering.cerner.com/terra-ui/components/cerner-terra-framework-docs/popup/popup).
Currently, the cell does not restrict interaction when active, and all interactive elements keep their native arrow key interactions.
If you place a text input, a text area, or select elements in a cell, you are unable to move away from the cell with the arrow keys.

</Notice>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useState, useCallback } from 'react';
import React, { useState, useCallback, useRef } from 'react';
import CompactInteractiveList, { alignTypes } from 'terra-compact-interactive-list';
import {
IconFeaturedOff, IconFeatured, IconMultipleResultsNormal, IconMultipleResultsNotNormal, IconMultipleResultsCritical,
} from 'terra-icon';
import Button from 'terra-button';
import Hyperlink from 'terra-hyperlink';
import Checkbox, { CheckboxField } from 'terra-form-checkbox';
import Popup from 'terra-popup';
import BasicMenu from '../../menu/example/BasicMenu';

// eslint-disable-next-line no-alert
const buttonCell = <Button text="Learn more" />;
const buttonCell = <Button text="Learn more" onClick={() => alert('Learn more button was clicked')} />;
const anchorCell = <Hyperlink href="https://www.cerner.com" text="Documents" />;
const iconResultsNormal = <IconMultipleResultsNormal a11yLabel="Results normal" height="1.5em" width="1.5em" />;
const iconResultsNotNormal = <IconMultipleResultsNotNormal a11yLabel="Results not normal" height="1.5em" width="1.5em" />;
Expand All @@ -34,7 +36,56 @@ const FeaturedIcon = () => {
const [isFeatured, setIsFeatured] = useState(false);
const onButtonClick = () => setIsFeatured(!isFeatured);
return (
isFeatured ? <Button variant="utility" text="Unfavorite item" icon={<IconFeatured />} onClick={onButtonClick} /> : <Button variant="utility" text="Favorite item" icon={<IconFeaturedOff />} onClick={onButtonClick} />
isFeatured
? <Button variant="utility" text="Unfavorite item" icon={<IconFeatured />} onClick={onButtonClick} />
: <Button variant="utility" text="Favorite item" icon={<IconFeaturedOff />} onClick={onButtonClick} />
);
};

const PopupWithInteractiveContent = () => {
const [isOpen, setIsOpen] = useState(false);
const [selected, setSelected] = useState(null);
const buttonRef = useRef(null);

const setButtonNode = useCallback((node) => { buttonRef.current = node; }, []);
const getButtonNode = useCallback(() => buttonRef.current, []);
const handleButtonClick = useCallback(() => { setIsOpen(true); }, []);
const handleRequestClose = useCallback(() => { setIsOpen(false); }, []);
const closeAndSetFocus = useCallback(() => {
handleRequestClose();
buttonRef.current.focus();
}, [handleRequestClose]);

const handleOnChange = useCallback((e) => {
const selectedAnswers = [...selected];
if (e.currentTarget.checked) {
selectedAnswers.push(e.currentTarget.value);
} else {
selectedAnswers.splice(selectedAnswers.indexOf(e.currentTarget.value), 1);
}
setSelected(selectedAnswers);
}, [selected]);

return (
<>
<Button text="Clinical Suite" onClick={handleButtonClick} refCallback={setButtonNode} />
<Popup
isOpen={isOpen}
targetRef={getButtonNode}
onRequestClose={handleRequestClose}
contentHeight="auto"
>
{/* eslint-disable-next-line react/forbid-dom-props */}
<div style={{ padding: '1em' }}>
<CheckboxField legend="Do you want to use any of our clinical applications?">
<Checkbox id="drug-database" name="applications[]" labelText="Drug Database" onChange={handleOnChange} value="drug-database" />
<Checkbox id="vitals-collection" name="applications[]" labelText="Vitals Collection" onChange={handleOnChange} value="vitals-collection" />
<Checkbox id="immunization-manager" name="applications[]" labelText="Immunization Manager" onChange={handleOnChange} value="immunization-manager" />
</CheckboxField>
<Button text="Submit Request" onClick={closeAndSetFocus} />
</div>
</Popup>
</>
);
};

Expand All @@ -52,7 +103,7 @@ const rows = [
id: 'row_2',
cells: [
{ content: iconResultsNormal },
{ content: 'Initial observation Care/Day High Severity 99220 (2)' },
{ content: 'Initial Observation Care/Day High Severity 99220 (2)' },
{ content: buttonCell },
{ content: <FeaturedIcon /> },
],
Expand All @@ -71,7 +122,7 @@ const rows = [
cells: [
{ content: ' ' },
{ content: 'Sbsq Observation Care/Day High Severity 99226 (4)' },
{ content: buttonCell },
{ content: <PopupWithInteractiveContent /> },
{ content: <FeaturedIcon /> },
],
},
Expand Down Expand Up @@ -106,7 +157,7 @@ const cols = [
{
id: 'Column-2',
displayName: 'Details',
width: '210px',
width: '225px',
align: alignTypes.RIGHT,
isSelectable: true,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { useState, useCallback } from 'react';
import React, { useState, useCallback, useRef } from 'react';
import CompactInteractiveList, { alignTypes } from 'terra-compact-interactive-list';
import {
IconFeaturedOff, IconFeatured, IconMultipleResultsNormal, IconMultipleResultsNotNormal, IconMultipleResultsCritical,
} from 'terra-icon';
import Button from 'terra-button';
import Hyperlink from 'terra-hyperlink';
import Checkbox, { CheckboxField } from 'terra-form-checkbox';
import Popup from 'terra-popup';
import MenuButton from './MenuButton';

const menuButton = <MenuButton />;
Expand Down Expand Up @@ -34,7 +36,56 @@ const FeaturedIcon = () => {
const [isFeatured, setIsFeatured] = useState(false);
const onButtonClick = () => setIsFeatured(!isFeatured);
return (
isFeatured ? <Button variant="utility" text="Unfavorite item" icon={<IconFeatured />} onClick={onButtonClick} /> : <Button variant="utility" text="Favorite item" icon={<IconFeaturedOff />} onClick={onButtonClick} />
isFeatured
? <Button variant="utility" text="Unfavorite item" icon={<IconFeatured />} onClick={onButtonClick} />
: <Button variant="utility" text="Favorite item" icon={<IconFeaturedOff />} onClick={onButtonClick} />
);
};

const PopupWithInteractiveContent = () => {
const [isOpen, setIsOpen] = useState(false);
const [selected, setSelected] = useState(null);
const buttonRef = useRef(null);

const setButtonNode = useCallback((node) => { buttonRef.current = node; }, []);
const getButtonNode = useCallback(() => buttonRef.current, []);
const handleButtonClick = useCallback(() => { setIsOpen(true); }, []);
const handleRequestClose = useCallback(() => { setIsOpen(false); }, []);
const closeAndSetFocus = useCallback(() => {
handleRequestClose();
buttonRef.current.focus();
}, [handleRequestClose]);

const handleOnChange = useCallback((e) => {
const selectedAnswers = [...selected];
if (e.currentTarget.checked) {
selectedAnswers.push(e.currentTarget.value);
} else {
selectedAnswers.splice(selectedAnswers.indexOf(e.currentTarget.value), 1);
}
setSelected(selectedAnswers);
}, [selected]);

return (
<>
<Button id="popup-button" text="Clinical Suite" onClick={handleButtonClick} refCallback={setButtonNode} />
<Popup
isOpen={isOpen}
targetRef={getButtonNode}
onRequestClose={handleRequestClose}
contentHeight="auto"
>
{/* eslint-disable-next-line react/forbid-dom-props */}
<div style={{ padding: '1em' }}>
<CheckboxField legend="Do you want to use any of our clinical applications?">
<Checkbox id="drug-database" name="applications[]" labelText="Drug Database" onChange={handleOnChange} value="drug-database" />
<Checkbox id="vitals-collection" name="applications[]" labelText="Vitals Collection" onChange={handleOnChange} value="vitals-collection" />
<Checkbox id="immunization-manager" name="applications[]" labelText="Immunization Manager" onChange={handleOnChange} value="immunization-manager" />
</CheckboxField>
<Button text="Submit Request" onClick={closeAndSetFocus} />
</div>
</Popup>
</>
);
};

Expand All @@ -52,7 +103,7 @@ const rows = [
id: 'row_2',
cells: [
{ content: iconResultsNormal },
{ content: 'Initial observation Care/Day High Severity 99220 (2)' },
{ content: 'Initial Observation Care/Day High Severity 99220 (2)' },
{ content: buttonCell },
{ content: <FeaturedIcon /> },
],
Expand All @@ -71,7 +122,7 @@ const rows = [
cells: [
{ content: ' ' },
{ content: 'Sbsq Observation Care/Day High Severity 99226 (4)' },
{ content: buttonCell },
{ content: <PopupWithInteractiveContent /> },
{ content: <FeaturedIcon /> },
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ exports[`Menu correctly applies the theme context className 1`] = `
hookshotPostionFixed={true}
onContentResize={[Function]}
onEsc={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onResize={[Function]}
outsideClickIgnoreClass="ignore-react-onclickoutside"
preventDefault={false}
Expand All @@ -343,6 +345,8 @@ exports[`Menu correctly applies the theme context className 1`] = `
hookshotPostionFixed={true}
onContentResize={[Function]}
onEsc={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onResize={[Function]}
outsideClickIgnoreClass="ignore-react-onclickoutside"
preventDefault={false}
Expand All @@ -354,6 +358,8 @@ exports[`Menu correctly applies the theme context className 1`] = `
<div
className="content content orion-fusion-theme fixed-position"
data-terra-popup-content={true}
onFocus={[Function]}
onKeyDown={[Function]}
role={null}
tabIndex={null}
>
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-popup/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Changed
* Added event handlers to call `stopPropagation()` on key and focus events on PopupContent in other components.

## 6.80.0 - (April 4, 2024)

* Changed
Expand Down
11 changes: 11 additions & 0 deletions packages/terra-popup/src/_PopupContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class PopupContent extends React.Component {
constructor(props) {
super(props);
this.handleOnResize = this.handleOnResize.bind(this);
this.handlePropagation = this.handlePropagation.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -168,6 +169,14 @@ class PopupContent extends React.Component {
return null;
}

/**
* This method stopps key and focus events from bubbling for Popup support in terra-compact-interactive-list.
* The key and focus events still work inside the popup as expected.
*/
handlePropagation = (event) => {
event.stopPropagation();
};

handleOnResize(event) {
if (this.props.onResize) {
this.props.onResize(event, this.windowWidth);
Expand Down Expand Up @@ -237,6 +246,8 @@ class PopupContent extends React.Component {
onResize={this.handleOnResize}
refCallback={refCallback}
role={popupContentRole || null}
onKeyDown={this.handlePropagation}
onFocus={this.handlePropagation}
>
{arrowContent}
{/* eslint-disable-next-line react/forbid-dom-props */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ exports[`correctly applies the theme context className 1`] = `
}
excludeScrollbar={false}
onEsc={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onResize={[Function]}
outsideClickIgnoreClass="ignore-react-onclickoutside"
preventDefault={false}
Expand All @@ -181,6 +183,8 @@ exports[`correctly applies the theme context className 1`] = `
]
}
onEsc={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onResize={[Function]}
outsideClickIgnoreClass="ignore-react-onclickoutside"
preventDefault={false}
Expand All @@ -192,6 +196,8 @@ exports[`correctly applies the theme context className 1`] = `
<div
className="content content orion-fusion-theme"
data-terra-popup-content={true}
onFocus={[Function]}
onKeyDown={[Function]}
role="dialog"
tabIndex="0"
>
Expand Down
Loading

0 comments on commit bbc7c11

Please sign in to comment.