Skip to content

Commit

Permalink
feat(tables): toggle header cells only on the first row or column (#2120
Browse files Browse the repository at this point in the history
)

* feat(tables): toggle header cells only on the first row or column
  • Loading branch information
whawker committed Jul 14, 2023
1 parent ef7d923 commit 2ff2a02
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-students-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@remirror/react': patch
---

Bump the package for the changes included in https://github.com/remirror/remirror/pull/2119
26 changes: 26 additions & 0 deletions .changeset/tiny-dryers-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
'@remirror/extension-tables': minor
---

Expose a `toggleTableHeader` command, which only toggles the first row or column in a table.

```tsx
const { toggleTableHeader } = useCommands();

const handleClick = useCallback(() => {
toggleTableHeader(); // row by default

// Or
toggleTableHeader('column');
}, [toggleTableHeader]);
```

Expose a `tableHasHeader` helper, which returns a boolean stating if the first column or row in a table is a header.

```tsx
const { tableHasHeader } = useHelpers(true);

console.log('first row is header', tableHasHeader());

console.log('first column is header', tableHasHeader('column'));
```
136 changes: 136 additions & 0 deletions packages/remirror__extension-tables/__tests__/table-extensions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,29 @@ describe('commands', () => {
return table(...rows.map((r) => row(...r.map((content) => cell(p(content))))));
};

const buildWithHeader = (type: 'row' | 'column', ...rows: string[][]) => {
// Ensure that all rows have same length
expect([...new Set(rows.map((row) => row.length))]).toHaveLength(1);

return table(
...rows.map((r, i) => {
if (type === 'row' && i === 0) {
return row(...r.map((content) => header(p(content))));
}

return row(
...r.map((content, j) => {
if (type === 'column' && j === 0) {
return header(p(content));
}

return cell(p(content));
}),
);
}),
);
};

return {
editor,
commands,
Expand All @@ -74,6 +97,7 @@ describe('commands', () => {
header,
table,
build,
buildWithHeader,
};
};

Expand Down Expand Up @@ -176,6 +200,118 @@ describe('commands', () => {
expect(view.state.doc).toEqualRemirrorDocument(doc(p('text')));
});
});

describe('toggleTableHeader', () => {
it('can toggle the first row of cells into a header row', () => {
const { build, buildWithHeader, add, view, commands, doc } = setup();

const table = build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3<cursor>', 'C3']);
add(doc(table));

commands.toggleTableHeader();

expect(view.state.doc).toEqualRemirrorDocument(
doc(buildWithHeader('row', ['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'])),
);
});

it('can toggle the first row of header cells into a normal cell row', () => {
const { build, buildWithHeader, add, view, commands, doc } = setup();

const table = buildWithHeader(
'row',
['A1', 'B1', 'C1'],
['A2<cursor>', 'B2', 'C2'],
['A3', 'B3', 'C3'],
);
add(doc(table));

commands.toggleTableHeader();

expect(view.state.doc).toEqualRemirrorDocument(
doc(build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'])),
);
});

it('can toggle the first column of cells into a header column', () => {
const { build, buildWithHeader, add, view, commands, doc } = setup();

const table = build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3<cursor>', 'C3']);
add(doc(table));

commands.toggleTableHeader('column');

expect(view.state.doc).toEqualRemirrorDocument(
doc(buildWithHeader('column', ['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'])),
);
});

it('can toggle the first column of header cells into a normal cell column', () => {
const { build, buildWithHeader, add, view, commands, doc } = setup();

const table = buildWithHeader(
'column',
['A1', 'B1', 'C1'],
['A2<cursor>', 'B2', 'C2'],
['A3', 'B3', 'C3'],
);
add(doc(table));

commands.toggleTableHeader('column');

expect(view.state.doc).toEqualRemirrorDocument(
doc(build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'])),
);
});
});

describe('tableHasHeader (helper)', () => {
it('detects when the table has a header row', () => {
const { buildWithHeader, add, editor, doc } = setup();

const table = buildWithHeader(
'row',
['A1', 'B1', 'C1'],
['A2<cursor>', 'B2', 'C2'],
['A3', 'B3', 'C3'],
);
add(doc(table));

expect(editor.helpers.tableHasHeader()).toBeTrue();
});

it('detects when the table does NOT have a header row', () => {
const { build, add, editor, doc } = setup();

const table = build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3<cursor>', 'C3']);
add(doc(table));

expect(editor.helpers.tableHasHeader()).toBeFalse();
});

it('detects when the table has a header column', () => {
const { buildWithHeader, add, editor, doc } = setup();

const table = buildWithHeader(
'column',
['A1', 'B1', 'C1'],
['A2<cursor>', 'B2', 'C2'],
['A3', 'B3', 'C3'],
);
add(doc(table));

expect(editor.helpers.tableHasHeader('column')).toBeTrue();
});

it('detects when the table does NOT have a header column', () => {
const { build, add, editor, doc } = setup();

const table = build(['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3<cursor>', 'C3']);
add(doc(table));

expect(editor.helpers.tableHasHeader('column')).toBeFalse();
});
});
});

// Test to replicate https://github.com/remirror/remirror/issues/677
Expand Down
34 changes: 34 additions & 0 deletions packages/remirror__extension-tables/src/table-extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
addRowAfter,
addRowBefore,
CellSelection,
columnIsHeader,
columnResizing,
deleteColumn,
deleteRow,
Expand All @@ -37,10 +38,13 @@ import {
fixTablesKey,
isCellSelection,
mergeCells,
rowIsHeader,
setCellAttr,
splitCell,
tableEditing,
TableMap,
TableView,
toggleHeader,
toggleHeaderCell,
toggleHeaderColumn,
toggleHeaderRow,
Expand Down Expand Up @@ -294,6 +298,14 @@ export class TableExtension extends NodeExtension<TableOptions> {
return convertCommand(splitCell);
}

/**
* Toggles between row/column header and normal cells (Only applies to first row/column).
*/
@command()
toggleTableHeader(type: 'column' | 'row' = 'row'): CommandFunction {
return convertCommand(toggleHeader(type));
}

/**
* Toggles a column as the header column.
*/
Expand Down Expand Up @@ -349,6 +361,28 @@ export class TableExtension extends NodeExtension<TableOptions> {
}
}

/**
* Determines if the first row/column is a header row/column
*/
@helper()
tableHasHeader(
type: 'column' | 'row' = 'row',
state: EditorState = this.store.getState(),
): Helper<boolean> {
const { selection } = state;
const table = findParentNodeOfType({ selection, types: 'table' });

if (!table) {
return false;
}

const { node } = table;
const map = TableMap.get(node);

const isHeaderFunc = type === 'column' ? columnIsHeader : rowIsHeader;
return isHeaderFunc(map, node, 0);
}

/**
* Update the background of one cell or multiple cells by passing a color
* string. You can also remove the color by passing a `null`.
Expand Down

1 comment on commit 2ff2a02

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Published on https://remirror.io as production
🚀 Deployed on https://64b12605be2b3500a1a6ebe9--remirror.netlify.app

Please sign in to comment.