Skip to content

Commit

Permalink
fix(table): column resize fails when adding columns
Browse files Browse the repository at this point in the history
  • Loading branch information
bjornalm committed Aug 5, 2020
1 parent 8416701 commit 1996a0a
Show file tree
Hide file tree
Showing 6 changed files with 16,591 additions and 67 deletions.
137 changes: 125 additions & 12 deletions src/components/Table/Table.story.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ import Add from '@carbon/icons-react/lib/add/16';
import Edit from '@carbon/icons-react/lib/edit/16';
import { spacing03 } from '@carbon/layout';
import { Add20, TrashCan16, SettingsAdjust16 as SettingsAdjust } from '@carbon/icons-react';
import { Tooltip, TextInput, Checkbox, ToastNotification, Button } from 'carbon-components-react';
import {
Tooltip,
TextInput,
Checkbox,
ToastNotification,
Button,
FormGroup,
Form,
} from 'carbon-components-react';
import cloneDeep from 'lodash/cloneDeep';

import { getSortedData, csvDownloadHandler } from '../../utils/componentUtilityFunctions';
Expand Down Expand Up @@ -1664,21 +1672,126 @@ storiesOf('Watson IoT/Table', module)
}
)
.add(
'with resize, onColumnResize callback and no initial column width',
'with resize, onColumnResize callback, no initial column width and column management',
() => {
const ColumnsModifier = ({ onAdd, onRemove, columns, ordering }) => {
const [colsToAddField, setColsToAddField] = useState('colX, colY');
const [colsToAddWidthField, setColsToAddWidthField] = useState('100px, 150px');
const [colsToDeleteField, setColsToDeleteField] = useState('select, status');
const [isHidden, setIsHidden] = useState(false);

return (
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '2rem' }}>
<Form style={{ maxWidth: '300px', marginRight: '2rem' }}>
<TextInput
labelText="Ids of one or more columns"
id="colsToAddInput"
value={colsToAddField}
type="text"
onChange={evt => setColsToAddField(evt.currentTarget.value)}
/>
<FormGroup legendText="" style={{ marginBottom: '1rem' }}>
<Checkbox
labelText="add as hidden column(s)"
id="isHiddenCheckbox"
value={isHidden}
onChange={() => setIsHidden(!isHidden)}
/>
</FormGroup>
<TextInput
labelText="The width of the added columns (if any)"
id="colsToAddWidthInput"
value={colsToAddWidthField}
type="text"
onChange={evt => setColsToAddWidthField(evt.currentTarget.value)}
/>
<Button
style={{ marginTop: '1rem' }}
onClick={() => onAdd(colsToAddField, colsToAddWidthField, isHidden)}
>
Add
</Button>
</Form>
<div style={{ maxWidth: '50%' }}>
<div style={{ margin: '1rem' }}>
<p>COLUMNS prop</p>
<samp>{JSON.stringify(columns)}</samp>
</div>
<div style={{ margin: '1rem' }}>
<p>ORDERING prop</p>
<samp>{JSON.stringify(ordering)}</samp>
</div>
</div>

<Form style={{ maxWidth: '300px' }}>
<TextInput
labelText="One or more IDs of columns to delete"
id="removeColInput"
value={colsToDeleteField}
type="text"
onChange={evt => setColsToDeleteField(evt.currentTarget.value)}
/>
<Button
style={{ marginTop: '1rem' }}
id="removeColInput"
onClick={() => onRemove(colsToDeleteField)}
>
Remove
</Button>
</Form>
</div>
);
};

