@portabletext/editor 7.10.15 → 7.10.17

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 (63) hide show
  1. package/lib/{_chunks-dts/behavior.types.action.d.ts → behavior.types.action-CYtiRDck.d.ts} +260 -59
  2. package/lib/behavior.types.action-CYtiRDck.d.ts.map +1 -0
  3. package/lib/behavior.types.behavior-B_77VtQR.js +159 -0
  4. package/lib/behavior.types.behavior-B_77VtQR.js.map +1 -0
  5. package/lib/behaviors/index.d.ts +1 -1
  6. package/lib/behaviors/index.js +2 -35
  7. package/lib/get-container-BeXYKpoi.js +222 -0
  8. package/lib/get-container-BeXYKpoi.js.map +1 -0
  9. package/lib/get-parent-51Kzgaf9.js +237 -0
  10. package/lib/get-parent-51Kzgaf9.js.map +1 -0
  11. package/lib/get-path-sub-schema--2I4NJbG.js +513 -0
  12. package/lib/get-path-sub-schema--2I4NJbG.js.map +1 -0
  13. package/lib/index.d.ts +2 -67
  14. package/lib/index.js +16743 -18963
  15. package/lib/index.js.map +1 -1
  16. package/lib/plugins/index.d.ts +1 -2
  17. package/lib/plugins/index.d.ts.map +1 -1
  18. package/lib/plugins/index.js +103 -41
  19. package/lib/plugins/index.js.map +1 -1
  20. package/lib/selector.is-at-the-start-of-block-gJIMWRpU.js +822 -0
  21. package/lib/selector.is-at-the-start-of-block-gJIMWRpU.js.map +1 -0
  22. package/lib/selectors/index.d.ts +1 -3
  23. package/lib/selectors/index.d.ts.map +1 -1
  24. package/lib/selectors/index.js +256 -215
  25. package/lib/selectors/index.js.map +1 -1
  26. package/lib/traversal/index.d.ts +1 -1
  27. package/lib/traversal/index.d.ts.map +1 -1
  28. package/lib/traversal/index.js +33 -52
  29. package/lib/traversal/index.js.map +1 -1
  30. package/lib/use-editor-CwNeVwVC.js +47 -0
  31. package/lib/use-editor-CwNeVwVC.js.map +1 -0
  32. package/lib/util.is-equal-selections-BF4WJtz5.js +25 -0
  33. package/lib/util.is-equal-selections-BF4WJtz5.js.map +1 -0
  34. package/lib/util.slice-blocks-DQnr9X2s.js +633 -0
  35. package/lib/util.slice-blocks-DQnr9X2s.js.map +1 -0
  36. package/lib/utils/index.d.ts +11 -39
  37. package/lib/utils/index.d.ts.map +1 -1
  38. package/lib/utils/index.js +87 -123
  39. package/lib/utils/index.js.map +1 -1
  40. package/package.json +18 -15
  41. package/lib/_chunks-dts/behavior.types.action.d.ts.map +0 -1
  42. package/lib/_chunks-dts/block-offset.d.ts +0 -10
  43. package/lib/_chunks-dts/block-offset.d.ts.map +0 -1
  44. package/lib/_chunks-dts/editor-selector.d.ts +0 -33
  45. package/lib/_chunks-dts/editor-selector.d.ts.map +0 -1
  46. package/lib/_chunks-dts/editor.d.ts +0 -99
  47. package/lib/_chunks-dts/editor.d.ts.map +0 -1
  48. package/lib/_chunks-es/get-container.js +0 -187
  49. package/lib/_chunks-es/get-container.js.map +0 -1
  50. package/lib/_chunks-es/get-parent.js +0 -195
  51. package/lib/_chunks-es/get-parent.js.map +0 -1
  52. package/lib/_chunks-es/get-path-sub-schema.js +0 -399
  53. package/lib/_chunks-es/get-path-sub-schema.js.map +0 -1
  54. package/lib/_chunks-es/selector.is-at-the-start-of-block.js +0 -947
  55. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +0 -1
  56. package/lib/_chunks-es/use-editor.js +0 -20
  57. package/lib/_chunks-es/use-editor.js.map +0 -1
  58. package/lib/_chunks-es/util.is-equal-selections.js +0 -20
  59. package/lib/_chunks-es/util.is-equal-selections.js.map +0 -1
  60. package/lib/_chunks-es/util.slice-blocks.js +0 -720
  61. package/lib/_chunks-es/util.slice-blocks.js.map +0 -1
  62. package/lib/behaviors/index.js.map +0 -1
  63. package/lib/index.d.ts.map +0 -1
