diff --git a/.changeset/quick-lamps-check.md b/.changeset/quick-lamps-check.md
new file mode 100644
index 0000000..562ce27
--- /dev/null
+++ b/.changeset/quick-lamps-check.md
@@ -0,0 +1,7 @@
+---
+"@graphcms/html-to-slate-ast": minor
+---
+
+- Add IFrame support
+- Add bold text support to table cells
+- Add nested tags support to table cells
diff --git a/packages/html-to-slate-ast/src/index.ts b/packages/html-to-slate-ast/src/index.ts
index 41c6b74..1b1abdd 100644
--- a/packages/html-to-slate-ast/src/index.ts
+++ b/packages/html-to-slate-ast/src/index.ts
@@ -62,6 +62,25 @@ const ELEMENT_TAGS: Record<
};
},
PRE: () => ({ type: 'code-block' }),
+ IFRAME: el => {
+ const src = el.getAttribute('src');
+ if (!src) return {};
+ const height = el.getAttribute('height');
+ const width = el.getAttribute('width');
+ return {
+ type: 'iframe',
+ url: '//www.youtube.com/embed/ljiWOrULppk?rel=0',
+ // default iframe height is 150
+ height: Number(height || 150),
+ // default iframe width is 300
+ width: Number(width || 300),
+ children: [
+ {
+ text: '',
+ },
+ ],
+ };
+ },
};
const TEXT_TAGS: Record<
@@ -215,19 +234,17 @@ function deserialize<
} else if (nodeName === 'TD' || nodeName === 'TH') {
// if TD or TH is empty, insert a paragraph to ensure selection can be placed inside
const childNodes = Array.from((el as HTMLTableCellElement).childNodes);
- const modifiedChildren =
- childNodes.length === 0
- ? [
- {
- type: 'paragraph',
- children: [{ text: '' }],
- },
- ]
- : childNodes.map(child => ({
- type: 'paragraph',
- children: [{ text: child.textContent ? child.textContent : '' }],
- }));
- return jsx('element', attrs, modifiedChildren);
+ if (childNodes.length === 0) {
+ return jsx('element', attrs, [
+ {
+ type: 'paragraph',
+ children: [{ text: '' }],
+ },
+ ]);
+ } else {
+ const children = childNodes.map(c => deserialize(c, global)).flat();
+ return jsx('element', attrs, children);
+ }
} else if (nodeName === 'IMG') {
return jsx('element', attrs, [attrs.href]);
}
diff --git a/packages/html-to-slate-ast/test/html_input_iframe.html b/packages/html-to-slate-ast/test/html_input_iframe.html
new file mode 100644
index 0000000..d4e64db
--- /dev/null
+++ b/packages/html-to-slate-ast/test/html_input_iframe.html
@@ -0,0 +1,34 @@
+
+
+ SANTA CLARA, Calif., (June 20, 2017) – experience for fans and newcomers alike.
+
+
+
+
+
+
+ .hack is a multimedia franchise created and developed by famed
+ Japanese developer CyberConnect2. Comprising of video games, anime, novels,
+ and manga, the world of .hack focuses on the mysterious events
+ surrounding a wildly popular in-universe massively multiplayer role-playing
+ game called The World. .hack//G.U. begins after the events of the
+ original .hack series with players assuming the role of Haseo as he
+ tracks down a powerful Player Killer named Tri-Edge who killed his friend’s
+ in-game avatar Shino, and put her into a coma in real life.
+
+
diff --git a/packages/html-to-slate-ast/test/html_input_table.html b/packages/html-to-slate-ast/test/html_input_table.html
new file mode 100644
index 0000000..bcfa0ac
--- /dev/null
+++ b/packages/html-to-slate-ast/test/html_input_table.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ R1C1 - BOLD TEXT
+ |
+
+ R1C2
+ |
+ R1C3 |
+
+
+
+ R2C1
+ |
+
+ R2C2 - ITALIC TEXT
+ |
+
+
+ R2C3 - BOLD TEXT
+
+ |
+
+
+
+
diff --git a/packages/html-to-slate-ast/test/index.test.ts b/packages/html-to-slate-ast/test/index.test.ts
index fca9c22..1de8614 100644
--- a/packages/html-to-slate-ast/test/index.test.ts
+++ b/packages/html-to-slate-ast/test/index.test.ts
@@ -491,11 +491,205 @@ test('Transforms inner spans wrapped in a div into paragraph', () => {
);
});
+test('Transforms iframe correctly', async () => {
+ const input = fs
+ .readFileSync(__dirname + '/html_input_iframe.html')
+ .toString();
+
+ const ast = await htmlToSlateAST(input);
+ expect(ast).toStrictEqual([
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: 'SANTA CLARA, Calif., (June 20, 2017) –',
+ bold: true,
+ },
+ {
+ text: ' experience for fans and newcomers alike.\n ',
+ },
+ ],
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ url: '//www.youtube.com/embed/ljiWOrULppk?rel=0',
+ type: 'iframe',
+ width: 640,
+ height: 360,
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: ' ',
+ },
+ ],
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: '.hack',
+ italic: true,
+ },
+ {
+ text:
+ ' is a multimedia franchise created and developed by famed\n Japanese developer CyberConnect2. Comprising of video games, anime, novels,\n and manga, the world of ',
+ },
+ {
+ text: '.hack',
+ italic: true,
+ },
+ {
+ text:
+ ' focuses on the mysterious events\n surrounding a wildly popular in-universe massively multiplayer role-playing\n game called The World. ',
+ },
+ {
+ text: '.hack//G.U. ',
+ italic: true,
+ },
+ {
+ text: 'begins after the events of the\n original ',
+ },
+ {
+ text: '.hack ',
+ italic: true,
+ },
+ {
+ text:
+ 'series with players assuming the role of Haseo as he\n tracks down a powerful Player Killer named Tri-Edge who killed his friend’s\n in-game avatar Shino, and put her into a coma in real life.\n ',
+ },
+ ],
+ },
+ {
+ text: '\n',
+ },
+ ]);
+});
+
+test('Transforms tables with nested html tags as cells', async () => {
+ const input = fs
+ .readFileSync(__dirname + '/html_input_table.html')
+ .toString();
+
+ const ast = await htmlToSlateAST(input);
+ expect(ast).toStrictEqual([
+ {
+ type: 'table',
+ children: [
+ {
+ type: 'table_body',
+ children: [
+ {
+ type: 'table_row',
+ children: [
+ {
+ type: 'table_cell',
+ children: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ bold: true,
+ text: 'R1C1 - BOLD TEXT',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'table_cell',
+ children: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: 'R1C2',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'table_cell',
+ children: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: 'R1C3',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'table_row',
+ children: [
+ {
+ type: 'table_cell',
+ children: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: 'R2C1',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: 'table_cell',
+ children: [
+ {
+ italic: true,
+ text: 'R2C2 - ITALIC TEXT',
+ },
+ ],
+ },
+ {
+ type: 'table_cell',
+ children: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ bold: true,
+ text: 'R2C3 - BOLD TEXT',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ text: '\n',
+ },
+ ]);
+});
+
test('Transforms Google Docs input', () => {
const input = fs
.readFileSync(__dirname + '/google-docs_input.html')
.toString();
- return htmlToSlateAST(input).then(ast =>
+ return htmlToSlateAST(input).then(ast => {
expect(ast).toEqual([
{
type: 'heading-one',
@@ -733,12 +927,7 @@ test('Transforms Google Docs input', () => {
type: 'table_cell',
children: [
{
- type: 'paragraph',
- children: [
- {
- text: '',
- },
- ],
+ text: '\n',
},
],
},
@@ -746,12 +935,7 @@ test('Transforms Google Docs input', () => {
type: 'table_cell',
children: [
{
- type: 'paragraph',
- children: [
- {
- text: '',
- },
- ],
+ text: '\n',
},
],
},
@@ -787,8 +971,8 @@ test('Transforms Google Docs input', () => {
},
],
},
- ])
- );
+ ]);
+ });
});
test('Converts word documents', () => {