@portabletext/editor 1.21.5 → 1.22.0

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 (53) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  2. package/lib/_chunks-cjs/selector.get-text-before.cjs +4 -4
  3. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  4. package/lib/_chunks-cjs/{util.get-block-start-point.cjs → util.reverse-selection.cjs} +12 -12
  5. package/lib/_chunks-cjs/util.reverse-selection.cjs.map +1 -0
  6. package/lib/_chunks-cjs/util.slice-blocks.cjs +75 -0
  7. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -0
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/selector.get-text-before.js +1 -1
  10. package/lib/_chunks-es/{util.get-block-start-point.js → util.reverse-selection.js} +12 -12
  11. package/lib/_chunks-es/util.reverse-selection.js.map +1 -0
  12. package/lib/_chunks-es/util.slice-blocks.js +76 -0
  13. package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
  14. package/lib/behaviors/index.cjs.map +1 -1
  15. package/lib/behaviors/index.d.cts +57 -0
  16. package/lib/behaviors/index.d.ts +57 -0
  17. package/lib/behaviors/index.js.map +1 -1
  18. package/lib/index.cjs +32 -19
  19. package/lib/index.cjs.map +1 -1
  20. package/lib/index.d.cts +130 -0
  21. package/lib/index.d.ts +130 -0
  22. package/lib/index.js +33 -20
  23. package/lib/index.js.map +1 -1
  24. package/lib/selectors/index.cjs +10 -4
  25. package/lib/selectors/index.cjs.map +1 -1
  26. package/lib/selectors/index.d.cts +5 -0
  27. package/lib/selectors/index.d.ts +5 -0
  28. package/lib/selectors/index.js +9 -2
  29. package/lib/selectors/index.js.map +1 -1
  30. package/lib/utils/index.cjs +4 -3
  31. package/lib/utils/index.cjs.map +1 -1
  32. package/lib/utils/index.d.cts +11 -0
  33. package/lib/utils/index.d.ts +11 -0
  34. package/lib/utils/index.js +3 -1
  35. package/lib/utils/index.js.map +1 -1
  36. package/package.json +11 -11
  37. package/src/behaviors/behavior.markdown.ts +42 -0
  38. package/src/behaviors/behavior.types.ts +15 -0
  39. package/src/editor/Editable.tsx +17 -0
  40. package/src/editor/define-schema.ts +24 -1
  41. package/src/editor/editor-event-listener.tsx +45 -0
  42. package/src/editor/editor-machine.ts +6 -26
  43. package/src/editor/editor-provider.tsx +27 -0
  44. package/src/editor/editor-selector.ts +21 -0
  45. package/src/editor/editor-snapshot.ts +37 -1
  46. package/src/editor/plugins/createWithInsertData.ts +6 -7
  47. package/src/selectors/index.ts +1 -0
  48. package/src/selectors/selector.get-selected-slice.ts +12 -0
  49. package/src/utils/index.ts +1 -0
  50. package/src/utils/util.slice-blocks.test.ts +163 -0
  51. package/src/utils/util.slice-blocks.ts +143 -0
  52. package/lib/_chunks-cjs/util.get-block-start-point.cjs.map +0 -1
  53. package/lib/_chunks-es/util.get-block-start-point.js.map +0 -1
package/lib/index.d.cts CHANGED
@@ -377,6 +377,26 @@ declare type CustomBehaviorEvent<
377
377
 
378
378
  /**
379
379
  * @public
380
+ * A helper wrapper that adds editor support, such as autocomplete and type checking, for a schema definition.
381
+ * @example
382
+ * ```ts
383
+ * import { defineSchema } from '@portabletext/editor'
384
+ *
385
+ * const schemaDefinition = defineSchema({
386
+ * decorators: [{name: 'strong'}, {name: 'em'}, {name: 'underline'}],
387
+ * annotations: [{name: 'link'}],
388
+ * styles: [
389
+ * {name: 'normal'},
390
+ * {name: 'h1'},
391
+ * {name: 'h2'},
392
+ * {name: 'h3'},
393
+ * {name: 'blockquote'},
394
+ * ],
395
+ * lists: [],
396
+ * inlineObjects: [],
397
+ * blockObjects: [],
398
+ * }
399
+ * ```
380
400
  */
381
401
  export declare function defineSchema<
