@bigbinary/neeto-editor 1.45.26 → 1.45.28

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/dist/Editor.js CHANGED
@@ -4,7 +4,7 @@ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
4
4
  import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
5
5
  import * as React from 'react';
6
6
  import React__default, { memo, useEffect, useState, useRef, useCallback, createElement, forwardRef, useImperativeHandle } from 'react';
7
- import { E as Extension, a as Mark, m as mergeAttributes, b as markInputRule, c as markPasteRule, D as DecorationSet, d as Decoration, g as getMarkAttributes, N as Node, w as wrappingInputRule, t as textblockTypeInputRule, k as keydownHandler, e as callOrReturn, f as getExtensionField, i as isNodeSelection, n as nodeInputRule, h as findChildren, j as NodeViewWrapper, l as NodeViewContent, R as ReactNodeViewRenderer, P as PasteRule, v as validateUrl, o as escapeForRegEx, p as ReactRenderer, q as EmojiPickerMenu, r as emojiPickerApi, s as liftTarget, u as combineTransactionSteps, x as getChangedRanges, y as findChildrenInRange, z as getMarksBetween, A as getAttributes, I as InputRule, B as highlightFocussedNode, C as resetFocussedNode, F as findParentNodeClosestToPos, G as BubbleMenu, H as getLinkPopoverPosition, J as getMarkType, K as getMarkRange, L as useEditor, O as useEditorState, M as Menu$3, Q as EditorContent, S as MediaUploader, T as EmbedOption, U as EditorView } from './chunk-B_ypvaUL.js';
7
+ import { E as Extension, a as Mark, m as mergeAttributes, b as markInputRule, c as markPasteRule, D as DecorationSet, d as Decoration, g as getMarkAttributes, N as Node, i as isNodeActive, e as isAtStartOfNode, f as isAtEndOfNode, h as getNodeType, j as getNodeAtPosition, w as wrappingInputRule, t as textblockTypeInputRule, k as keydownHandler, l as callOrReturn, n as getExtensionField, o as isNodeSelection, p as nodeInputRule, q as findChildren, r as NodeViewWrapper, s as NodeViewContent, R as ReactNodeViewRenderer, P as PasteRule, v as validateUrl, u as escapeForRegEx, x as ReactRenderer, y as EmojiPickerMenu, z as emojiPickerApi, A as combineTransactionSteps, B as getChangedRanges, C as findChildrenInRange, F as getMarksBetween, G as getAttributes, I as InputRule, H as highlightFocussedNode, J as resetFocussedNode, K as findParentNodeClosestToPos, L as BubbleMenu, O as getLinkPopoverPosition, Q as getMarkType, S as getMarkRange, T as useEditor, U as useEditorState, M as Menu$3, V as EditorContent, W as MediaUploader, X as EmbedOption, Y as EditorView } from './chunk-C0xZGEez.js';
8
8
  import classnames from 'classnames';
9
9
  import { C as COMBINED_REGEX, D as DIRECT_UPLOAD_ENDPOINT, E as EDITOR_OPTIONS, a as EDITOR_SIZES } from './chunk-FWwP48qR.js';
10
10
  import { isNotPresent, isNotEmpty, isPresent, noop as noop$1, slugify } from '@bigbinary/neeto-cist';
@@ -3008,6 +3008,268 @@ const Highlight = Mark.create({
3008
3008
  },
3009
3009
  });
3010
3010
 
