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