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

Commit

Permalink
[terra-clinical-item-view] Implement unordered list to create
Browse files Browse the repository at this point in the history
header/content relationship
  • Loading branch information
ry061521 committed Sep 8, 2023
1 parent 6fa2823 commit ab9b4f5
Show file tree
Hide file tree
Showing 26 changed files with 2,479 additions and 1,520 deletions.
3 changes: 3 additions & 0 deletions packages/terra-clinical-item-view/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* Added
* Added `trueColumn` prop so consumers can choose whether to separate displays in the two column layout by row or by column.

* Changed
* Changed displays to exist in an unordered list as list items with the first display as a programmatic header.

## 4.10.0 - (August 16, 2023)

* Changed
Expand Down
3 changes: 2 additions & 1 deletion packages/terra-clinical-item-view/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"terra-clinical-item-display": "^4.9.0",
"terra-icon": "^3.0.0",
"terra-mixins": "^1.0.0",
"terra-theme-context": "^1.0.0"
"terra-theme-context": "^1.0.0",
"uuid": "^3.4.0"
},
"scripts": {
"compile": "babel --root-mode upward src --out-dir lib --copy-files",
Expand Down
213 changes: 134 additions & 79 deletions packages/terra-clinical-item-view/src/ItemView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';
import { v4 as uuidv4 } from 'uuid';
import ThemeContext from 'terra-theme-context';
import ItemDisplay from 'terra-clinical-item-display';
import ItemComment from 'terra-clinical-item-display/lib/ItemComment';
Expand Down Expand Up @@ -145,6 +146,114 @@ const classesForContent = (rowIndex, rowCount, contentIndex, emphasis) => {
return ['content'].concat(classes);
};

const renderRow = (row, rowIndex, rowCount, emphasis, overrideDefaultStyling) => {
const rowKey = rowIndex;

return (
<li className={cx('row')} key={rowKey}>
<ul className={cx('row-list')} key={rowKey}>
{row.map((display, displayIndex) => {
const displayKey = displayIndex;
const contentClasses = overrideDefaultStyling ? 'content' : classesForContent(rowIndex, rowCount, displayIndex, emphasis);

return (
<li className={cx(contentClasses)} key={displayKey}>
{display}
</li>
);
})}
</ul>
</li>
);
};

const renderTwoColumns = (displayGroup, displayGroupIndex, emphasis, overrideDefaultStyling) => {
const columnKey = displayGroupIndex;
const displayCount = displayGroup.length;
const containerStyling = displayGroupIndex === 0 ? 'primary-column' : 'secondary-column';

return (
<li className={cx(containerStyling)} key={columnKey}>
<ul className={cx('column-list')} key={columnKey}>
{displayGroup.map((display, contentIndex) => {
const contentKey = contentIndex;
const contentClasses = overrideDefaultStyling ? 'content' : classesForContent(contentIndex, displayCount, displayGroupIndex, emphasis);

return (
<li className={cx(contentClasses)} key={contentKey}>
{display}
</li>
);
})}
</ul>
</li>
);
};

const renderColumn = (displays, emphasis, overrideDefaultStyling, header) => {
const displayCount = displays.length;
const headerID = `single-column-header-${uuidv4()}`;

return (
<div>
<h6 id={headerID} hidden>{header}</h6>
<ul aria-labelledby={headerID} className={cx('column-list-container')}>
{displays.map((display, displayIndex) => {
const contentKey = displayIndex;
/**
* We are only ever rendering one column so zero is being passed into classesForContent for the contentIndex variable.
* classesForContent would usually take in an index for that but in this case we don't have one explicitly.
*/
const contentClasses = overrideDefaultStyling ? 'content' : classesForContent(displayIndex, displayCount, 0, emphasis);

return (
<li className={cx(contentClasses)} key={contentKey}>
{display}
</li>
);
})}
</ul>
</div>
);
};

const renderByRowView = (displays, emphasis, overrideDefaultStyling, header) => {
const displayGroups = [];
const headerID = `by-row-header-${uuidv4()}`;

while (displays.length) {
displayGroups.push(displays.splice(0, 2));
}

return (
<div>
<h6 id={headerID} hidden>{header}</h6>
<ul aria-labelledby={headerID} className={cx('row-list-container')}>
{displayGroups.map((displayRow, rowIndex) => {
const row = renderRow(displayRow, rowIndex, displayGroups.length, emphasis, overrideDefaultStyling);
return row;
})}
</ul>
</div>
);
};

const renderSingleDisplayView = (singleDisplay, overrideDefaultStyling) => {
/**
* Since this is always a singular display, the content styling will be the primary defaults if they are not overridden.
* We don't have to call into the classesForContent method and instead can just set the primary size and color here.
*/
const contentClass = overrideDefaultStyling ? 'content' : ['content', 'content-primary-size', 'content-primary-color'];

return (
<div className={cx('single-result-column-container')}>
<div className={cx(contentClass)}>
{singleDisplay}
</div>
</div>
);
};

const twoColumnGrouping = (displays) => {
let count = 0;
const displayGroups = [];
Expand All @@ -167,97 +276,43 @@ const twoColumnGrouping = (displays) => {
return displayGroups;
};

const renderRow = (row, rowIndex, rowCount, emphasis) => {
const rowKey = rowIndex;
return (
<div className={cx('row')} key={rowKey}>
{row.map((display, displayIndex) => {
const displayKey = displayIndex;
const contentClasses = classesForContent(rowIndex, rowCount, displayIndex, emphasis);

return (
<div className={cx(contentClasses)} key={displayKey}>
{display}
</div>
);
})}
</div>
);
};

const renderColumn = (displayGroup, displayGroupIndex, emphasis, overrideDefaultStyling) => {
const columnKey = displayGroupIndex;
const displayCount = displayGroup.length;
let containerStyling;

if (displayGroupIndex === 0) {
containerStyling = 'primary-column';
} else {
containerStyling = 'secondary-column';
}

return (
<div className={cx(containerStyling)} key={columnKey}>
{displayGroup.map((display, contentIndex) => {
const contentKey = contentIndex;
let contentClasses;

if (overrideDefaultStyling) {
contentClasses = 'content';
} else {
contentClasses = classesForContent(contentIndex, displayCount, displayGroupIndex, emphasis);
}

return (
<div className={cx(contentClasses)} key={contentKey}>
{display}
</div>
);
})}
</div>
);
};

const renderView = (displays, layout, emphasis, overrideDefaultStyling, trueColumn) => {
if (displays === null || displays === undefined || !displays.length) {
return undefined;
}

let displayGroups = [];
const displaysSlice = displays.slice(0, 8);
const primaryColumn = [];

/**
* If there is only one display we don't want to return it as an item in a list nor have a header attached to it.
* The method renderSingleDisplayView here takes in the single display and returns it within simple divs instead.
*/
if (displaysSlice.length === 1) { return renderSingleDisplayView(displaysSlice, overrideDefaultStyling); }

const header = displays.slice(0, 1);

if (layout === Layouts.TWO_COLUMNS) {
if (trueColumn) {
displayGroups = twoColumnGrouping(displaysSlice);
} else {
while (displaysSlice.length) {
displayGroups.push(displaysSlice.splice(0, 2));
}

return (
<div className={cx('row-container')}>
{displayGroups.map((displayRow, rowIndex) => {
const row = renderRow(displayRow, rowIndex, displayGroups.length, emphasis);
return row;
if (!trueColumn) { return renderByRowView(displaysSlice, emphasis, overrideDefaultStyling, header); }

const displayGroups = twoColumnGrouping(displaysSlice);
const headerID = `two-column-header-${uuidv4()}`;

return (
<div>
<h6 id={headerID} hidden>{header}</h6>
<ul aria-labelledby={headerID} className={cx('column-list-container')}>
{displayGroups.map((group, index) => {
const column = renderTwoColumns(group, index, emphasis, overrideDefaultStyling);
return column;
})}
</div>
);
}
} else {
while (displaysSlice.length) {
primaryColumn.push(displaysSlice.splice(0, 1));
}

displayGroups.push(primaryColumn);
</ul>
</div>
);
}

return (
<div className={cx('column-container')}>
{displayGroups.map((group, index) => {
const column = renderColumn(group, index, emphasis, overrideDefaultStyling);
return column;
})}
<div>
{renderColumn(displaysSlice, emphasis, overrideDefaultStyling, header)}
</div>
);
};
Expand Down
71 changes: 55 additions & 16 deletions packages/terra-clinical-item-view/src/ItemView.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,55 @@
overflow: hidden; // VERY IMPORTANT FOR IE10
}

.column-container {
.content {
align-items: flex-start;
display: flex;
overflow: hidden; // VERY IMPORTANT FOR IE10
}

.single-result-column-container {
display: flex;
flex-flow: row nowrap;
}

.content {
align-items: flex-start;
.column-list-container {
display: flex;
overflow: hidden; // VERY IMPORTANT FOR IE10
list-style-type: none;
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
}

.column-list {
display: flex;
flex-flow: column nowrap;
list-style-type: none;
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
}

.row-list-container {
display: flex;
flex-flow: row wrap;
list-style-type: none;
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
}

.row {
display: flex;
width: 100%;
}

.row-list {
display: flex;
list-style-type: none;
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
width: 100%;
}

.secondary-column {
Expand All @@ -78,31 +118,30 @@
}
}

.row {
display: flex;
width: 100%;
}

.is-truncated,
.is-truncated [data-terra-clinical-item-display-text] {
@include terra-clinical-text-truncate;
}

// Layouts
/* stylelint-disable selector-max-compound-selectors */
.one-column {
.primary-column {
width: 100%;
.column-list-container {
flex-flow: column nowrap;
}
}
/* stylelint-enable selector-max-compound-selectors */

/* stylelint-disable selector-max-compound-selectors */
.two-columns {
.primary-column {
flex: 1 1 auto;
float: left;
.column-list-container {
flex-flow: row nowrap;

.primary-column {
flex: 1 1 auto;
float: left;
}
}
}
/* stylelint-enable selector-max-compound-selectors */

.two-columns-by-row {
.content:nth-child(odd) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import IconAlert from 'terra-icon/lib/icon/IconAlert';
import ItemView from '../../../ItemView';

const display1 = <ItemView.Display icon={<IconAlert />} iconAlignment="inline" text="display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text" key="123" />;

const views = () => (
<div>
<h2>One Column - Single Display</h2>
<p>When there is only one display we return it without putting it into an unordered list and returning it as a list item.</p>
<ItemView displays={[display1]} id="test-single-display" />
</div>
);

export default views;
Loading

0 comments on commit ab9b4f5

Please sign in to comment.