3011
+ const findListItemPos = (typeOrName, state) => {
3012
+ const { $from } = state.selection;
3013
+ const nodeType = getNodeType(typeOrName, state.schema);
3014
+ let currentNode = null;
3015
+ let currentDepth = $from.depth;
3016
+ let currentPos = $from.pos;
3017
+ let targetDepth = null;
3018
+ while (currentDepth > 0 && targetDepth === null) {
3019
+ currentNode = $from.node(currentDepth);
3020
+ if (currentNode.type === nodeType) {
3021
+ targetDepth = currentDepth;
3022
+ }
3023
+ else {
3024
+ currentDepth -= 1;
3025
+ currentPos -= 1;
3026
+ }
3027
+ }
3028
+ if (targetDepth === null) {
3029
+ return null;
3030
+ }
3031
+ return { $pos: state.doc.resolve(currentPos), depth: targetDepth };
3032
+ };
3033
+
3034
+ const getNextListDepth = (typeOrName, state) => {
3035
+ const listItemPos = findListItemPos(typeOrName, state);
3036
+ if (!listItemPos) {
3037
+ return false;
3038
+ }
3039
+ const [, depth] = getNodeAtPosition(state, typeOrName, listItemPos.$pos.pos + 4);
3040
+ return depth;
3041
+ };
3042
+
3043
+ const hasListBefore = (editorState, name, parentListTypes) => {
3044
+ const { $anchor } = editorState.selection;
3045
+ const previousNodePos = Math.max(0, $anchor.pos - 2);
3046
+ const previousNode = editorState.doc.resolve(previousNodePos).node();
3047
+ if (!previousNode || !parentListTypes.includes(previousNode.type.name)) {
3048
+ return false;
3049
+ }
3050
+ return true;
3051
+ };
3052
+
3053
+ const hasListItemBefore = (typeOrName, state) => {
3054
+ var _a;
3055
+ const { $anchor } = state.selection;
3056
+ const $targetPos = state.doc.resolve($anchor.pos - 2);
3057
+ if ($targetPos.index() === 0) {
3058
+ return false;
3059
+ }
3060
+ if (((_a = $targetPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.type.name) !== typeOrName) {
3061
+ return false;
3062
+ }
3063
+ return true;
3064
+ };
3065
+
3066
+ const listItemHasSubList = (typeOrName, state, node) => {
3067
+ if (!node) {
3068
+ return false;
3069
+ }
3070
+ const nodeType = getNodeType(typeOrName, state.schema);
3071
+ let hasSubList = false;
3072
+ node.descendants(child => {
3073
+ if (child.type === nodeType) {
3074
+ hasSubList = true;
3075
+ }
3076
+ });
3077
+ return hasSubList;
3078
+ };
3079
+
3080
+ const handleBackspace = (editor, name, parentListTypes) => {
3081
+ // this is required to still handle the undo handling
3082
+ if (editor.commands.undoInputRule()) {
3083
+ return true;
3084
+ }
3085
+ // if the selection is not collapsed
3086
+ // we can rely on the default backspace behavior
3087
+ if (editor.state.selection.from !== editor.state.selection.to) {
3088
+ return false;
3089
+ }
3090
+ // if the current item is NOT inside a list item &
3091
+ // the previous item is a list (orderedList or bulletList)
3092
+ // move the cursor into the list and delete the current item
3093
+ if (!isNodeActive(editor.state, name) && hasListBefore(editor.state, name, parentListTypes)) {
3094
+ const { $anchor } = editor.state.selection;
3095
+ const $listPos = editor.state.doc.resolve($anchor.before() - 1);
3096
+ const listDescendants = [];
3097
+ $listPos.node().descendants((node, pos) => {
3098
+ if (node.type.name === name) {
3099
+ listDescendants.push({ node, pos });
3100
+ }
3101
+ });
3102
+ const lastItem = listDescendants.at(-1);
3103
+ if (!lastItem) {
3104
+ return false;
3105
+ }
3106
+ const $lastItemPos = editor.state.doc.resolve($listPos.start() + lastItem.pos + 1);
3107
+ return editor.chain().cut({ from: $anchor.start() - 1, to: $anchor.end() + 1 }, $lastItemPos.end()).joinForward().run();
3108
+ }
3109
+ // if the cursor is not inside the current node type
3110
+ // do nothing and proceed
3111
+ if (!isNodeActive(editor.state, name)) {
3112
+ return false;
3113
+ }
3114
+ // if the cursor is not at the start of a node
3115
+ // do nothing and proceed
3116
+ if (!isAtStartOfNode(editor.state)) {
3117
+ return false;
3118
+ }
3119
+ const listItemPos = findListItemPos(name, editor.state);
3120
+ if (!listItemPos) {
3121
+ return false;
3122
+ }
3123
+ const $prev = editor.state.doc.resolve(listItemPos.$pos.pos - 2);
3124
+ const prevNode = $prev.node(listItemPos.depth);
3125
+ const previousListItemHasSubList = listItemHasSubList(name, editor.state, prevNode);
3126
+ // if the previous item is a list item and doesn't have a sublist, join the list items
3127
+ if (hasListItemBefore(name, editor.state) && !previousListItemHasSubList) {
3128
+ return editor.commands.joinItemBackward();
3129
+ }
3130
+ // otherwise in the end, a backspace should
3131
+ // always just lift the list item if
3132
+ // joining / merging is not possible
3133
+ return editor.chain().liftListItem(name).run();
3134
+ };
3135
+
3136
+ const nextListIsDeeper = (typeOrName, state) => {
3137
+ const listDepth = getNextListDepth(typeOrName, state);
3138
+ const listItemPos = findListItemPos(typeOrName, state);
3139
+ if (!listItemPos || !listDepth) {
3140
+ return false;
3141
+ }
3142
+ if (listDepth > listItemPos.depth) {
3143
+ return true;
3144
+ }
3145
+ return false;
3146
+ };
3147
+
3148
+ const nextListIsHigher = (typeOrName, state) => {
3149
+ const listDepth = getNextListDepth(typeOrName, state);
3150
+ const listItemPos = findListItemPos(typeOrName, state);
3151
+ if (!listItemPos || !listDepth) {
3152
+ return false;
3153
+ }
3154
+ if (listDepth < listItemPos.depth) {
3155
+ return true;
3156
+ }
3157
+ return false;
3158
+ };
3159
+
3160
+ const handleDelete = (editor, name) => {
3161
+ // if the cursor is not inside the current node type
3162
+ // do nothing and proceed
3163
+ if (!isNodeActive(editor.state, name)) {
3164
+ return false;
3165
+ }
3166
+ // if the cursor is not at the end of a node
3167
+ // do nothing and proceed
3168
+ if (!isAtEndOfNode(editor.state, name)) {
3169
+ return false;
3170
+ }
3171
+ // if the selection is not collapsed, or not within a single node
3172
+ // do nothing and proceed
3173
+ const { selection } = editor.state;
3174
+ const { $from, $to } = selection;
3175
+ if (!selection.empty && $from.sameParent($to)) {
3176
+ return false;
3177
+ }
3178
+ // check if the next node is a list with a deeper depth
3179
+ if (nextListIsDeeper(name, editor.state)) {
3180
+ return editor
3181
+ .chain()
3182
+ .focus(editor.state.selection.from + 4)
3183
+ .lift(name)
3184
+ .joinBackward()
3185
+ .run();
3186
+ }
3187
+ if (nextListIsHigher(name, editor.state)) {
3188
+ return editor.chain()
3189
+ .joinForward()
3190
+ .joinBackward()
3191
+ .run();
3192
+ }
3193
+ return editor.commands.joinItemForward();
3194
+ };
3195
+
3196
+ /**
3197
+ * This extension registers custom keymaps to change the behaviour of the backspace and delete keys.
3198
+ * By default Prosemirror keyhandling will always lift or sink items so paragraphs are joined into
3199
+ * the adjacent or previous list item. This extension will prevent this behaviour and instead will
3200
+ * try to join paragraphs from two list items into a single list item.
3201
+ * @see https://www.tiptap.dev/api/extensions/list-keymap
3202
+ */
3203
+ const ListKeymap = Extension.create({
3204
+ name: 'listKeymap',
3205
+ addOptions() {
3206
+ return {
3207
+ listTypes: [
3208
+ {
3209
+ itemName: 'listItem',
3210
+ wrapperNames: ['bulletList', 'orderedList'],
3211
+ },
3212
+ {
3213
+ itemName: 'taskItem',
3214
+ wrapperNames: ['taskList'],
3215
+ },
3216
+ ],
3217
+ };
3218
+ },
3219
+ addKeyboardShortcuts() {
3220
+ return {
3221
+ Delete: ({ editor }) => {
3222
+ let handled = false;
3223
+ this.options.listTypes.forEach(({ itemName }) => {
3224
+ if (editor.state.schema.nodes[itemName] === undefined) {
3225
+ return;
3226
+ }
3227
+ if (handleDelete(editor, itemName)) {
3228
+ handled = true;
3229
+ }
3230
+ });
3231
+ return handled;
3232
+ },
3233
+ 'Mod-Delete': ({ editor }) => {
3234
+ let handled = false;
3235
+ this.options.listTypes.forEach(({ itemName }) => {
3236
+ if (editor.state.schema.nodes[itemName] === undefined) {
3237
+ return;
3238
+ }
3239
+ if (handleDelete(editor, itemName)) {
3240
+ handled = true;
3241
+ }
3242
+ });
3243
+ return handled;
3244
+ },
3245
+ Backspace: ({ editor }) => {
3246
+ let handled = false;
3247
+ this.options.listTypes.forEach(({ itemName, wrapperNames }) => {
3248
+ if (editor.state.schema.nodes[itemName] === undefined) {
3249
+ return;
3250
+ }
3251
+ if (handleBackspace(editor, itemName, wrapperNames)) {
3252
+ handled = true;
3253
+ }
3254
+ });
3255
+ return handled;
3256
+ },
3257
+ 'Mod-Backspace': ({ editor }) => {
3258
+ let handled = false;
3259
+ this.options.listTypes.forEach(({ itemName, wrapperNames }) => {
3260
+ if (editor.state.schema.nodes[itemName] === undefined) {
3261
+ return;
3262
+ }
3263
+ if (handleBackspace(editor, itemName, wrapperNames)) {
3264
+ handled = true;
3265
+ }
3266
+ });
3267
+ return handled;
3268
+ },
3269
+ };
3270
+ },
3271
+ });
3272
+
3011
3273
  /**
3012
3274
  * This extension allows you to create table cells.
3013
3275
  * @see https://www.tiptap.dev/api/nodes/table-cell
@@ -10751,51 +11013,16 @@ var KeyboardShortcuts = function KeyboardShortcuts(_ref) {
10751
11013
  return true;
10752
11014
  }
10753
11015
  return false;
10754
- },
10755
- // To fix the issue with backspace on the empty list item moving the focus to the block on top.
10756
- // https://github.com/ueberdosis/tiptap/issues/2829#issuecomment-1511064298
10757
- Backspace: function Backspace() {
10758
- return _this.editor.commands.command(function (_ref2) {
10759
- var tr = _ref2.tr;
10760
- var selection = tr.selection,
10761
- doc = tr.doc;
10762
- var $cursor = selection.$cursor;
10763
- var depth = $cursor === null || $cursor === void 0 ? void 0 : $cursor.depth;
10764
- if ($cursor && depth >= 3 &&
10765
- // At least the structure is doc -> orderedList/bulletList -> listItem -> paragraph
10766
- $cursor.parent.type.name === "paragraph" &&
10767
- // The cursor is inside a paragraph.
10768
- $cursor.parentOffset === 0 &&
10769
- // The cursor is at the beginning of the paragraph.
10770
- $cursor.node(depth - 1).type.name === "listItem" &&
10771
- // The paragraph is inside a listItem.
10772
- $cursor.index(depth - 1) === 0 &&
10773
- // The paragraph is at the beginning of the listItem.
10774
- $cursor.index(depth - 2) === 0 // The listItem is at the beginning of the list.
10775
- ) {
10776
- var listItemNode = $cursor.node(depth - 1);
10777
- var listItemPos = $cursor.before(depth - 1);
10778
- var $contentBegin = doc.resolve(listItemPos + 1);
10779
- var $contentEnd = doc.resolve(listItemPos + listItemNode.nodeSize - 1);
10780
- var range = $contentBegin.blockRange($contentEnd);
10781
- var target = liftTarget(range);
10782
- if (target !== null) {
10783
- tr.lift(range, target);
10784
- return true;
10785
- }
10786
- }
10787
- return false;
10788
- });
10789
11016
  }
10790
11017
  }, shortcuts);
10791
11018
  }
10792
11019
  });
10793
11020
  };
10794
11021
  var KeyboardShortcuts$1 = {
10795
- configure: function configure(_ref3) {
10796
- var onSubmit = _ref3.onSubmit,
10797
- shortcuts = _ref3.shortcuts,
10798
- isBlockQuoteActive = _ref3.isBlockQuoteActive;
11022
+ configure: function configure(_ref2) {
11023
+ var onSubmit = _ref2.onSubmit,
11024
+ shortcuts = _ref2.shortcuts,
11025
+ isBlockQuoteActive = _ref2.isBlockQuoteActive;
10799
11026
  return KeyboardShortcuts({
10800
11027
  onSubmit: onSubmit,
10801
11028
  shortcuts: shortcuts,
@@ -19184,7 +19411,7 @@ var useCustomExtensions = function useCustomExtensions(_ref) {
19184
19411
  onSubmit: onSubmit,
19185
19412
  shortcuts: keyboardShortcuts,
19186
19413
  isBlockQuoteActive: options.includes(EDITOR_OPTIONS.BLOCKQUOTE)
19187
- })];
19414
+ }), ListKeymap];
19188
19415
  if (isVideoEmbedActive) {
19189
19416
  customExtensions.push(Embeds);
19190
19417
  }