382
402
  const TSchemaDefinition extends SchemaDefinition,
@@ -602,6 +622,51 @@ export declare type EditorEvent =
602
622
 
603
623
  /**
604
624
  * @public
625
+ * Listen for events emitted by the editor. Must be used inside `EditorProvider`. Events available include:
626
+ * - 'blurred'
627
+ * - 'done loading'
628
+ * - 'editable'
629
+ * - 'error'
630
+ * - 'focused'
631
+ * - 'invalid value'
632
+ * - 'loading'
633
+ * - 'mutation'
634
+ * - 'patch'
635
+ * - 'read only'
636
+ * - 'ready'
637
+ * - 'selection'
638
+ * - 'value changed'
639
+ *
640
+ * @example
641
+ * Listen and log events.
642
+ * ```tsx
643
+ * import {EditorEventListener, EditorProvider} from '@portabletext/editor'
644
+ *
645
+ * function MyComponent() {
646
+ * return (
647
+ * <EditorProvider>
648
+ * <EditorEventListener
649
+ * on={(event) => {
650
+ * console.log(event)
651
+ * }
652
+ * } />
653
+ * { ... }
654
+ * </EditorProvider>
655
+ * )
656
+ * }
657
+ * ```
658
+ * @example
659
+ * Handle events when there is a mutation.
660
+ * ```tsx
661
+ * <EditorEventListener
662
+ * on={(event) => {
663
+ * if (event.type === 'mutation') {
664
+ * console.log('Value changed:', event.snapshot)
665
+ * }
666
+ * }}
667
+ * />
668
+ * ```
669
+ * @group Components
605
670
  */
