diff --git a/packages/terra-clinical-item-view/src/ItemView.jsx b/packages/terra-clinical-item-view/src/ItemView.jsx
index 9e16fd91c..23be5cb04 100644
--- a/packages/terra-clinical-item-view/src/ItemView.jsx
+++ b/packages/terra-clinical-item-view/src/ItemView.jsx
@@ -26,9 +26,13 @@ const AccessoryAlignments = {
const propTypes = {
/**
- * The column layout in which to present the displays. One of `oneColumn`, `twoColumn`.
+ * The visual column layout in which to present the displays. One of `oneColumn`, `twoColumn`.
*/
layout: PropTypes.oneOf(['oneColumn', 'twoColumns']),
+ /**
+ * Determines whether the displays are programatically separated by row or as true columns when layout is set to `twoColumns`.
+ */
+ trueColumn: PropTypes.bool,
/**
* The text color emphasis when using two columns. One of `default`, `start`.
*/
@@ -73,6 +77,7 @@ const propTypes = {
const defaultProps = {
layout: Layouts.ONE_COLUMN,
+ trueColumn: true,
textEmphasis: TextEmphasisTypes.DEFAULT,
overrideDefaultStyling: false,
isTruncated: false,
@@ -120,19 +125,19 @@ const defaultEmphasisContentClassesFromIndexes = (rowIndex, rowCount) => {
return [contentSize, contentColor];
};
-const startEmphasisContentClassesFromIndexes = (rowIndex, rowCount, columnIndex) => {
- if (columnIndex > 0 || rowIndex >= 2) {
+const startEmphasisContentClassesFromIndexes = (rowIndex, rowCount, contentIndex) => {
+ if (contentIndex > 0 || rowIndex >= 2) {
return ['content-secondary-size', 'content-secondary-color'];
}
return defaultEmphasisContentClassesFromIndexes(rowIndex, rowCount);
};
-const classesForContent = (rowIndex, rowCount, columnIndex, emphasis) => {
+const classesForContent = (rowIndex, rowCount, contentIndex, emphasis) => {
let classes;
if (emphasis === TextEmphasisTypes.START) {
- classes = startEmphasisContentClassesFromIndexes(rowIndex, rowCount, columnIndex);
+ classes = startEmphasisContentClassesFromIndexes(rowIndex, rowCount, contentIndex);
} else {
classes = defaultEmphasisContentClassesFromIndexes(rowIndex, rowCount);
}
@@ -140,6 +145,45 @@ const classesForContent = (rowIndex, rowCount, columnIndex, emphasis) => {
return ['content'].concat(classes);
};
+const twoColumnGrouping = (displays) => {
+ let count = 0;
+ const displayGroups = [];
+ const primaryColumn = [];
+ const secondaryColumn = [];
+
+ while (displays.length) {
+ count += 1;
+
+ if (count % 2 === 0) {
+ secondaryColumn.push(displays.splice(0, 1));
+ } else {
+ primaryColumn.push(displays.splice(0, 1));
+ }
+ }
+
+ displayGroups.push(primaryColumn);
+ displayGroups.push(secondaryColumn);
+
+ return displayGroups;
+};
+
+const renderRow = (row, rowIndex, rowCount, emphasis) => {
+ const rowKey = rowIndex;
+ return (
+
+ {row.map((display, displayIndex) => {
+ const displayKey = displayIndex;
+ const contentClasses = classesForContent(rowIndex, rowCount, displayIndex, emphasis);
+ return (
+
+ {display}
+
+ );
+ })}
+
+ );
+};
+
const renderColumn = (displayGroup, displayGroupIndex, emphasis, overrideDefaultStyling) => {
const columnKey = displayGroupIndex;
const displayCount = displayGroup.length;
@@ -173,31 +217,32 @@ const renderColumn = (displayGroup, displayGroupIndex, emphasis, overrideDefault
);
};
-const renderView = (displays, layout, emphasis, overrideDefaultStyling) => {
+const renderView = (displays, layout, emphasis, overrideDefaultStyling, trueColumn) => {
if (displays === null || displays === undefined || !displays.length) {
return undefined;
}
- const primaryColumn = [];
- const displayGroups = [];
+ let displayGroups = [];
const displaysSlice = displays.slice(0, 8);
+ const primaryColumn = [];
if (layout === Layouts.TWO_COLUMNS) {
- let count = 0;
- const secondaryColumn = [];
-
- while (displaysSlice.length) {
- count += 1;
-
- if (count % 2 === 0) {
- secondaryColumn.push(displaysSlice.splice(0, 1));
- } else {
- primaryColumn.push(displaysSlice.splice(0, 1));
+ if (trueColumn) {
+ displayGroups = twoColumnGrouping(displaysSlice);
+ } else {
+ while (displaysSlice.length) {
+ displayGroups.push(displaysSlice.splice(0, 2));
}
- }
- displayGroups.push(primaryColumn);
- displayGroups.push(secondaryColumn);
+ return (
+
+ {displayGroups.map((displayRow, rowIndex) => {
+ const row = renderRow(displayRow, rowIndex, displayGroups.length, emphasis);
+ return row;
+ })}
+
+ );
+ }
} else {
while (displaysSlice.length) {
primaryColumn.push(displaysSlice.splice(0, 1));
@@ -216,8 +261,21 @@ const renderView = (displays, layout, emphasis, overrideDefaultStyling) => {
);
};
+const isDisplaysTruncated = (displays) => {
+ const displaysSlice = displays.slice(0, 8);
+
+ for (let i = 0; i < displaysSlice.length; i += 1) {
+ if (displaysSlice[i].props.isTruncated === true) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
const ItemView = ({
layout,
+ trueColumn,
textEmphasis,
overrideDefaultStyling,
isTruncated,
@@ -231,13 +289,16 @@ const ItemView = ({
...customProps
}) => {
const theme = React.useContext(ThemeContext);
+ const isTrueTwoColumnView = layout === Layouts.TWO_COLUMNS && trueColumn;
+ const isTruncatedDisplay = isTruncated || isDisplaysTruncated(displays);
const viewClassNames = classNames(
cx(
'item-view',
{ 'is-truncated': isTruncated },
{ 'one-column': layout === Layouts.ONE_COLUMN },
- { 'two-columns': (layout === Layouts.TWO_COLUMNS && !isTruncated) },
- { 'truncated-two-columns': (layout === Layouts.TWO_COLUMNS && isTruncated) },
+ { 'two-columns': isTrueTwoColumnView && !isTruncatedDisplay },
+ { 'truncated-two-columns': isTrueTwoColumnView && isTruncatedDisplay },
+ { 'two-columns-by-row': layout === Layouts.TWO_COLUMNS && !trueColumn },
theme.className,
),
customProps.className,
@@ -247,7 +308,7 @@ const ItemView = ({
{renderAccessory(startAccessory, reserveStartAccessorySpace, accessoryAlignment, 'start')}
- {renderView(displays, layout, textEmphasis, overrideDefaultStyling)}
+ {renderView(displays, layout, textEmphasis, overrideDefaultStyling, trueColumn)}
{comment}
{renderAccessory(endAccessory, false, accessoryAlignment, 'end')}
diff --git a/packages/terra-clinical-item-view/src/ItemView.module.scss b/packages/terra-clinical-item-view/src/ItemView.module.scss
index 361536565..53ce8065a 100644
--- a/packages/terra-clinical-item-view/src/ItemView.module.scss
+++ b/packages/terra-clinical-item-view/src/ItemView.module.scss
@@ -78,6 +78,11 @@
}
}
+ .row {
+ display: flex;
+ width: 100%;
+ }
+
.is-truncated,
.is-truncated [data-terra-clinical-item-display-text] {
@include terra-clinical-text-truncate;
@@ -99,6 +104,25 @@
}
}
+ .two-columns-by-row {
+ .content:nth-child(odd) {
+ flex: 1 1 auto;
+ float: left;
+ justify-content: flex-start;
+ }
+
+ .content:nth-child(even) {
+ @include terra-text-align-end();
+ flex: 1 0 auto;
+ float: right;
+ justify-content: flex-end;
+ // Set a max-width and disable flexbox-squishing on the right-most displays. This will ensure that they aren't
+ // prematurely squished and maximize the available space for all labels.
+ max-width: 60%;
+ padding-left: 5px;
+ }
+ }
+
.truncated-two-columns {
.primary-column {
flex: 1 1 auto;
diff --git a/packages/terra-clinical-item-view/src/terra-dev-site/doc/clinical-item-view/clinicalItemView.1.doc.mdx b/packages/terra-clinical-item-view/src/terra-dev-site/doc/clinical-item-view/clinicalItemView.1.doc.mdx
index c28080b2a..bd4a73aac 100644
--- a/packages/terra-clinical-item-view/src/terra-dev-site/doc/clinical-item-view/clinicalItemView.1.doc.mdx
+++ b/packages/terra-clinical-item-view/src/terra-dev-site/doc/clinical-item-view/clinicalItemView.1.doc.mdx
@@ -3,6 +3,7 @@ import { Badge } from 'terra-clinical-item-view/package.json?dev-site-package';
import ItemViewStandard from '../example/ItemViewStandard?dev-site-example';
import ItemViewTwoColumn from '../example/ItemViewTwoColumn?dev-site-example';
import ItemViewTwoColumnStart from '../example/ItemViewTwoColumnStart?dev-site-example';
+import ItemViewTwoColumnByRow from '../example/ItemViewTwoColumnByRow?dev-site-example';
import ItemViewComment from '../example/ItemViewComment?dev-site-example';
import ItemViewAll from '../example/ItemViewAll?dev-site-example';
import ItemViewAllTopAligned from '../example/ItemViewAllTopAligned?dev-site-example';
@@ -37,6 +38,10 @@ import ItemView from 'terra-clinical-item-view';
title="ItemView - Two Column Layout"
description="When including icons as part of an '
'', it is recommended to use the iconAlignment='inline' prop for best alignment and wrapping with the text."
/>
+
diff --git a/packages/terra-clinical-item-view/src/terra-dev-site/doc/example/ItemViewTwoColumnByRow.jsx b/packages/terra-clinical-item-view/src/terra-dev-site/doc/example/ItemViewTwoColumnByRow.jsx
new file mode 100644
index 000000000..e3b01a274
--- /dev/null
+++ b/packages/terra-clinical-item-view/src/terra-dev-site/doc/example/ItemViewTwoColumnByRow.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import IconBriefcase from 'terra-icon/lib/icon/IconBriefcase';
+import IconPerson from 'terra-icon/lib/icon/IconPerson';
+import ItemView from 'terra-clinical-item-view';
+
+const display1 =
} iconAlignment="inline" text="Asif Khan" />;
+const display2 =
} iconAlignment="inline" text="Care Position: Primary" />;
+const display3 =
;
+const display4 =
;
+const display5 =
;
+const display6 =
;
+const displays = [display1, display2, display3, display4, display5, display6];
+
+export default () =>
;
diff --git a/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/DisplaysItemViewByRow.test.jsx b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/DisplaysItemViewByRow.test.jsx
new file mode 100644
index 000000000..3757b1d32
--- /dev/null
+++ b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/DisplaysItemViewByRow.test.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import IconAlert from 'terra-icon/lib/icon/IconAlert';
+import ItemView from '../../../ItemView';
+
+const display1 =
} iconAlignment="inline" text="display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text display1 Text" key="123" />;
+const display2 =
} iconAlignment="inline" text="display2 Text display2 Text display2 Text display2 Text display2 Text display2 Text display2 Text display2 Text display2 Text" key="124" />;
+const display3 =
;
+const display4 =
;
+const display5 =
;
+const display6 =
;
+const displays = [display1, display2, display3, display4, display5, display6];
+
+const views = () => (
+
+
Two Column Layout by Row
+
+
+ Two Column Layout by Row with Start TextEmphasis
+
+
+);
+
+export default views;
diff --git a/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemView.test.jsx b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemView.test.jsx
index 8b42dc607..a3c359002 100644
--- a/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemView.test.jsx
+++ b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemView.test.jsx
@@ -14,6 +14,11 @@ const display4 =
;
const display5 =
;
const display6 =
;
const displays = [display1, display2, display3, display4, display5, display6];
+const isTruncatedDisplay1 =
;
+const isTruncatedDisplay2 =
;
+const partialTruncatedDisplays = [isTruncatedDisplay1, isTruncatedDisplay2, display3, display4, display5, display6];
+const leftPartialTruncatedDisplays = [isTruncatedDisplay1, display2, display3, display4, display5, display6];
+const rightPartialTruncatedDisplays = [display1, isTruncatedDisplay2, display3, display4, display5, display6];
const accessoryStart = id =>
;
const accessoryEnd = id =>
;
@@ -24,14 +29,26 @@ const views = () => (
Applied width of 900px to show the default vs truncated styling.
Full Examples - Default
-
+
-
+
Full Examples - Truncated
-
+
-
+
+
+
Partial Truncation Examples - Single Column
+
+
+
Partial Truncation Examples - Two Column Left and Right Truncated
+
+
+
Partial Truncation Examples - Two Column Left Truncated
+
+
+
Partial Truncation Examples - Two Column Right Truncated
+
);
diff --git a/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemViewByRow.test.jsx b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemViewByRow.test.jsx
new file mode 100644
index 000000000..4fef5acff
--- /dev/null
+++ b/packages/terra-clinical-item-view/src/terra-dev-site/test/clinical-item-view/OverflowDisplaysItemViewByRow.test.jsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import IconAlert from 'terra-icon/lib/icon/IconAlert';
+import IconInformation from 'terra-icon/lib/icon/IconInformation';
+import classNames from 'classnames/bind';
+import ItemView from '../../../ItemView';
+import styles from './ItemViewCommon.test.module.scss';
+
+const cx = classNames.bind(styles);
+
+const display1 = ;
+const display2 = ;
+const display3 = ;
+const display4 = ;
+const display5 = ;
+const display6 = ;
+const displays = [display1, display2, display3, display4, display5, display6];
+const isTruncatedDisplay1 = ;
+const isTruncatedDisplay2 = ;
+const partialTruncatedDisplays = [isTruncatedDisplay1, isTruncatedDisplay2, display3, display4, display5, display6];
+const leftPartialTruncatedDisplays = [isTruncatedDisplay1, display2, display3, display4, display5, display6];
+const rightPartialTruncatedDisplays = [display1, isTruncatedDisplay2, display3, display4, display5, display6];
+
+const accessoryStart = id => ;
+const accessoryEnd = id => ;
+const comment = id => ;
+
+const views = () => (
+
+
Applied width of 900px to show the default vs truncated styling.
+
+
Default ItemView
+
+
+
Truncated ItemView
+
+
+
The next examples include when ItemView has `isTruncated` set to `false` while the ItemDisplays passed in to the ItemView have the `isTruncated` prop set to `true`.
+
Left and Right Displays Truncated
+
+
+
Left Display Truncated
+
+
+
Right Display Truncated
+
+
+);
+
+export default views;
diff --git a/packages/terra-clinical-item-view/tests/jest/ItemView.test.jsx b/packages/terra-clinical-item-view/tests/jest/ItemView.test.jsx
index 7d0ff01d3..fad1b7aaa 100644
--- a/packages/terra-clinical-item-view/tests/jest/ItemView.test.jsx
+++ b/packages/terra-clinical-item-view/tests/jest/ItemView.test.jsx
@@ -210,6 +210,24 @@ it('should render two columns with an odd number of displays', () => {
expect(itemView).toMatchSnapshot();
});
+it('should render two columns with 8 displays when trueColumn is false', () => {
+ const display1 = shallowWithIntl();
+ const display2 = shallowWithIntl();
+ const display3 = shallowWithIntl();
+ const display4 = shallowWithIntl();
+ const display5 = shallowWithIntl();
+ const display6 = shallowWithIntl();
+ const display7 = shallowWithIntl();
+ const display8 = shallowWithIntl();
+ const display9 = shallowWithIntl();
+
+ const displays = [display1, display2, display3, display4, display5, display6, display7, display8, display9];
+ const itemView = shallow();
+ expect(itemView.find('ItemDisplay')).toHaveLength(8);
+ expect(itemView.find('div.two-columns-by-row')).toHaveLength(1);
+ expect(itemView).toMatchSnapshot();
+});
+
it('correctly applies the theme context className', () => {
jest.spyOn(React, 'useContext')
.mockReturnValue({
diff --git a/packages/terra-clinical-item-view/tests/jest/__snapshots__/ItemView.test.jsx.snap b/packages/terra-clinical-item-view/tests/jest/__snapshots__/ItemView.test.jsx.snap
index c5d3d97c5..54e0fca7c 100644
--- a/packages/terra-clinical-item-view/tests/jest/__snapshots__/ItemView.test.jsx.snap
+++ b/packages/terra-clinical-item-view/tests/jest/__snapshots__/ItemView.test.jsx.snap
@@ -1108,6 +1108,353 @@ exports[`should render two columns with 8 displays 1`] = `
`;
+exports[`should render two columns with 8 displays when trueColumn is false 1`] = `
+
+`;
+
exports[`should render two columns with an odd number of displays 1`] = `
{
- it('with one column displays', () => {
+ it('with displays', () => {
browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/displays-item-view');
Terra.validates.element('with one column', { selector: '#test-displays' });
@@ -7,6 +7,13 @@ Terra.describeViewports('Clinical Item View', ['tiny', 'small', 'medium', 'large
Terra.validates.element('with two column and start displays', { selector: '#test-displays-two-start' });
});
+ it('with displays by row', () => {
+ browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/displays-item-view-by-row');
+
+ Terra.validates.element('with two columns by row', { selector: '#test-displays-two-row' });
+ Terra.validates.element('with two columns and start displays by row', { selector: '#test-displays-two-row-start' });
+ });
+
it('with accessories', () => {
browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/accessory-item-view');
@@ -20,13 +27,19 @@ Terra.describeViewports('Clinical Item View', ['tiny', 'small', 'medium', 'large
Terra.validates.element('truncated comment', { selector: '#ItemView2' });
});
- it('with the full example word wrap', () => {
+ it('with word wrap', () => {
browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/overflow-displays-item-view');
Terra.validates.element('with word wrap in one column', { selector: '#ItemView-one-wrap' });
Terra.validates.element('with word wrap in two columns', { selector: '#ItemView-two-wrap' });
});
+ it('with word wrap by row', () => {
+ browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/overflow-displays-item-view-by-row');
+
+ Terra.validates.element('with word wrap in two columns by row', { selector: '#ItemView-by-row-two-wrap' });
+ });
+
it('with override default styling', () => {
browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/styling-override-item-view');
@@ -35,10 +48,19 @@ Terra.describeViewports('Clinical Item View', ['tiny', 'small', 'medium', 'large
});
Terra.describeViewports('Clinical Item View', ['enormous'], () => {
- it('with the full example truncated - one truncated', () => {
+ it('with truncation', () => {
browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/overflow-displays-item-view');
- Terra.validates.element('with truncation in one column', { selector: '#ItemView-one-wrap' });
- Terra.validates.element('with truncation in two columns', { selector: '#ItemView-two-wrap' });
+ Terra.validates.element('with truncation in one column', { selector: '#ItemView-one-truncate' });
+ Terra.validates.element('with truncation in two columns', { selector: '#ItemView-two-truncate' });
});
});
+
+Terra.describeViewports('Clinical Item View', ['enormous'], () => {
+ it('with by row truncation', () => {
+ browser.url('/raw/tests/terra-clinical-item-view/clinical-item-view/overflow-displays-item-view-by-row');
+
+ Terra.validates.element('with truncation in two columns by row', { selector: '#ItemView-by-row-two-truncate' });
+ });
+});
+