@portabletext/editor 7.10.1 → 7.10.2

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
@@ -3,13 +3,13 @@ import { c } from "react/compiler-runtime";
3
3
  import { useSelector, useActorRef } from "@xstate/react";
4
4
  import React, { createContext, useContext, useRef, useEffect, useLayoutEffect, useState, useReducer, useCallback, memo, forwardRef, useMemo, Component, useSyncExternalStore, startTransition } from "react";
5
5
  import { serializePath, isKeyedSegment, getNode, getParent, parentPath, getChildren, getNodeChildren } from "./_chunks-es/get-parent.js";
6
- import { isPath, getLeaf, isRange, isPoint, isObject, isLeafObject, getAncestor, pathContains, getSpan, isBeforePoint, getText, rangeIntersects, getTextBlock, getUnionSchema, getFirstChild, getContainer } from "./_chunks-es/get-container.js";
6
+ import { isPath, getLeaf, isRange, isPoint, isObject, isLeafObject, getAncestor, pathContains, getSpan, isBeforePoint, getText, rangeIntersects, getTextBlock, getFirstChild, getLastChild, getUnionSchema, getContainer } from "./_chunks-es/get-container.js";
7
7
  import { rangeEdges, isTextBlockNode, isBackwardRange, hasNode, getNodes, isAncestorPath, isEditableContainer, getSibling, isInline, isObject as isObject$1, isSpanNode, isBlock, getEnclosingBlock, getAncestors, getPathSubSchema, getBlock, resolveContainerAt, resolveChildEntryIndex, getEnclosingContainer, comparePoints$1 as comparePoints, comparePaths, isAfterPoint } from "./_chunks-es/get-path-sub-schema.js";
8
8
  import { isSpan, isTextBlock, getSubSchema, compileSchema } from "@portabletext/schema";
9
9
  import { defineSchema } from "@portabletext/schema";
10
10
  import scrollIntoView from "scroll-into-view-if-needed";
11
11
  import { createKeyboardShortcut, undo, redo, code, underline, italic as italic$1, bold as bold$1 } from "@portabletext/keyboard-shortcuts";
12
- import { rangesOverlap, getFocusInlineObject, isSelectionCollapsed as isSelectionCollapsed$1, getFocusTextBlock, getFocusSpan, getFragment, isSelectionExpanded, getSelectionStartBlock, getSelectionEndBlock, isOverlappingSelection, getFocusBlock, getSelectedBlocks, isSelectingEntireBlocks, getSelectedValue, isActiveAnnotation, getActiveAnnotationsMarks, getActiveDecorators, getCaretWordSelection, getSelectionStartChild, getSelectionStartPoint, getSelectionEndChild, getSelectionEndPoint, getPreviousSpan, getNextSpan, getFocusBlockObject, getLastBlock, getFirstBlock, isAtTheEndOfBlock, isAtTheStartOfBlock, getRootAcceptedTypes, getMarkState, getFocusListBlock, getNextBlock, getPreviousBlock, getSelectedTextBlocks, isActiveDecorator, getFocusChild, getActiveAnnotations, isActiveListItem, isActiveStyle } from "./_chunks-es/selector.is-at-the-start-of-block.js";
12
+ import { rangesOverlap, getFocusInlineObject, isSelectionCollapsed as isSelectionCollapsed$1, getFocusTextBlock, getFocusSpan, getFragment, isSelectionExpanded, getSelectionStartBlock, getSelectionEndBlock, isOverlappingSelection, getFocusBlock, getSelectedBlocks, isSelectingEntireBlocks, getSelectedValue, isActiveAnnotation, getActiveAnnotationsMarks, getActiveDecorators, getCaretWordSelection, getSelectionStartChild, getSelectionStartPoint, getSelectionEndChild, getSelectionEndPoint, getPreviousSpan, getNextSpan, getFocusBlockObject, isAtTheEndOfBlock, isAtTheStartOfBlock, getLastBlock, getRootAcceptedTypes, getMarkState, getFocusListBlock, getNextBlock, getPreviousBlock, getSelectedTextBlocks, isActiveDecorator, getFocusChild, getActiveAnnotations, isActiveListItem, isActiveStyle } from "./_chunks-es/selector.is-at-the-start-of-block.js";
13
13
  import { isEqualSelectionPoints, blockOffsetToSpanSelectionPoint, getBlockKeyFromSelectionPoint, getBlockEndPoint, getBlockStartPoint, isSelectionCollapsed, defaultKeyGenerator, parseBlocks, parseBlock, isListBlock, getSelectionStartPoint as getSelectionStartPoint$1, getSelectionEndPoint as getSelectionEndPoint$1, parseAnnotation, parseMarkDefs, parseSpan, parseInlineObject } from "./_chunks-es/util.slice-blocks.js";
