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
26 changes: 26 additions & 0 deletions packages/core/src/blocks/Table/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
TableContent,
} from "../../schema/index.js";
import { mergeCSSClasses } from "../../util/browser.js";
import { camelToDataKebab } from "../../util/string.js";
import { createDefaultBlockDOMOutputSpec } from "../defaultBlockHelpers.js";
import { defaultProps } from "../defaultProps.js";
import { EMPTY_CELL_WIDTH, TableExtension } from "./TableExtension.js";
Expand Down Expand Up @@ -252,6 +253,31 @@ const TiptapTableNode = Node.create({
super.ignoreMutation(record)
);
}

// `TableView` implements its own `update` method, as the view needs to
// be persisted across updates for column resizing to work properly.
// However, it doesn't do anything else, so we have to re-apply the
// HTML attributes from props manually. This isn't an issue for node
// views created e.g. by custom blocks, as those aren't persisted
// across updates (they are reinstantiated each time), and so
// `HTMLAttributes` is always up-to-date for those.
update(updatedNode: PMNode): boolean {
if (!super.update(updatedNode)) {
return false;
}

for (const [propName, propSpec] of Object.entries(tablePropSchema)) {
const attrName = camelToDataKebab(propName);
const value = updatedNode.attrs[propName];
if (value !== propSpec.default) {
this.dom.setAttribute(attrName, String(value));
} else {
this.dom.removeAttribute(attrName);
}
}

return true;
}
}

return new BlockNoteTableView(node, EMPTY_CELL_WIDTH, {
Expand Down
24 changes: 24 additions & 0 deletions tests/src/end-to-end/colors/colors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import {
DRAG_HANDLE_MENU_SELECTOR,
DRAG_HANDLE_SELECTOR,
H_TWO_BLOCK_SELECTOR,
TABLE_SELECTOR,
TEXT_COLOR_SELECTOR,
} from "../../utils/const.js";
import { insertHeading, insertParagraph } from "../../utils/copypaste.js";
import { focusOnEditor } from "../../utils/editor.js";
import { executeSlashCommand } from "../../utils/slashmenu.js";

test.beforeEach(async ({ page }) => {
await page.goto(BASE_URL, { waitUntil: "networkidle" });
Expand Down Expand Up @@ -109,4 +111,26 @@ test.describe("Check Background & Text Color Functionality", () => {

expect(await page.screenshot()).toMatchSnapshot("blockBackgroundColor.png");
});
// Regression test: prosemirror-tables' TableView.update() preserves the
// NodeView's DOM without re-applying node attrs, so prop changes (e.g.
// textColor) wouldn't propagate to the blockContent wrapper. BlockNoteTableView
// overrides update() to sync prop-derived data-* attributes.
test("Should be able to set block text color on a table", async ({
page,
}) => {
await focusOnEditor(page);
await executeSlashCommand(page, "table");
await page.keyboard.type("Table Cell");

await page.hover(TABLE_SELECTOR);
await page.click(DRAG_HANDLE_SELECTOR);
await page.waitForSelector(DRAG_HANDLE_MENU_SELECTOR);
await page.hover("text=Colors");

const element = page.locator(TEXT_COLOR_SELECTOR("red"));
const boundingBox = (await element.boundingBox())!;
await page.mouse.click(boundingBox.x + 10, boundingBox.y + 10);

expect(await page.screenshot()).toMatchSnapshot("blockTextColorTable.png");
});
Comment thread
matthewlipski marked this conversation as resolved.
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading