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
11 changes: 11 additions & 0 deletions .changeset/calm-news-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@wangeditor-next/core': patch
'@wangeditor-next/editor': patch
'@wangeditor-next/table-module': patch
---

feat(table): add configurable width export mode for table html

- Added `insertTable.widthExportMode` with `adaptive | explicit`.
- Default mode remains `explicit` for backward compatibility.
- `adaptive` mode can be enabled to keep `width:auto` on table export.
5 changes: 4 additions & 1 deletion packages/core/src/config/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface IHoverbarConf {
export type AlertType = 'success' | 'info' | 'warning' | 'error'
export type TextStyleMode = 'inline' | 'class'
export type ClassStylePolicy = 'preserve-data' | 'fallback-inline' | 'strict'
export type TableWidthExportMode = 'adaptive' | 'explicit'
export type StyleClassTokenType =
| 'color'
| 'bgColor'
Expand Down Expand Up @@ -116,12 +117,14 @@ interface IEmotionConfig {

interface IInsertTableConfig {
minWidth: number;
minRowHeight: number;
tableHeader: {
selected: boolean;
};
tableFullWidth: {
selected: boolean;
}
};
widthExportMode: TableWidthExportMode;
Comment on lines 118 to +127

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

widthExportMode is typed on the wrong menu config contract key.

widthExportMode was added to IInsertTableConfig, but IMenuConfig currently binds that type to
insertTableRow, while runtime/test usage reads MENU_CONF.insertTable. This makes the new public
type contract inaccurate and hides the real config shape behind ISingleMenuConfig’s index signature.

Suggested contract alignment
 interface IMenuConfig {
-  insertTable: ISingleMenuConfig;
+  insertTable: IInsertTableConfig;
   deleteTable: ISingleMenuConfig;
-  insertTableRow: IInsertTableConfig;
+  insertTableRow: ISingleMenuConfig;
   deleteTableRow: ISingleMenuConfig;
   ...
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/config/interface.ts` around lines 118 - 127, The new
widthExportMode property was added to IInsertTableConfig but the runtime and
tests expect it on the menu config key used by MENU_CONF.insertTable
(IMenuConfig currently maps it to insertTableRow), so remove widthExportMode
from IInsertTableConfig and instead add/align it to the menu config type that
represents MENU_CONF.insertTable (update IMenuConfig/ISingleMenuConfig mapping
or the explicit insertTable type so that IMenuConfig.insertTable includes
widthExportMode); reference IInsertTableConfig, IMenuConfig, ISingleMenuConfig,
insertTableRow, and insertTable to locate and adjust the types accordingly.

}

interface IInsertTableColConfig {
Expand Down
35 changes: 33 additions & 2 deletions packages/editor/__tests__/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,39 @@ describe('create editor and toolbar', () => {
expect(exportedHtml).toContain('<p>123</p>')
})

test('getHtml exports explicit table width when imported table uses colgroup widths', () => {
test('getHtml keeps auto table width when imported table uses colgroup widths in adaptive mode', () => {
const html = `<table style="width: auto;table-layout: fixed;height:auto">
<colgroup contentEditable="false">
<col width="120"></col>
<col width="80"></col>
</colgroup>
<tbody>
<tr><td>A</td><td>B</td></tr>
</tbody>
</table>`

const editor = customCreateEditor({
html,
config: {
MENU_CONF: {
insertTable: {
widthExportMode: 'adaptive',
},
},
},
})
const exportedHtml = editor.getHtml()

editor.setHtml(exportedHtml)
const roundTripHtml = editor.getHtml()

expect(exportedHtml).toContain('style="width: auto;table-layout: fixed;')
expect(roundTripHtml).toContain('style="width: auto;table-layout: fixed;')
expect(exportedHtml).not.toContain('height:NaN')
expect(exportedHtml).toContain('<colgroup contentEditable="false"><col width=120></col><col width=80></col></colgroup>')
})

test('getHtml exports explicit table width by default for imported colgroup widths', () => {
const html = `<table style="width: auto;table-layout: fixed;height:auto">
<colgroup contentEditable="false">
<col width="120"></col>
Expand All @@ -200,7 +232,6 @@ describe('create editor and toolbar', () => {
const exportedHtml = editor.getHtml()

expect(exportedHtml).toContain('style="width: 200px;table-layout: fixed;')
expect(exportedHtml).not.toContain('height:NaN')
expect(exportedHtml).toContain('<colgroup contentEditable="false"><col width=120></col><col width=80></col></colgroup>')
})

Expand Down
24 changes: 22 additions & 2 deletions packages/table-module/src/module/elem-to-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Element } from 'slate'

import { TableCellElement, TableElement, TableRowElement } from './custom-types'

type TableWidthExportMode = 'adaptive' | 'explicit'

function escapeHtml(raw: string): string {
return raw
.replace(/&/g, '&amp;')
Expand All @@ -17,13 +19,31 @@ function escapeHtml(raw: string): string {
.replace(/'/g, '&#39;')
}

function getExportTableWidth(tableNode: TableElement): string {
function getTableWidthExportMode(editor?: IDomEditor): TableWidthExportMode {
if (!editor || typeof editor.getMenuConfig !== 'function') {
return 'explicit'
}

const menuConf = editor.getMenuConfig('insertTable') as { widthExportMode?: TableWidthExportMode }

return menuConf?.widthExportMode === 'explicit' ? 'explicit' : 'adaptive'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Default missing widthExportMode to explicit

Treat missing/unknown widthExportMode as 'explicit' here; the current fallback returns 'adaptive' for any non-'explicit' value, including when editor.getMenuConfig('insertTable') returns {} or a malformed config. In those cases, tables with width: auto + columnWidths stop exporting pixel widths and unexpectedly emit width:auto, which breaks the commit’s backward-compatibility guarantee for default behavior.

Useful? React with 👍 / 👎.

}
Comment on lines +22 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default fallback is inverted to adaptive when config is missing/undefined.

This function currently defaults to adaptive for any non-explicit value. That breaks the stated
backward-compatible default. Missing/invalid config should resolve to explicit.

Suggested fix
-  return menuConf?.widthExportMode === 'explicit' ? 'explicit' : 'adaptive'
+  return menuConf?.widthExportMode === 'adaptive' ? 'adaptive' : 'explicit'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/table-module/src/module/elem-to-html.ts` around lines 22 - 30, The
current getTableWidthExportMode function treats any non-'explicit' value
(including undefined) as 'adaptive'; change the logic so missing/invalid config
falls back to 'explicit' instead. In getTableWidthExportMode, read
menuConf?.widthExportMode and return 'adaptive' only when it is explicitly
'adaptive' (e.g., menuConf?.widthExportMode === 'adaptive' ? 'adaptive' :
'explicit'); keep checks for editor and getMenuConfig as-is and update the
return expression accordingly.


function getExportTableWidth(tableNode: TableElement, editor?: IDomEditor): string {
const { width = 'auto', columnWidths = [] } = tableNode

if (width && width !== 'auto') {
return width
}

const widthExportMode = getTableWidthExportMode(editor)

// In adaptive mode, keep imported or generated auto-width tables as auto
// and only persist explicit fixed widths when width is not auto.
if (widthExportMode === 'adaptive') {
return 'auto'
}

const totalWidth = columnWidths.reduce((sum, columnWidth) => {
if (!Number.isFinite(columnWidth)) { return sum }
if (columnWidth <= 0) { return sum }
Expand All @@ -48,7 +68,7 @@ function tableToHtml(elemNode: Element, childrenHtml: string, editor?: IDomEdito

const captionStr = caption ? `<caption>${escapeHtml(caption)}</caption>` : ''
const colgroupStr = cols ? `<colgroup contentEditable="false">${cols}</colgroup>` : ''
const exportedWidth = getExportTableWidth(tableNode)
const exportedWidth = getExportTableWidth(tableNode, editor)
const textStyleMode = getTextStyleMode(editor)

if (textStyleMode === 'class') {
Expand Down
11 changes: 11 additions & 0 deletions packages/table-module/src/module/menu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ import TableProperty from './TableProperty'

export const insertTableMenuConf = {
key: 'insertTable',
config: {
minWidth: 60,
minRowHeight: 30,
tableHeader: {
selected: true,
},
tableFullWidth: {
selected: false,
},
widthExportMode: 'explicit',
},
factory() {
return new InsertTable()
},
Expand Down