14
14
  import rawDebug from "debug";
15
15
  import { isEmptyTextBlock, isEqualSelections, getTextBlockText } from "./_chunks-es/util.is-equal-selections.js";
@@ -3900,7 +3900,14 @@ const RestoreDOM = IS_ANDROID ? RestoreDOMComponent : ({
3900
3900
  return;
3901
3901
  }
3902
3902
  leafEl.getBoundingClientRect = domFocusPoint.getBoundingClientRect.bind(domFocusPoint), scrollIntoView(leafEl, {
3903
- scrollMode: "if-needed"
3903
+ scrollMode: "if-needed",
3904
+ // Native-caret semantics: the minimal delta to the nearest edge. The
3905
+ // library's default `block: 'center'` re-centered the viewport on
3906
+ // every sync whose focus was even slightly clipped, yanking the
3907
+ // editor around on programmatic selects (a table handle click whose
3908
+ // rectangle ends in an off-screen column, for example).
3909
+ block: "nearest",
3910
+ inline: "nearest"
3904
3911
  }), delete leafEl.getBoundingClientRect;
3905
3912
  }
3906
3913
  }, isEventHandled = (event, handler) => handler ? handler(event) ?? (event.isDefaultPrevented() || event.isPropagationStopped()) : !1, isDOMEventTargetInput = (event) => isDOMNode(event.target) && (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement), isDOMEventHandled = (event, handler) => handler ? handler(event) ?? event.defaultPrevented : !1, handleNativeHistoryEvents = (editor, editorActor, event) => {
@@ -4127,7 +4134,7 @@ function getEventPosition({
4127
4134
  }
4128
4135
  }
4129
4136
  };
