@portabletext/editor 3.2.6 → 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.
@@ -1,9 +1,13 @@
1
1
  import React, { createContext } from "react";
2
2
  function getGlobalScope() {
3
- if (typeof globalThis < "u") return globalThis;
4
- if (typeof window < "u") return window;
5
- if (typeof self < "u") return self;
6
- if (typeof global < "u") return global;
3
+ if (typeof globalThis < "u")
4
+ return globalThis;
5
+ if (typeof window < "u")
6
+ return window;
7
+ if (typeof self < "u")
8
+ return self;
9
+ if (typeof global < "u")
10
+ return global;
7
11
  throw new Error("@portabletext/editor: could not locate global scope");
8
12
  }
9
13
  const globalScope = getGlobalScope();
@@ -1 +1 @@
1
- {"version":3,"file":"use-editor.js","sources":["../../src/internal-utils/global-scope.ts","../../src/internal-utils/globally-scoped-context.ts","../../src/editor/editor-context.tsx","../../src/editor/use-editor.ts"],"sourcesContent":["/**\n * Gets the global scope instance in a given environment.\n *\n * The strategy is to return the most modern, and if not, the most common:\n * - The `globalThis` variable is the modern approach to accessing the global scope\n * - The `window` variable is the global scope in a web browser\n * - The `self` variable is the global scope in workers and others\n * - The `global` variable is the global scope in Node.js\n */\nfunction getGlobalScope() {\n if (typeof globalThis !== 'undefined') return globalThis\n if (typeof window !== 'undefined') return window\n if (typeof self !== 'undefined') return self\n if (typeof global !== 'undefined') return global\n\n throw new Error('@portabletext/editor: could not locate global scope')\n}\n\nexport const globalScope = getGlobalScope() as any\n","import {createContext, type Context} from 'react'\nimport {globalScope} from './global-scope'\n\n/**\n * As `@portabletext/editor` is declared as a dependency, and may be\n * duplicated, sometimes across major versions it's critical that vital\n * React Contexts are shared even when there is a duplicate.\n *\n * We have to support a Sanity Plugin being able to call hooks like\n * `useEditor`, and then read the context setup by `sanity`, which calls\n * `EditorProvider`, even if the provider and hook are different instances in\n * memory.\n *\n * For this reason it's vital that all changes to globally scoped providers\n * remain fully backwards compatible.\n */\nexport function createGloballyScopedContext<\n ContextType,\n const T extends ContextType = ContextType,\n>(\n /**\n * Enforce that all Symbol.for keys used for globally scoped contexts have a predictable prefix\n */\n key: `@portabletext/editor/context/${string}`,\n defaultValue: T,\n): Context<ContextType> {\n const symbol = Symbol.for(key)\n\n /**\n * Prevent errors about re-renders on React SSR on Next.js App Router\n */\n if (typeof document === 'undefined') {\n return createContext<ContextType>(defaultValue)\n }\n\n globalScope[symbol] = globalScope[symbol] ?? createContext<T>(defaultValue)\n\n return globalScope[symbol]\n}\n","import type {Editor} from '../editor'\nimport {createGloballyScopedContext} from '../internal-utils/globally-scoped-context'\n\nexport const EditorContext = createGloballyScopedContext<Editor | null>(\n '@portabletext/editor/context/editor',\n null,\n)\n","import React from 'react'\nimport {EditorContext} from './editor-context'\n\n/**\n * @public\n * Get the current editor context from the `EditorProvider`.\n * Must be used inside the `EditorProvider` component.\n * @returns The current editor object.\n * @example\n * ```tsx\n * import { useEditor } from '@portabletext/editor'\n *\n * function MyComponent() {\n * const editor = useEditor()\n * }\n * ```\n * @group Hooks\n */\nexport function useEditor() {\n const editor = React.useContext(EditorContext)\n\n if (!editor) {\n throw new Error('No Editor set. Use EditorProvider to set one.')\n }\n\n return editor\n}\n"],"names":["getGlobalScope","globalThis","window","self","global","Error","globalScope","createGloballyScopedContext","key","defaultValue","symbol","Symbol","for","document","createContext","EditorContext","useEditor","editor","React","useContext"],"mappings":";AASA,SAASA,iBAAiB;AACxB,MAAI,OAAOC,aAAe,IAAa,QAAOA;AAC9C,MAAI,OAAOC,SAAW,IAAa,QAAOA;AAC1C,MAAI,OAAOC,OAAS,IAAa,QAAOA;AACxC,MAAI,OAAOC,SAAW,IAAa,QAAOA;AAE1C,QAAM,IAAIC,MAAM,qDAAqD;AACvE;AAEO,MAAMC,cAAcN,eAAAA;ACFpB,SAASO,4BAOdC,KACAC,cACsB;AACtB,QAAMC,SAASC,OAAOC,IAAIJ,GAAG;AAK7B,SAAI,OAAOK,WAAa,MACfC,cAA2BL,YAAY,KAGhDH,YAAYI,MAAM,IAAIJ,YAAYI,MAAM,KAAKI,cAAiBL,YAAY,GAEnEH,YAAYI,MAAM;AAC3B;ACnCO,MAAMK,gBAAgBR,4BAC3B,uCACA,IACF;ACYO,SAAAS,YAAA;AACL,QAAAC,SAAeC,MAAKC,WAAYJ,aAAa;AAE7C,MAAI,CAACE;AACH,UAAM,IAAIZ,MAAM,+CAA+C;AAChE,SAEMY;AAAM;"}
1
+ {"version":3,"file":"use-editor.js","sources":["../../src/internal-utils/global-scope.ts","../../src/internal-utils/globally-scoped-context.ts","../../src/editor/editor-context.tsx","../../src/editor/use-editor.ts"],"sourcesContent":["/**\n * Gets the global scope instance in a given environment.\n *\n * The strategy is to return the most modern, and if not, the most common:\n * - The `globalThis` variable is the modern approach to accessing the global scope\n * - The `window` variable is the global scope in a web browser\n * - The `self` variable is the global scope in workers and others\n * - The `global` variable is the global scope in Node.js\n */\nfunction getGlobalScope() {\n if (typeof globalThis !== 'undefined') {\n return globalThis\n }\n if (typeof window !== 'undefined') {\n return window\n }\n if (typeof self !== 'undefined') {\n return self\n }\n if (typeof global !== 'undefined') {\n return global\n }\n\n throw new Error('@portabletext/editor: could not locate global scope')\n}\n\nexport const globalScope = getGlobalScope() as any\n","import {createContext, type Context} from 'react'\nimport {globalScope} from './global-scope'\n\n/**\n * As `@portabletext/editor` is declared as a dependency, and may be\n * duplicated, sometimes across major versions it's critical that vital\n * React Contexts are shared even when there is a duplicate.\n *\n * We have to support a Sanity Plugin being able to call hooks like\n * `useEditor`, and then read the context setup by `sanity`, which calls\n * `EditorProvider`, even if the provider and hook are different instances in\n * memory.\n *\n * For this reason it's vital that all changes to globally scoped providers\n * remain fully backwards compatible.\n */\nexport function createGloballyScopedContext<\n ContextType,\n const T extends ContextType = ContextType,\n>(\n /**\n * Enforce that all Symbol.for keys used for globally scoped contexts have a predictable prefix\n */\n key: `@portabletext/editor/context/${string}`,\n defaultValue: T,\n): Context<ContextType> {\n const symbol = Symbol.for(key)\n\n /**\n * Prevent errors about re-renders on React SSR on Next.js App Router\n */\n if (typeof document === 'undefined') {\n return createContext<ContextType>(defaultValue)\n }\n\n globalScope[symbol] = globalScope[symbol] ?? createContext<T>(defaultValue)\n\n return globalScope[symbol]\n}\n","import type {Editor} from '../editor'\nimport {createGloballyScopedContext} from '../internal-utils/globally-scoped-context'\n\nexport const EditorContext = createGloballyScopedContext<Editor | null>(\n '@portabletext/editor/context/editor',\n null,\n)\n","import React from 'react'\nimport {EditorContext} from './editor-context'\n\n/**\n * @public\n * Get the current editor context from the `EditorProvider`.\n * Must be used inside the `EditorProvider` component.\n * @returns The current editor object.\n * @example\n * ```tsx\n * import { useEditor } from '@portabletext/editor'\n *\n * function MyComponent() {\n * const editor = useEditor()\n * }\n * ```\n * @group Hooks\n */\nexport function useEditor() {\n const editor = React.useContext(EditorContext)\n\n if (!editor) {\n throw new Error('No Editor set. Use EditorProvider to set one.')\n }\n\n return editor\n}\n"],"names":["getGlobalScope","globalThis","window","self","global","Error","globalScope","createGloballyScopedContext","key","defaultValue","symbol","Symbol","for","document","createContext","EditorContext","useEditor","editor","React","useContext"],"mappings":";AASA,SAASA,iBAAiB;AACxB,MAAI,OAAOC,aAAe;AACxB,WAAOA;AAET,MAAI,OAAOC,SAAW;AACpB,WAAOA;AAET,MAAI,OAAOC,OAAS;AAClB,WAAOA;AAET,MAAI,OAAOC,SAAW;AACpB,WAAOA;AAGT,QAAM,IAAIC,MAAM,qDAAqD;AACvE;AAEO,MAAMC,cAAcN,eAAAA;ACVpB,SAASO,4BAOdC,KACAC,cACsB;AACtB,QAAMC,SAASC,OAAOC,IAAIJ,GAAG;AAK7B,SAAI,OAAOK,WAAa,MACfC,cAA2BL,YAAY,KAGhDH,YAAYI,MAAM,IAAIJ,YAAYI,MAAM,KAAKI,cAAiBL,YAAY,GAEnEH,YAAYI,MAAM;AAC3B;ACnCO,MAAMK,gBAAgBR,4BAC3B,uCACA,IACF;ACYO,SAAAS,YAAA;AACL,QAAAC,SAAeC,MAAKC,WAAYJ,aAAa;AAE7C,MAAI,CAACE;AACH,UAAM,IAAIZ,MAAM,+CAA+C;AAChE,SAEMY;AAAM;"}
package/lib/index.js CHANGED
@@ -19,6 +19,7 @@ import { setup, fromCallback, assign, and, enqueueActions, emit, assertEvent, ra
19
19
  import { compileSchemaDefinitionToPortableTextMemberSchemaTypes, createPortableTextMemberSchemaTypes, portableTextMemberSchemaTypesToSchema } from "@portabletext/sanity-bridge";
20
20
  import { htmlToBlocks } from "@portabletext/block-tools";
21
21
  import { toHTML } from "@portabletext/to-html";
22
+ import { markdownToPortableText, portableTextToMarkdown } from "@portabletext/markdown";
22
23
  import { Schema } from "@sanity/schema";
23
24
  import flatten from "lodash/flatten.js";
24
25
  import { set, applyAll, unset, insert, setIfMissing, diffMatchPatch as diffMatchPatch$1 } from "@portabletext/patches";
@@ -442,7 +443,15 @@ function getEventNode({
442
443
  slateEditor,
443
444
  event
444
445
  }) {
445
- return DOMEditor.hasTarget(slateEditor, event.target) ? DOMEditor.toSlateNode(slateEditor, event.target) : void 0;
446
+ if (!DOMEditor.hasTarget(slateEditor, event.target))
447
+ return;
448
+ let node;
449
+ try {
450
+ node = DOMEditor.toSlateNode(slateEditor, event.target);
451
+ } catch (error) {
452
+ console.error(error);
453
+ }
454
+ return node;
446
455
  }
447
456
  function getEventPositionBlock({
448
457
  node,
@@ -454,7 +463,15 @@ function getEventPositionBlock({
454
463
  });
455
464
  if (!firstBlock)
456
465
  return;
457
- const firstBlockRect = DOMEditor.toDOMNode(slateEditor, firstBlock).getBoundingClientRect();
466
+ let firstBlockElement;
467
+ try {
468
+ firstBlockElement = DOMEditor.toDOMNode(slateEditor, firstBlock);
469
+ } catch (error) {
470
+ console.error(error);
471
+ }
472
+ if (!firstBlockElement)
473
+ return;
474
+ const firstBlockRect = firstBlockElement.getBoundingClientRect();
458
475
  if (event.pageY < firstBlockRect.top)
459
476
  return "start";
460
477
  const [lastBlock] = getLastBlock({
@@ -462,10 +479,26 @@ function getEventPositionBlock({
462
479
  });
463
480
  if (!lastBlock)
464
481
  return;
465
- const lastBlockRef = DOMEditor.toDOMNode(slateEditor, lastBlock).getBoundingClientRect();
482
+ let lastBlockElement;
483
+ try {
484
+ lastBlockElement = DOMEditor.toDOMNode(slateEditor, lastBlock);
485
+ } catch (error) {
486
+ console.error(error);
487
+ }
488
+ if (!lastBlockElement)
489
+ return;
490
+ const lastBlockRef = lastBlockElement.getBoundingClientRect();
466
491
  if (event.pageY > lastBlockRef.bottom)
467
492
  return "end";
468
- const elementRect = DOMEditor.toDOMNode(slateEditor, node).getBoundingClientRect(), top = elementRect.top, height = elementRect.height;
493
+ let element;
494
+ try {
495
+ element = DOMEditor.toDOMNode(slateEditor, node);
496
+ } catch (error) {
497
+ console.error(error);
498
+ }
499
+ if (!element)
500
+ return;
501
+ const elementRect = element.getBoundingClientRect(), top = elementRect.top, height = elementRect.height;
469
502
  return Math.abs(top - event.pageY) < height / 2 ? "start" : "end";
470
503
  }
471
504
  function getEventSelection({
@@ -2733,6 +2766,57 @@ function createConverterTextHtml(legacySchema) {
2733
2766
  }
2734
2767
  };
2735
2768
  }
2769
+ const converterTextMarkdown = {
2770
+ mimeType: "text/markdown",
2771
+ serialize: ({
2772
+ snapshot,
2773
+ event
2774
+ }) => {
2775
+ if (!snapshot.context.selection)
2776
+ return {
2777
+ type: "serialization.failure",
2778
+ mimeType: "text/markdown",
2779
+ reason: "No selection",
2780
+ originEvent: event.originEvent
2781
+ };
2782
+ const blocks = getSelectedValue(snapshot);
2783
+ return {
2784
+ type: "serialization.success",
2785
+ data: portableTextToMarkdown(blocks),
2786
+ mimeType: "text/markdown",
2787
+ originEvent: event.originEvent
2788
+ };
2789
+ },
2790
+ deserialize: ({
2791
+ snapshot,
2792
+ event
2793
+ }) => {
2794
+ const parsedBlocks = markdownToPortableText(event.data, {
2795
+ keyGenerator: snapshot.context.keyGenerator,
2796
+ schema: snapshot.context.schema
2797
+ }).flatMap((block) => {
2798
+ const parsedBlock = parseBlock({
2799
+ context: snapshot.context,
2800
+ block,
2801
+ options: {
2802
+ normalize: !1,
2803
+ removeUnusedMarkDefs: !0,
2804
+ validateFields: !1
2805
+ }
2806
+ });
2807
+ return parsedBlock ? [parsedBlock] : [];
2808
+ });
2809
+ return parsedBlocks.length === 0 ? {
2810
+ type: "deserialization.failure",
2811
+ mimeType: "text/markdown",
2812
+ reason: "No blocks deserialized"
2813
+ } : {
2814
+ type: "deserialization.success",
2815
+ data: parsedBlocks,
2816
+ mimeType: "text/markdown"
2817
+ };
2818
+ }
2819
+ };
2736
2820
  function createConverterTextPlain(legacySchema) {
2737
2821
  return {
2738
2822
  mimeType: "text/plain",
@@ -2796,7 +2880,7 @@ function escapeHtml(str) {
2796
2880
  return String(str).replace(/[&<>"'`=/]/g, (s) => entityMap[s]);
2797
2881
  }
2798
2882
  function createCoreConverters(legacySchema) {
2799
- return [converterJson, converterPortableText, createConverterTextHtml(legacySchema), createConverterTextPlain(legacySchema)];
2883
+ return [converterJson, converterPortableText, converterTextMarkdown, createConverterTextHtml(legacySchema), createConverterTextPlain(legacySchema)];
2800
2884
  }
2801
2885
  function compileType(rawType) {
2802
2886
  return Schema.compile({
@@ -6581,7 +6665,8 @@ function applyOperationToPortableTextImmutable(context, root, operation) {
6581
6665
  offset,
6582
6666
  text
6583
6667
  } = operation;
6584
- if (text.length === 0) return root;
6668
+ if (text.length === 0)
6669
+ return root;
6585
6670
  const span = getSpan(context, root, path);
6586
6671
  if (!span)
6587
6672
  return root;
@@ -8606,41 +8691,37 @@ const abstractAnnotationBehaviors = [defineBehavior({
8606
8691
  ...event,
8607
8692
  type: "delete"
8608
8693
  })]]
8609
- })], abstractDeserializeBehaviors = [
8694
+ })], mimeTypePriority = ["application/x-portable-text", "application/json", "text/markdown", "text/html", "text/plain"];
8695
+ function getFirstAvailableData({
8696
+ dataTransfer,
8697
+ startAfter
8698
+ }) {
8699
+ const startIndex = startAfter ? mimeTypePriority.indexOf(startAfter) + 1 : 0;
8700
+ for (let index = startIndex; index < mimeTypePriority.length; index++) {
8701
+ const mimeType = mimeTypePriority.at(index);
8702
+ if (!mimeType)
8703
+ continue;
8704
+ const data = dataTransfer.getData(mimeType);
8705
+ if (data)
8706
+ return {
8707
+ mimeType,
8708
+ data
8709
+ };
8710
+ }
8711
+ }
8712
+ const abstractDeserializeBehaviors = [
8610
8713
  defineBehavior({
8611
8714
  on: "deserialize",
8612
8715
  guard: ({
8613
8716
  event
8614
8717
  }) => {
8615
- const portableText = event.originEvent.originEvent.dataTransfer.getData("application/x-portable-text");
8616
- if (portableText)
8617
- return {
8618
- type: "deserialize.data",
8619
- mimeType: "application/x-portable-text",
8620
- data: portableText,
8621
- originEvent: event.originEvent
8622
- };
8623
- const json = event.originEvent.originEvent.dataTransfer.getData("application/json");
8624
- if (json)
8625
- return {
8626
- type: "deserialize.data",
8627
- mimeType: "application/json",
8628
- data: json,
8629
- originEvent: event.originEvent
8630
- };
8631
- const html = event.originEvent.originEvent.dataTransfer.getData("text/html");
8632
- if (html)
8633
- return {
8634
- type: "deserialize.data",
8635
- mimeType: "text/html",
8636
- data: html,
8637
- originEvent: event.originEvent
8638
- };
8639
- const text = event.originEvent.originEvent.dataTransfer.getData("text/plain");
8640
- return text ? {
8718
+ const availableData = getFirstAvailableData({
8719
+ dataTransfer: event.originEvent.originEvent.dataTransfer
8720
+ });
8721
+ return availableData ? {
8641
8722
  type: "deserialize.data",
8642
- mimeType: "text/plain",
8643
- data: text,
8723
+ mimeType: availableData.mimeType,
8724
+ data: availableData.data,
8644
8725
  originEvent: event.originEvent
8645
8726
  } : !1;
8646
8727
  },
@@ -8747,37 +8828,18 @@ const abstractAnnotationBehaviors = [defineBehavior({
8747
8828
  guard: ({
8748
8829
  event
8749
8830
  }) => {
8750
- if (event.mimeType === "application/x-portable-text") {
8751
- const json = event.originEvent.originEvent.dataTransfer.getData("application/json");
8752
- if (json)
8753
- return {
8754
- type: "deserialize.data",
8755
- mimeType: "application/json",
8756
- data: json,
8757
- originEvent: event.originEvent
8758
- };
8759
- }
8760
- if (event.mimeType === "application/json") {
8761
- const html = event.originEvent.originEvent.dataTransfer.getData("text/html");
8762
- if (html)
8763
- return {
8764
- type: "deserialize.data",
8765
- mimeType: "text/html",
8766
- data: html,
8767
- originEvent: event.originEvent
8768
- };
8769
- }
8770
- if (event.mimeType === "text/html") {
8771
- const text = event.originEvent.originEvent.dataTransfer.getData("text/plain");
8772
- if (text)
8773
- return {
8774
- type: "deserialize.data",
8775
- mimeType: "text/plain",
8776
- data: text,
8777
- originEvent: event.originEvent
8778
- };
8779
- }
8780
- return !1;
8831
+ if (event.mimeType === "*/*")
8832
+ return !1;
8833
+ const availableData = getFirstAvailableData({
8834
+ dataTransfer: event.originEvent.originEvent.dataTransfer,
8835
+ startAfter: event.mimeType
8836
+ });
8837
+ return availableData ? {
8838
+ type: "deserialize.data",
8839
+ mimeType: availableData.mimeType,
8840
+ data: availableData.data,
8841
+ originEvent: event.originEvent
8842
+ } : !1;
8781
8843
  },
8782
8844
  actions: [(_, deserializeDataEvent) => [raise(deserializeDataEvent)]]
8783
8845
  }),
@@ -12793,7 +12855,8 @@ class PortableTextEditor extends Component {
12793
12855
  static insertBreak = (editor) => editor.editable?.insertBreak();
12794
12856
  static isVoid = (editor, element) => editor.editable?.isVoid(element);
12795
12857
  static isObjectPath = (_editor, path) => {
12796
- if (!path || !Array.isArray(path)) return !1;
12858
+ if (!path || !Array.isArray(path))
12859
+ return !1;
12797
12860
  const isChildObjectEditPath = path.length > 3 && path[1] === "children";
12798
12861
  return path.length > 1 && path[1] !== "children" || isChildObjectEditPath;
12799
12862
  };