Skip to content

Commit

Permalink
feat: support vertical alignment (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
nam-hle authored May 7, 2021
1 parent a0103e4 commit d652f5c
Show file tree
Hide file tree
Showing 15 changed files with 249 additions and 46 deletions.
11 changes: 6 additions & 5 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,22 @@

{"gitdown": "include", "file": "./api/table/index.md"}
{"gitdown": "include", "file": "./api/table/border.md"}
{"gitdown": "include", "file": "./api/table/draw_vertical_line.md"}
{"gitdown": "include", "file": "./api/table/draw_horizontal_line.md"}
{"gitdown": "include", "file": "./api/table/single_line.md"}
{"gitdown": "include", "file": "./api/table/drawVerticalLine.md"}
{"gitdown": "include", "file": "./api/table/drawHorizontalLine.md"}
{"gitdown": "include", "file": "./api/table/singleLine.md"}

{"gitdown": "include", "file": "./api/table/columns/index.md"}
{"gitdown": "include", "file": "./api/table/columns/width.md"}
{"gitdown": "include", "file": "./api/table/columns/alignment.md"}
{"gitdown": "include", "file": "./api/table/columns/verticalAlignment.md"}
{"gitdown": "include", "file": "./api/table/columns/padding.md"}
{"gitdown": "include", "file": "./api/table/columns/truncate.md"}
{"gitdown": "include", "file": "./api/table/columns/wrapWord.md"}

{"gitdown": "include", "file": "./api/table/column_default.md"}
{"gitdown": "include", "file": "./api/table/columnDefault.md"}

{"gitdown": "include", "file": "./api/table/header.md"}

{"gitdown": "include", "file": "./api/stream/index.md"}

{"gitdown": "include", "file": "./api/get_border_characters.md"}
{"gitdown": "include", "file": "./api/getBorderCharacters.md"}
33 changes: 33 additions & 0 deletions .README/api/table/columns/verticalAlignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
###### config.columns[*].verticalAlignment

Type: `'top' | 'middle' | 'bottom'`\
Default: `'top'`

Cell content vertical alignment

```js
const data = [
['A', 'B', 'C', 'DEF'],
];

const config = {
columnDefault: {
width: 1,
},
columns: [
{ verticalAlignment: 'top' },
{ verticalAlignment: 'middle' },
{ verticalAlignment: 'bottom' },
],
};

console.log(table(data, config));
```

```
╔═══╤═══╤═══╤═══╗
║ A │ │ │ D ║
║ │ B │ │ E ║
║ │ │ C │ F ║
╚═══╧═══╧═══╧═══╝
```
3 changes: 2 additions & 1 deletion .README/api/table/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ The header configuration inherits the most of the column's, except:
- `content` **{string}**: the header content.
- `width:` calculate based on the content width automatically.
- `alignment:` `center` be default.
- `config.border.topJoin` will be `config.border.topBody` for more prettier.
- `verticalAlignment:` is not supported.
- `config.border.topJoin` will be `config.border.topBody` for prettier.

```js
const data = [
Expand Down
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,41 @@ console.log(table(data, config));
╚════════════╧════════════╧════════════╧════════════╝
```

<a name="table-api-table-1-config-columns-config-columns-verticalalignment"></a>
###### config.columns[*].verticalAlignment

Type: `'top' | 'middle' | 'bottom'`\
Default: `'top'`

Cell content vertical alignment

```js
const data = [
['A', 'B', 'C', 'DEF'],
];

const config = {
columnDefault: {
width: 1,
},
columns: [
{ verticalAlignment: 'top' },
{ verticalAlignment: 'middle' },
{ verticalAlignment: 'bottom' },
],
};

console.log(table(data, config));
```

```
╔═══╤═══╤═══╤═══╗
║ A │ │ │ D ║
║ │ B │ │ E ║
║ │ │ C │ F ║
╚═══╧═══╧═══╧═══╝
```

<a name="table-api-table-1-config-columns-config-columns-paddingleft"></a>
###### config.columns[*].paddingLeft

Expand Down Expand Up @@ -496,6 +531,7 @@ When `wrapWord` is `true`:
```


<a name="table-api-table-1-config-columndefault"></a>
##### config.columnDefault

Expand All @@ -516,7 +552,8 @@ The header configuration inherits the most of the column's, except:
- `content` **{string}**: the header content.
- `width:` calculate based on the content width automatically.
- `alignment:` `center` be default.
- `config.border.topJoin` will be `config.border.topBody` for more prettier.
- `verticalAlignment:` is not supported.
- `config.border.topJoin` will be `config.border.topBody` for prettier.

```js
const data = [
Expand Down
12 changes: 1 addition & 11 deletions src/alignString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,7 @@ const alignRight = (subject: string, width: number): string => {
};

const alignCenter = (subject: string, width: number): string => {
let halfWidth;

halfWidth = width / 2;

if (width % 2 === 0) {
return ' '.repeat(halfWidth) + subject + ' '.repeat(halfWidth);
} else {
halfWidth = Math.floor(halfWidth);

return ' '.repeat(halfWidth) + subject + ' '.repeat(halfWidth + 1);
}
return ' '.repeat(Math.floor(width / 2)) + subject + ' '.repeat(Math.ceil(width / 2));
};

const alignJustify = (subject: string, width: number): string => {
Expand Down
1 change: 1 addition & 0 deletions src/makeStreamConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const makeColumnsConfig = (columnCount: number,
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
verticalAlignment: 'top',
wrapWord: false,
...columnDefault,
...columns[index],
Expand Down
1 change: 1 addition & 0 deletions src/makeTableConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const makeColumnsConfig = (rows: Row[],
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
verticalAlignment: 'top',
width: columnWidths[columnIndex],
wrapWord: false,
...columnDefault,
Expand Down
31 changes: 29 additions & 2 deletions src/mapDataUsingRowHeights.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import type {
BaseConfig,
BaseConfig, ColumnConfig,
Row,
} from './types/internal';
import {
wrapCell,
} from './wrapCell';

const createEmptyStrings = (length: number) => {
return new Array(length).fill('');
};

const padCellVertically = (lines: string[], rowHeight: number, columnConfig: ColumnConfig): string[] => {
const {verticalAlignment} = columnConfig;

const availableLines = rowHeight - lines.length;

if (verticalAlignment === 'top') {
return [...lines, ...createEmptyStrings(availableLines)];
}

if (verticalAlignment === 'bottom') {
return [...createEmptyStrings(availableLines), ...lines];
}

return [
...createEmptyStrings(Math.floor(availableLines / 2)),
...lines,
...createEmptyStrings(Math.ceil(availableLines / 2)),
];
};

const flatten = <T>(array: T[][]): T[] => {
return ([] as T[]).concat(...array);
};
Expand All @@ -22,7 +46,9 @@ export const mapDataUsingRowHeights = (unmappedRows: Row[], rowHeights: number[]
unmappedRow.forEach((cell, cellIndex) => {
const cellLines = wrapCell(cell, config.columns[cellIndex].width, config.columns[cellIndex].wrapWord);

cellLines.forEach((cellLine, cellLineIndex) => {
const paddedCellLines = padCellVertically(cellLines, outputRowHeight, config.columns[cellIndex]);

paddedCellLines.forEach((cellLine, cellLineIndex) => {
outputRow[cellLineIndex][cellIndex] = cellLine;
});
});
Expand All @@ -32,3 +58,4 @@ export const mapDataUsingRowHeights = (unmappedRows: Row[], rowHeights: number[]

return flatten(mappedRows);
};

8 changes: 8 additions & 0 deletions src/schemas/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
"alignment": {
"$ref": "#/definitions/alignment"
},
"verticalAlignment": {
"type": "string",
"enum": [
"top",
"middle",
"bottom"
]
},
"width": {
"type": "integer",
"minimum": 1
Expand Down
9 changes: 8 additions & 1 deletion src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ export type BorderConfig = Required<BorderUserConfig>;

export type Alignment = 'center' | 'justify' | 'left' | 'right';

export type VerticalAlignment = 'bottom' | 'middle' | 'top';

export type ColumnUserConfig = {

/**
* Cell content horizontal alignment (default: left)
*/
readonly alignment?: Alignment,

/**
* Cell content vertical alignment (default: top)
*/
readonly verticalAlignment?: VerticalAlignment,

/**
* Column width (default: auto calculation based on the cell content)
*/
Expand All @@ -62,7 +69,7 @@ export type ColumnUserConfig = {
readonly wrapWord?: boolean,
};

export type HeaderUserConfig = Omit<ColumnUserConfig, 'width'> & {
export type HeaderUserConfig = Omit<ColumnUserConfig, 'verticalAlignment' | 'width'> & {
readonly content: string,
};

Expand Down
35 changes: 35 additions & 0 deletions test/README/api/table/column/verticalAlignment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type {
TableUserConfig,
} from '../../../../../src';
import {
table,
} from '../../../../../src';
import {
expectTable,
} from '../../../../utils';

describe('README.md api/table/columns', () => {
it('/verticalAlignment', () => {
const data = [
['A', 'B', 'C', 'DEF'],
];

const config: TableUserConfig = {
columnDefault: {
width: 1,
},
columns: [
{verticalAlignment: 'top'},
{verticalAlignment: 'middle'},
{verticalAlignment: 'bottom'},
],
};

expectTable(table(data, config), `
╔═══╤═══╤═══╤═══╗
║ A │ │ │ D ║
║ │ B │ │ E ║
║ │ │ C │ F ║
╚═══╧═══╧═══╧═══╝`);
});
});
29 changes: 7 additions & 22 deletions test/makeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,38 +56,23 @@ describe('makeConfig', () => {
});
});

context('"paddingLeft"', () => {
context('"padding"', () => {
context('is not provided', () => {
it('defaults to 1', () => {
const config = makeTableConfig(rows);

expect(config.columns[0].paddingLeft).to.equal(1);
});
});

context('is provided', () => {
it('uses the custom value', () => {
const config = makeTableConfig(rows, {columns: {0: {paddingLeft: 3}}});

expect(config.columns[0].paddingLeft).to.equal(3);
});
});
});

context('"paddingRight"', () => {
context('is not provided', () => {
it('defaults to 1', () => {
const config = makeTableConfig(rows);

expect(config.columns[0].paddingRight).to.equal(1);
});
});

context('is provided', () => {
it('uses the custom value', () => {
const config = makeTableConfig(rows, {columns: {0: {paddingRight: 3}}});
const config = makeTableConfig(rows, {columns: {0: {paddingLeft: 3,
paddingRight: 2}}});

expect(config.columns[0].paddingRight).to.equal(3);
expect(config.columns[0].paddingLeft).to.equal(3);
expect(config.columns[0].paddingRight).to.equal(2);
});
});
});
Expand Down Expand Up @@ -180,7 +165,7 @@ describe('makeConfig', () => {
context('when given extra configs', () => {
it('overrides the default', () => {
const config = makeTableConfig(rows, {header: {
alignment: 'left',
alignment: 'center',
content: 'bb',
paddingLeft: 2,
paddingRight: 3,
Expand All @@ -189,7 +174,7 @@ describe('makeConfig', () => {
}});

expect(config.header).to.deep.equal({
alignment: 'left',
alignment: 'center',
content: 'bb',
paddingLeft: 2,
paddingRight: 3,
Expand Down
Loading

0 comments on commit d652f5c

Please sign in to comment.