return React.createElement(() => {
const [myColumns, setMyColumns] = useState(tableColumns);
const [myColumns, setMyColumns] = useState(tableColumns.map(({ filter, ...rest }) => rest));
const [myOrdering, setMyOrdering] = useState(defaultOrdering);

const onAdd = (colIds, colWidths, isHidden) => {
const colsToAdd = colIds.split(', ');
const widths = colWidths.split(', ');
const newColumns = [];
const newOrdering = [];
colsToAdd.forEach((colToAddId, index) => {
newColumns.push({ id: colToAddId, name: colToAddId, width: widths[index] });
newOrdering.push({ columnId: colToAddId, isHidden });
});
setMyColumns([...myColumns, ...newColumns]);
setMyOrdering([...myOrdering, ...newOrdering]);
};

const onRemove = colIds => {
const colsToDelete = colIds.split(', ');
setMyColumns(myColumns.filter(col => !colsToDelete.includes(col.id)));
setMyOrdering(myOrdering.filter(col => !colsToDelete.includes(col.columnId)));
};
const onColumnResize = cols => setMyColumns(cols);

return (
<Table
options={{
hasResize: true,
wrapCellText: select('wrapCellText', selectTextWrapping, 'always'),
}}
columns={myColumns}
data={tableData}
actions={{ ...actions, table: { ...actions.table, onColumnResize } }}
/>
<>
<ColumnsModifier
onAdd={onAdd}
onRemove={onRemove}
columns={myColumns}
ordering={myOrdering}
/>
<Table
options={{
hasColumnSelection: true,
hasResize: true,
wrapCellText: select('wrapCellText', selectTextWrapping, 'always'),
}}
columns={myColumns}
view={{
filters: [],
table: {
ordering: myOrdering,
},
}}
data={tableData}
actions={{ ...actions, table: { ...actions.table, onColumnResize } }}
/>
</>
);
});
},
Expand Down
23 changes: 17 additions & 6 deletions src/components/Table/TableHead/TableHead.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ import TableHeader from './TableHeader';
import ColumnResize from './ColumnResize';
import {
createNewWidthsMap,
calculateWidthOnHide,
calculateWidthsOnToggle,
adjustLastColumnWidth,
calculateWidthOnShow,
visibleColumnsHaveWidth,
getIDsOfAddedColumns,
getIDsOfRemovedColumns,
} from './columnWidthUtilityFunctions';

const { iotPrefix } = settings;
Expand Down Expand Up @@ -221,10 +226,9 @@ const TableHead = ({
() => {
// An initial measuring is needed since there might not be an initial value from the columns prop
// which means that the layout engine will have to set the widths dynamically
// before we know what they are. More importantly, the sum of the inital widths may not match
// the available width of the table, e.g. if the user has resized the browser since the
// column widths was last saved.
// before we know what they are.
if (hasResize && columns.length && isEmpty(currentColumnWidths)) {
console.info('setting currentColumnWidths');
const measuredWidths = measureColumnWidths();
const adjustedWidths = adjustLastColumnWidth(ordering, columns, measuredWidths);
const newWidthsMap = createNewWidthsMap(ordering, currentColumnWidths, adjustedWidths);
Expand All @@ -236,10 +240,17 @@ const TableHead = ({

useDeepCompareEffect(
() => {
// We need to update the currentColumnWidths (state) only if the widths
// of the column prop is updated after the initial render.
// We need to update the currentColumnWidths (state) after the initial render
// only if the widths of the column prop is updated or columns are added/removed .
if (hasResize && columns.length && !isEmpty(currentColumnWidths)) {
if (columns.every(col => col.hasOwnProperty('width'))) {
const addedColumnIDs = getIDsOfAddedColumns(ordering, currentColumnWidths);
const removedColumnIDs = getIDsOfRemovedColumns(ordering, currentColumnWidths);

if (addedColumnIDs.length > 0 || removedColumnIDs.length > 0) {
const afterRemove = calculateWidthOnHide(currentColumnWidths, ordering, removedColumnIDs);
const afterAdd = calculateWidthOnShow(afterRemove, ordering, addedColumnIDs, columns);
setCurrentColumnWidths(afterAdd);
} else if (visibleColumnsHaveWidth(ordering, columns)) {
const propsColumnWidths = createNewWidthsMap(ordering, columns);
if (!isEqual(currentColumnWidths, propsColumnWidths)) {
setCurrentColumnWidths(propsColumnWidths);
Expand Down
Loading

0 comments on commit 1996a0a

Please sign in to comment.