@portabletext/editor 1.39.0 → 1.40.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 (109) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +16 -5
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/editor-provider.cjs +158 -153
  4. package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
  5. package/lib/_chunks-cjs/selector.get-text-before.cjs +0 -1
  6. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  7. package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs +0 -3
  8. package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -1
  9. package/lib/_chunks-cjs/selector.is-overlapping-selection.cjs +0 -4
  10. package/lib/_chunks-cjs/selector.is-overlapping-selection.cjs.map +1 -1
  11. package/lib/_chunks-cjs/{parse-blocks.cjs → util.selection-point-to-block-offset.cjs} +74 -4
  12. package/lib/_chunks-cjs/util.selection-point-to-block-offset.cjs.map +1 -0
  13. package/lib/_chunks-cjs/util.slice-blocks.cjs +2 -2
  14. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  15. package/lib/_chunks-cjs/util.split-text-block.cjs +68 -0
  16. package/lib/_chunks-cjs/util.split-text-block.cjs.map +1 -0
  17. package/lib/_chunks-es/behavior.core.js +17 -6
  18. package/lib/_chunks-es/behavior.core.js.map +1 -1
  19. package/lib/_chunks-es/editor-provider.js +155 -150
  20. package/lib/_chunks-es/editor-provider.js.map +1 -1
  21. package/lib/_chunks-es/selector.get-text-before.js +1 -2
  22. package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
  23. package/lib/_chunks-es/selector.is-at-the-start-of-block.js +1 -4
  24. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
  25. package/lib/_chunks-es/selector.is-overlapping-selection.js +1 -5
  26. package/lib/_chunks-es/selector.is-overlapping-selection.js.map +1 -1
  27. package/lib/_chunks-es/{parse-blocks.js → util.selection-point-to-block-offset.js} +76 -5
  28. package/lib/_chunks-es/util.selection-point-to-block-offset.js.map +1 -0
  29. package/lib/_chunks-es/util.slice-blocks.js +2 -2
  30. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  31. package/lib/_chunks-es/util.split-text-block.js +70 -0
  32. package/lib/_chunks-es/util.split-text-block.js.map +1 -0
  33. package/lib/behaviors/index.d.cts +1516 -911
  34. package/lib/behaviors/index.d.ts +1516 -911
  35. package/lib/index.cjs +197 -200
  36. package/lib/index.cjs.map +1 -1
  37. package/lib/index.d.cts +1247 -717
  38. package/lib/index.d.ts +1247 -717
  39. package/lib/index.js +204 -207
  40. package/lib/index.js.map +1 -1
  41. package/lib/plugins/index.cjs +11 -12
  42. package/lib/plugins/index.cjs.map +1 -1
  43. package/lib/plugins/index.d.cts +1238 -721
  44. package/lib/plugins/index.d.ts +1238 -721
  45. package/lib/plugins/index.js +3 -4
  46. package/lib/plugins/index.js.map +1 -1
  47. package/lib/selectors/index.d.cts +1237 -710
  48. package/lib/selectors/index.d.ts +1237 -710
  49. package/lib/utils/index.cjs +15 -87
  50. package/lib/utils/index.cjs.map +1 -1
  51. package/lib/utils/index.d.cts +1290 -713
  52. package/lib/utils/index.d.ts +1290 -713
  53. package/lib/utils/index.js +13 -86
  54. package/lib/utils/index.js.map +1 -1
  55. package/package.json +10 -10
  56. package/src/behavior-actions/behavior.action.decorator.add.ts +13 -2
  57. package/src/behaviors/behavior.core.block-objects.ts +32 -2
  58. package/src/behaviors/behavior.default.ts +59 -16
  59. package/src/behaviors/behavior.types.ts +67 -30
  60. package/src/editor/Editable.tsx +122 -68
  61. package/src/editor/PortableTextEditor.tsx +8 -8
  62. package/src/editor/__tests__/self-solving.test.tsx +1 -1
  63. package/src/editor/components/Element.tsx +1 -3
  64. package/src/editor/create-editor.ts +13 -5
  65. package/src/editor/editor-machine.ts +13 -3
  66. package/src/editor/editor-provider.tsx +11 -7
  67. package/src/editor/editor-selector.ts +4 -3
  68. package/src/editor/editor-snapshot.ts +2 -2
  69. package/src/editor/plugins/create-with-event-listeners.ts +18 -3
  70. package/src/editor/plugins/createWithPortableTextMarkModel.ts +1 -2
  71. package/src/internal-utils/block-keys.ts +9 -0
  72. package/src/internal-utils/collapse-selection.ts +36 -0
  73. package/src/internal-utils/compound-client-rect.ts +28 -0
  74. package/src/internal-utils/drag-selection.test.ts +507 -0
  75. package/src/internal-utils/drag-selection.ts +66 -0
  76. package/src/internal-utils/editor-selection.test.ts +40 -0
  77. package/src/internal-utils/editor-selection.ts +60 -0
  78. package/src/internal-utils/event-position.ts +55 -80
  79. package/src/internal-utils/inline-object-selection.ts +115 -0
  80. package/src/internal-utils/selection-block-keys.ts +20 -0
  81. package/src/internal-utils/selection-elements.ts +61 -0
  82. package/src/internal-utils/selection-focus-text.ts +38 -0
  83. package/src/internal-utils/selection-text.test.ts +23 -0
  84. package/src/internal-utils/selection-text.ts +90 -0
  85. package/src/internal-utils/split-string.ts +12 -0
  86. package/src/internal-utils/string-overlap.test.ts +14 -0
  87. package/src/internal-utils/string-overlap.ts +28 -0
  88. package/src/internal-utils/string-utils.ts +7 -0
  89. package/src/internal-utils/terse-pt.test.ts +60 -0
  90. package/src/internal-utils/terse-pt.ts +36 -0
  91. package/src/internal-utils/text-block-key.test.ts +30 -0
  92. package/src/internal-utils/text-block-key.ts +30 -0
  93. package/src/internal-utils/text-marks.test.ts +33 -0
  94. package/src/internal-utils/text-marks.ts +26 -0
  95. package/src/internal-utils/text-selection.test.ts +175 -0
  96. package/src/internal-utils/text-selection.ts +122 -0
  97. package/src/internal-utils/value-annotations.ts +31 -0
  98. package/src/internal-utils/values.ts +16 -5
  99. package/src/utils/index.ts +5 -0
  100. package/src/utils/util.block-offset-to-block-selection-point.ts +28 -0
  101. package/src/utils/util.block-offset-to-selection-point.ts +33 -0
  102. package/src/utils/util.block-offsets-to-selection.ts +3 -3
  103. package/src/utils/util.is-equal-selections.ts +20 -0
  104. package/src/utils/util.is-selection-collapsed.ts +15 -0
  105. package/src/utils/util.reverse-selection.ts +9 -5
  106. package/src/utils/util.selection-point-to-block-offset.ts +31 -0
  107. package/lib/_chunks-cjs/parse-blocks.cjs.map +0 -1
  108. package/lib/_chunks-es/parse-blocks.js.map +0 -1
  109. package/src/editor/components/use-draggable.ts +0 -123
