@portabletext/block-tools 3.2.1 → 3.3.1

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016 - 2024 Sanity.io
3
+ Copyright (c) 2016 - 2025 Sanity.io
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/lib/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanityBridge = require("@portabletext/sanity-bridge"), flatten = require("lodash/flatten.js"), isEqual = require("lodash/isEqual.js"), uniq = require("lodash/uniq.js"), getRandomValues = require("get-random-values-esm");
3
+ var sanityBridge = require("@portabletext/sanity-bridge"), flatten = require("lodash/flatten.js"), getRandomValues = require("get-random-values-esm"), isEqual = require("lodash/isEqual.js"), uniq = require("lodash/uniq.js");
4
4
  function _interopDefaultCompat(e) {
5
5
  return e && typeof e == "object" && "default" in e ? e : { default: e };
6
6
  }
7
- var flatten__default = /* @__PURE__ */ _interopDefaultCompat(flatten), isEqual__default = /* @__PURE__ */ _interopDefaultCompat(isEqual), uniq__default = /* @__PURE__ */ _interopDefaultCompat(uniq), getRandomValues__default = /* @__PURE__ */ _interopDefaultCompat(getRandomValues);
7
+ var flatten__default = /* @__PURE__ */ _interopDefaultCompat(flatten), getRandomValues__default = /* @__PURE__ */ _interopDefaultCompat(getRandomValues), isEqual__default = /* @__PURE__ */ _interopDefaultCompat(isEqual), uniq__default = /* @__PURE__ */ _interopDefaultCompat(uniq);
8
8
  function isArbitraryTypedObject(object) {
9
9
  return isRecord(object) && typeof object._type == "string";
10
10
  }