606
671
  export declare function EditorEventListener(props: {
607
672
  on: (event: EditorEmittedEvent) => void
@@ -7565,6 +7630,21 @@ export declare type EditorNode = Node_2 & {
7565
7630
 
7566
7631
  /**
7567
7632
  * @public
7633
+ * The EditorProvider component is used to set up the editor context and configure the Portable Text Editor.
7634
+ * @example
7635
+ * ```tsx
7636
+ * import {EditorProvider} from '@portabletext/editor'
7637
+ *
7638
+ * function App() {
7639
+ * return (
7640
+ * <EditorProvider initialConfig={{ ... }} >
7641
+ * ...
7642
+ * </EditorProvider>
7643
+ * )
7644
+ * }
7645
+ *
7646
+ * ```
7647
+ * @group Components
7568
7648
  */
7569
7649
  export declare function EditorProvider(
7570
7650
  props: EditorProviderProps,
@@ -7984,6 +8064,23 @@ export {PortableTextChild}
7984
8064
 
7985
8065
  /**
7986
8066
  * @public
8067
+ *
8068
+ *
8069
+ * The core component that renders the editor. Must be placed within the {@link EventProvider} component.
8070
+ *
8071
+ * @example
8072
+ * ```tsx
8073
+ * import { PortableTextEditable, EditorProvider } from '@portabletext/editor'
8074
+ *
8075
+ * function MyComponent() {
8076
+ * return (
8077
+ * <EditorProvider>
8078
+ * <PortableTextEditable />
8079
+ * </EditorProvider>
8080
+ * )
8081
+ * }
8082
+ * ```
8083
+ * @group Components
7987
8084
  */
7988
8085
  export declare const PortableTextEditable: ForwardRefExoticComponent<
7989
8086
  Omit<PortableTextEditableProps, 'ref'> &
@@ -8502,11 +8599,44 @@ export declare type UnsetChange = {
8502
8599
 
8503
8600
  /**
8504
8601
  * @public
8602
+ * Get the current editor context from the `EditorProvider`.
8603
+ * Must be used inside the `EditorProvider` component.
8604
+ * @returns The current editor object.
8605
+ * @example
8606
+ * ```tsx
8607
+ * import { useEditor } from '@portabletext/editor'
8608
+ *
8609
+ * function MyComponent() {
8610
+ * const editor = useEditor()
8611
+ * }
8612
+ * ```
8613
+ * @group Hooks
8505
8614
  */
8506
8615
  export declare function useEditor(): Editor
8507
8616
 
8508
8617
  /**
8509
8618
  * @public
8619
+ * Hook to select a value from the editor state.
8620
+ * @example
8621
+ * Pass a selector as the second argument
8622
+ * ```tsx
8623
+ * import { useEditorSelector } from '@portabletext/editor'
8624
+ *
8625
+ * function MyComponent(editor) {
8626
+ * const value = useEditorSelector(editor, selector)
8627
+ * }
8628
+ * ```
8629
+ * @example
8630
+ * Pass an inline selector as the second argument.
8631
+ * In this case, use the editor context to obtain the schema.
8632
+ * ```tsx
8633
+ * import { useEditorSelector } from '@portabletext/editor'
8634
+ *
8635
+ * function MyComponent(editor) {
8636
+ * const schema = useEditorSelector(editor, (snapshot) => snapshot.context.schema)
8637
+ * }
8638
+ * ```
8639
+ * @group Hooks
8510
8640
  */
8511
8641
  export declare function useEditorSelector<TSelected>(
8512
8642
  editor: Editor,
package/lib/index.d.ts CHANGED
@@ -377,6 +377,26 @@ declare type CustomBehaviorEvent<
377
377
 
378
378
  /**
379
379
  * @public
380
+ * A helper wrapper that adds editor support, such as autocomplete and type checking, for a schema definition.
381
+ * @example
382
+ * ```ts
383
+ * import { defineSchema } from '@portabletext/editor'
384
+ *
385
+ * const schemaDefinition = defineSchema({
386
+ * decorators: [{name: 'strong'}, {name: 'em'}, {name: 'underline'}],
387
+ * annotations: [{name: 'link'}],
388
+ * styles: [
389
+ * {name: 'normal'},
390
+ * {name: 'h1'},
391
+ * {name: 'h2'},
392
+ * {name: 'h3'},
393
+ * {name: 'blockquote'},
394
+ * ],
395
+ * lists: [],
396
+ * inlineObjects: [],
397
+ * blockObjects: [],
398
+ * }
399
+ * ```
380
400
  */
381
401
  export declare function defineSchema<
382
402
  const TSchemaDefinition extends SchemaDefinition,
@@ -602,6 +622,51 @@ export declare type EditorEvent =
602
622
 
603
623
  /**
604
624
  * @public
625
+ * Listen for events emitted by the editor. Must be used inside `EditorProvider`. Events available include:
626
+ * - 'blurred'
627
+ * - 'done loading'
628
+ * - 'editable'
629
+ * - 'error'
630
+ * - 'focused'
631
+ * - 'invalid value'
632
+ * - 'loading'
633
+ * - 'mutation'
634
+ * - 'patch'
635
+ * - 'read only'
636
+ * - 'ready'
637
+ * - 'selection'
638
+ * - 'value changed'
639
+ *
640
+ * @example
641
+ * Listen and log events.
642
+ * ```tsx
643
+ * import {EditorEventListener, EditorProvider} from '@portabletext/editor'
644
+ *
645
+ * function MyComponent() {
646
+ * return (
647
+ * <EditorProvider>
648
+ * <EditorEventListener
649
+ * on={(event) => {
650
+ * console.log(event)
651
+ * }
652
+ * } />
653
+ * { ... }
654
+ * </EditorProvider>
655
+ * )
656
+ * }
657
+ * ```
658
+ * @example
659
+ * Handle events when there is a mutation.
660
+ * ```tsx
661
+ * <EditorEventListener
662
+ * on={(event) => {
663
+ * if (event.type === 'mutation') {
664
+ * console.log('Value changed:', event.snapshot)
665
+ * }
666
+ * }}
667
+ * />
668
+ * ```
669
+ * @group Components
605
670
  */
606
671
  export declare function EditorEventListener(props: {
607
672
  on: (event: EditorEmittedEvent) => void
@@ -7565,6 +7630,21 @@ export declare type EditorNode = Node_2 & {
7565
7630
 
7566
7631
  /**
7567
7632
  * @public
7633
+ * The EditorProvider component is used to set up the editor context and configure the Portable Text Editor.
7634
+ * @example
7635
+ * ```tsx
7636
+ * import {EditorProvider} from '@portabletext/editor'
7637
+ *
7638
+ * function App() {
7639
+ * return (
7640
+ * <EditorProvider initialConfig={{ ... }} >
7641
+ * ...
7642
+ * </EditorProvider>
7643
+ * )
7644
+ * }
7645
+ *
7646
+ * ```
7647
+ * @group Components
7568
7648
  */
7569
7649
  export declare function EditorProvider(
7570
7650
  props: EditorProviderProps,
@@ -7984,6 +8064,23 @@ export {PortableTextChild}
7984
8064
 
7985
8065
  /**
7986
8066
  * @public
8067
+ *
8068
+ *
8069
+ * The core component that renders the editor. Must be placed within the {@link EventProvider} component.
8070
+ *
8071
+ * @example
8072
+ * ```tsx
8073
+ * import { PortableTextEditable, EditorProvider } from '@portabletext/editor'
8074
+ *
8075
+ * function MyComponent() {
8076
+ * return (
8077
+ * <EditorProvider>
8078
+ * <PortableTextEditable />
8079
+ * </EditorProvider>
8080
+ * )
8081
+ * }
8082
+ * ```
8083
+ * @group Components
7987
8084
  */
7988
8085
  export declare const PortableTextEditable: ForwardRefExoticComponent<
7989
8086
  Omit<PortableTextEditableProps, 'ref'> &
@@ -8502,11 +8599,44 @@ export declare type UnsetChange = {
8502
8599
 
8503
8600
  /**
8504
8601
  * @public
8602
+ * Get the current editor context from the `EditorProvider`.
8603
+ * Must be used inside the `EditorProvider` component.
8604
+ * @returns The current editor object.
8605
+ * @example
8606
+ * ```tsx
8607
+ * import { useEditor } from '@portabletext/editor'
8608
+ *
8609
+ * function MyComponent() {
8610
+ * const editor = useEditor()
8611
+ * }
8612
+ * ```
8613
+ * @group Hooks
8505
8614
  */
8506
8615
  export declare function useEditor(): Editor
8507
8616
 
8508
8617
  /**
8509
8618
  * @public
8619
+ * Hook to select a value from the editor state.
8620
+ * @example
8621
+ * Pass a selector as the second argument
8622
+ * ```tsx
8623
+ * import { useEditorSelector } from '@portabletext/editor'
8624
+ *
8625
+ * function MyComponent(editor) {
8626
+ * const value = useEditorSelector(editor, selector)
8627
+ * }
8628
+ * ```
8629
+ * @example
8630
+ * Pass an inline selector as the second argument.
8631
+ * In this case, use the editor context to obtain the schema.
8632
+ * ```tsx
8633
+ * import { useEditorSelector } from '@portabletext/editor'
8634
+ *
8635
+ * function MyComponent(editor) {
8636
+ * const schema = useEditorSelector(editor, (snapshot) => snapshot.context.schema)
8637
+ * }
8638
+ * ```
8639
+ * @group Hooks
8510
8640
  */
8511
8641
  export declare function useEditorSelector<TSelected>(
8512
8642
  editor: Editor,
package/lib/index.js CHANGED
@@ -24,7 +24,7 @@ import { createGuards } from "./_chunks-es/selector.is-selection-collapsed.js";
24
24
  import { blockOffsetToSpanSelectionPoint } from "./_chunks-es/util.is-empty-text-block.js";
25
25
  import { coreBehaviors, isCustomBehaviorEvent, isHotkey } from "./_chunks-es/behavior.core.js";
26
26
  import getRandomValues from "get-random-values-esm";
27
- import { htmlToBlocks, normalizeBlock } from "@portabletext/block-tools";
27
+ import { htmlToBlocks } from "@portabletext/block-tools";
28
28
  function createEditorSchema(portableTextType) {
29
29
  if (!portableTextType)
30
30
  throw new Error("Parameter 'portabletextType' missing (required)");
@@ -86,7 +86,7 @@ function compileSchemaDefinition(definition) {
86
86
  // Very naive way to work around `SanitySchema.compile` adding default
87
87
  // fields to objects with the name `image`
88
88
  name: blockObject.name === "image" ? "tmp-image" : blockObject.name,
89
- title: blockObject.title,
89
+ title: blockObject.name === "image" && blockObject.title === void 0 ? "Image" : blockObject.title,
90
90
  fields: []
91
91
  })) ?? [], inlineObjects = definition?.inlineObjects?.map((inlineObject) => defineType({
92
92
  type: "object",
@@ -5580,6 +5580,25 @@ function getActiveDecorators({
5580
5580
  ...Editor.marks(slateEditorInstance) ?? {}
5581
5581
  }.marks ?? []).filter((mark) => decorators.includes(mark));
5582
5582
  }
5583
+ function createEditorSnapshot({
5584
+ editor,
5585
+ keyGenerator,
5586
+ schema
5587
+ }) {
5588
+ const value = fromSlateValue(editor.children, schema.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), selection = toPortableTextRange(value, editor.selection, schema);
5589
+ return {
5590
+ context: {
5591
+ activeDecorators: getActiveDecorators({
5592
+ schema,
5593
+ slateEditorInstance: editor
5594
+ }),
5595
+ keyGenerator,
5596
+ schema,
5597
+ selection,
5598
+ value
5599
+ }
5600
+ };
5601
+ }
5583
5602
  const editorMachine = setup({
5584
5603
  types: {
5585
5604
  context: {},
@@ -5680,26 +5699,21 @@ const editorMachine = setup({
5680
5699
  }), event.editor.onChange();
5681
5700
  return;
5682
5701
  }
5683
- const value = fromSlateValue(event.editor.children, context.schema.block.name, KEY_TO_VALUE_ELEMENT.get(event.editor)), selection = toPortableTextRange(value, event.editor.selection, context.schema), editorContext = {
5684
- activeDecorators: getActiveDecorators({
5685
- schema: context.schema,
5686
- slateEditorInstance: event.editor
5687
- }),
5702
+ const editorSnapshot = createEditorSnapshot({
5703
+ editor: event.editor,
5688
5704
  keyGenerator: context.keyGenerator,
5689
- schema: context.schema,
5690
- selection,
5691
- value
5692
- };
5705
+ schema: context.schema
5706
+ });
5693
5707
  let behaviorOverwritten = !1;
5694
5708
  for (const eventBehavior of eventBehaviors) {
5695
5709
  const shouldRun = eventBehavior.guard === void 0 || eventBehavior.guard({
5696
- context: editorContext,
5710
+ context: editorSnapshot.context,
5697
5711
  event: event.behaviorEvent
5698
5712
  });
5699
5713
  if (!shouldRun)
5700
5714
  continue;
5701
5715
  const actionIntendSets = eventBehavior.actions.map((actionSet) => actionSet({
5702
- context: editorContext,
5716
+ context: editorSnapshot.context,
5703
5717
  event: event.behaviorEvent
5704
5718
  }, shouldRun));
5705
5719
  for (const actionIntends of actionIntendSets)
@@ -6618,18 +6632,17 @@ function createWithInsertData(editorActor, schemaTypes) {
6618
6632
  let portableText, fragment, insertedType;
6619
6633
  if (html) {
6620
6634
  if (portableText = htmlToBlocks(html, schemaTypes.portableText, {
6621
- unstable_whitespaceOnPasteMode: whitespaceOnPasteMode
6622
- }).map((block) => normalizeBlock(block, {
6623
- blockTypeName
6624
- })), fragment = toSlateValue(portableText, {
6635
+ unstable_whitespaceOnPasteMode: whitespaceOnPasteMode,
6636
+ keyGenerator: editorActor.getSnapshot().context.keyGenerator
6637
+ }), fragment = toSlateValue(portableText, {
6625
6638
  schemaTypes
6626
6639
  }), insertedType = "HTML", portableText.length === 0)
6627
6640
  return !1;
6628
6641
  } else {
6629
6642
  const textToHtml = `<html><body>${escapeHtml(text).split(/\n{2,}/).map((line) => line ? `<p>${line.replace(/(?:\r\n|\r|\n)/g, "<br/>")}</p>` : "<p></p>").join("")}</body></html>`;
6630
- portableText = htmlToBlocks(textToHtml, schemaTypes.portableText).map((block) => normalizeBlock(block, {
6631
- blockTypeName
6632
- })), fragment = toSlateValue(portableText, {
6643
+ portableText = htmlToBlocks(textToHtml, schemaTypes.portableText, {
6644
+ keyGenerator: editorActor.getSnapshot().context.keyGenerator
6645
+ }), fragment = toSlateValue(portableText, {
6633
6646
  schemaTypes
6634
6647
  }), insertedType = "text";
6635
6648
  }