Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions src/components/ContentNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ const TableHeaderStyle = {
row: 'row',
};

const TableColumnAlignments = {
left: 'left',
right: 'right',
center: 'center',
unset: 'unset',
};

// The point after which a TabNavigator turns to vertical mode.
const TabNavigatorVerticalThreshold = 5;

Expand All @@ -115,17 +122,22 @@ function renderNode(createElement, references) {
));

const renderTableCell = (
element, attrs, data, cellIndex, rowIndex, extendedData,
element, attrs, data, cellIndex, rowIndex, extendedData, alignments,
) => {
const { colspan, rowspan } = extendedData[`${rowIndex}_${cellIndex}`] || {};
// if either is `0`, then its spanned over and should not be rendered
if (colspan === 0 || rowspan === 0) return null;
return createElement(element, { attrs: { ...attrs, colspan, rowspan } }, (
const align = alignments[cellIndex] || TableColumnAlignments.unset;
let classes = null;
if (align !== TableColumnAlignments.unset) classes = `${align}-cell`;
return createElement(element, { attrs: { ...attrs, colspan, rowspan }, class: classes }, (
renderChildren(data)
));
};

const renderTableChildren = (rows, headerStyle = TableHeaderStyle.none, extendedData = {}) => {
const renderTableChildren = (
rows, headerStyle = TableHeaderStyle.none, extendedData = {}, alignments = [],
) => {
// build the matrix for the array
switch (headerStyle) {
// thead with first row and th for each first row cell
Expand All @@ -135,14 +147,16 @@ function renderNode(createElement, references) {
return [
createElement('thead', {}, [
createElement('tr', {}, firstRow.map((cell, cellIndex) => (
renderTableCell('th', { scope: 'col' }, cell, cellIndex, 0, extendedData)
renderTableCell('th', { scope: 'col' }, cell, cellIndex, 0, extendedData, alignments)
))),
]),
createElement('tbody', {}, otherRows.map(([firstCell, ...otherCells], rowIndex) => (
createElement('tr', {}, [
renderTableCell('th', { scope: 'row' }, firstCell, 0, rowIndex + 1, extendedData),
renderTableCell(
'th', { scope: 'row' }, firstCell, 0, rowIndex + 1, extendedData, alignments,
),
...otherCells.map((cell, cellIndex) => (
renderTableCell('td', {}, cell, cellIndex + 1, rowIndex + 1, extendedData)
renderTableCell('td', {}, cell, cellIndex + 1, rowIndex + 1, extendedData, alignments)
)),
])
))),
Expand All @@ -153,9 +167,11 @@ function renderNode(createElement, references) {
return [
createElement('tbody', {}, rows.map(([firstCell, ...otherCells], rowIndex) => (
createElement('tr', {}, [
renderTableCell('th', { scope: 'row' }, firstCell, 0, rowIndex, extendedData),
renderTableCell(
'th', { scope: 'row' }, firstCell, 0, rowIndex, extendedData, alignments,
),
...otherCells.map((cell, cellIndex) => (
renderTableCell('td', {}, cell, cellIndex + 1, rowIndex, extendedData)
renderTableCell('td', {}, cell, cellIndex + 1, rowIndex, extendedData, alignments)
)),
])
))),
Expand All @@ -167,12 +183,12 @@ function renderNode(createElement, references) {
return [
createElement('thead', {}, [
createElement('tr', {}, firstRow.map((cell, cellIndex) => renderTableCell(
'th', { scope: 'col' }, cell, cellIndex, 0, extendedData,
'th', { scope: 'col' }, cell, cellIndex, 0, extendedData, alignments,
))),
]),
createElement('tbody', {}, otherRows.map((row, rowIndex) => (
createElement('tr', {}, row.map((cell, cellIndex) => (
renderTableCell('td', {}, cell, cellIndex, rowIndex + 1, extendedData)
renderTableCell('td', {}, cell, cellIndex, rowIndex + 1, extendedData, alignments)
)))
))),
];
Expand All @@ -184,7 +200,7 @@ function renderNode(createElement, references) {
rows.map((row, rowIndex) => (
createElement('tr', {}, (
row.map((cell, cellIndex) => (
renderTableCell('td', {}, cell, cellIndex, rowIndex, extendedData)
renderTableCell('td', {}, cell, cellIndex, rowIndex, extendedData, alignments)
))
))
))
Expand Down Expand Up @@ -269,7 +285,7 @@ function renderNode(createElement, references) {
spanned: !!node.extendedData,
},
}, (
renderTableChildren(node.rows, node.header, node.extendedData)
renderTableChildren(node.rows, node.header, node.extendedData, node.alignments)
));
case BlockType.termList:
return createElement('dl', {}, node.items.map(({ term, definition }) => [
Expand Down Expand Up @@ -417,7 +433,7 @@ function renderNode(createElement, references) {

export default {
name: 'ContentNode',
constants: { TableHeaderStyle },
constants: { TableHeaderStyle, TableColumnAlignments },
render: function render(createElement) {
// Dynamically map each content item and any children to their
// corresponding components, and wrap the whole tree in a <div>
Expand Down
12 changes: 12 additions & 0 deletions src/components/ContentNode/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ table {
border-style: solid;
border-width: var(--table-border-width, 1px 1px);
padding: rem(10px);

&.left-cell {
text-align: left;
}

&.right-cell {
text-align: right;
}

&.center-cell {
text-align: center;
}
}
}
</style>
141 changes: 140 additions & 1 deletion tests/unit/components/ContentNode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Column from '@/components/ContentNode/Column.vue';
import TabNavigator from '@/components/ContentNode/TabNavigator.vue';
import TaskList from 'docc-render/components/ContentNode/TaskList.vue';

const { TableHeaderStyle } = ContentNode.constants;
const { TableHeaderStyle, TableColumnAlignments } = ContentNode.constants;

const mountWithContent = (content = [], provide = { references: {} }) => (
shallowMount(ContentNode, {
Expand Down Expand Up @@ -1414,6 +1414,145 @@ describe('ContentNode', () => {
`);
});
});

describe('and column alignments', () => {
const alignedRows = [
[
[{ type: 'text', text: 'row0col0' }],
[{ type: 'text', text: 'row0col1' }],
[{ type: 'text', text: 'row0col2' }],
[{ type: 'text', text: 'row0col3' }],
],
[
[{ type: 'text', text: 'row1col0' }],
[{ type: 'text', text: 'row1col1' }],
[{ type: 'text', text: 'row1col2' }],
[{ type: 'text', text: 'row1col3' }],
],
];
const alignments = [
TableColumnAlignments.left,
TableColumnAlignments.right,
TableColumnAlignments.center,
TableColumnAlignments.unset,
];

it('renders header="none" style tables, with column alignments', () => {
const wrapper = mountWithItem({
type: 'table',
header: TableHeaderStyle.none,
alignments,
rows: alignedRows,
});
const table = wrapper.find('.content').find(Table);
expect(table.html()).toMatchInlineSnapshot(`
<table-stub>
<tbody>
<tr>
<td class="left-cell">row0col0</td>
<td class="right-cell">row0col1</td>
<td class="center-cell">row0col2</td>
<td>row0col3</td>
</tr>
<tr>
<td class="left-cell">row1col0</td>
<td class="right-cell">row1col1</td>
<td class="center-cell">row1col2</td>
<td>row1col3</td>
</tr>
</tbody>
</table-stub>
`);
});

it('renders header="both" style tables, with column alignments', () => {
const wrapper = mountWithItem({
type: 'table',
header: TableHeaderStyle.both,
alignments,
rows: alignedRows,
});
const table = wrapper.find('.content').find(Table);
expect(table.html()).toMatchInlineSnapshot(`
<table-stub>
<thead>
<tr>
<th scope="col" class="left-cell">row0col0</th>
<th scope="col" class="right-cell">row0col1</th>
<th scope="col" class="center-cell">row0col2</th>
<th scope="col">row0col3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" class="left-cell">row1col0</th>
<td class="right-cell">row1col1</td>
<td class="center-cell">row1col2</td>
<td>row1col3</td>
</tr>
</tbody>
</table-stub>
`);
});

it('renders header="row" style tables, with column alignments', () => {
const wrapper = mountWithItem({
type: 'table',
header: TableHeaderStyle.row,
alignments,
rows: alignedRows,
});
const table = wrapper.find('.content').find(Table);
expect(table.html()).toMatchInlineSnapshot(`
<table-stub>
<thead>
<tr>
<th scope="col" class="left-cell">row0col0</th>
<th scope="col" class="right-cell">row0col1</th>
<th scope="col" class="center-cell">row0col2</th>
<th scope="col">row0col3</th>
</tr>
</thead>
<tbody>
<tr>
<td class="left-cell">row1col0</td>
<td class="right-cell">row1col1</td>
<td class="center-cell">row1col2</td>
<td>row1col3</td>
</tr>
</tbody>
</table-stub>
`);
});

it('renders header="column" style tables, with column alignments', () => {
const wrapper = mountWithItem({
type: 'table',
header: TableHeaderStyle.column,
alignments,
rows: alignedRows,
});
const table = wrapper.find('.content').find(Table);
expect(table.html()).toMatchInlineSnapshot(`
<table-stub>
<tbody>
<tr>
<th scope="row" class="left-cell">row0col0</th>
<td class="right-cell">row0col1</td>
<td class="center-cell">row0col2</td>
<td>row0col3</td>
</tr>
<tr>
<th scope="row" class="left-cell">row1col0</th>
<td class="right-cell">row1col1</td>
<td class="center-cell">row1col2</td>
<td>row1col3</td>
</tr>
</tbody>
</table-stub>
`);
});
});
});

describe('with type="termList"', () => {
Expand Down