Open emaborsa opened 11 months ago
Can you be more specific about which part doesn't meet your expectations here?
Actually all the td
s style. Why are they added?
Same issue to me
I found in the exportDOM
of the LexicalTableCellNode
has this weird style injection. Does anyone know why?
https://github.com/facebook/lexical/blob/ed8f85fb5e5106dba237e2a166e57acaa28e8fbe/packages/lexical-table/src/LexicalTableCellNode.ts#L141
To overcome this, it is possible to use "replace" with a "CustomCellNode" rewriting the function without the injection. It works, but...
// illustrative code
import { SerializedTableCellNode, TableCellNode } from '@lexical/table'
import {
$applyNodeReplacement,
type DOMConversionMap,
type DOMExportOutput,
type LexicalEditor,
DOMConversionOutput
} from 'lexical'
import { nanoid } from 'nanoid'
import { $createTableNode } from './TableNode'
export const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/
export declare const TableCellHeaderStates: {
BOTH: number
COLUMN: number
NO_STATUS: number
ROW: number
}
export type Cell = {
colSpan: number
json: string
type: 'normal' | 'header'
id: string
width: number | null
}
export type Row = {
cells: Array<Cell>
height: null | number
id: string
}
export type Rows = Array<Row>
export type TableCellHeaderState = (typeof TableCellHeaderStates)[keyof typeof TableCellHeaderStates]
export class CustomTableCellNode extends TableCellNode {
static getType(): string {
return 'custom-tablecell'
}
exportDOM(editor: LexicalEditor): DOMExportOutput {
const domExported = super.exportDOM(editor)
if (domExported.element) {
const element_ = domExported.element as HTMLElement
element_.style.border = ''
element_.style.width = this.getWidth() ? `${this.getWidth()}px` : ''
return {
...domExported,
element: element_
}
}
return domExported
}
exportJSON(): SerializedTableCellNode {
return {
...super.exportJSON(),
type: 'custom-tablecell'
}
}
static importJSON(serializedNode: SerializedTableCellNode): TableCellNode {
const colSpan = serializedNode.colSpan || 1
const rowSpan = serializedNode.rowSpan || 1
const cellNode = $applyNodeReplacement(
new CustomTableCellNode(serializedNode.headerState, colSpan, serializedNode.width || undefined)
) as TableCellNode
cellNode.__rowSpan = rowSpan
cellNode.__backgroundColor = serializedNode.backgroundColor || null
return cellNode
}
static importDOM(): DOMConversionMap | null {
return {
table: (_node: Node) => ({
conversion: convertTableElement,
priority: 0
})
}
}
static clone(node: CustomTableCellNode) {
const cellNode = new CustomTableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key)
cellNode.__rowSpan = node.__rowSpan
cellNode.__backgroundColor = node.__backgroundColor
return cellNode
}
}
export function $createTableCellNode(headerState: TableCellHeaderState, colSpan = 1, width?: number): TableCellNode {
return $applyNodeReplacement(new CustomTableCellNode(headerState, colSpan, width))
}
function createCell(type: 'normal' | 'header'): Cell {
return {
colSpan: 1,
id: nanoid(),
json: emptyEditorJSON,
type,
width: null
}
}
const emptyEditorJSON =
'{"root":{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'
const plainTextEditorJSON = (text: string) =>
text === ''
? emptyEditorJSON
: `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":${text},"type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`
export function createRow(): Row {
return {
cells: [],
height: null,
id: nanoid()
}
}
function convertTableElement(domNode: HTMLElement): null | DOMConversionOutput {
const rowElems = domNode.querySelectorAll('tr')
if (!rowElems || rowElems.length === 0) {
return null
}
const rows: Rows = []
for (let y = 0; y < rowElems.length; y++) {
const rowElem = rowElems[y]
const cellElems = rowElem.querySelectorAll('td,th')
if (!cellElems || cellElems.length === 0) {
continue
}
const cells: Array<Cell> = []
for (let x = 0; x < cellElems.length; x++) {
const cellElem = cellElems[x] as HTMLElement
const isHeader = cellElem.nodeName === 'TH'
const cell = createCell(isHeader ? 'header' : 'normal')
cell.json = plainTextEditorJSON(JSON.stringify(cellElem.innerText.replace(/\n/g, ' ')))
cells.push(cell)
}
const row = createRow()
row.cells = cells
rows.push(row)
}
return { node: $createTableNode(rows) }
}
Same issue. Why does $generateHtmlFromNodes
add styles? Styles are not visible when inspecting the table elements in the editor. But the generated HTML includes hardcoded styles for th
and td
.
My workaround is to remove any style attributes from the HTML. I use the Lexical theme to configured classes to separate styling from the content.
const regex = /(style=".+?")/gm;
const editorState = editor.getEditorState().toJSON();
let html = $generateHtmlFromNodes(editor, null);
html = html.replace(regex, '');
console.log(html);
Same issue. Why does
$generateHtmlFromNodes
add styles? Styles are not visible when inspecting the table elements in the editor. But the generated HTML includes hardcoded styles forand . My workaround is to remove any style attributes from the HTML.
const regex = /(style=".+?")/gm; const editorState = editor.getEditorState().toJSON(); let html = $generateHtmlFromNodes(editor, null); html = html.replace(regex, ''); console.log(html);
If you only remove the style, when you try to define a width for the column, it will not be defined in the generated HTML.
emaborsa commented 9 months ago
Same issue. Why does
$generateHtmlFromNodes
add styles? Styles are not visible when inspecting the table elements in the editor. But the generated HTML includes hardcoded styles for and .My workaround is to remove any style attributes from the HTML.
const regex = /(style=".+?")/gm; const editorState = editor.getEditorState().toJSON(); let html = $generateHtmlFromNodes(editor, null); html = html.replace(regex, ''); console.log(html);
Be aware, removing all the styles you are going to loose the italic and bold of the paragraphs.
nocodehummel commented 9 months ago
Same issue. Why does
$generateHtmlFromNodes
add styles? Styles are not visible when inspecting the table elements in the editor. But the generated HTML includes hardcoded styles for and . My workaround is to remove any style attributes from the HTML.const regex = /(style=".+?")/gm; const editorState = editor.getEditorState().toJSON(); let html = $generateHtmlFromNodes(editor, null); html = html.replace(regex, ''); console.log(html);
Be aware, removing all the styles you are going to loose the italic and bold of the paragraphs.
This is not an issue in my implementation since I always use the theme classes to control styling.
emaborsa commented 9 months ago
Same issue. Why does
$generateHtmlFromNodes
add styles? Styles are not visible when inspecting the table elements in the editor. But the generated HTML includes hardcoded styles for and . My workaround is to remove any style attributes from the HTML.const regex = /(style=".+?")/gm; const editorState = editor.getEditorState().toJSON(); let html = $generateHtmlFromNodes(editor, null); html = html.replace(regex, ''); console.log(html);
Be aware, removing all the styles you are going to loose the italic and bold of the paragraphs.
This is not an issue in my implementation since I always use the theme classes to control styling.
If in lexical you set italic and bold to a paragraph, one of them is set as a style and if you remove it, how can you apply your style?
nocodehummel commented 9 months ago
I use the below theme that adds the specified class to each of the HTML elements.
const themeClasses = { paragraph: 'editorParagraph', link: 'editorLink', text: { bold: 'editorBold', underline: 'editorUnderline', italic: 'editorItalic', }...... }
<LexicalComposer initialConfig={{ namespace: 'markdown-editor', theme: themeClasses, nodes: EDITOR_NODES, onError: (error) => { console.log(error); }, }} >
This renders HTML
my text is <strong class='editorBold'>bold</strong> :-)
which I format with external CSS. I prefer to work with classes and leave the CSS outside the editor state so I can adjust the CSS as needed.
Lexical version:
@lexical/react 0.10.0 lexical 0.10.0
as well with @lexical/react 0.12.2 lexical 0.12.2
Problem
Unexpected style for generated html
table
using$generateHtmlFromNodes
Lexical JSON
Current result
Expected result