terra-clinical-item-view
Version:
The Item View component allows displays to be organized into rows and column and themed, while providing means to add accessory elements and a comment.
347 lines (345 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.TextEmphasisTypes = exports.Layouts = exports.AccessoryAlignments = void 0;
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _bind = _interopRequireDefault(require("classnames/bind"));
var _terraThemeContext = _interopRequireDefault(require("terra-theme-context"));
var _terraClinicalItemDisplay = _interopRequireDefault(require("terra-clinical-item-display"));
var _ItemComment = _interopRequireDefault(require("terra-clinical-item-display/lib/ItemComment"));
var _ItemViewModule = _interopRequireDefault(require("./ItemView.module.scss"));
var _excluded = ["layout", "trueColumn", "textEmphasis", "overrideDefaultStyling", "isTruncated", "accessoryAlignment", "startAccessory", "reserveStartAccessorySpace", "endAccessory", "displays", "comment", "refCallback", "contentWidth"];
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
var cx = _bind.default.bind(_ItemViewModule.default);
var Layouts = exports.Layouts = {
ONE_COLUMN: 'oneColumn',
TWO_COLUMNS: 'twoColumns'
};
var TextEmphasisTypes = exports.TextEmphasisTypes = {
DEFAULT: 'default',
START: 'start'
};
var AccessoryAlignments = exports.AccessoryAlignments = {
ALIGN_TOP: 'alignTop',
ALIGN_CENTER: 'alignCenter'
};
var propTypes = {
/**
* The visual column layout in which to present the displays. One of `oneColumn`, `twoColumn`.
* When using the `twoColumn` layout, the displays are split between the columns by placing every other display into the second column.
*/
layout: _propTypes.default.oneOf(['oneColumn', 'twoColumns']),
/**
* Determines whether the displays are programmatically separated by row or as true columns when layout is set to `twoColumns`.
* Screenreaders will read `trueColumn` displays from top to bottom, one column at a time.
* However, this prop defaults to `false` and therefore the screenreader will read the displays in both columns together, left to right, one row at a time.
* For accessibility purposes it is recommended to set trueColumn to `true`.
*/
trueColumn: _propTypes.default.bool,
/**
* The text color emphasis when using two columns. One of `default`, `start`.
*/
textEmphasis: _propTypes.default.oneOf(['default', 'start']),
/**
* Option to override the item view default styling so the original styling for item display is shown.
*/
overrideDefaultStyling: _propTypes.default.bool,
/**
* Whether or not all text on the view should be truncated.
*/
isTruncated: _propTypes.default.bool,
/**
* The vertical alignment of the start and end accessories. One of `alignTop`, `alignCenter`.
*/
accessoryAlignment: _propTypes.default.oneOf(['alignTop', 'alignCenter']),
/**
* The react element to be placed in the start aligned accessory position.
*/
startAccessory: _propTypes.default.node,
/**
* Indicates whether or not space is allocated for the start accessory if none is given.
*/
reserveStartAccessorySpace: _propTypes.default.bool,
/**
* The react element to be placed in the end aligned accessory position.
*/
endAccessory: _propTypes.default.node,
/**
* An array of terra-clinical-item-displays to be presented.
* The Item View can only have 8 displays at a time, any additional displays passed in will be ignored.
*/
displays: _propTypes.default.arrayOf(_propTypes.default.element),
/**
* The react element for the comment element.
*/
comment: _propTypes.default.node,
/**
* Function callback for the ref of the outer most div.
*/
refCallback: _propTypes.default.func,
/**
* A string for content's width. Any valid css string.
*/
contentWidth: _propTypes.default.string
};
var defaultProps = {
layout: Layouts.ONE_COLUMN,
trueColumn: false,
textEmphasis: TextEmphasisTypes.DEFAULT,
overrideDefaultStyling: false,
isTruncated: false,
accessoryAlignment: AccessoryAlignments.ALIGN_CENTER,
startAccessory: undefined,
reserveStartAccessorySpace: false,
endAccessory: undefined,
displays: [],
comment: undefined,
contentWidth: undefined
};
var renderAccessory = function renderAccessory(accessory, reserveSpace, accessoryAlignment, type) {
var accessorySection;
if (accessory || reserveSpace) {
var accessoryClassNames = cx('accessory', "".concat(type, "-accessory"), {
'accessory-align-center': accessoryAlignment === AccessoryAlignments.ALIGN_CENTER
}, {
'accessory-align-top': accessoryAlignment === AccessoryAlignments.ALIGN_TOP
});
accessorySection = /*#__PURE__*/_react.default.createElement("div", {
className: accessoryClassNames
}, accessory);
}
return accessorySection;
};
var defaultEmphasisContentClassesFromIndexes = function defaultEmphasisContentClassesFromIndexes(rowIndex, rowCount) {
var contentSize = 'content-primary-size';
var contentColor = 'content-primary-color';
if (rowIndex > 0) {
contentSize = 'content-secondary-size';
}
if (rowIndex >= 2 || rowCount === 2 && rowIndex === 1) {
contentColor = 'content-secondary-color';
}
return [contentSize, contentColor];
};
var startEmphasisContentClassesFromIndexes = function startEmphasisContentClassesFromIndexes(rowIndex, rowCount, contentIndex) {
if (contentIndex > 0 || rowIndex >= 2) {
return ['content-secondary-size', 'content-secondary-color'];
}
return defaultEmphasisContentClassesFromIndexes(rowIndex, rowCount);
};
var classesForContent = function classesForContent(rowIndex, rowCount, contentIndex, emphasis) {
var classes;
if (emphasis === TextEmphasisTypes.START) {
classes = startEmphasisContentClassesFromIndexes(rowIndex, rowCount, contentIndex);
} else {
classes = defaultEmphasisContentClassesFromIndexes(rowIndex, rowCount);
}
return ['content'].concat(classes);
};
var renderRow = function renderRow(row, rowIndex, rowCount, emphasis, overrideDefaultStyling, contentWidth) {
var rowKey = rowIndex;
var style = contentWidth && {
width: contentWidth
};
return /*#__PURE__*/_react.default.createElement("li", {
className: cx('row'),
key: rowKey
}, /*#__PURE__*/_react.default.createElement("ul", {
className: cx('row-list'),
key: rowKey
}, row.map(function (display, displayIndex) {
var displayKey = displayIndex;
var contentClasses = overrideDefaultStyling ? 'content' : classesForContent(rowIndex, rowCount, displayIndex, emphasis);
return (
/*#__PURE__*/
// eslint-disable-next-line react/forbid-dom-props
_react.default.createElement("li", {
style: style,
className: cx(contentClasses),
key: displayKey
}, display)
);
})));
};
var renderTwoColumns = function renderTwoColumns(displayGroup, displayGroupIndex, emphasis, overrideDefaultStyling, contentWidth) {
var columnKey = displayGroupIndex;
var displayCount = displayGroup.length;
var containerStyling = displayGroupIndex === 0 ? 'primary-column' : 'secondary-column';
var style = contentWidth && {
width: contentWidth
};
return /*#__PURE__*/_react.default.createElement("li", {
className: cx(containerStyling),
key: columnKey
}, /*#__PURE__*/_react.default.createElement("ul", {
className: cx('column-list'),
key: columnKey
}, displayGroup.map(function (display, contentIndex) {
var contentKey = contentIndex;
var contentClasses = overrideDefaultStyling ? 'content' : classesForContent(contentIndex, displayCount, displayGroupIndex, emphasis);
return (
/*#__PURE__*/
// eslint-disable-next-line react/forbid-dom-props
_react.default.createElement("li", {
style: style,
className: cx(contentClasses),
key: contentKey
}, display)
);
})));
};
var renderColumn = function renderColumn(displays, emphasis, overrideDefaultStyling, contentWidth) {
var displayCount = displays.length;
var style = contentWidth && {
width: contentWidth
};
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("ul", {
className: cx('column-list-container')
}, displays.map(function (display, displayIndex) {
var 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.
*/
var contentClasses = overrideDefaultStyling ? 'content' : classesForContent(displayIndex, displayCount, 0, emphasis);
return (
/*#__PURE__*/
// eslint-disable-next-line react/forbid-dom-props
_react.default.createElement("li", {
style: style,
className: cx(contentClasses),
key: contentKey
}, display)
);
})));
};
var renderByRowView = function renderByRowView(displays, emphasis, overrideDefaultStyling, contentWidth) {
var displayGroups = [];
while (displays.length) {
displayGroups.push(displays.splice(0, 2));
}
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("ul", {
className: cx('row-list-container')
}, displayGroups.map(function (displayRow, rowIndex) {
var row = renderRow(displayRow, rowIndex, displayGroups.length, emphasis, overrideDefaultStyling, contentWidth);
return row;
})));
};
var renderSingleDisplayView = function renderSingleDisplayView(singleDisplay, overrideDefaultStyling, contentWidth) {
/**
* 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.
*/
var contentClass = overrideDefaultStyling ? 'content' : ['content', 'content-primary-size', 'content-primary-color'];
var style = contentWidth && {
width: contentWidth
};
return /*#__PURE__*/_react.default.createElement("div", {
className: cx('single-result-column-container')
}, /*#__PURE__*/_react.default.createElement("div", {
style: style,
className: cx(contentClass)
}, singleDisplay));
};
var twoColumnGrouping = function twoColumnGrouping(displays) {
var count = 0;
var displayGroups = [];
var primaryColumn = [];
var 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;
};
var renderView = function renderView(displays, layout, emphasis, overrideDefaultStyling, trueColumn, contentWidth) {
if (displays === null || displays === undefined || !displays.length) {
return undefined;
}
var displaysSlice = displays.slice(0, 8);
/**
* If there is only one display we don't want to return it as an item in a list.
* The method renderSingleDisplayView here takes in the single display and returns it within simple divs instead.
*/
if (displaysSlice.length === 1) {
return renderSingleDisplayView(displaysSlice, overrideDefaultStyling, contentWidth);
}
if (layout === Layouts.TWO_COLUMNS) {
if (!trueColumn) {
return renderByRowView(displaysSlice, emphasis, overrideDefaultStyling, contentWidth);
}
var displayGroups = twoColumnGrouping(displaysSlice);
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("ul", {
className: cx('column-list-container')
}, displayGroups.map(function (group, index) {
var column = renderTwoColumns(group, index, emphasis, overrideDefaultStyling, contentWidth);
return column;
})));
}
return /*#__PURE__*/_react.default.createElement("div", null, renderColumn(displaysSlice, emphasis, overrideDefaultStyling, contentWidth));
};
var isDisplaysTruncated = function isDisplaysTruncated(displays) {
if (displays) {
var displaysSlice = displays.slice(0, 8);
for (var i = 0; i < displaysSlice.length; i += 1) {
var _displaysSlice$i;
if (((_displaysSlice$i = displaysSlice[i]) === null || _displaysSlice$i === void 0 ? void 0 : _displaysSlice$i.props.isTruncated) === true) {
return true;
}
}
}
return false;
};
var ItemView = function ItemView(_ref) {
var layout = _ref.layout,
trueColumn = _ref.trueColumn,
textEmphasis = _ref.textEmphasis,
overrideDefaultStyling = _ref.overrideDefaultStyling,
isTruncated = _ref.isTruncated,
accessoryAlignment = _ref.accessoryAlignment,
startAccessory = _ref.startAccessory,
reserveStartAccessorySpace = _ref.reserveStartAccessorySpace,
endAccessory = _ref.endAccessory,
displays = _ref.displays,
comment = _ref.comment,
refCallback = _ref.refCallback,
contentWidth = _ref.contentWidth,
customProps = _objectWithoutProperties(_ref, _excluded);
var theme = _react.default.useContext(_terraThemeContext.default);
var isTrueTwoColumnView = layout === Layouts.TWO_COLUMNS && trueColumn;
var isTruncatedDisplay = isTruncated || isDisplaysTruncated(displays);
var viewClassNames = (0, _classnames.default)(cx('item-view', {
'is-truncated': isTruncated
}, {
'one-column': layout === Layouts.ONE_COLUMN
}, {
'two-columns': isTrueTwoColumnView && !isTruncatedDisplay
}, {
'truncated-two-columns': isTrueTwoColumnView && isTruncatedDisplay
}, {
'two-columns-by-row': layout === Layouts.TWO_COLUMNS && !trueColumn
}, theme.className), customProps.className);
return /*#__PURE__*/_react.default.createElement("div", _extends({}, customProps, {
className: viewClassNames,
ref: refCallback
}), renderAccessory(startAccessory, reserveStartAccessorySpace, accessoryAlignment, 'start'), /*#__PURE__*/_react.default.createElement("div", {
className: cx('body')
}, renderView(displays, layout, textEmphasis, overrideDefaultStyling, trueColumn, contentWidth), comment), renderAccessory(endAccessory, false, accessoryAlignment, 'end'));
};
ItemView.propTypes = propTypes;
ItemView.defaultProps = defaultProps;
ItemView.Display = _terraClinicalItemDisplay.default;
ItemView.Comment = _ItemComment.default;
var _default = exports.default = ItemView;