@@ -0,0 +1,822 @@
1
+ import { a as getNodeChildren, i as getChildren, n as parentPath, r as getNode, t as getParent, u as isKeyedSegment } from "./get-parent-51Kzgaf9.js";
2
+ import { S as hasNode, _ as comparePoints, a as isInline, b as isEditableContainer, c as isSpanNode, i as getEnclosingBlock, l as getSibling, m as rangeEdges, o as getBlock, p as isTextBlockNode, t as getPathSubSchema, u as getNodes, x as resolveContainerAt, y as isObject } from "./get-path-sub-schema--2I4NJbG.js";
3
+ import { d as getSelectionEndPoint$1, f as isSelectionCollapsed$1, g as isEqualSelectionPoints, m as getBlockEndPoint, n as isListBlock, p as getBlockStartPoint, t as sliceBlocks, u as getSelectionStartPoint$1, v as blockOffsetToSpanSelectionPoint, y as spanSelectionPointToBlockOffset } from "./util.slice-blocks-DQnr9X2s.js";
4
+ import { isSpan, isTextBlock } from "@portabletext/schema";
5
+ /**
6
+ * Returns true if the two ranges share at least one point.
7
+ *
8
+ * Two ranges overlap iff each one's start is at or before the other's end.
9
+ * Adjacent ranges that touch at a single point are considered overlapping.
10
+ */
11
+ function rangesOverlap(rangeA, rangeB, root) {
12
+ let [startA, endA] = rangeEdges(rangeA, root), [startB, endB] = rangeEdges(rangeB, root);
13
+ return comparePoints(startA, endB, root) <= 0 && comparePoints(startB, endA, root) <= 0;
14
+ }
15
+ /**
16
+ * Get the node at the given path if it is inline (a span or inline object).
17
+ *
18
+ * A node is inline if its parent is a text block. Returns the node narrowed
19
+ * to `PortableTextSpan | PortableTextObject`, or `undefined` if the node
20
+ * doesn't exist or is not inline.
21
+ */
22
+ function getInline(snapshot, path) {
23
+ let entry = getNode(snapshot, path);
24
+ if (!(!entry || !isInline(snapshot, entry.path)) && !(!isSpanNode({ schema: snapshot.context.schema }, entry.node) && !isObject(snapshot, entry.node))) return {
25
+ node: entry.node,
26
+ path: entry.path
27
+ };
28
+ }
29
+ /**
30
+ * Returns the child (span or inline object) containing the focus selection,
31
+ * resolved at any depth.
32
+ *
33
+ * @public
34
+ */
35
+ const getFocusChild = (snapshot) => {
36
+ let selection = snapshot.context.selection;
37
+ if (selection) return getInline(snapshot, selection.focus.path);
38
+ }, getFocusInlineObject = (snapshot) => {
39
+ let focusChild = getFocusChild(snapshot);
40
+ return focusChild && !isSpanNode(snapshot.context, focusChild.node) ? {
41
+ node: focusChild.node,
42
+ path: focusChild.path
43
+ } : void 0;
44
+ }, getFocusSpan = (snapshot) => {
45
+ let focusChild = getFocusChild(snapshot);
46
+ return focusChild && isSpan(snapshot.context, focusChild.node) ? {
47
+ node: focusChild.node,
48
+ path: focusChild.path
49
+ } : void 0;
50
+ }, getFocusBlock = (snapshot) => {
51
+ let selection = snapshot.context.selection;
52
+ if (selection) return getEnclosingBlock(snapshot, selection.focus.path);
53
+ }, getFocusTextBlock = (snapshot) => {
54
+ let focusBlock = getFocusBlock(snapshot);
55
+ return focusBlock && isTextBlock(snapshot.context, focusBlock.node) ? {
56
+ node: focusBlock.node,
57
+ path: focusBlock.path
58
+ } : void 0;
59
+ };
60
+ /**
61
+ * Set of types that are valid at the root of the editor's value: the
62
+ * configured text-block type plus every registered block-object type.
63
+ *
64
+ * The editor accepts these at the top level of `value` and uses them
65
+ * to validate input and as the implicit accept-list for any payload
66
+ * that escapes registered containers.
67
+ */
68
+ function getRootAcceptedTypes(schema) {
69
+ return /* @__PURE__ */ new Set([schema.block.name, ...schema.blockObjects.map((blockObject) => blockObject.name)]);
70
+ }
71
+ /**
72
+ * Returns the portion of the document's value covered by the selection,
73
+ * resolved at any depth.
74
+ *
75
+ * Containers fully inside the selection are preserved verbatim. Containers
76
+ * on the selection boundary are recursed into so only the selected portion
77
+ * of their content is kept. Text blocks on the boundary are span-sliced.
78
+ *
79
+ * The result preserves the full ancestor envelope around the selection. For
80
+ * the clipboard-shaped view that unwraps the envelope toward the selection's
81
+ * lowest common ancestor, see {@link getFragment}.
82
+ *
83
+ * @public
84
+ */
85
+ const getSelectedValue = (snapshot) => {
86
+ let selection = snapshot.context.selection;
87
+ if (!selection) return [];
88
+ let startPoint = getSelectionStartPoint$1(selection), endPoint = getSelectionEndPoint$1(selection);
89
+ return !startPoint || !endPoint ? [] : sliceArray({
90
+ context: snapshot.context,
91
+ blocks: snapshot.context.value,
92
+ pathPrefix: [],
93
+ fieldNameInPrefix: void 0,
94
+ startEdge: startPoint,
95
+ endEdge: endPoint
96
+ });
97
+ };
98
+ function sliceArray({ context, blocks, pathPrefix, fieldNameInPrefix, startEdge, endEdge, parent }) {
99
+ if (blocks.length === 0) return [];
100
+ let startIdx = resolveIndex(blocks, pathPrefix, startEdge), endIdx = resolveIndex(blocks, pathPrefix, endEdge);
101
+ if (startIdx === -1 || endIdx === -1) return [];
102
+ let [lo, hi, loEdge, hiEdge] = startIdx <= endIdx ? [
103
+ startIdx,
104
+ endIdx,
105
+ startEdge,
106
+ endEdge
107
+ ] : [
108
+ endIdx,
109
+ startIdx,
110
+ endEdge,
111
+ startEdge
112
+ ], result = [];
113
+ for (let i = lo; i <= hi; i++) {
114
+ let block = blocks[i], blockPath = [
115
+ ...pathPrefix,
116
+ ...fieldNameInPrefix ? [fieldNameInPrefix] : [],
117
+ { _key: block._key }
118
+ ], startPointForBlock = i === lo ? loEdge : "array-start", endPointForBlock = i === hi ? hiEdge : "array-end", startInside = edgeIsInside(startPointForBlock, blockPath), endInside = edgeIsInside(endPointForBlock, blockPath);
119
+ if (!startInside && !endInside) {
120
+ result.push(block);
121
+ continue;
122
+ }
123
+ if (isTextBlock({ schema: context.schema }, block)) {
124
+ let sliced = sliceBoundaryTextBlock({
125
+ context,
126
+ block,
127
+ blockPath,
128
+ startEdge: startPointForBlock,
129
+ endEdge: endPointForBlock
130
+ });
131
+ sliced && result.push(sliced);
132
+ continue;
133
+ }
134
+ let childInfo = getNodeChildren(context, block, parent);
135
+ if (!childInfo) {
136
+ result.push(block);
137
+ continue;
138
+ }
139
+ let innerSliced = sliceArray({
140
+ context,
141
+ blocks: childInfo.children,
142
+ pathPrefix: blockPath,
143
+ fieldNameInPrefix: childInfo.fieldName,
144
+ startEdge: startPointForBlock,
145
+ endEdge: endPointForBlock,
146
+ parent: childInfo.parent
147
+ }), updatedBlock = { ...block };
148
+ updatedBlock[childInfo.fieldName] = innerSliced, result.push(updatedBlock);
149
+ }
150
+ return result;
151
+ }
152
+ function resolveIndex(blocks, pathPrefix, edge) {
153
+ return edge === "array-start" ? 0 : edge === "array-end" ? blocks.length - 1 : findBlockIndexForPoint(blocks, pathPrefix, edge);
154
+ }
155
+ function findBlockIndexForPoint(blocks, pathPrefix, point) {
156
+ let nodeSegmentIndex = pathPrefix.length;
157
+ nodeSegmentIndex < point.path.length && typeof point.path[nodeSegmentIndex] == "string" && nodeSegmentIndex++;
158
+ let segment = point.path[nodeSegmentIndex];
159
+ return segment === void 0 ? -1 : isKeyedSegment(segment) ? blocks.findIndex((block) => block._key === segment._key) : typeof segment == "number" && segment >= 0 && segment < blocks.length ? segment : -1;
160
+ }
161
+ function edgeIsInside(edge, blockPath) {
162
+ return edge === "array-start" || edge === "array-end" ? !1 : edge.path.length > blockPath.length;
163
+ }
164
+ function sliceBoundaryTextBlock({ context, block, blockPath, startEdge, endEdge }) {
165
+ if (!isTextBlock({ schema: context.schema }, block)) return block;
166
+ let firstChild = block.children[0], lastChild = block.children[block.children.length - 1], blockRelativeStart = stripPrefix(startEdge, blockPath, block, {
167
+ fallback: "block-start",
168
+ firstChild
169
+ }), blockRelativeEnd = stripPrefix(endEdge, blockPath, block, {
170
+ fallback: "block-end",
171
+ lastChild,
172
+ context
173
+ });
174
+ return sliceBlocks({
175
+ context: {
176
+ ...context,
177
+ selection: {
178
+ anchor: blockRelativeStart,
179
+ focus: blockRelativeEnd
180
+ }
181
+ },
182
+ blocks: [block]
183
+ })[0];
184
+ }
185
+ function stripPrefix(edge, blockPath, block, opts) {
186
+ return edge !== "array-start" && edge !== "array-end" && edge.path.length > blockPath.length ? {
187
+ path: edge.path.slice(blockPath.length - 1),
188
+ offset: edge.offset
189
+ } : opts.fallback === "block-start" ? {
190
+ path: [
191
+ { _key: block._key },
192
+ "children",
193
+ { _key: opts.firstChild?._key ?? "" }
194
+ ],
195
+ offset: 0
196
+ } : {
197
+ path: [
198
+ { _key: block._key },
199
+ "children",
200
+ { _key: opts.lastChild?._key ?? "" }
201
+ ],
202
+ offset: opts.lastChild && opts.context && isSpan({ schema: opts.context.schema }, opts.lastChild) ? opts.lastChild.text.length : 0
203
+ };
204
+ }
205
+ /**
206
+ * Returns the smallest top-level-valid fragment of the editor's value
207
+ * that covers the current selection.
208
+ *
209
+ * Starts from {@link getSelectedValue}'s envelope and unwraps it toward
210
+ * the selection's lowest common ancestor, stopping at the deepest level
211
+ * whose siblings are all root-accepted types. Intermediate single-child
212
+ * containers (a single row inside a table, a single cell inside a row)
213
+ * are walked through to look for a deeper unwrap target; an intermediate
214
+ * level with multiple siblings (the lowest common ancestor across two
215
+ * cells in one row) ends the walk and the last root-valid wrapping is
216
+ * returned.
217
+ *
218
+ * A selection whose endpoints terminate at the root level (collapsed at
219
+ * a root-level node, or expanded across root siblings without descending
220
+ * into them) is treated as the user pointing AT the named node(s) rather
221
+ * than INTO them; the envelope is returned as-is and the unwrap walk is
222
+ * skipped. This is how a chrome drag carries the container itself rather
223
+ * than its unwrapped content.
224
+ *
225
+ * Backs every registered clipboard converter, `editor.getFragment()`
226
+ * (which projects to blocks only), and the drag preview pipeline (which
227
+ * uses the paths to find DOM nodes). Exposed for custom converters and
228
+ * any consumer that needs the clipboard-shaped view of the current
229
+ * selection without redundant ancestor envelopes.
230
+ *
231
+ * @public
232
+ */
233
+ const getFragment = (snapshot) => {
234
+ let envelope = getSelectedValue(snapshot);
235
+ if (envelope.length === 0) return [];
236
+ let selection = snapshot.context.selection;
237
+ if (selection && selection.anchor.path.length <= 1 && selection.focus.path.length <= 1) return envelope.map((block) => ({
238
+ node: block,
239
+ path: [{ _key: block._key }]
240
+ }));
241
+ let { schema, containers, value } = snapshot.context, rootAcceptedTypes = getRootAcceptedTypes(schema), textBlockName = schema.block.name, lastRootValid = envelope, lastRootValidPrefix = [], current = envelope, pathPrefix = [];
242
+ for (; current.length === 1;) {
243
+ let single = current[0], singlePath = [...pathPrefix, { _key: single._key }], container = resolveContainerAt(containers, value, singlePath);
244
+ if (!container || !("field" in container)) break;
245
+ let children = single[container.field.name];
246
+ if (!Array.isArray(children) || children.length === 0) break;
247
+ let childBlocks = children;
248
+ if (pathPrefix.push({ _key: single._key }, container.field.name), current = childBlocks, childBlocks.every((block) => block._type === textBlockName || rootAcceptedTypes.has(block._type))) {
249
+ lastRootValid = childBlocks, lastRootValidPrefix = [...pathPrefix];
250
+ continue;
251
+ }
252
+ if (childBlocks.length !== 1) break;
253
+ }
254
+ return lastRootValid.map((block) => ({
255
+ node: block,
256
+ path: [...lastRootValidPrefix, { _key: block._key }]
257
+ }));
258
+ }, getSelectionEndBlock = (snapshot) => {
259
+ let endPoint = getSelectionEndPoint$1(snapshot.context.selection);
260
+ if (endPoint) return getFocusBlock({
261
+ ...snapshot,
262
+ context: {
263
+ ...snapshot.context,
264
+ selection: {
265
+ anchor: endPoint,
266
+ focus: endPoint
267
+ }
268
+ }
269
+ });
270
+ }, getSelectionStartBlock = (snapshot) => {
271
+ let startPoint = getSelectionStartPoint$1(snapshot.context.selection);
272
+ if (startPoint) return getFocusBlock({
273
+ ...snapshot,
274
+ context: {
275
+ ...snapshot.context,
276
+ selection: {
277
+ anchor: startPoint,
278
+ focus: startPoint
279
+ }
280
+ }
281
+ });
282
+ };
283
+ /**
284
+ * Returns true if the supplied selection shares at least one point with the
285
+ * editor's current selection. Resolves at any container depth.
286
+ *
287
+ * Two selections that touch at a single endpoint share that point and are
288
+ * considered overlapping.
289
+ *
290
+ * @public
291
+ */
292
+ function isOverlappingSelection(selection) {
293
+ return (snapshot) => {
294
+ let editorSelection = snapshot.context.selection;
295
+ return !selection || !editorSelection || !hasNode(snapshot, selection.anchor.path) || !hasNode(snapshot, selection.focus.path) || !hasNode(snapshot, editorSelection.anchor.path) || !hasNode(snapshot, editorSelection.focus.path) ? !1 : rangesOverlap(selection, editorSelection, { value: snapshot.context.value });
296
+ };
297
+ }
298
+ /**
299
+ * @public
300
+ */
301
+ const isSelectionCollapsed = (snapshot) => isSelectionCollapsed$1(snapshot.context.selection), isSelectionExpanded$1 = (snapshot) => snapshot.context.selection !== null && !isSelectionCollapsed(snapshot), getSelectedBlocks = (snapshot) => {
302
+ let selection = snapshot.context.selection;
303
+ if (!selection) return [];
304
+ let startPoint = getSelectionStartPoint$1(selection), endPoint = getSelectionEndPoint$1(selection);
305
+ if (!startPoint || !endPoint) return [];
306
+ let startRootKey = startPoint.path.find(isKeyedSegment)?._key, endRootKey = endPoint.path.find(isKeyedSegment)?._key;
307
+ if (startRootKey && startRootKey === endRootKey) {
308
+ let block = getBlock(snapshot, [{ _key: startRootKey }]);
309
+ if (block) return [{
310
+ node: block.node,
311
+ path: block.path
312
+ }];
313
+ }
314
+ let result = [];
315
+ for (let entry of getNodes(snapshot, {
316
+ from: startPoint.path,
317
+ to: endPoint.path,
318
+ match: (_, path) => path.length === 1
319
+ })) {
320
+ let block = getBlock(snapshot, entry.path);
321
+ block && result.push({
322
+ node: block.node,
323
+ path: block.path
324
+ });
325
+ }
326
+ return result;
327
+ }, isSelectingEntireBlocks = (snapshot) => {
328
+ if (!snapshot.context.selection) return !1;
329
+ let startPoint = snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor, endPoint = snapshot.context.selection.backward ? snapshot.context.selection.anchor : snapshot.context.selection.focus, startBlock = getSelectionStartBlock(snapshot), endBlock = getSelectionEndBlock(snapshot);
330
+ if (!startBlock || !endBlock) return !1;
331
+ let startBlockStartPoint = getBlockStartPoint({
332
+ context: snapshot.context,
333
+ block: startBlock
334
+ }), endBlockEndPoint = getBlockEndPoint({
335
+ context: snapshot.context,
336
+ block: endBlock
337
+ });
338
+ return isEqualSelectionPoints(startBlockStartPoint, startPoint) && isEqualSelectionPoints(endBlockEndPoint, endPoint);
339
+ };
340
+ /**
341
+ * @public
342
+ */
343
+ function isSelectionExpanded(selection) {
344
+ return selection ? !isSelectionCollapsed$1(selection) : !1;
345
+ }
346
+ /**
347
+ * @public
348
+ */
349
+ const getSelectionEndPoint = (snapshot) => {
350
+ if (snapshot.context.selection) return snapshot.context.selection.backward ? snapshot.context.selection.anchor : snapshot.context.selection.focus;
351
+ }, getNextSpan = (snapshot) => {
352
+ let point = getSelectionEndPoint(snapshot);
353
+ if (point) return getSibling(snapshot, point.path, {
354
+ direction: "next",
355
+ match: (node) => isSpan(snapshot.context, node)
356
+ });
357
+ }, getSelectionStartPoint = (snapshot) => {
358
+ if (snapshot.context.selection) return snapshot.context.selection.backward ? snapshot.context.selection.focus : snapshot.context.selection.anchor;
359
+ }, getPreviousSpan = (snapshot) => {
360
+ let point = getSelectionStartPoint(snapshot);
361
+ if (point) return getSibling(snapshot, point.path, {
362
+ direction: "previous",
363
+ match: (node) => isSpan(snapshot.context, node)
364
+ });
365
+ };
366
+ /**
367
+ * Returns the inline children (spans and inline objects) touched by the
368
+ * selection, resolved at any depth.
369
+ *
370
+ * @public
371
+ */
372
+ function getSelectedChildren(options) {
373
+ let filter = options?.filter;
374
+ return (snapshot) => {
375
+ let startPoint = getSelectionStartPoint$1(snapshot.context.selection), endPoint = getSelectionEndPoint$1(snapshot.context.selection);
376
+ if (!startPoint || !endPoint) return [];
377
+ let startChildKey = startPoint.path.findLast(isKeyedSegment)?._key, endChildKey = endPoint.path.findLast(isKeyedSegment)?._key, result = [];
378
+ if (startChildKey && startChildKey === endChildKey && isInline(snapshot, startPoint.path)) {
379
+ let node = getNode(snapshot, startPoint.path);
380
+ if (node) {
381
+ let child = node.node, skip = !1;
382
+ child._key === startChildKey && isSpan(snapshot.context, child) && (startPoint.offset >= child.text.length && (skip = !0), endPoint.offset <= 0 && (skip = !0)), !skip && (!filter || filter(child)) && result.push({
383
+ node: child,
384
+ path: node.path
385
+ });
386
+ }
387
+ return result;
388
+ }
389
+ for (let entry of getNodes(snapshot, {
390
+ from: startPoint.path,
391
+ to: endPoint.path,
392
+ match: (_, path) => isInline(snapshot, path)
393
+ })) {
394
+ let child = entry.node;
395
+ child._key === startChildKey && isSpan(snapshot.context, child) && startPoint.offset >= child.text.length || child._key === endChildKey && isSpan(snapshot.context, child) && endPoint.offset <= 0 || filter && !filter(child) || result.push({
396
+ node: child,
397
+ path: entry.path
398
+ });
399
+ }
400
+ return result;
401
+ };
402
+ }
403
+ /**
404
+ * Returns the spans touched by the selection, resolved at any depth.
405
+ *
406
+ * @public
407
+ */
408
+ const getSelectedSpans = (snapshot) => snapshot.context.selection ? getSelectedChildren({ filter: (child) => isSpan(snapshot.context, child) })(snapshot) : [], getMarkState = (snapshot) => {
409
+ if (!snapshot.context.selection) return;
410
+ let selection = snapshot.context.selection;
411
+ if (getBlock(snapshot, selection.anchor.path)) {
412
+ let spanSelectionPoint = blockOffsetToSpanSelectionPoint({
413
+ snapshot,
414
+ blockOffset: {
415
+ path: selection.anchor.path,
416
+ offset: selection.anchor.offset
417
+ },
418
+ direction: selection.backward ? "backward" : "forward"
419
+ });
420
+ selection = spanSelectionPoint ? {
421
+ ...selection,
422
+ anchor: spanSelectionPoint
423
+ } : selection;
424
+ }
425
+ if (getBlock(snapshot, selection.focus.path)) {
426
+ let spanSelectionPoint = blockOffsetToSpanSelectionPoint({
427
+ snapshot,
428
+ blockOffset: {
429
+ path: selection.focus.path,
430
+ offset: selection.focus.offset
431
+ },
432
+ direction: selection.backward ? "backward" : "forward"
433
+ });
434
+ selection = spanSelectionPoint ? {
435
+ ...selection,
436
+ focus: spanSelectionPoint
437
+ } : selection;
438
+ }
439
+ let focusSpan = getFocusSpan({
440
+ ...snapshot,
441
+ context: {
442
+ ...snapshot.context,
443
+ selection
444
+ }
445
+ });
446
+ if (!focusSpan) return;
447
+ if (isSelectionExpanded(selection)) {
448
+ let spanInfo = getSelectedSpans({
449
+ ...snapshot,
450
+ context: {
451
+ ...snapshot.context,
452
+ selection
453
+ }
454
+ }).map((span) => {
455
+ let block = getParent(snapshot, span.path, { match: (node) => isTextBlock({ schema: snapshot.context.schema }, node) });
456
+ return {
457
+ marks: span.node.marks ?? [],
458
+ decoratorNames: getPathSubSchema(snapshot, span.path).decorators.map((decorator) => decorator.name),
459
+ markDefKeys: (block?.node.markDefs ?? []).map((markDef) => markDef._key)
460
+ };
461
+ }), candidateMarks = /* @__PURE__ */ new Set();
462
+ for (let { marks: spanMarks } of spanInfo) for (let mark of spanMarks) candidateMarks.add(mark);
463
+ let marks = [];
464
+ for (let candidate of candidateMarks) {
465
+ let isDecoratorSomewhere = spanInfo.some(({ decoratorNames }) => decoratorNames.includes(candidate)), active = !0;
466
+ for (let { marks: spanMarks, decoratorNames, markDefKeys } of spanInfo) if ((isDecoratorSomewhere ? decoratorNames.includes(candidate) : markDefKeys.includes(candidate)) && !spanMarks.includes(candidate)) {
467
+ active = !1;
468
+ break;
469
+ }
470
+ active && marks.push(candidate);
471
+ }
472
+ return {
473
+ state: "unchanged",
474
+ marks
475
+ };
476
+ }
477
+ let decorators = getPathSubSchema(snapshot, focusSpan.path).decorators.map((decorator) => decorator.name), marks = focusSpan.node.marks ?? [], marksWithoutAnnotations = marks.filter((mark) => decorators.includes(mark)), spanHasAnnotations = marks.length > marksWithoutAnnotations.length, spanIsEmpty = focusSpan.node.text.length === 0, atTheBeginningOfSpan = snapshot.context.selection.anchor.offset === 0, atTheEndOfSpan = snapshot.context.selection.anchor.offset === focusSpan.node.text.length, previousSpan = getPreviousSpan({
478
+ ...snapshot,
479
+ context: {
480
+ ...snapshot.context,
481
+ selection
482
+ }
483
+ }), nextSpan = getNextSpan({
484
+ ...snapshot,
485
+ context: {
486
+ ...snapshot.context,
487
+ selection
488
+ }
489
+ }), nextSpanAnnotations = nextSpan?.node?.marks?.filter((mark) => !decorators.includes(mark)) ?? [], spanAnnotations = marks.filter((mark) => !decorators.includes(mark)), previousSpanHasAnnotations = previousSpan ? previousSpan.node.marks?.some((mark) => !decorators.includes(mark)) : !1, previousSpanHasSameAnnotations = previousSpan ? previousSpan.node.marks?.filter((mark) => !decorators.includes(mark)).every((mark) => marks.includes(mark)) : !1, previousSpanHasSameAnnotation = previousSpan ? previousSpan.node.marks?.some((mark) => !decorators.includes(mark) && marks.includes(mark)) : !1, previousSpanHasSameMarks = previousSpan ? previousSpan.node.marks?.every((mark) => marks.includes(mark)) : !1, nextSpanSharesSomeAnnotations = spanAnnotations.some((mark) => nextSpanAnnotations?.includes(mark));
490
+ if (spanHasAnnotations && !spanIsEmpty) {
491
+ if (atTheBeginningOfSpan) {
492
+ if (previousSpanHasSameMarks || previousSpanHasSameAnnotations) return {
493
+ state: "changed",
494
+ previousMarks: marks,
495
+ marks: previousSpan?.node.marks ?? []
496
+ };
497
+ if (previousSpanHasSameAnnotation) return {
498
+ state: "unchanged",
499
+ marks: focusSpan.node.marks ?? []
500
+ };
501
+ if (!previousSpan) return {
502
+ state: "changed",
503
+ previousMarks: marks,
504
+ marks: []
505
+ };
506
+ }
507
+ if (atTheEndOfSpan) {
508
+ if (!nextSpan || nextSpanAnnotations.length > 0 && !nextSpanSharesSomeAnnotations) return {
509
+ state: "changed",
510
+ previousMarks: marks,
511
+ marks: []
512
+ };
513
+ if (nextSpanSharesSomeAnnotations && nextSpanAnnotations.length < spanAnnotations.length || !nextSpanSharesSomeAnnotations) return {
514
+ state: "changed",
515
+ previousMarks: marks,
516
+ marks: nextSpan?.node.marks ?? []
517
+ };
518
+ }
519
+ }
520
+ return atTheBeginningOfSpan && !spanIsEmpty && previousSpan ? previousSpanHasAnnotations ? {
521
+ state: "changed",
522
+ marks,
523
+ previousMarks: previousSpan?.node.marks ?? []
524
+ } : {
525
+ state: "changed",
526
+ previousMarks: marks,
527
+ marks: (previousSpan?.node.marks ?? []).filter((mark) => decorators.includes(mark))
528
+ } : {
529
+ state: "unchanged",
530
+ marks
531
+ };
532
+ };
533
+ function getActiveAnnotationsMarks(snapshot) {
534
+ let schema = snapshot.context.schema;
535
+ return (getMarkState(snapshot)?.marks ?? []).filter((mark) => !schema.decorators.map((decorator) => decorator.name).includes(mark));
536
+ }
537
+ /**
538
+ * Returns the text blocks touched by the selection, resolved at any depth.
539
+ *
540
+ * Walks the tree between the selection endpoints and returns every text
541
+ * block found, regardless of container nesting. For toolbar state and
542
+ * anywhere that needs "text blocks with text in the selection".
543
+ *
544
+ * @public
545
+ */
546
+ const getSelectedTextBlocks = (snapshot) => {
547
+ let selection = snapshot.context.selection;
548
+ if (!selection) return [];
549
+ let startPoint = getSelectionStartPoint$1(selection), endPoint = getSelectionEndPoint$1(selection);
550
+ if (!startPoint || !endPoint) return [];
551
+ let startBlock = getEnclosingBlock(snapshot, startPoint.path), endBlock = getEnclosingBlock(snapshot, endPoint.path);
552
+ if (startBlock && endBlock && startBlock.node._key === endBlock.node._key && isTextBlock(snapshot.context, startBlock.node)) return [{
553
+ node: startBlock.node,
554
+ path: startBlock.path
555
+ }];
556
+ let result = [];
557
+ for (let entry of getNodes(snapshot, {
558
+ from: startPoint.path,
559
+ to: endPoint.path,
560
+ match: (node) => isTextBlock(snapshot.context, node)
561
+ })) isTextBlock(snapshot.context, entry.node) && result.push({
562
+ node: entry.node,
563
+ path: entry.path
564
+ });
565
+ return result;
566
+ };
567
+ function getActiveDecorators(snapshot) {
568
+ let decoratorState = snapshot.decoratorState, markState = getMarkState(snapshot), selectedBlocks = getSelectedTextBlocks(snapshot), decorators = /* @__PURE__ */ new Set();
569
+ for (let block of selectedBlocks) for (let decorator of getPathSubSchema(snapshot, block.path).decorators) decorators.add(decorator.name);
570
+ if (decorators.size === 0) for (let decorator of snapshot.context.schema.decorators) decorators.add(decorator.name);
571
+ let activeDecorators = (markState?.marks ?? []).filter((mark) => decorators.has(mark));
572
+ for (let decorator in decoratorState) decoratorState[decorator] === !1 ? activeDecorators = activeDecorators.filter((activeDecorator) => activeDecorator !== decorator) : decoratorState[decorator] === !0 && (activeDecorators.includes(decorator) || activeDecorators.push(decorator));
573
+ return activeDecorators;
574
+ }
575
+ /**
576
+ * Check whether an annotation is active in the given `snapshot`.
577
+ *
578
+ * @public
579
+ */
580
+ function isActiveAnnotation(annotation, options) {
581
+ return (snapshot) => {
582
+ if ((options?.mode ?? "full") === "partial" && isSelectionExpanded$1(snapshot)) return getSelectedValue(snapshot).some((block) => {
583
+ if (!isTextBlock(snapshot.context, block)) return !1;
584
+ let annotationKeys = new Set((block.markDefs ?? []).filter((markDef) => markDef._type === annotation).map((markDef) => markDef._key));
585
+ return annotationKeys.size !== 0 && block.children.some((child) => isSpan(snapshot.context, child) && child.text.length > 0 && child.marks?.some((mark) => annotationKeys.has(mark)));
586
+ });
587
+ let selectionMarkDefs = getSelectedTextBlocks(snapshot).flatMap((block) => block.node.markDefs ?? []), activeAnnotations = getActiveAnnotationsMarks(snapshot);
588
+ return selectionMarkDefs.filter((markDef) => markDef._type === annotation && activeAnnotations.includes(markDef._key)).length > 0;
589
+ };
590
+ }
591
+ /**
592
+ * @public
593
+ */
594
+ const getActiveAnnotations = (snapshot) => {
595
+ if (!snapshot.context.selection) return [];
596
+ let selectedBlocks = getSelectedTextBlocks(snapshot), markState = getMarkState(snapshot), decoratorNames = /* @__PURE__ */ new Set();
597
+ for (let block of selectedBlocks) for (let decorator of getPathSubSchema(snapshot, block.path).decorators) decoratorNames.add(decorator.name);
598
+ if (decoratorNames.size === 0) for (let decorator of snapshot.context.schema.decorators) decoratorNames.add(decorator.name);
599
+ let activeAnnotations = (markState?.marks ?? []).filter((mark) => !decoratorNames.has(mark));
600
+ return selectedBlocks.flatMap((block) => block.node.markDefs ?? []).filter((markDef) => activeAnnotations.includes(markDef._key));
601
+ }, getActiveListItem = (snapshot) => {
602
+ if (!snapshot.context.selection) return;
603
+ let selectedTextBlocks = getSelectedTextBlocks(snapshot), firstTextBlock = selectedTextBlocks.at(0);
604
+ if (!firstTextBlock) return;
605
+ let firstListItem = firstTextBlock.node.listItem;
606
+ if (firstListItem && selectedTextBlocks.filter((block) => getPathSubSchema(snapshot, block.path).lists.some((l) => l.name === firstListItem)).every((block) => block.node.listItem === firstListItem)) return firstListItem;
607
+ }, getActiveStyle = (snapshot) => {
608
+ if (!snapshot.context.selection) return;
609
+ let selectedTextBlocks = getSelectedTextBlocks(snapshot), firstTextBlock = selectedTextBlocks.at(0);
610
+ if (!firstTextBlock) return;
611
+ let firstStyle = firstTextBlock.node.style ?? getPathSubSchema(snapshot, firstTextBlock.path).styles.at(0)?.name;
612
+ if (firstStyle && selectedTextBlocks.filter((block) => getPathSubSchema(snapshot, block.path).styles.some((s) => s.name === firstStyle)).every((block) => (block.node.style ?? getPathSubSchema(snapshot, block.path).styles.at(0)?.name) === firstStyle)) return firstStyle;
613
+ }, getNextInlineObject = (snapshot) => {
614
+ let point = getSelectionEndPoint(snapshot);
615
+ if (point) return getSibling(snapshot, point.path, {
616
+ direction: "next",
617
+ match: (node) => isObject(snapshot, node)
618
+ });
619
+ }, getPreviousInlineObject = (snapshot) => {
620
+ let point = getSelectionStartPoint(snapshot);
621
+ if (point) return getSibling(snapshot, point.path, {
622
+ direction: "previous",
623
+ match: (node) => isObject(snapshot, node)
624
+ });
625
+ }, getSelectionText = (snapshot) => {
626
+ let selectedValue = getSelectedValue(snapshot);
627
+ return collectText(snapshot.context, selectedValue);
628
+ };
629
+ function collectText(context, blocks, parent) {
630
+ let text = "";
631
+ for (let block of blocks) {
632
+ if (isTextBlock(context, block)) {
633
+ for (let child of block.children) isSpan(context, child) && (text += child.text);
634
+ continue;
635
+ }
636
+ let childInfo = getNodeChildren(context, block, parent);
637
+ childInfo && (text += collectText(context, childInfo.children, childInfo.parent));
638
+ }
639
+ return text;
640
+ }
641
+ /**
642
+ * @public
643
+ * Returns the selection of the of the word the caret is placed in.
644
+ * Note: Only returns a word selection if the current selection is collapsed
645
+ */
646
+ const getCaretWordSelection = (snapshot) => {
647
+ if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return null;
648
+ let focusTextBlock = getFocusTextBlock(snapshot), selectionStartPoint = getSelectionStartPoint(snapshot), selectionStartOffset = selectionStartPoint ? spanSelectionPointToBlockOffset({
649
+ snapshot,
650
+ selectionPoint: selectionStartPoint
651
+ }) : void 0;
652
+ if (!focusTextBlock || !selectionStartPoint || !selectionStartOffset) return null;
653
+ let previousInlineObject = getPreviousInlineObject(snapshot), blockStartPoint = getBlockStartPoint({
654
+ context: snapshot.context,
655
+ block: focusTextBlock
656
+ }), textDirectlyBefore = getSelectionText({
657
+ ...snapshot,
658
+ context: {
659
+ ...snapshot.context,
660
+ selection: {
661
+ anchor: previousInlineObject ? {
662
+ path: previousInlineObject.path,
663
+ offset: 0
664
+ } : blockStartPoint,
665
+ focus: selectionStartPoint
666
+ }
667
+ }
668
+ }).split(/\s+/).at(-1), nextInlineObject = getNextInlineObject(snapshot), blockEndPoint = getBlockEndPoint({
669
+ context: snapshot.context,
670
+ block: focusTextBlock
671
+ }), textDirectlyAfter = getSelectionText({
672
+ ...snapshot,
673
+ context: {
674
+ ...snapshot.context,
675
+ selection: {
676
+ anchor: selectionStartPoint,
677
+ focus: nextInlineObject ? {
678
+ path: nextInlineObject.path,
679
+ offset: 0
680
+ } : blockEndPoint
681
+ }
682
+ }
683
+ }).split(/\s+/).at(0);
684
+ if ((textDirectlyBefore === void 0 || textDirectlyBefore === "") && (textDirectlyAfter === void 0 || textDirectlyAfter === "")) return null;
685
+ let caretWordStartOffset = textDirectlyBefore ? {
686
+ ...selectionStartOffset,
687
+ offset: selectionStartOffset.offset - textDirectlyBefore.length
688
+ } : selectionStartOffset, caretWordEndOffset = textDirectlyAfter ? {
689
+ ...selectionStartOffset,
690
+ offset: selectionStartOffset.offset + textDirectlyAfter.length
691
+ } : selectionStartOffset, caretWordStartSelectionPoint = blockOffsetToSpanSelectionPoint({
692
+ snapshot,
693
+ blockOffset: caretWordStartOffset,
694
+ direction: "backward"
695
+ }), caretWordEndSelectionPoint = blockOffsetToSpanSelectionPoint({
696
+ snapshot,
697
+ blockOffset: caretWordEndOffset,
698
+ direction: "forward"
699
+ });
700
+ if (!caretWordStartSelectionPoint || !caretWordEndSelectionPoint) return null;
701
+ let caretWordSelection = {
702
+ anchor: caretWordStartSelectionPoint,
703
+ focus: caretWordEndSelectionPoint
704
+ };
705
+ return isSelectionExpanded$1({
706
+ ...snapshot,
707
+ context: {
708
+ ...snapshot.context,
709
+ selection: caretWordSelection
710
+ }
711
+ }) ? caretWordSelection : null;
712
+ }, getFocusBlockObject = (snapshot) => {
713
+ let focusBlock = getFocusBlock(snapshot);
714
+ if (focusBlock && !isTextBlockNode(snapshot.context, focusBlock.node) && !isEditableContainer(snapshot, focusBlock.node, focusBlock.path)) return {
715
+ node: focusBlock.node,
716
+ path: focusBlock.path
717
+ };
718
+ }, getFocusListBlock = (snapshot) => {
719
+ let focusTextBlock = getFocusTextBlock(snapshot);
720
+ return focusTextBlock && isListBlock(snapshot.context, focusTextBlock.node) ? {
721
+ node: focusTextBlock.node,
722
+ path: focusTextBlock.path
723
+ } : void 0;
724
+ }, getLastBlock = (snapshot) => {
725
+ let focusBlock = getFocusBlock(snapshot);
726
+ if (focusBlock) {
727
+ let last = getChildren(snapshot, parentPath(focusBlock.path)).at(-1);
728
+ if (last) return getBlock(snapshot, last.path);
729
+ }
730
+ let node = snapshot.context.value.at(-1);
731
+ return node ? {
732
+ node,
733
+ path: [{ _key: node._key }]
734
+ } : void 0;
735
+ }, getNextBlock = (snapshot) => {
736
+ let selectionEndBlock = getSelectionEndBlock(snapshot);
737
+ if (!selectionEndBlock) return;
738
+ let next = getSibling(snapshot, selectionEndBlock.path, { direction: "next" });
739
+ if (next) return getBlock(snapshot, next.path);
740
+ }, getPreviousBlock = (snapshot) => {
741
+ let selectionStartBlock = getSelectionStartBlock(snapshot);
742
+ if (!selectionStartBlock) return;
743
+ let previous = getSibling(snapshot, selectionStartBlock.path, { direction: "previous" });
744
+ if (previous) return getBlock(snapshot, previous.path);
745
+ }, getSelectionEndChild = (snapshot) => {
746
+ let endPoint = getSelectionEndPoint$1(snapshot.context.selection);
747
+ if (endPoint) return getFocusChild({
748
+ ...snapshot,
749
+ context: {
750
+ ...snapshot.context,
751
+ selection: {
752
+ anchor: endPoint,
753
+ focus: endPoint
754
+ }
755
+ }
756
+ });
757
+ }, getSelectionStartChild = (snapshot) => {
758
+ let startPoint = getSelectionStartPoint$1(snapshot.context.selection);
759
+ if (startPoint) return getFocusChild({
760
+ ...snapshot,
761
+ context: {
762
+ ...snapshot.context,
763
+ selection: {
764
+ anchor: startPoint,
765
+ focus: startPoint
766
+ }
767
+ }
768
+ });
769
+ };
770
+ /**
771
+ * @public
772
+ */
773
+ function isActiveDecorator(decorator) {
774
+ return (snapshot) => {
775
+ if (isSelectionExpanded$1(snapshot)) {
776
+ let inScopeSpans = getSelectedSpans(snapshot).filter((span) => getPathSubSchema(snapshot, span.path).decorators.some((d) => d.name === decorator));
777
+ return inScopeSpans.length > 0 && inScopeSpans.every((span) => span.node.marks?.includes(decorator));
778
+ }
779
+ return getActiveDecorators(snapshot).includes(decorator);
780
+ };
781
+ }
782
+ /**
783
+ * @public
784
+ */
785
+ function isActiveListItem(listItem) {
786
+ return (snapshot) => getActiveListItem(snapshot) === listItem;
787
+ }
788
+ /**
789
+ * @public
790
+ */
791
+ function isActiveStyle(style) {
792
+ return (snapshot) => getActiveStyle(snapshot) === style;
793
+ }
794
+ /**
795
+ * @public
796
+ */
797
+ function isAtTheEndOfBlock(block) {
798
+ return (snapshot) => {
799
+ if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return !1;
800
+ let blockEndPoint = getBlockEndPoint({
801
+ context: snapshot.context,
802
+ block
803
+ });
804
+ return isEqualSelectionPoints(snapshot.context.selection.focus, blockEndPoint);
805
+ };
806
+ }
807
+ /**
808
+ * @public
809
+ */
810
+ function isAtTheStartOfBlock(block) {
811
+ return (snapshot) => {
812
+ if (!snapshot.context.selection || !isSelectionCollapsed(snapshot)) return !1;
813
+ let blockStartPoint = getBlockStartPoint({
814
+ context: snapshot.context,
815
+ block
816
+ });
817
+ return isEqualSelectionPoints(snapshot.context.selection.focus, blockStartPoint);
818
+ };
819
+ }
820
+ export { isSelectingEntireBlocks as A, getFocusTextBlock as B, getActiveAnnotationsMarks as C, getSelectionStartPoint as D, getPreviousSpan as E, getSelectionStartBlock as F, getInline as G, getFocusSpan as H, getSelectionEndBlock as I, rangesOverlap as K, getFragment as L, isSelectionExpanded$1 as M, isSelectionCollapsed as N, getNextSpan as O, isOverlappingSelection as P, getSelectedValue as R, getSelectedTextBlocks as S, getSelectedSpans as T, getFocusInlineObject as U, getFocusBlock as V, getFocusChild as W, getActiveStyle as _, isActiveDecorator as a, isActiveAnnotation as b, getPreviousBlock as c, getFocusListBlock as d, getFocusBlockObject as f, getNextInlineObject as g, getPreviousInlineObject as h, isActiveListItem as i, getSelectedBlocks as j, getSelectionEndPoint as k, getNextBlock as l, getSelectionText as m, isAtTheEndOfBlock as n, getSelectionStartChild as o, getCaretWordSelection as p, isActiveStyle as r, getSelectionEndChild as s, isAtTheStartOfBlock as t, getLastBlock as u, getActiveListItem as v, getMarkState as w, getActiveDecorators as x, getActiveAnnotations as y, getRootAcceptedTypes as z };
821
+
822
+ //# sourceMappingURL=selector.is-at-the-start-of-block-gJIMWRpU.js.map