@examind/block-sdk 0.1.19 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +168 -54
  2. package/dist/index.mjs +168 -54
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -254,6 +254,10 @@ var HorizontalRuleNodeHandler = class extends NodeHandler {
254
254
  }
255
255
  };
256
256
 
257
+ // src/config/constants.ts
258
+ var IMAGE_CONTAINER_ATTRIBUTE = "data-block-image-container";
259
+ var IMAGE_CONTAINER_CLASS = "block-image-container";
260
+
257
261
  // src/typeGuards/isSerializedImageNode.ts
258
262
  var isSerializedImageNode = (node) => {
259
263
  return node?.type === "image" && "altText" in node && typeof node.altText === "string" && "caption" in node && "showCaption" in node && typeof node.showCaption === "boolean" && "src" in node && typeof node.src === "string" && "width" in node && typeof node.width === "string" && "align" in node && typeof node.align === "string" && "showBorder" in node && typeof node.showBorder === "boolean";
@@ -261,39 +265,62 @@ var isSerializedImageNode = (node) => {
261
265
 
262
266
  // src/exportToHtml/ImageNodeHandler.ts
263
267
  var ImageNodeHandler = class extends NodeHandler {
268
+ alignItemsAttribute(node) {
269
+ return node.align === "left" ? "start" : node.align === "right" ? "end" : "center";
270
+ }
264
271
  srcAttribute(node) {
265
272
  return `src="${node.src}"`;
266
273
  }
267
274
  altAttribute(node) {
268
275
  return node.altText ? `alt="${node.altText}"` : null;
269
276
  }
270
- styleAttribute(node) {
271
- const styleProps = [];
277
+ fillStyleWidth(styleProps, node) {
272
278
  if (node.width) {
273
279
  styleProps.push(`width: ${node.width};`);
274
280
  styleProps.push(`max-width: 100%;`);
275
281
  }
282
+ return styleProps;
283
+ }
284
+ imageStyleAttribute(node) {
285
+ const styleProps = this.fillStyleWidth([], node);
276
286
  if (node.showBorder) {
277
287
  styleProps.push(`border: 1px solid #ccc;`);
278
288
  }
279
289
  return styleProps.length ? `style="${styleProps.join(" ")}"` : null;
280
290
  }
281
- alignAttribute(node) {
282
- return node.align !== "left" ? `align="${node.align}"` : null;
291
+ captionStyleAttribute(node) {
292
+ const styleProps = this.fillStyleWidth([], node);
293
+ return styleProps.length ? `style="${styleProps.join(" ")}"` : null;
283
294
  }
284
- attributes(node) {
295
+ imageAttributes(node) {
285
296
  const attributes = [
286
297
  this.srcAttribute(node),
287
298
  this.altAttribute(node),
288
- this.styleAttribute(node),
289
- this.alignAttribute(node)
299
+ this.imageStyleAttribute(node)
290
300
  ].filter(Boolean).join(" ");
291
301
  return attributes;
292
302
  }
303
+ captionAttributes(node) {
304
+ const attributes = [this.captionStyleAttribute(node)].filter(Boolean).join(" ");
305
+ return attributes;
306
+ }
307
+ wrapContainer(node, imageHtml, captionHtml) {
308
+ const styles = [
309
+ "display: flex;",
310
+ "flex-direction: column;",
311
+ "justify-content: center;",
312
+ "width: 100%;",
313
+ "align-items: " + this.alignItemsAttribute(node) + ";"
314
+ ];
315
+ return `<div ${IMAGE_CONTAINER_ATTRIBUTE} class="${IMAGE_CONTAINER_CLASS}" style="${styles.join(" ")}">${imageHtml}${captionHtml}</div>`;
316
+ }
293
317
  processNode(node) {
294
318
  if (!isSerializedImageNode(node)) return null;
295
- const attributes = this.attributes(node);
296
- return `<img ${attributes} />`;
319
+ return this.wrapContainer(
320
+ node,
321
+ `<img ${this.imageAttributes(node)} />`,
322
+ node.showCaption ? `<p ${this.captionAttributes(node)}>${createHtmlFromNestedEditor(node.caption)}</p>` : ""
323
+ );
297
324
  }
298
325
  };
299
326
 
@@ -949,7 +976,9 @@ var createNestedNodesFromHtml = (node) => {
949
976
  for (const child of node.childNodes) {
950
977
  const processedChildren = traverse2(child);
951
978
  for (const processedChild of processedChildren) {
952
- const isBlockElement = processedChild.type === "paragraph" || processedChild.type === "table" || processedChild.type === "list";
979
+ const isBlockElement = processedChild.type === "paragraph" || processedChild.type === "table" || processedChild.type === "list" || // Block Editor considers images a block level root node (no wrapping with p)
980
+ // https://github.com/examind-ai/block-editor/issues/232
981
+ processedChild.type === "image";
953
982
  if (isBlockElement) {
954
983
  appendInlinesInParagraphIfNotEmptyBR(
955
984
  results,
@@ -968,6 +997,105 @@ var createNestedNodesFromHtml = (node) => {
968
997
  else return results;
969
998
  };
970
999
 
1000
+ // src/importFromHtml/createImageNode.ts
1001
+ function createImageNode(src, altText, width, align, showBorder, caption) {
1002
+ return {
1003
+ src,
1004
+ altText,
1005
+ width,
1006
+ align,
1007
+ showBorder,
1008
+ showCaption: !!caption,
1009
+ caption: {
1010
+ editorState: {
1011
+ root: {
1012
+ children: caption ? caption.split("\n").reduce((nodes, line, index, lines) => {
1013
+ nodes.push({
1014
+ detail: 0,
1015
+ format: 0,
1016
+ mode: "normal",
1017
+ style: "",
1018
+ text: line,
1019
+ type: "text",
1020
+ version: 1
1021
+ });
1022
+ if (index < lines.length - 1) {
1023
+ nodes.push({
1024
+ type: "linebreak",
1025
+ version: 1
1026
+ });
1027
+ }
1028
+ return nodes;
1029
+ }, []) : [],
1030
+ direction: null,
1031
+ format: "",
1032
+ indent: 0,
1033
+ type: "root",
1034
+ version: 1
1035
+ }
1036
+ }
1037
+ },
1038
+ type: "image",
1039
+ version: 1
1040
+ };
1041
+ }
1042
+
1043
+ // src/importFromHtml/extractFlexAlign.ts
1044
+ function extractFlexAlign(element) {
1045
+ const style = element.getAttribute("style");
1046
+ if (!style) return "left";
1047
+ const flexAlignMatch = style.match(/align-items:\s*([^;]+);?/i);
1048
+ if (flexAlignMatch && flexAlignMatch[1]) {
1049
+ const value = flexAlignMatch[1].trim();
1050
+ if (value === "start") return "left";
1051
+ if (value === "end") return "right";
1052
+ return value;
1053
+ }
1054
+ return "left";
1055
+ }
1056
+
1057
+ // src/importFromHtml/extractWidth.ts
1058
+ function extractWidth(element) {
1059
+ const style = element.getAttribute("style");
1060
+ if (style) {
1061
+ const widthMatch = style.match(/width:\s*([^;]+);?/i);
1062
+ if (widthMatch && widthMatch[1]) {
1063
+ return widthMatch[1].trim();
1064
+ }
1065
+ }
1066
+ const width = element.getAttribute("width");
1067
+ return width ? `${width}px` : "";
1068
+ }
1069
+
1070
+ // src/importFromHtml/hasBorder.ts
1071
+ function hasBorder(element) {
1072
+ const style = element.getAttribute("style");
1073
+ if (!style) return false;
1074
+ return /border\s*:/i.test(style);
1075
+ }
1076
+
1077
+ // src/importFromHtml/processImageNodeContainer.ts
1078
+ function processImageNodeContainer(node) {
1079
+ if (!node.hasAttribute(IMAGE_CONTAINER_ATTRIBUTE)) {
1080
+ return null;
1081
+ }
1082
+ const imageNode = node.querySelector("img");
1083
+ const captionNode = node.querySelector("p");
1084
+ if (!imageNode) {
1085
+ return null;
1086
+ }
1087
+ return [
1088
+ createImageNode(
1089
+ imageNode.attributes["src"] ?? "",
1090
+ imageNode.attributes["alt"] ?? "",
1091
+ extractWidth(imageNode),
1092
+ extractFlexAlign(node),
1093
+ hasBorder(imageNode),
1094
+ captionNode?.text
1095
+ )
1096
+ ];
1097
+ }
1098
+
971
1099
  // src/importFromHtml/types.ts
972
1100
  var NodeHandler2 = class {
973
1101
  constructor() {
@@ -995,15 +1123,18 @@ var NodeHandler2 = class {
995
1123
  };
996
1124
 
997
1125
  // src/importFromHtml/DivNodeHandler.ts
998
- var isHtmlDivElement = (node) => {
999
- return node instanceof import_node_html_parser2.HTMLElement && node.tagName === "DIV";
1000
- };
1001
1126
  var DivNodeHandler = class extends NodeHandler2 {
1127
+ isHtmlDivElement(node) {
1128
+ return node instanceof import_node_html_parser2.HTMLElement && node.tagName === "DIV";
1129
+ }
1002
1130
  processNode(node) {
1003
- if (!isHtmlDivElement(node)) {
1131
+ if (!this.isHtmlDivElement(node)) {
1004
1132
  return null;
1005
1133
  }
1006
- return createNestedNodesFromHtml(node);
1134
+ return (
1135
+ // Native Block Editor exported image container is a div with a specific attribute
1136
+ processImageNodeContainer(node) ?? createNestedNodesFromHtml(node)
1137
+ );
1007
1138
  }
1008
1139
  };
1009
1140
 
@@ -1336,49 +1467,18 @@ var HorizontalRuleNodeHandler2 = class extends NodeHandler2 {
1336
1467
  var import_node_html_parser9 = require("node-html-parser");
1337
1468
  var TAG_IMG = "img";
1338
1469
  var ImageNodeHandler2 = class extends NodeHandler2 {
1339
- extractWidth(element) {
1340
- const style = element.getAttribute("style");
1341
- if (style) {
1342
- const widthMatch = style.match(/width:\s*([^;]+);?/i);
1343
- if (widthMatch && widthMatch[1]) {
1344
- return widthMatch[1].trim();
1345
- }
1346
- }
1347
- const width = element.getAttribute("width");
1348
- return width ? `${width}px` : "";
1349
- }
1350
- hasBorder(element) {
1351
- const style = element.getAttribute("style");
1352
- if (!style) return false;
1353
- return /border\s*:/i.test(style);
1354
- }
1355
1470
  processNode(node) {
1356
1471
  if (!(node instanceof import_node_html_parser9.HTMLElement) || node.tagName !== TAG_IMG.toUpperCase()) {
1357
1472
  return null;
1358
1473
  }
1359
- const imageNode = {
1360
- src: node.getAttribute("src") || "",
1361
- altText: node.getAttribute("alt") || "",
1362
- width: this.extractWidth(node),
1363
- align: node.getAttribute("align") || "left",
1364
- showBorder: this.hasBorder(node),
1365
- showCaption: false,
1366
- caption: {
1367
- editorState: {
1368
- root: {
1369
- children: [],
1370
- direction: null,
1371
- format: "",
1372
- indent: 0,
1373
- type: "root",
1374
- version: 1
1375
- }
1376
- }
1377
- },
1378
- type: "image",
1379
- version: 1
1380
- };
1381
- return imageNode;
1474
+ return createImageNode(
1475
+ node.getAttribute("src") || "",
1476
+ node.getAttribute("alt") || "",
1477
+ extractWidth(node),
1478
+ node.getAttribute("align") || "left",
1479
+ hasBorder(node),
1480
+ void 0
1481
+ );
1382
1482
  }
1383
1483
  };
1384
1484
 
@@ -1687,9 +1787,23 @@ var ParagraphNodeHandler2 = class extends NodeHandler2 {
1687
1787
  }
1688
1788
  return "";
1689
1789
  }
1790
+ processImageNode(node) {
1791
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof import_node_html_parser17.HTMLElement && node.childNodes[0].tagName === "IMG") {
1792
+ return traverse2(node.childNodes[0]);
1793
+ }
1794
+ return null;
1795
+ }
1796
+ processSpanImageNode(node) {
1797
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof import_node_html_parser17.HTMLElement && node.childNodes[0].tagName === "SPAN" && node.childNodes[0].childNodes.length === 1 && node.childNodes[0].childNodes[0] instanceof import_node_html_parser17.HTMLElement && node.childNodes[0].childNodes[0].tagName === "IMG") {
1798
+ return traverse2(node.childNodes[0].childNodes[0]);
1799
+ }
1800
+ return null;
1801
+ }
1690
1802
  processNode(node) {
1691
1803
  if (!(node instanceof import_node_html_parser17.HTMLElement)) return null;
1692
1804
  if (node.tagName !== "P") return null;
1805
+ const imageNode = this.processImageNode(node) ?? this.processSpanImageNode(node);
1806
+ if (imageNode) return imageNode;
1693
1807
  const jsonNode = createEmptyParagraphNode();
1694
1808
  jsonNode.format = this.extractTextAlignment(node);
1695
1809
  if (node.childNodes.length === 1 && node.childNodes[0] instanceof import_node_html_parser17.HTMLElement && node.childNodes[0].tagName === "BR")
package/dist/index.mjs CHANGED
@@ -227,6 +227,10 @@ var HorizontalRuleNodeHandler = class extends NodeHandler {
227
227
  }
228
228
  };
229
229
 
230
+ // src/config/constants.ts
231
+ var IMAGE_CONTAINER_ATTRIBUTE = "data-block-image-container";
232
+ var IMAGE_CONTAINER_CLASS = "block-image-container";
233
+
230
234
  // src/typeGuards/isSerializedImageNode.ts
231
235
  var isSerializedImageNode = (node) => {
232
236
  return node?.type === "image" && "altText" in node && typeof node.altText === "string" && "caption" in node && "showCaption" in node && typeof node.showCaption === "boolean" && "src" in node && typeof node.src === "string" && "width" in node && typeof node.width === "string" && "align" in node && typeof node.align === "string" && "showBorder" in node && typeof node.showBorder === "boolean";
@@ -234,39 +238,62 @@ var isSerializedImageNode = (node) => {
234
238
 
235
239
  // src/exportToHtml/ImageNodeHandler.ts
236
240
  var ImageNodeHandler = class extends NodeHandler {
241
+ alignItemsAttribute(node) {
242
+ return node.align === "left" ? "start" : node.align === "right" ? "end" : "center";
243
+ }
237
244
  srcAttribute(node) {
238
245
  return `src="${node.src}"`;
239
246
  }
240
247
  altAttribute(node) {
241
248
  return node.altText ? `alt="${node.altText}"` : null;
242
249
  }
243
- styleAttribute(node) {
244
- const styleProps = [];
250
+ fillStyleWidth(styleProps, node) {
245
251
  if (node.width) {
246
252
  styleProps.push(`width: ${node.width};`);
247
253
  styleProps.push(`max-width: 100%;`);
248
254
  }
255
+ return styleProps;
256
+ }
257
+ imageStyleAttribute(node) {
258
+ const styleProps = this.fillStyleWidth([], node);
249
259
  if (node.showBorder) {
250
260
  styleProps.push(`border: 1px solid #ccc;`);
251
261
  }
252
262
  return styleProps.length ? `style="${styleProps.join(" ")}"` : null;
253
263
  }
254
- alignAttribute(node) {
255
- return node.align !== "left" ? `align="${node.align}"` : null;
264
+ captionStyleAttribute(node) {
265
+ const styleProps = this.fillStyleWidth([], node);
266
+ return styleProps.length ? `style="${styleProps.join(" ")}"` : null;
256
267
  }
257
- attributes(node) {
268
+ imageAttributes(node) {
258
269
  const attributes = [
259
270
  this.srcAttribute(node),
260
271
  this.altAttribute(node),
261
- this.styleAttribute(node),
262
- this.alignAttribute(node)
272
+ this.imageStyleAttribute(node)
263
273
  ].filter(Boolean).join(" ");
264
274
  return attributes;
265
275
  }
276
+ captionAttributes(node) {
277
+ const attributes = [this.captionStyleAttribute(node)].filter(Boolean).join(" ");
278
+ return attributes;
279
+ }
280
+ wrapContainer(node, imageHtml, captionHtml) {
281
+ const styles = [
282
+ "display: flex;",
283
+ "flex-direction: column;",
284
+ "justify-content: center;",
285
+ "width: 100%;",
286
+ "align-items: " + this.alignItemsAttribute(node) + ";"
287
+ ];
288
+ return `<div ${IMAGE_CONTAINER_ATTRIBUTE} class="${IMAGE_CONTAINER_CLASS}" style="${styles.join(" ")}">${imageHtml}${captionHtml}</div>`;
289
+ }
266
290
  processNode(node) {
267
291
  if (!isSerializedImageNode(node)) return null;
268
- const attributes = this.attributes(node);
269
- return `<img ${attributes} />`;
292
+ return this.wrapContainer(
293
+ node,
294
+ `<img ${this.imageAttributes(node)} />`,
295
+ node.showCaption ? `<p ${this.captionAttributes(node)}>${createHtmlFromNestedEditor(node.caption)}</p>` : ""
296
+ );
270
297
  }
271
298
  };
272
299
 
@@ -922,7 +949,9 @@ var createNestedNodesFromHtml = (node) => {
922
949
  for (const child of node.childNodes) {
923
950
  const processedChildren = traverse2(child);
924
951
  for (const processedChild of processedChildren) {
925
- const isBlockElement = processedChild.type === "paragraph" || processedChild.type === "table" || processedChild.type === "list";
952
+ const isBlockElement = processedChild.type === "paragraph" || processedChild.type === "table" || processedChild.type === "list" || // Block Editor considers images a block level root node (no wrapping with p)
953
+ // https://github.com/examind-ai/block-editor/issues/232
954
+ processedChild.type === "image";
926
955
  if (isBlockElement) {
927
956
  appendInlinesInParagraphIfNotEmptyBR(
928
957
  results,
@@ -941,6 +970,105 @@ var createNestedNodesFromHtml = (node) => {
941
970
  else return results;
942
971
  };
943
972
 
973
+ // src/importFromHtml/createImageNode.ts
974
+ function createImageNode(src, altText, width, align, showBorder, caption) {
975
+ return {
976
+ src,
977
+ altText,
978
+ width,
979
+ align,
980
+ showBorder,
981
+ showCaption: !!caption,
982
+ caption: {
983
+ editorState: {
984
+ root: {
985
+ children: caption ? caption.split("\n").reduce((nodes, line, index, lines) => {
986
+ nodes.push({
987
+ detail: 0,
988
+ format: 0,
989
+ mode: "normal",
990
+ style: "",
991
+ text: line,
992
+ type: "text",
993
+ version: 1
994
+ });
995
+ if (index < lines.length - 1) {
996
+ nodes.push({
997
+ type: "linebreak",
998
+ version: 1
999
+ });
1000
+ }
1001
+ return nodes;
1002
+ }, []) : [],
1003
+ direction: null,
1004
+ format: "",
1005
+ indent: 0,
1006
+ type: "root",
1007
+ version: 1
1008
+ }
1009
+ }
1010
+ },
1011
+ type: "image",
1012
+ version: 1
1013
+ };
1014
+ }
1015
+
1016
+ // src/importFromHtml/extractFlexAlign.ts
1017
+ function extractFlexAlign(element) {
1018
+ const style = element.getAttribute("style");
1019
+ if (!style) return "left";
1020
+ const flexAlignMatch = style.match(/align-items:\s*([^;]+);?/i);
1021
+ if (flexAlignMatch && flexAlignMatch[1]) {
1022
+ const value = flexAlignMatch[1].trim();
1023
+ if (value === "start") return "left";
1024
+ if (value === "end") return "right";
1025
+ return value;
1026
+ }
1027
+ return "left";
1028
+ }
1029
+
1030
+ // src/importFromHtml/extractWidth.ts
1031
+ function extractWidth(element) {
1032
+ const style = element.getAttribute("style");
1033
+ if (style) {
1034
+ const widthMatch = style.match(/width:\s*([^;]+);?/i);
1035
+ if (widthMatch && widthMatch[1]) {
1036
+ return widthMatch[1].trim();
1037
+ }
1038
+ }
1039
+ const width = element.getAttribute("width");
1040
+ return width ? `${width}px` : "";
1041
+ }
1042
+
1043
+ // src/importFromHtml/hasBorder.ts
1044
+ function hasBorder(element) {
1045
+ const style = element.getAttribute("style");
1046
+ if (!style) return false;
1047
+ return /border\s*:/i.test(style);
1048
+ }
1049
+
1050
+ // src/importFromHtml/processImageNodeContainer.ts
1051
+ function processImageNodeContainer(node) {
1052
+ if (!node.hasAttribute(IMAGE_CONTAINER_ATTRIBUTE)) {
1053
+ return null;
1054
+ }
1055
+ const imageNode = node.querySelector("img");
1056
+ const captionNode = node.querySelector("p");
1057
+ if (!imageNode) {
1058
+ return null;
1059
+ }
1060
+ return [
1061
+ createImageNode(
1062
+ imageNode.attributes["src"] ?? "",
1063
+ imageNode.attributes["alt"] ?? "",
1064
+ extractWidth(imageNode),
1065
+ extractFlexAlign(node),
1066
+ hasBorder(imageNode),
1067
+ captionNode?.text
1068
+ )
1069
+ ];
1070
+ }
1071
+
944
1072
  // src/importFromHtml/types.ts
945
1073
  var NodeHandler2 = class {
946
1074
  constructor() {
@@ -968,15 +1096,18 @@ var NodeHandler2 = class {
968
1096
  };
969
1097
 
970
1098
  // src/importFromHtml/DivNodeHandler.ts
971
- var isHtmlDivElement = (node) => {
972
- return node instanceof HTMLElement2 && node.tagName === "DIV";
973
- };
974
1099
  var DivNodeHandler = class extends NodeHandler2 {
1100
+ isHtmlDivElement(node) {
1101
+ return node instanceof HTMLElement2 && node.tagName === "DIV";
1102
+ }
975
1103
  processNode(node) {
976
- if (!isHtmlDivElement(node)) {
1104
+ if (!this.isHtmlDivElement(node)) {
977
1105
  return null;
978
1106
  }
979
- return createNestedNodesFromHtml(node);
1107
+ return (
1108
+ // Native Block Editor exported image container is a div with a specific attribute
1109
+ processImageNodeContainer(node) ?? createNestedNodesFromHtml(node)
1110
+ );
980
1111
  }
981
1112
  };
982
1113
 
@@ -1309,49 +1440,18 @@ var HorizontalRuleNodeHandler2 = class extends NodeHandler2 {
1309
1440
  import { HTMLElement as HTMLElement9 } from "node-html-parser";
1310
1441
  var TAG_IMG = "img";
1311
1442
  var ImageNodeHandler2 = class extends NodeHandler2 {
1312
- extractWidth(element) {
1313
- const style = element.getAttribute("style");
1314
- if (style) {
1315
- const widthMatch = style.match(/width:\s*([^;]+);?/i);
1316
- if (widthMatch && widthMatch[1]) {
1317
- return widthMatch[1].trim();
1318
- }
1319
- }
1320
- const width = element.getAttribute("width");
1321
- return width ? `${width}px` : "";
1322
- }
1323
- hasBorder(element) {
1324
- const style = element.getAttribute("style");
1325
- if (!style) return false;
1326
- return /border\s*:/i.test(style);
1327
- }
1328
1443
  processNode(node) {
1329
1444
  if (!(node instanceof HTMLElement9) || node.tagName !== TAG_IMG.toUpperCase()) {
1330
1445
  return null;
1331
1446
  }
1332
- const imageNode = {
1333
- src: node.getAttribute("src") || "",
1334
- altText: node.getAttribute("alt") || "",
1335
- width: this.extractWidth(node),
1336
- align: node.getAttribute("align") || "left",
1337
- showBorder: this.hasBorder(node),
1338
- showCaption: false,
1339
- caption: {
1340
- editorState: {
1341
- root: {
1342
- children: [],
1343
- direction: null,
1344
- format: "",
1345
- indent: 0,
1346
- type: "root",
1347
- version: 1
1348
- }
1349
- }
1350
- },
1351
- type: "image",
1352
- version: 1
1353
- };
1354
- return imageNode;
1447
+ return createImageNode(
1448
+ node.getAttribute("src") || "",
1449
+ node.getAttribute("alt") || "",
1450
+ extractWidth(node),
1451
+ node.getAttribute("align") || "left",
1452
+ hasBorder(node),
1453
+ void 0
1454
+ );
1355
1455
  }
1356
1456
  };
1357
1457
 
@@ -1660,9 +1760,23 @@ var ParagraphNodeHandler2 = class extends NodeHandler2 {
1660
1760
  }
1661
1761
  return "";
1662
1762
  }
1763
+ processImageNode(node) {
1764
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement17 && node.childNodes[0].tagName === "IMG") {
1765
+ return traverse2(node.childNodes[0]);
1766
+ }
1767
+ return null;
1768
+ }
1769
+ processSpanImageNode(node) {
1770
+ if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement17 && node.childNodes[0].tagName === "SPAN" && node.childNodes[0].childNodes.length === 1 && node.childNodes[0].childNodes[0] instanceof HTMLElement17 && node.childNodes[0].childNodes[0].tagName === "IMG") {
1771
+ return traverse2(node.childNodes[0].childNodes[0]);
1772
+ }
1773
+ return null;
1774
+ }
1663
1775
  processNode(node) {
1664
1776
  if (!(node instanceof HTMLElement17)) return null;
1665
1777
  if (node.tagName !== "P") return null;
1778
+ const imageNode = this.processImageNode(node) ?? this.processSpanImageNode(node);
1779
+ if (imageNode) return imageNode;
1666
1780
  const jsonNode = createEmptyParagraphNode();
1667
1781
  jsonNode.format = this.extractTextAlignment(node);
1668
1782
  if (node.childNodes.length === 1 && node.childNodes[0] instanceof HTMLElement17 && node.childNodes[0].tagName === "BR")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@examind/block-sdk",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "@comment version": [
5
5
  "Don't specify package version here. It will be injected by publish workflow."
6
6
  ],
@@ -21,7 +21,7 @@
21
21
  "peerDependencies": {
22
22
  "nanoid": ">=3.0.0",
23
23
  "node-html-parser": ">=6.0.0",
24
- "@examind/block-types": "^0.1.19"
24
+ "@examind/block-types": "^0.1.20"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@eslint/js": "^9.17.0",
@@ -36,7 +36,7 @@
36
36
  "tsup": "^8.3.5",
37
37
  "typescript": "^5.7.2",
38
38
  "typescript-eslint": "^8.18.2",
39
- "@examind/block-types": "0.1.19"
39
+ "@examind/block-types": "0.1.20"
40
40
  },
41
41
  "dependencies": {
42
42
  "lodash-es": "4.17.21"