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

Commit

Permalink
Merge remote-tracking branch 'origin' into table-single-row-select
Browse files Browse the repository at this point in the history
  • Loading branch information
cm9361 committed Nov 21, 2023
2 parents 2b04ef1 + 5847800 commit 96036c0
Show file tree
Hide file tree
Showing 110 changed files with 2,513 additions and 106 deletions.
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"terra-application": "^1.48.0",
"terra-disclosure-manager": "^4.9.0",
"terra-enzyme-intl": "^3.4.0",
"terra-icon": "^3.58.0",
"webpack": "^5.28.0",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^4.11.1",
Expand Down
3 changes: 2 additions & 1 deletion packages/terra-compact-interactive-list/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "terra-compact-interactive-list",
"main": "lib/CompactInteractiveList.js",
"main": "lib/index.js",
"version": "0.1.0",
"description": "The Terra Compact Interactive List component provides users a way to render a collection of interactive data in a list format into a single tab stop.",
"repository": {
Expand Down Expand Up @@ -32,6 +32,7 @@
"classnames": "^2.2.5",
"keycode-js": "^3.1.0",
"prop-types": "^15.5.8",
"terra-icon": "^3.58.0",
"terra-theme-context": "^1.0.0"
},
"scripts": {
Expand Down
176 changes: 169 additions & 7 deletions packages/terra-compact-interactive-list/src/CompactInteractiveList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ import { injectIntl } from 'react-intl';
import classNames from 'classnames/bind';
import ThemeContext from 'terra-theme-context';
import styles from './CompactInteractiveList.module.scss';
import rowShape from './proptypes/rowShape';
import Row from './subcomponents/Row';
import columnShape from './proptypes/columnShape';
import { widthUnitTypes, DefaultListValues, WARNINGS } from './utils/constants';
import {
getRowMaximumWidth,
getRowMinimumWidth,
checkIfRowHasResponsiveColumns,
getValueUnitTypePair,
converseColumnTypes,
} from './utils/utils';

const cx = classNames.bind(styles);

Expand All @@ -23,23 +34,153 @@ const propTypes = {
* String that labels the table for accessibility. If ariaLabelledBy is specified, ariaLabel will not be used.
*/
ariaLabel: PropTypes.string,

/**
* Data for columns.
*/
columns: PropTypes.arrayOf(columnShape),

/**
* Data for rows (list items) content.
*/
rows: PropTypes.arrayOf(rowShape),

/**
* Row height should be a valid css string with height in px, em, or rem units.
*/
rowHeight: PropTypes.string,

/**
* A number of visual columns. Defaults to 1.
*/
numberOfColumns: PropTypes.number,

/**
* By default the items go from top to bottom, then break to the next column.
* If flowHorizontally prop is set to true, items will flow left to right, then break to the next row.
*/
flowHorizontally: PropTypes.bool,

/**
* A string for container's width. Any valid css string. Defaults to '100%'.
* In case when all the columns has their widths explicitly set to a number, the width of the list will be determined by the width of it's columns unless the flexGrow prop would allow them grow.
*/
width: PropTypes.string,

/**
* Columns minimum width should be a valid css string in value in px, em, or rem units..
*/
columnMinimumWidth: PropTypes.string,

/**
* Columns maximum width should be a valid css string in value in px, em, or rem units..
*/
columnMaximumWidth: PropTypes.string,
};

// const defaultColumnMinimumWidth = 60;
// const defaultColumnMaximumWidth = 300;
const defaultProps = {
rows: [],
numberOfColumns: 1,
width: '100%',
};

const CompactInteractiveList = (props) => {
const {
id,
ariaLabelledBy,
ariaLabel,
columns,
rows,
rowHeight,
numberOfColumns,
flowHorizontally,
width,
columnMinimumWidth,
columnMaximumWidth,
} = props;

const theme = useContext(ThemeContext);

const defaultUnitType = widthUnitTypes.PX;
// map the columns to ensure that width, maximumWidth and minimumWidth use same units (px, em, or rem) across all columns.
// if a width prop uses different units, it will be disregarded.
const [conversionedColumns, widthUnit] = converseColumnTypes(columns, defaultUnitType);
// ensure columnMinimumWidth is in the same width units
let columnMinWidth = getValueUnitTypePair(columnMinimumWidth);
if (!columnMinWidth) {
columnMinWidth = getValueUnitTypePair(DefaultListValues.minimumWidth[widthUnit]);
} else if (columnMinWidth.unitType !== widthUnit) {
// eslint-disable-next-line no-console
console.warn(WARNINGS.COLUMN_MIN_WIDTH_UNIT_TYPE);
columnMinWidth = getValueUnitTypePair(DefaultListValues.minimumWidth[widthUnit]);
}
// ensure columnMinimumWidth has proper width units
let columnMaxWidth = getValueUnitTypePair(columnMaximumWidth);
if (columnMaxWidth && columnMaxWidth.unitType !== widthUnit) {
// eslint-disable-next-line no-console
console.warn(WARNINGS.COLUMN_MAX_WIDTH_UNIT_TYPE);
columnMaxWidth = null;
}

// check if list has responsive columns
const isResponsive = checkIfRowHasResponsiveColumns(conversionedColumns);
// if there are responsive columns, we need maxWidth and minWidth for semantic rows specifically.

const rowMaxWidth = isResponsive ? getRowMaximumWidth(conversionedColumns, columnMaxWidth?.value) : null;
const rowMinWidth = isResponsive ? getRowMinimumWidth(conversionedColumns, columnMinWidth?.value) : null;

// calculate row width based on the width of its columns
const getRowWidthSum = (total, column) => total + column.width;
const rowWidth = isResponsive ? null : conversionedColumns.reduce(getRowWidthSum, 0);
const rowsPerColumn = Math.ceil(rows.length / numberOfColumns);

const calculatedRowHeight = flowHorizontally ? null : getValueUnitTypePair(rowHeight || DefaultListValues.rowDefaultHeight[widthUnit]);
// calculate list width based on the semantic row width and number of columns
const listWidth = `${rowWidth * numberOfColumns}${widthUnit}`;
// calculate list min width or use default
const defaultListMinWidth = getValueUnitTypePair(DefaultListValues.listMinimumWidth[widthUnit])?.value;
const listMinWidth = isResponsive ? Math.max(rowMinWidth * numberOfColumns, defaultListMinWidth) : null;
// defining styles to apply to the list
const style = {
width: isResponsive ? width : listWidth,
height: flowHorizontally ? null : `${calculatedRowHeight?.value * rowsPerColumn}${calculatedRowHeight?.unitType}`,
minWidth: isResponsive ? `${listMinWidth}${widthUnit}` : null,
flexDirection: flowHorizontally ? 'row' : 'column',
};
if (rowMaxWidth) {
style.maxWidth = `${rowMaxWidth * numberOfColumns}${widthUnit}`;
}

// number of rows including placeholder rows
const numberOfRows = Math.ceil(rows.length / numberOfColumns);
// map rows differently depending on vertical or horizontal orientation
const mapRows = () => {
const placeholdersNumber = isResponsive ? (numberOfRows * numberOfColumns) - rows.length : 0;
let result = [];
result = [...rows];
if (flowHorizontally) {
// all placeholder rows go in the end.
for (let i = rows.length; i < rows.length + placeholdersNumber; i += 1) {
result.push({ id: `placeholder-row-${i - rows.length + 1}` });
}
} else {
// inject placeholders to specific positions so that they all appear in the last row.
let position = rows.length;
for (let i = placeholdersNumber; i > 0; i -= 1) {
result.splice(position, 0, { id: `placeholder-row-${i}` });
position -= rowsPerColumn - 1;
}
}
return result;
};

const mappedRows = mapRows();
const checkIfRowIsLeftMost = (index) => (flowHorizontally ? index % numberOfColumns === 0 : index < rowsPerColumn);
const checkIfRowIsTopMost = (index) => (flowHorizontally ? index < numberOfColumns : index % rowsPerColumn === 0);

return (
<div
className={cx('compact-interactive-list-container')}
className={cx('compact-interactive-list-container', theme.className)}
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
tabIndex={0}
>
Expand All @@ -48,16 +189,37 @@ const CompactInteractiveList = (props) => {
role="grid"
aria-labelledby={ariaLabelledBy}
aria-label={ariaLabel}
className={cx('compact-interactive-list', theme.className)}
className={cx('compact-interactive-list')}
// eslint-disable-next-line react/forbid-dom-props
style={style}
>
<div role="row">
<div role="gridcell">This is the placeholder div</div>
</div>
{mappedRows.map((row, index) => (
<Row
key={row.id}
id={row.id}
cells={row.cells}
ariaLabel={row.ariaLabel}
columns={conversionedColumns}
columnMaximumWidth={columnMaxWidth?.value}
columnMinimumWidth={columnMinWidth?.value}
numberOfColumns={numberOfColumns}
rowWidth={rowWidth}
isResponsive={isResponsive}
rowMaximumWidth={rowMaxWidth}
rowMinimumWidth={rowMinWidth}
widthUnit={widthUnit}
flowHorizontally={flowHorizontally}
rowHeight={calculatedRowHeight}
isTopmost={checkIfRowIsTopMost(index)}
isLeftmost={checkIfRowIsLeftMost(index)}
/>
))}
</div>
</div>
);
};

CompactInteractiveList.propTypes = propTypes;
CompactInteractiveList.defaultProps = defaultProps;

export default injectIntl(CompactInteractiveList);
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// Themes
@import './clinical-lowlight-theme/CompactInteractiveList.module';
@import './orion-fusion-theme/CompactInteractiveList.module';

:local {
.compact-interactive-list-container {
height: 100%;
height: auto;
overflow: auto;
width: 100%;

> * {
box-sizing: border-box;
}
}

.compact-interactive-list {
display: flex;
flex-wrap: wrap;

:focus {
outline: var(--terra-compact-interactive-list-cell-focus-outline, 3px dashed #000);
outline-offset: var(--terra-compact-interactive-list-cell-focus-outline-offset, -2px);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:local {
.clinical-lowlight-theme {
--terra-compact-interactive-list-hover-background-color: #25282a;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
.clinical-lowlight-theme {
--terra-compact-interactive-list-cell-focus-outline: 3px dashed #fff;
--terra-compact-interactive-list-cell-focus-outline-offset: -2px;
--terra-compact-interactive-list-headerless-first-row-border-top: 1px solid #181b1d;

--terra-compact-interactive-list-row-border: 1px solid #181b1d;
--terra-compact-interactive-list-row-background-color: #6e6f71;
}
}
5 changes: 5 additions & 0 deletions packages/terra-compact-interactive-list/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import CompactInteractiveList from './CompactInteractiveList';
import { widthUnitTypes, alignTypes } from './utils/constants';

export default CompactInteractiveList;
export { widthUnitTypes, alignTypes };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:local {
.orion-fusion-theme {
--terra-compact-interactive-list-hover-background-color: #e0f2fb;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
.orion-fusion-theme {
--terra-compact-interactive-list-cell-focus-outline: 3px dashed #000;
--terra-compact-interactive-list-cell-focus-outline-offset: -2px;
--terra-compact-interactive-list-headerless-first-row-border-top: 1px solid #c8cacb;

--terra-compact-interactive-list-row-background-color: #fefffe;
--terra-compact-interactive-list-row-border-top: 1px solid #c8cacb;
--terra-compact-interactive-list-row-border-bottom: 1px solid #c8cacb;
--terra-compact-interactive-list-row-border-left: 1px solid #c8cacb;
--terra-compact-interactive-list-row-border-right: 1px solid #c8cacb;
}
}
10 changes: 0 additions & 10 deletions packages/terra-compact-interactive-list/src/proptypes/cellShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,6 @@ const cellShape = PropTypes.shape({
* Content that will be rendered within the Cell.
*/
content: PropTypes.node,
/**
* @private
* Boolean value indicating whether or not the column header is selectable.
*/
isSelectable: PropTypes.bool,
/**
* @private
* Boolean value indicating whether or not the cell should render as selected.
*/
isSelected: PropTypes.bool,
});

export default cellShape;
Loading

0 comments on commit 96036c0

Please sign in to comment.