@@ -17,6 +17,19 @@ function isTextBlock(schema, block) {
17
17
  function isSpan(schema, child) {
18
18
  return !(!isArbitraryTypedObject(child) || child._type !== schema.span.name || typeof child.text != "string");
19
19
  }
20
+ function keyGenerator() {
21
+ return randomKey(12);
22
+ }
23
+ function whatwgRNG(length = 16) {
24
+ const rnds8 = new Uint8Array(length);
25
+ return getRandomValues__default.default(rnds8), rnds8;
26
+ }
27
+ const byteToHex = [];
28
+ for (let i = 0; i < 256; ++i)
29
+ byteToHex[i] = (i + 256).toString(16).slice(1);
30
+ function randomKey(length) {
31
+ return whatwgRNG(length).reduce((str, n) => str + byteToHex[n], "").slice(0, length);
32
+ }
20
33
  const objectToString = Object.prototype.toString;
21
34
  function resolveJsType(val) {
22
35
  switch (objectToString.call(val)) {
@@ -298,12 +311,67 @@ function defaultParseHtml() {
298
311
  );
299
312
  return (html) => new DOMParser().parseFromString(html, "text/html");
300
313
  }
301
- function flattenNestedBlocks(schema, blocks2) {
314
+ function flattenNestedBlocks(context, blocks2) {
302
315
  let depth = 0;
303
316
  const flattened = [], traverse = (nodes) => {
304
317
  const toRemove = [];
305
318
  nodes.forEach((node) => {
306
- depth === 0 && flattened.push(node), isTextBlock(schema, node) && (depth > 0 && (toRemove.push(node), flattened.push(node)), depth++, traverse(node.children)), node._type === "__block" && (toRemove.push(node), flattened.push(node.block));
319
+ if (depth === 0)
320
+ if (context.schema.blockObjects.length > 0 && isTextBlock(context.schema, node)) {
321
+ const hasBlockObjects = node.children.some((child) => context.schema.blockObjects.some(
322
+ (blockObject) => blockObject.name === child._type
323
+ )), hasBlocks = node.children.some(
324
+ (child) => child._type === "__block"
325
+ );
326
+ if (hasBlockObjects || hasBlocks) {
327
+ node.children.reduce(
328
+ (slices, child) => {
329
+ const knownInlineObject = context.schema.inlineObjects.some(
330
+ (inlineObject) => inlineObject.name === child._type
331
+ ), knownBlockObject = context.schema.blockObjects.some(
332
+ (blockObject) => blockObject.name === child._type
333
+ ), lastSlice = slices.pop();
334
+ return !isSpan(context.schema, child) && !knownInlineObject && knownBlockObject ? [
335
+ ...slices,
336
+ ...lastSlice ? [lastSlice] : [],
337
+ { type: "block object", block: child }
338
+ ] : child._type === "__block" ? [
339
+ ...slices,
340
+ ...lastSlice ? [lastSlice] : [],
341
+ {
342
+ type: "block object",
343
+ block: child.block
344
+ }
345
+ ] : lastSlice && lastSlice.type === "children" ? [
346
+ ...slices,
347
+ {
348
+ type: "children",
349
+ children: [...lastSlice.children, child]
350
+ }
351
+ ] : [
352
+ ...slices,
353
+ ...lastSlice ? [lastSlice] : [],
354
+ { type: "children", children: [child] }
355
+ ];
356
+ },
357
+ []
358
+ ).forEach((slice) => {
359
+ if (slice.type === "block object")
360
+ flattened.push(slice.block);
361
+ else if (slice.children.length > 0) {
362
+ const newBlock = {
363
+ ...node,
364
+ children: slice.children
365
+ };
366
+ flattened.push(newBlock);
367
+ }
368
+ });
369
+ return;
370
+ } else
371
+ flattened.push(node);
372
+ } else
373
+ flattened.push(node);
374
+ isTextBlock(context.schema, node) && (depth > 0 && (toRemove.push(node), flattened.push(node)), depth++, traverse(node.children)), node._type === "__block" && (toRemove.push(node), flattened.push(node.block));
307
375
  }), toRemove.forEach((node) => {
308
376
  nodes.splice(nodes.indexOf(node), 1);
309
377
  }), depth--;
@@ -453,8 +521,10 @@ function getBlockStyle(schema, el) {
453
521
  function createGDocsRules(schema) {
454
522
  return [
455
523
  {
456
- deserialize(el) {
524
+ deserialize(el, next) {
457
525
  if (isElement(el) && tagName(el) === "span" && isGoogleDocs(el)) {
526
+ if (!el.textContent)
527
+ return !el.previousSibling && !el.nextSibling && el.setAttribute("data-lonely-child", "true"), next(el.childNodes);
458
528
  const span = {
459
529
  ...DEFAULT_SPAN,
460
530
  marks: [],
@@ -497,19 +567,6 @@ function createGDocsRules(schema) {
497
567
  }
498
568
  ];
499
569
  }
500
- function keyGenerator() {
501
- return randomKey(12);
502
- }
503
- function whatwgRNG(length = 16) {
504
- const rnds8 = new Uint8Array(length);
505
- return getRandomValues__default.default(rnds8), rnds8;
506
- }
507
- const byteToHex = [];
508
- for (let i = 0; i < 256; ++i)
509
- byteToHex[i] = (i + 256).toString(16).slice(1);
510
- function randomKey(length) {
511
- return whatwgRNG(length).reduce((str, n) => str + byteToHex[n], "").slice(0, length);
512
- }
513
570
  const whitespaceTextNodeRule = {
514
571
  deserialize(node) {
515
572
  return node.nodeName === "#text" && isWhitespaceTextNode(node) ? {
@@ -682,6 +739,62 @@ function createHTMLRules(schema, options) {
682
739
  children: next(el.childNodes)
683
740
  } : el.appendChild(el.ownerDocument.createTextNode(` (${href})`)) && next(el.childNodes) : next(el.childNodes);
684
741
  }
742
+ },
743
+ {
744
+ deserialize(el) {
745
+ if (isElement(el) && tagName(el) === "img") {
746
+ const src = el.getAttribute("src") ?? void 0, alt = el.getAttribute("alt") ?? void 0, props = Object.fromEntries(
747
+ Array.from(el.attributes).map((attr) => [attr.name, attr.value])
748
+ ), ancestorOfLonelyChild = el?.parentElement?.parentElement?.getAttribute("data-lonely-child"), ancestorOfListItem = el.closest("li") !== null;
749
+ if (ancestorOfLonelyChild && !ancestorOfListItem) {
750
+ const image2 = options.matchers?.image?.({
751
+ context: {
752
+ schema,
753
+ keyGenerator: options.keyGenerator ?? keyGenerator
754
+ },
755
+ props: {
756
+ ...props,
757
+ ...src ? { src } : {},
758
+ ...alt ? { alt } : {}
759
+ }
760
+ });
761
+ if (image2)
762
+ return {
763
+ _type: "__block",
764
+ block: image2
765
+ };
766
+ }
767
+ const inlineImage = options.matchers?.inlineImage?.({
768
+ context: {
769
+ schema,
770
+ keyGenerator: options.keyGenerator ?? keyGenerator
771
+ },
772
+ props: {
773
+ ...props,
774
+ ...src ? { src } : {},
775
+ ...alt ? { alt } : {}
776
+ }
777
+ });
778
+ if (inlineImage)
779
+ return inlineImage;
780
+ const image = options.matchers?.image?.({
781
+ context: {
782
+ schema,
783
+ keyGenerator: options.keyGenerator ?? keyGenerator
784
+ },
785
+ props: {
786
+ ...props,
787
+ ...src ? { src } : {},
788
+ ...alt ? { alt } : {}
789
+ }
790
+ });
791
+ if (image)
792
+ return {
793
+ _type: "__block",
794
+ block: image
795
+ };
796
+ }
797
+ }
685
798
  }
686
799
  ];
687
800
  }
@@ -759,6 +872,7 @@ function createRules(schema, options) {
759
872
  ];
760
873
  }
761
874
  class HtmlDeserializer {
875
+ keyGenerator;
762
876
  schema;
763
877
  rules;
764
878
  parseHtml;
@@ -771,9 +885,10 @@ class HtmlDeserializer {
771
885
  */
772
886
  constructor(schema, options = {}) {
773
887
  const { rules = [], unstable_whitespaceOnPasteMode = "preserve" } = options, standardRules = createRules(schema, {
774
- keyGenerator: options.keyGenerator
888
+ keyGenerator: options.keyGenerator,
889
+ matchers: options.matchers
775
890
  });
776
- this.schema = schema, this.rules = [...rules, ...standardRules];
891
+ this.schema = schema, this.keyGenerator = options.keyGenerator ?? keyGenerator, this.rules = [...rules, ...standardRules];
777
892
  const parseHtml = options.parseHtml || defaultParseHtml();
778
893
  this.parseHtml = (html) => preprocess(html, parseHtml, { unstable_whitespaceOnPasteMode }).body;
779
894
  }
@@ -788,8 +903,11 @@ class HtmlDeserializer {
788
903
  const { parseHtml } = this, fragment = parseHtml(html), children = Array.from(fragment.childNodes), blocks2 = trimWhitespace(
789
904
  this.schema,
790
905
  flattenNestedBlocks(
791
- this.schema,
792
- ensureRootIsBlocks(this.schema, this.deserializeElements(children))
906
+ { schema: this.schema },
907
+ ensureRootIsBlocks(
908
+ this.schema,
909
+ this.deserializeElements(children)
910
+ )
793
911
  )
794
912
  );
795
913
  return this._markDefs.length > 0 && blocks2.filter((block) => isTextBlock(this.schema, block)).forEach((block) => {