diff --git a/src/components/ContentNode.vue b/src/components/ContentNode.vue index 05c41b40f..c8a6d9ed3 100644 --- a/src/components/ContentNode.vue +++ b/src/components/ContentNode.vue @@ -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; @@ -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 @@ -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) )), ]) ))), @@ -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) )), ]) ))), @@ -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) ))) ))), ]; @@ -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) )) )) )) @@ -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 }) => [ @@ -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
diff --git a/src/components/ContentNode/Table.vue b/src/components/ContentNode/Table.vue index b3d653013..b86645934 100644 --- a/src/components/ContentNode/Table.vue +++ b/src/components/ContentNode/Table.vue @@ -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; + } } } diff --git a/tests/unit/components/ContentNode.spec.js b/tests/unit/components/ContentNode.spec.js index a48875cda..4ef53e40b 100644 --- a/tests/unit/components/ContentNode.spec.js +++ b/tests/unit/components/ContentNode.spec.js @@ -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, { @@ -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(` + + + + row0col0 + row0col1 + row0col2 + row0col3 + + + row1col0 + row1col1 + row1col2 + row1col3 + + + + `); + }); + + 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(` + + + + row0col0 + row0col1 + row0col2 + row0col3 + + + + + row1col0 + row1col1 + row1col2 + row1col3 + + + + `); + }); + + 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(` + + + + row0col0 + row0col1 + row0col2 + row0col3 + + + + + row1col0 + row1col1 + row1col2 + row1col3 + + + + `); + }); + + 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(` + + + + row0col0 + row0col1 + row0col2 + row0col3 + + + row1col0 + row1col1 + row1col2 + row1col3 + + + + `); + }); + }); }); describe('with type="termList"', () => {