@@ -3,20 +3,24 @@ import type {EditorSelection} from '../types/editor'
3
3
  /**
4
4
  * @public
5
5
  */
6
- export function reverseSelection(
7
- selection: NonNullable<EditorSelection>,
8
- ): NonNullable<EditorSelection> {
6
+ export function reverseSelection<
7
+ TEditorSelection extends NonNullable<EditorSelection> | null,
8
+ >(selection: TEditorSelection): TEditorSelection {
9
+ if (!selection) {
10
+ return selection
11
+ }
12
+
9
13
  if (selection.backward) {
10
14
  return {
11
15
  anchor: selection.focus,
12
16
  focus: selection.anchor,
13
17
  backward: false,
14
- }
18
+ } as TEditorSelection
15
19
  }
16
20
 
17
21
  return {
18
22
  anchor: selection.focus,
19
23
  focus: selection.anchor,
20
24
  backward: true,
21
- }
25
+ } as TEditorSelection
22
26
  }
@@ -0,0 +1,31 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {BlockOffset} from '../types/block-offset'
3
+ import type {EditorSelectionPoint} from '../types/editor'
4
+ import {childSelectionPointToBlockOffset} from './util.child-selection-point-to-block-offset'
5
+ import {isKeyedSegment} from './util.is-keyed-segment'
6
+
7
+ /**
8
+ * @public
9
+ */
10
+ export function selectionPointToBlockOffset({
11
+ value,
12
+ selectionPoint,
13
+ }: {
14
+ value: Array<PortableTextBlock>
15
+ selectionPoint: EditorSelectionPoint
16
+ }): BlockOffset | undefined {
17
+ if (
18
+ selectionPoint.path.length === 1 &&
19
+ isKeyedSegment(selectionPoint.path[0])
20
+ ) {
21
+ return {
22
+ path: [{_key: selectionPoint.path[0]._key}],
23
+ offset: selectionPoint.offset,
24
+ }
25
+ }
26
+
27
+ return childSelectionPointToBlockOffset({
28
+ value,
29
+ selectionPoint,
30
+ })
31
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"parse-blocks.cjs","sources":["../../src/utils/util.block-offsets-to-selection.ts","../../src/internal-utils/asserters.ts","../../src/internal-utils/parse-blocks.ts"],"sourcesContent":["import type {PortableTextBlock} from '@sanity/types'\nimport type {EditorSelection} from '..'\nimport type {BlockOffset} from '../types/block-offset'\nimport {blockOffsetToSpanSelectionPoint} from './util.block-offset'\n\n/**\n * @public\n */\nexport function blockOffsetsToSelection({\n value,\n offsets,\n backward,\n}: {\n value: Array<PortableTextBlock>\n offsets: {anchor: BlockOffset; focus: BlockOffset}\n backward?: boolean\n}): EditorSelection {\n const anchor = blockOffsetToSpanSelectionPoint({\n value,\n blockOffset: offsets.anchor,\n direction: backward ? 'backward' : 'forward',\n })\n const focus = blockOffsetToSpanSelectionPoint({\n value,\n blockOffset: offsets.focus,\n direction: backward ? 'forward' : 'backward',\n })\n\n if (!anchor || !focus) {\n return null\n }\n\n return {\n anchor,\n focus,\n backward,\n }\n}\n","import type {TypedObject} from '@sanity/types'\n\nexport function isTypedObject(object: unknown): object is TypedObject {\n return isRecord(object) && typeof object._type === 'string'\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && (typeof value === 'object' || typeof value === 'function')\n}\n","import type {\n PortableTextBlock,\n PortableTextObject,\n PortableTextSpan,\n PortableTextTextBlock,\n} from '@sanity/types'\nimport type {EditorSchema} from '../editor/define-schema'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isTypedObject} from './asserters'\n\nexport function parseBlocks({\n context,\n blocks,\n options,\n}: {\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n blocks: unknown\n options: {\n refreshKeys: boolean\n }\n}): Array<PortableTextBlock> {\n if (!Array.isArray(blocks)) {\n return []\n }\n\n return blocks.flatMap((block) => {\n const parsedBlock = parseBlock({context, block, options})\n\n return parsedBlock ? [parsedBlock] : []\n })\n}\n\nexport function parseBlock({\n context,\n block,\n options,\n}: {\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n block: unknown\n options: {\n refreshKeys: boolean\n }\n}): PortableTextBlock | undefined {\n return (\n parseTextBlock({block, context, options}) ??\n parseBlockObject({blockObject: block, context, options})\n )\n}\n\nfunction parseBlockObject({\n blockObject,\n context,\n options,\n}: {\n blockObject: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextObject | undefined {\n if (!isTypedObject(blockObject)) {\n return undefined\n }\n\n if (\n blockObject._type === context.schema.block.name ||\n blockObject._type === 'block' ||\n !context.schema.blockObjects.some(({name}) => name === blockObject._type)\n ) {\n return undefined\n }\n\n return {\n ...blockObject,\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof blockObject._key === 'string'\n ? blockObject._key\n : context.keyGenerator(),\n }\n}\n\nexport function isTextBlock(\n schema: EditorSchema,\n block: unknown,\n): block is PortableTextTextBlock {\n return (\n parseTextBlock({\n block,\n context: {schema, keyGenerator: () => ''},\n options: {refreshKeys: false},\n }) !== undefined\n )\n}\n\nfunction parseTextBlock({\n block,\n context,\n options,\n}: {\n block: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextTextBlock | undefined {\n if (!isTypedObject(block)) {\n return undefined\n }\n\n if (block._type !== context.schema.block.name) {\n return undefined\n }\n\n const _key = options.refreshKeys\n ? context.keyGenerator()\n : typeof block._key === 'string'\n ? block._key\n : context.keyGenerator()\n\n const unparsedMarkDefs: Array<unknown> = Array.isArray(block.markDefs)\n ? block.markDefs\n : []\n const markDefKeyMap = new Map<string, string>()\n const markDefs = unparsedMarkDefs.flatMap((markDef) => {\n if (!isTypedObject(markDef)) {\n return []\n }\n\n if (typeof markDef._key !== 'string') {\n return []\n }\n\n if (\n context.schema.annotations.some(\n (annotation) => annotation.name === markDef._type,\n )\n ) {\n const _key = options.refreshKeys ? context.keyGenerator() : markDef._key\n markDefKeyMap.set(markDef._key, _key)\n\n return [\n {\n ...markDef,\n _key,\n },\n ]\n }\n\n return []\n })\n\n const unparsedChildren: Array<unknown> = Array.isArray(block.children)\n ? block.children\n : []\n\n const children = unparsedChildren\n .map(\n (child) =>\n parseSpan({span: child, context, markDefKeyMap, options}) ??\n parseInlineObject({inlineObject: child, context, options}),\n )\n .filter((child) => child !== undefined)\n\n const parsedBlock: PortableTextTextBlock = {\n // Spread the entire block to allow custom properties on it\n ...block,\n _key,\n children:\n children.length > 0\n ? children\n : [\n {\n _key: context.keyGenerator(),\n _type: context.schema.span.name,\n text: '',\n marks: [],\n },\n ],\n markDefs,\n }\n\n /**\n * Reset text block .style if it's somehow set to an invalid type\n */\n if (\n typeof parsedBlock.style !== 'string' ||\n !context.schema.styles.find((style) => style.value === block.style)\n ) {\n const defaultStyle = context.schema.styles.at(0)?.value\n\n if (defaultStyle !== undefined) {\n parsedBlock.style = defaultStyle\n } else {\n delete parsedBlock.style\n }\n }\n\n /**\n * Reset text block .listItem if it's somehow set to an invalid type\n */\n if (\n typeof parsedBlock.listItem !== 'string' ||\n !context.schema.lists.find((list) => list.value === block.listItem)\n ) {\n delete parsedBlock.listItem\n }\n\n /**\n * Reset text block .level if it's somehow set to an invalid type\n */\n if (typeof parsedBlock.level !== 'number') {\n delete parsedBlock.level\n }\n\n return parsedBlock\n}\n\nexport function parseSpan({\n span,\n context,\n markDefKeyMap,\n options,\n}: {\n span: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n markDefKeyMap: Map<string, string>\n options: {refreshKeys: boolean}\n}): PortableTextSpan | undefined {\n if (!isTypedObject(span)) {\n return undefined\n }\n\n // In reality, the span schema name is always 'span', but we only the check here anyway\n if (span._type !== context.schema.span.name || span._type !== 'span') {\n return undefined\n }\n\n const unparsedMarks: Array<unknown> = Array.isArray(span.marks)\n ? span.marks\n : []\n const marks = unparsedMarks.flatMap((mark) => {\n if (typeof mark !== 'string') {\n return []\n }\n\n const markDefKey = markDefKeyMap.get(mark)\n\n if (markDefKey !== undefined) {\n return [markDefKey]\n }\n\n if (\n context.schema.decorators.some((decorator) => decorator.value === mark)\n ) {\n return [mark]\n }\n\n return []\n })\n\n return {\n // Spread the entire span to allow custom properties on it\n ...span,\n _type: 'span',\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof span._key === 'string'\n ? span._key\n : context.keyGenerator(),\n text: typeof span.text === 'string' ? span.text : '',\n marks,\n }\n}\n\nfunction parseInlineObject({\n inlineObject,\n context,\n options,\n}: {\n inlineObject: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextObject | undefined {\n if (!isTypedObject(inlineObject)) {\n return undefined\n }\n\n if (\n inlineObject._type === context.schema.span.name ||\n inlineObject._type === 'span' ||\n // Respect the schema definition and don't parse inline objects that are not defined\n !context.schema.inlineObjects.some(({name}) => name === inlineObject._type)\n ) {\n return undefined\n }\n\n return {\n // Spread the entire inline object to allow custom properties on it\n ...inlineObject,\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof inlineObject._key === 'string'\n ? inlineObject._key\n : context.keyGenerator(),\n }\n}\n"],"names":["blockOffsetsToSelection","value","offsets","backward","anchor","blockOffsetToSpanSelectionPoint","blockOffset","direction","focus","isTypedObject","object","isRecord","_type","parseBlocks","context","blocks","options","Array","isArray","flatMap","block","parsedBlock","parseBlock","parseTextBlock","parseBlockObject","blockObject","schema","name","blockObjects","some","_key","refreshKeys","keyGenerator","isTextBlock","undefined","unparsedMarkDefs","markDefs","markDefKeyMap","Map","markDef","annotations","annotation","set","children","map","child","parseSpan","span","parseInlineObject","inlineObject","filter","length","text","marks","style","styles","find","defaultStyle","at","listItem","lists","list","level","mark","markDefKey","get","decorators","decorator","inlineObjects"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"parse-blocks.js","sources":["../../src/utils/util.block-offsets-to-selection.ts","../../src/internal-utils/asserters.ts","../../src/internal-utils/parse-blocks.ts"],"sourcesContent":["import type {PortableTextBlock} from '@sanity/types'\nimport type {EditorSelection} from '..'\nimport type {BlockOffset} from '../types/block-offset'\nimport {blockOffsetToSpanSelectionPoint} from './util.block-offset'\n\n/**\n * @public\n */\nexport function blockOffsetsToSelection({\n value,\n offsets,\n backward,\n}: {\n value: Array<PortableTextBlock>\n offsets: {anchor: BlockOffset; focus: BlockOffset}\n backward?: boolean\n}): EditorSelection {\n const anchor = blockOffsetToSpanSelectionPoint({\n value,\n blockOffset: offsets.anchor,\n direction: backward ? 'backward' : 'forward',\n })\n const focus = blockOffsetToSpanSelectionPoint({\n value,\n blockOffset: offsets.focus,\n direction: backward ? 'forward' : 'backward',\n })\n\n if (!anchor || !focus) {\n return null\n }\n\n return {\n anchor,\n focus,\n backward,\n }\n}\n","import type {TypedObject} from '@sanity/types'\n\nexport function isTypedObject(object: unknown): object is TypedObject {\n return isRecord(object) && typeof object._type === 'string'\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && (typeof value === 'object' || typeof value === 'function')\n}\n","import type {\n PortableTextBlock,\n PortableTextObject,\n PortableTextSpan,\n PortableTextTextBlock,\n} from '@sanity/types'\nimport type {EditorSchema} from '../editor/define-schema'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {isTypedObject} from './asserters'\n\nexport function parseBlocks({\n context,\n blocks,\n options,\n}: {\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n blocks: unknown\n options: {\n refreshKeys: boolean\n }\n}): Array<PortableTextBlock> {\n if (!Array.isArray(blocks)) {\n return []\n }\n\n return blocks.flatMap((block) => {\n const parsedBlock = parseBlock({context, block, options})\n\n return parsedBlock ? [parsedBlock] : []\n })\n}\n\nexport function parseBlock({\n context,\n block,\n options,\n}: {\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n block: unknown\n options: {\n refreshKeys: boolean\n }\n}): PortableTextBlock | undefined {\n return (\n parseTextBlock({block, context, options}) ??\n parseBlockObject({blockObject: block, context, options})\n )\n}\n\nfunction parseBlockObject({\n blockObject,\n context,\n options,\n}: {\n blockObject: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextObject | undefined {\n if (!isTypedObject(blockObject)) {\n return undefined\n }\n\n if (\n blockObject._type === context.schema.block.name ||\n blockObject._type === 'block' ||\n !context.schema.blockObjects.some(({name}) => name === blockObject._type)\n ) {\n return undefined\n }\n\n return {\n ...blockObject,\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof blockObject._key === 'string'\n ? blockObject._key\n : context.keyGenerator(),\n }\n}\n\nexport function isTextBlock(\n schema: EditorSchema,\n block: unknown,\n): block is PortableTextTextBlock {\n return (\n parseTextBlock({\n block,\n context: {schema, keyGenerator: () => ''},\n options: {refreshKeys: false},\n }) !== undefined\n )\n}\n\nfunction parseTextBlock({\n block,\n context,\n options,\n}: {\n block: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextTextBlock | undefined {\n if (!isTypedObject(block)) {\n return undefined\n }\n\n if (block._type !== context.schema.block.name) {\n return undefined\n }\n\n const _key = options.refreshKeys\n ? context.keyGenerator()\n : typeof block._key === 'string'\n ? block._key\n : context.keyGenerator()\n\n const unparsedMarkDefs: Array<unknown> = Array.isArray(block.markDefs)\n ? block.markDefs\n : []\n const markDefKeyMap = new Map<string, string>()\n const markDefs = unparsedMarkDefs.flatMap((markDef) => {\n if (!isTypedObject(markDef)) {\n return []\n }\n\n if (typeof markDef._key !== 'string') {\n return []\n }\n\n if (\n context.schema.annotations.some(\n (annotation) => annotation.name === markDef._type,\n )\n ) {\n const _key = options.refreshKeys ? context.keyGenerator() : markDef._key\n markDefKeyMap.set(markDef._key, _key)\n\n return [\n {\n ...markDef,\n _key,\n },\n ]\n }\n\n return []\n })\n\n const unparsedChildren: Array<unknown> = Array.isArray(block.children)\n ? block.children\n : []\n\n const children = unparsedChildren\n .map(\n (child) =>\n parseSpan({span: child, context, markDefKeyMap, options}) ??\n parseInlineObject({inlineObject: child, context, options}),\n )\n .filter((child) => child !== undefined)\n\n const parsedBlock: PortableTextTextBlock = {\n // Spread the entire block to allow custom properties on it\n ...block,\n _key,\n children:\n children.length > 0\n ? children\n : [\n {\n _key: context.keyGenerator(),\n _type: context.schema.span.name,\n text: '',\n marks: [],\n },\n ],\n markDefs,\n }\n\n /**\n * Reset text block .style if it's somehow set to an invalid type\n */\n if (\n typeof parsedBlock.style !== 'string' ||\n !context.schema.styles.find((style) => style.value === block.style)\n ) {\n const defaultStyle = context.schema.styles.at(0)?.value\n\n if (defaultStyle !== undefined) {\n parsedBlock.style = defaultStyle\n } else {\n delete parsedBlock.style\n }\n }\n\n /**\n * Reset text block .listItem if it's somehow set to an invalid type\n */\n if (\n typeof parsedBlock.listItem !== 'string' ||\n !context.schema.lists.find((list) => list.value === block.listItem)\n ) {\n delete parsedBlock.listItem\n }\n\n /**\n * Reset text block .level if it's somehow set to an invalid type\n */\n if (typeof parsedBlock.level !== 'number') {\n delete parsedBlock.level\n }\n\n return parsedBlock\n}\n\nexport function parseSpan({\n span,\n context,\n markDefKeyMap,\n options,\n}: {\n span: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n markDefKeyMap: Map<string, string>\n options: {refreshKeys: boolean}\n}): PortableTextSpan | undefined {\n if (!isTypedObject(span)) {\n return undefined\n }\n\n // In reality, the span schema name is always 'span', but we only the check here anyway\n if (span._type !== context.schema.span.name || span._type !== 'span') {\n return undefined\n }\n\n const unparsedMarks: Array<unknown> = Array.isArray(span.marks)\n ? span.marks\n : []\n const marks = unparsedMarks.flatMap((mark) => {\n if (typeof mark !== 'string') {\n return []\n }\n\n const markDefKey = markDefKeyMap.get(mark)\n\n if (markDefKey !== undefined) {\n return [markDefKey]\n }\n\n if (\n context.schema.decorators.some((decorator) => decorator.value === mark)\n ) {\n return [mark]\n }\n\n return []\n })\n\n return {\n // Spread the entire span to allow custom properties on it\n ...span,\n _type: 'span',\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof span._key === 'string'\n ? span._key\n : context.keyGenerator(),\n text: typeof span.text === 'string' ? span.text : '',\n marks,\n }\n}\n\nfunction parseInlineObject({\n inlineObject,\n context,\n options,\n}: {\n inlineObject: unknown\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n options: {refreshKeys: boolean}\n}): PortableTextObject | undefined {\n if (!isTypedObject(inlineObject)) {\n return undefined\n }\n\n if (\n inlineObject._type === context.schema.span.name ||\n inlineObject._type === 'span' ||\n // Respect the schema definition and don't parse inline objects that are not defined\n !context.schema.inlineObjects.some(({name}) => name === inlineObject._type)\n ) {\n return undefined\n }\n\n return {\n // Spread the entire inline object to allow custom properties on it\n ...inlineObject,\n _key: options.refreshKeys\n ? context.keyGenerator()\n : typeof inlineObject._key === 'string'\n ? inlineObject._key\n : context.keyGenerator(),\n }\n}\n"],"names":["blockOffsetsToSelection","value","offsets","backward","anchor","blockOffsetToSpanSelectionPoint","blockOffset","direction","focus","isTypedObject","object","isRecord","_type","parseBlocks","context","blocks","options","Array","isArray","flatMap","block","parsedBlock","parseBlock","parseTextBlock","parseBlockObject","blockObject","schema","name","blockObjects","some","_key","refreshKeys","keyGenerator","isTextBlock","undefined","unparsedMarkDefs","markDefs","markDefKeyMap","Map","markDef","annotations","annotation","set","children","map","child","parseSpan","span","parseInlineObject","inlineObject","filter","length","text","marks","style","styles","find","defaultStyle","at","listItem","lists","list","level","mark","markDefKey","get","decorators","decorator","inlineObjects"],"mappings":"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"}
@@ -1,123 +0,0 @@
1
- import {
2
- useCallback,
3
- useContext,
4
- useEffect,
5
- useState,
6
- type DragEvent,
7
- type RefObject,
8
- } from 'react'
9
- import type {Element as SlateElement} from 'slate'
10
- import {ReactEditor, useSlateStatic} from 'slate-react'
11
- import {getEventPosition} from '../../internal-utils/event-position'
12
- import {EditorActorContext} from '../editor-actor-context'
13
- import {getEditorSnapshot} from '../editor-selector'
14
-
15
- type Draggable = {
16
- draggableProps: {
17
- draggable: boolean
18
- onDragStart?: (event: DragEvent) => void
19
- onDragEnd?: (event: DragEvent) => void
20
- }
21
- }
22
-
23
- export function useDraggable(props: {
24
- element: SlateElement
25
- readOnly: boolean
26
- blockRef: RefObject<HTMLDivElement | null>
27
- }): Draggable {
28
- const editorActor = useContext(EditorActorContext)
29
- const editor = useSlateStatic()
30
- const [blockElement, setBlockElement] = useState<HTMLElement | null>(null)
31
-
32
- useEffect(
33
- () =>
34
- setBlockElement(
35
- props.blockRef
36
- ? props.blockRef.current
37
- : ReactEditor.toDOMNode(editor, props.element),
38
- ),
39
- [editor, props.element, props.blockRef],
40
- )
41
-
42
- const handleDragEnd = useCallback(() => {
43
- editorActor.send({type: 'dragend'})
44
- }, [editorActor])
45
-
46
- const handleDragStart = useCallback(
47
- (event: DragEvent) => {
48
- const position = getEventPosition({
49
- snapshot: getEditorSnapshot({
50
- editorActorSnapshot: editorActor.getSnapshot(),
51
- slateEditorInstance: editor,
52
- }),
53
- slateEditor: editor,
54
- event: event.nativeEvent,
55
- })
56
-
57
- if (!position) {
58
- console.error('Could not find position for dragstart event')
59
- return
60
- }
61
-
62
- // Clone blockElement so that it will not be visually clipped by scroll-containers etc.
63
- // The application that uses the portable-text-editor may indicate the element used as
64
- // drag ghost by adding a truthy data attribute 'data-pt-drag-ghost-element' to a HTML element.
65
- if (blockElement && blockElement instanceof HTMLElement) {
66
- let dragGhost = blockElement.cloneNode(true) as HTMLElement
67
- const customGhost = dragGhost.querySelector(
68
- '[data-pt-drag-ghost-element]',
69
- )
70
- if (customGhost) {
71
- dragGhost = customGhost as HTMLElement
72
- }
73
-
74
- // Set the `data-dragged` attribute so the consumer can style the element while it’s dragged
75
- dragGhost.setAttribute('data-dragged', '')
76
-
77
- if (document.body) {
78
- dragGhost.style.position = 'absolute'
79
- dragGhost.style.left = '-99999px'
80
- dragGhost.style.boxSizing = 'border-box'
81
- document.body.appendChild(dragGhost)
82
- const rect = blockElement.getBoundingClientRect()
83
- const x = event.clientX - rect.left
84
- const y = event.clientY - rect.top
85
- dragGhost.style.width = `${rect.width}px`
86
- dragGhost.style.height = `${rect.height}px`
87
- event.dataTransfer.setDragImage(dragGhost, x, y)
88
-
89
- editorActor.send({
90
- type: 'dragstart',
91
- origin: position,
92
- ghost: dragGhost,
93
- })
94
- return
95
- }
96
-
97
- editorActor.send({
98
- type: 'dragstart',
99
- origin: position,
100
- })
101
- }
102
- },
103
- [blockElement, editor, editorActor],
104
- )
105
-
106
- if (props.readOnly) {
107
- return {
108
- draggableProps: {
109
- draggable: false,
110
- onDragStart: undefined,
111
- onDragEnd: undefined,
112
- },
113
- }
114
- }
115
-
116
- return {
117
- draggableProps: {
118
- draggable: true,
119
- onDragStart: handleDragStart,
120
- onDragEnd: handleDragEnd,
121
- },
122
- }
123
- }