4130
- if (eventPositionBlock && !isEditor(eventNode) && isEditableContainer(editorEngine.snapshot, eventNode, eventPath) && isDragEvent(event))
4137
+ if (eventPositionBlock && !isEditor(eventNode) && isEditableContainer(editorEngine.snapshot, eventNode, eventPath) && (isDragEvent(event) || event.type === "click"))
4131
4138
  return {
4132
4139
  block: eventPositionBlock,
4133
4140
  isEditor: !1,
@@ -11276,32 +11283,36 @@ const addAnnotationOnCollapsedSelection = defineBehavior({
11276
11283
  }) => {
11277
11284
  if (snapshot.context.readOnly || snapshot.context.selection && !isSelectionCollapsed$1(snapshot))
11278
11285
  return !1;
11279
- const positionSnapshot = {
11280
- ...snapshot,
11281
- context: {
11282
- ...snapshot.context,
11283
- selection: event.position.selection
11284
- }
11285
- }, focusedBlockObject = getFocusBlockObject(positionSnapshot);
11286
- if (!focusedBlockObject)
11286
+ const focusPath = event.position.selection.focus.path, focusBlock = event.position.isEditor ? focusPath.length >= 1 ? getNode(snapshot, focusPath.slice(0, 1)) : void 0 : event.position.isContainer ? getFirstChild(snapshot, focusPath) : void 0;
11287
+ if (!focusBlock || isTextBlockNode(snapshot.context, focusBlock.node) || event.position.isContainer && !acceptsTextBlock(snapshot, focusBlock.path))
11287
11288
  return !1;
11288
- const previousSibling = getSibling(snapshot, focusedBlockObject.path, {
11289
+ const previousSibling = getSibling(snapshot, focusBlock.path, {
11289
11290
  direction: "previous"
11290
11291
  });
11291
- return (event.position.isEditor || event.position.isContainer) && event.position.block === "start" && !previousSibling;
11292
+ return (event.position.isEditor || event.position.isContainer) && event.position.block === "start" && !previousSibling ? {
11293
+ blockPath: focusBlock.path
11294
+ } : !1;
11292
11295
  },
11293
11296
  actions: [({
11294
- snapshot,
11295
- event
11297
+ snapshot
11298
+ }, {
11299
+ blockPath
11296
11300
  }) => [raise({
11297
- type: "select",
11298
- at: event.position.selection
11299
- }), raise({
11300
11301
  type: "insert.block",
11301
11302
  block: {
11302
11303
  _type: snapshot.context.schema.block.name
11303
11304
  },
11304
11305
  placement: "before",
11306
+ at: {
11307
+ anchor: {
11308
+ path: blockPath,
11309
+ offset: 0
11310
+ },
11311
+ focus: {
11312
+ path: blockPath,
11313
+ offset: 0
11314
+ }
11315
+ },
11305
11316
  select: "start"
11306
11317
  })]]
11307
11318
  }), clickingBelowLonelyBlockObject = defineBehavior({
@@ -11312,35 +11323,44 @@ const addAnnotationOnCollapsedSelection = defineBehavior({
11312
11323
  }) => {
11313
11324
  if (snapshot.context.readOnly || snapshot.context.selection && !isSelectionCollapsed$1(snapshot))
11314
11325
  return !1;
11315
- const positionSnapshot = {
11316
- ...snapshot,
11317
- context: {
11318
- ...snapshot.context,
11319
- selection: event.position.selection
11320
- }
11321
- }, focusedBlockObject = getFocusBlockObject(positionSnapshot);
11322
- if (!focusedBlockObject)
11326
+ const focusPath = event.position.selection.focus.path, focusBlock = event.position.isEditor ? focusPath.length >= 1 ? getNode(snapshot, focusPath.slice(0, 1)) : void 0 : event.position.isContainer ? getLastChild(snapshot, focusPath) : void 0;
11327
+ if (!focusBlock || isTextBlockNode(snapshot.context, focusBlock.node) || event.position.isContainer && !acceptsTextBlock(snapshot, focusBlock.path))
11323
11328
  return !1;
11324
- const nextSibling = getSibling(snapshot, focusedBlockObject.path, {
11329
+ const nextSibling = getSibling(snapshot, focusBlock.path, {
11325
11330
  direction: "next"
11326
11331
  });
11327
- return (event.position.isEditor || event.position.isContainer) && event.position.block === "end" && !nextSibling;
11332
+ return (event.position.isEditor || event.position.isContainer) && event.position.block === "end" && !nextSibling ? {
11333
+ blockPath: focusBlock.path
11334
+ } : !1;
11328
11335
  },
11329
11336
  actions: [({
11330
- snapshot,
11331
- event
11337
+ snapshot
11338
+ }, {
11339
+ blockPath
11332
11340
  }) => [raise({
11333
- type: "select",
11334
- at: event.position.selection
11335
- }), raise({
11336
11341
  type: "insert.block",
11337
11342
  block: {
11338
11343
  _type: snapshot.context.schema.block.name
11339
11344
  },
11340
11345
  placement: "after",
11346
+ at: {
11347
+ anchor: {
11348
+ path: blockPath,
11349
+ offset: 0
11350
+ },
11351
+ focus: {
11352
+ path: blockPath,
11353
+ offset: 0
11354
+ }
11355
+ },
11341
11356
  select: "start"
11342
11357
  })]]
11343
- }), deletingEmptyTextBlockAfterBlockObject = defineBehavior({
11358
+ });
11359
+ function acceptsTextBlock(snapshot, path2) {
11360
+ const enclosing = getEnclosingContainer(snapshot, path2);
11361
+ return !enclosing || enclosing.of.some((member) => member.type === snapshot.context.schema.block.name);
11362
+ }
11363
+ const deletingEmptyTextBlockAfterBlockObject = defineBehavior({
11344
11364
  on: "delete.backward",
11345
11365
  guard: ({
11346
11366
  snapshot
@@ -11426,34 +11446,80 @@ const addAnnotationOnCollapsedSelection = defineBehavior({
11426
11446
  clickingBelowLonelyBlockObject,
11427
11447
  deletingEmptyTextBlockAfterBlockObject,
11428
11448
  deletingEmptyTextBlockBeforeBlockObject
11429
- }, arrowDownOutOfContainer = defineBehavior({
11449
+ }, anyArrowDown = createKeyboardShortcut({
11450
+ default: [{
11451
+ key: "ArrowDown"
11452
+ }]
11453
+ }), anyArrowUp = createKeyboardShortcut({
11454
+ default: [{
11455
+ key: "ArrowUp"
11456
+ }]
11457
+ }), arrowDownOutOfContainer = defineBehavior({
11430
11458
  on: "keyboard.keydown",
11431
11459
  guard: ({
11432
11460
  snapshot,
11433
11461
  event
11434
- }) => event.originEvent.key === "ArrowDown" && isAtContainerDeadEnd(snapshot, "end"),
11435
- actions: []
11462
+ }) => !anyArrowDown.guard(event.originEvent) || !isAtContainerDeadEnd(snapshot, "end") ? !1 : {
11463
+ escapeTarget: arrowEscapeTarget(snapshot, event.originEvent, "end")
11464
+ },
11465
+ actions: [({
11466
+ snapshot
11467
+ }, {
11468
+ escapeTarget
11469
+ }) => escapeTarget ? [escapeAction(snapshot, escapeTarget, "after")] : []]
11436
11470
  }), arrowUpOutOfContainer = defineBehavior({
11437
11471
  on: "keyboard.keydown",
11438
11472
  guard: ({
11439
11473
  snapshot,
11440
11474
  event
11441
- }) => event.originEvent.key === "ArrowUp" && isAtContainerDeadEnd(snapshot, "start"),
11442
- actions: []
11475
+ }) => !anyArrowUp.guard(event.originEvent) || !isAtContainerDeadEnd(snapshot, "start") ? !1 : {
11476
+ escapeTarget: arrowEscapeTarget(snapshot, event.originEvent, "start")
11477
+ },
11478
+ actions: [({
11479
+ snapshot
11480
+ }, {
11481
+ escapeTarget
11482
+ }) => escapeTarget ? [escapeAction(snapshot, escapeTarget, "before")] : []]
11443
11483
  });
11484
+ function arrowEscapeTarget(snapshot, originEvent, edge) {
11485
+ if (!(edge === "end" ? defaultKeyboardShortcuts.arrowDown.guard(originEvent) : defaultKeyboardShortcuts.arrowUp.guard(originEvent)))
11486
+ return;
11487
+ const focusTextBlock = getFocusTextBlock(snapshot);
11488
+ return focusTextBlock ? getEscapeTarget(snapshot, focusTextBlock.path) : void 0;
11489
+ }
11490
+ function escapeAction(snapshot, escapeTarget, placement) {
11491
+ return raise({
11492
+ type: "insert.block",
11493
+ block: createPlaceholderBlock(snapshot, escapeTarget),
11494
+ placement,
11495
+ at: {
11496
+ anchor: {
11497
+ path: escapeTarget,
11498
+ offset: 0
11499
+ },
11500
+ focus: {
11501
+ path: escapeTarget,
11502
+ offset: 0
11503
+ }
11504
+ },
11505
+ select: "start"
11506
+ });
11507
+ }
11444
11508
  function isAtContainerDeadEnd(snapshot, edge) {
11445
11509
  if (!isSelectionCollapsed$1(snapshot))
11446
11510
  return !1;
11447
11511
  const focusTextBlock = getFocusTextBlock(snapshot);
11448
- if (!focusTextBlock)
11449
- return !1;
11450
- const container = getAncestor(snapshot, focusTextBlock.path, {
11512
+ if (!focusTextBlock || !getAncestor(snapshot, focusTextBlock.path, {
11451
11513
  match: (node, path2) => isEditableContainer(snapshot, node, path2)
11452
- });
11453
- if (!container)
11514
+ }))
11454
11515
  return !1;
11455
- const edgeBlock = edge === "end" ? getLastBlock(snapshot) : getFirstBlock(snapshot);
11456
- return !edgeBlock || !pathEquals(edgeBlock.path, focusTextBlock.path) || !(edge === "end" ? isAtTheEndOfBlock(focusTextBlock)(snapshot) : isAtTheStartOfBlock(focusTextBlock)(snapshot)) ? !1 : getSibling(snapshot, container.path, {
11516
+ const rootSegment = focusTextBlock.path[0];
11517
+ if (!rootSegment)
11518
+ return !1;
11519
+ const outerPath = [rootSegment], edgeLeaf = getLeaf(snapshot, outerPath, {
11520
+ edge
11521
+ }), edgeBlock = edgeLeaf && getEnclosingBlock(snapshot, edgeLeaf.path);
11522
+ return !edgeBlock || !pathEquals(edgeBlock.path, focusTextBlock.path) || !(edge === "end" ? isAtTheEndOfBlock(focusTextBlock)(snapshot) : isAtTheStartOfBlock(focusTextBlock)(snapshot)) ? !1 : getSibling(snapshot, outerPath, {
11457
11523
  direction: edge === "end" ? "next" : "previous"
11458
11524
  }) === void 0;
11459
11525
  }