@contentful/field-editor-rich-text 2.0.0-next.26 → 2.0.0-next.29
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/CHANGELOG.md +410 -0
- package/dist/field-editor-rich-text.cjs.development.js +121 -87
- package/dist/field-editor-rich-text.cjs.development.js.map +1 -1
- package/dist/field-editor-rich-text.cjs.production.min.js +1 -1
- package/dist/field-editor-rich-text.cjs.production.min.js.map +1 -1
- package/dist/field-editor-rich-text.esm.js +125 -91
- package/dist/field-editor-rich-text.esm.js.map +1 -1
- package/dist/helpers/editor.d.ts +1 -3
- package/dist/plugins/Table/insertTableFragment.d.ts +3 -0
- package/dist/plugins/Table/onKeyDownTable.d.ts +3 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React__default, { createContext, useContext, useMemo, createElement, useEffect, useState, memo, Fragment, useCallback } from 'react';
|
|
2
2
|
import { useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, EntityProvider, getScheduleTooltipContent } from '@contentful/field-editor-reference';
|
|
3
3
|
import { entityHelpers, shortenStorageUnit, isValidImage, ModalDialogLauncher, FieldConnector } from '@contentful/field-editor-shared';
|
|
4
|
-
import { BLOCKS, INLINES,
|
|
4
|
+
import { BLOCKS, INLINES, TEXT_CONTAINERS, HEADINGS, LIST_ITEM_BLOCKS, MARKS, CONTAINERS, TOP_LEVEL_BLOCKS, VOID_BLOCKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
|
|
5
5
|
import { usePlateEditorRef, usePlateEditorState, getNodes, toggleNodeType, getText, getAbove, setNodes, isAncestorEmpty, match, getLastChildPath, wrapNodes, getPluginType, unwrapNodes, isCollapsed, isRangeAcrossBlocks, ELEMENT_DEFAULT, findNode, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, deleteFragment, isMarkActive, toggleMark, someHtmlElement, KEY_DESERIALIZE_HTML, hasSingleChild, isLastChild, someNode, getChildren as getChildren$1, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, getPlateSelectors, getPlateActions, Plate } from '@udecode/plate-core';
|
|
6
6
|
import { css, cx } from 'emotion';
|
|
7
7
|
import deepEquals from 'fast-deep-equal';
|
|
@@ -10,7 +10,7 @@ import { createDeserializeDocxPlugin } from '@udecode/plate-serializer-docx';
|
|
|
10
10
|
import { createSoftBreakPlugin as createSoftBreakPlugin$1, createExitBreakPlugin as createExitBreakPlugin$1 } from '@udecode/plate-break';
|
|
11
11
|
import { createResetNodePlugin as createResetNodePlugin$1, onKeyDownResetNode, SIMULATE_BACKSPACE } from '@udecode/plate-reset-node';
|
|
12
12
|
import isHotkey from 'is-hotkey';
|
|
13
|
-
import { Text, Element, Editor, Transforms, Range,
|
|
13
|
+
import { Text, Element, Editor, Transforms, Range, Path, Node, Point } from 'slate';
|
|
14
14
|
import { ReactEditor, useSelected, useReadOnly, useFocused } from 'slate-react';
|
|
15
15
|
import constate from 'constate';
|
|
16
16
|
import { AssetCard, Menu, Text as Text$1, Notification, EntryCard, MenuItem, Button, Flex, Icon, InlineEntryCard, Tooltip, ModalContent, Form, FormControl, TextInput, Select, FormLabel, TextLink, ModalControls, IconButton } from '@contentful/f36-components';
|
|
@@ -26,7 +26,7 @@ import { createBoldPlugin as createBoldPlugin$1, createCodePlugin as createCodeP
|
|
|
26
26
|
import isPlainObject from 'is-plain-obj';
|
|
27
27
|
import { createParagraphPlugin as createParagraphPlugin$1 } from '@udecode/plate-paragraph';
|
|
28
28
|
import { createSelectOnBackspacePlugin as createSelectOnBackspacePlugin$1 } from '@udecode/plate-select';
|
|
29
|
-
import { ELEMENT_TABLE, ELEMENT_TR, getEmptyRowNode, ELEMENT_TD, ELEMENT_TH, getEmptyCellNode, insertTable, deleteRow, deleteColumn, deleteTable, createTablePlugin as createTablePlugin$1,
|
|
29
|
+
import { ELEMENT_TABLE, ELEMENT_TR, getEmptyRowNode, ELEMENT_TD, ELEMENT_TH, getEmptyCellNode, insertTable, deleteRow, deleteColumn, deleteTable, onKeyDownTable as onKeyDownTable$1, getTableCellEntry, createTablePlugin as createTablePlugin$1, withTable } from '@udecode/plate-table';
|
|
30
30
|
import { toContentfulDocument, toSlatejsDocument } from '@contentful/contentful-slatejs-adapter';
|
|
31
31
|
import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
|
|
32
32
|
import { createTrailingBlockPlugin } from '@udecode/plate-trailing-block';
|
|
@@ -454,7 +454,7 @@ function moveToTheNextChar(editor) {
|
|
|
454
454
|
unit: 'character'
|
|
455
455
|
});
|
|
456
456
|
}
|
|
457
|
-
function insertEmptyParagraph(editor) {
|
|
457
|
+
function insertEmptyParagraph(editor, options) {
|
|
458
458
|
var emptyParagraph = {
|
|
459
459
|
type: BLOCKS.PARAGRAPH,
|
|
460
460
|
children: [{
|
|
@@ -463,7 +463,7 @@ function insertEmptyParagraph(editor) {
|
|
|
463
463
|
data: {},
|
|
464
464
|
isVoid: false
|
|
465
465
|
};
|
|
466
|
-
Transforms.insertNodes(editor, emptyParagraph);
|
|
466
|
+
Transforms.insertNodes(editor, emptyParagraph, options);
|
|
467
467
|
}
|
|
468
468
|
function getElementFromCurrentSelection(editor) {
|
|
469
469
|
if (!editor.selection) return [];
|
|
@@ -583,58 +583,6 @@ function getAncestorPathFromSelection(editor) {
|
|
|
583
583
|
return level.length === 1;
|
|
584
584
|
});
|
|
585
585
|
}
|
|
586
|
-
var isAtEndOfTextSelection = function isAtEndOfTextSelection(editor) {
|
|
587
|
-
var _editor$selection2, _editor$selection3;
|
|
588
|
-
|
|
589
|
-
return ((_editor$selection2 = editor.selection) == null ? void 0 : _editor$selection2.focus.offset) === getText(editor, (_editor$selection3 = editor.selection) == null ? void 0 : _editor$selection3.focus.path).length;
|
|
590
|
-
};
|
|
591
|
-
function currentSelectionStartsTableCell(editor) {
|
|
592
|
-
var _editor$selection4;
|
|
593
|
-
|
|
594
|
-
var _getNodeEntryFromSele2 = getNodeEntryFromSelection(editor, [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL]),
|
|
595
|
-
tableCellNode = _getNodeEntryFromSele2[0],
|
|
596
|
-
path = _getNodeEntryFromSele2[1];
|
|
597
|
-
|
|
598
|
-
return !!tableCellNode && (!getText(editor, path) || ((_editor$selection4 = editor.selection) == null ? void 0 : _editor$selection4.focus.offset) === 0);
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* This traversal strategy is unfortunately necessary because Slate doesn't
|
|
602
|
-
* expose something like Node.next(editor).
|
|
603
|
-
*/
|
|
604
|
-
|
|
605
|
-
function getNextNode(editor) {
|
|
606
|
-
if (!editor.selection) {
|
|
607
|
-
return null;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
var descendants = Node.descendants(editor, {
|
|
611
|
-
from: editor.selection.focus.path
|
|
612
|
-
}); // eslint-disable-next-line no-constant-condition
|
|
613
|
-
|
|
614
|
-
while (true) {
|
|
615
|
-
var _descendants$next = descendants.next(),
|
|
616
|
-
done = _descendants$next.done,
|
|
617
|
-
value = _descendants$next.value;
|
|
618
|
-
|
|
619
|
-
if (done) {
|
|
620
|
-
return null;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
var node = value[0],
|
|
624
|
-
path = value[1];
|
|
625
|
-
|
|
626
|
-
if (Path.isCommon(path, editor.selection.focus.path)) {
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return node;
|
|
631
|
-
}
|
|
632
|
-
} // TODO: move to table plugin
|
|
633
|
-
|
|
634
|
-
function currentSelectionPrecedesTableCell(editor) {
|
|
635
|
-
var nextNode = getNextNode(editor);
|
|
636
|
-
return !!nextNode && TABLE_BLOCKS.includes(nextNode.type) && isAtEndOfTextSelection(editor);
|
|
637
|
-
}
|
|
638
586
|
var INLINE_TYPES = /*#__PURE__*/Object.values(INLINES);
|
|
639
587
|
var isInlineOrText = function isInlineOrText(node) {
|
|
640
588
|
// either text or inline elements
|
|
@@ -5916,21 +5864,126 @@ var Row = function Row(props) {
|
|
|
5916
5864
|
var _templateObject$a;
|
|
5917
5865
|
var style$5 = /*#__PURE__*/css(_templateObject$a || (_templateObject$a = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n margin-bottom: 1.5em;\n border-collapse: collapse;\n border-radius: 5px;\n border-style: hidden;\n box-shadow: 0 0 0 1px ", ";\n width: 100%;\n table-layout: fixed;\n overflow: hidden;\n"])), tokens.gray400);
|
|
5918
5866
|
var Table = function Table(props) {
|
|
5919
|
-
return /*#__PURE__*/createElement("
|
|
5867
|
+
return /*#__PURE__*/createElement("div", {
|
|
5868
|
+
"data-block-type": BLOCKS.TABLE
|
|
5869
|
+
}, /*#__PURE__*/createElement("table", Object.assign({
|
|
5920
5870
|
className: style$5
|
|
5921
|
-
}), /*#__PURE__*/createElement("tbody", null, props.children));
|
|
5871
|
+
}, props.attributes), /*#__PURE__*/createElement("tbody", null, props.children)));
|
|
5872
|
+
};
|
|
5873
|
+
|
|
5874
|
+
/**
|
|
5875
|
+
* Removes table wrappers when pasting a single table cell
|
|
5876
|
+
*
|
|
5877
|
+
* In Plate/Slate, copying the content of a table cell wraps
|
|
5878
|
+
* it in a <table><tr><td>{content}</td></tr></table> even
|
|
5879
|
+
* when copying partial cell content.
|
|
5880
|
+
*
|
|
5881
|
+
* That's really annoying as there is no way to remove the table
|
|
5882
|
+
* wrappers in that case.
|
|
5883
|
+
*/
|
|
5884
|
+
|
|
5885
|
+
var trimUnnecessaryTableWrapper = function trimUnnecessaryTableWrapper(node) {
|
|
5886
|
+
if (!Element.isElement(node)) {
|
|
5887
|
+
return [node];
|
|
5888
|
+
} // must be a table with a single row
|
|
5889
|
+
|
|
5890
|
+
|
|
5891
|
+
if (node.type !== BLOCKS.TABLE || node.children.length !== 1) {
|
|
5892
|
+
return [node];
|
|
5893
|
+
}
|
|
5894
|
+
|
|
5895
|
+
var row = node.children[0]; // the row must contain a single cell
|
|
5896
|
+
|
|
5897
|
+
if (row.children.length !== 1) {
|
|
5898
|
+
return [node];
|
|
5899
|
+
}
|
|
5900
|
+
|
|
5901
|
+
var cell = row.children[0];
|
|
5902
|
+
return cell.children;
|
|
5903
|
+
};
|
|
5904
|
+
|
|
5905
|
+
var insertTableFragment = function insertTableFragment(editor) {
|
|
5906
|
+
var insertFragment = editor.insertFragment;
|
|
5907
|
+
return function (fragments) {
|
|
5908
|
+
var _editor$selection;
|
|
5909
|
+
|
|
5910
|
+
if (!editor.selection) {
|
|
5911
|
+
return;
|
|
5912
|
+
}
|
|
5913
|
+
|
|
5914
|
+
fragments = fragments.flatMap(trimUnnecessaryTableWrapper); // We need to make sure we have a new, empty and clean paragraph in order to paste tables as-is due to how Slate behaves
|
|
5915
|
+
// More info: https://github.com/ianstormtaylor/slate/pull/4489 and https://github.com/ianstormtaylor/slate/issues/4542
|
|
5916
|
+
|
|
5917
|
+
var isInsertingTable = fragments.some(function (fragment) {
|
|
5918
|
+
return isTable(fragment);
|
|
5919
|
+
});
|
|
5920
|
+
var isTableFirstFragment = fragments.findIndex(function (fragment) {
|
|
5921
|
+
return isTable(fragment);
|
|
5922
|
+
}) === 0;
|
|
5923
|
+
var currentLineHasText = getText(editor, (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path) !== '';
|
|
5924
|
+
|
|
5925
|
+
if (isInsertingTable && isTableFirstFragment && currentLineHasText) {
|
|
5926
|
+
insertEmptyParagraph(editor);
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
return insertFragment(fragments);
|
|
5930
|
+
};
|
|
5922
5931
|
};
|
|
5923
5932
|
|
|
5924
|
-
var
|
|
5925
|
-
var defaultHandler = onKeyDownTable(editor, plugin);
|
|
5933
|
+
var onKeyDownTable = function onKeyDownTable(editor, plugin) {
|
|
5934
|
+
var defaultHandler = onKeyDownTable$1(editor, plugin);
|
|
5926
5935
|
return function (event) {
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5936
|
+
// This fixes `Cannot resolve a Slate point from DOM point: [object HTMLDivElement]` when typing while the cursor is before table
|
|
5937
|
+
var windowSelection = window.getSelection();
|
|
5938
|
+
|
|
5939
|
+
if (windowSelection) {
|
|
5940
|
+
var _windowSelection$anch, _windowSelection$anch2;
|
|
5941
|
+
|
|
5942
|
+
// @ts-expect-error
|
|
5943
|
+
var blockType = (_windowSelection$anch = windowSelection.anchorNode.attributes) == null ? void 0 : (_windowSelection$anch2 = _windowSelection$anch['data-block-type']) == null ? void 0 : _windowSelection$anch2.value; // this attribute comes from `plugins/Table/components/Table.tsx`
|
|
5944
|
+
|
|
5945
|
+
var isBeforeTable = blockType === BLOCKS.TABLE;
|
|
5946
|
+
|
|
5947
|
+
if (isBeforeTable) {
|
|
5948
|
+
if (event.key === 'Enter') {
|
|
5949
|
+
var above = getAbove(editor, {
|
|
5950
|
+
match: {
|
|
5951
|
+
type: BLOCKS.TABLE
|
|
5952
|
+
}
|
|
5953
|
+
});
|
|
5954
|
+
if (!above) return;
|
|
5955
|
+
var tablePath = above[1];
|
|
5956
|
+
insertEmptyParagraph(editor, {
|
|
5957
|
+
at: tablePath,
|
|
5958
|
+
select: true
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
event.preventDefault();
|
|
5963
|
+
event.stopPropagation();
|
|
5964
|
+
return;
|
|
5965
|
+
}
|
|
5966
|
+
} // Pressing Tab on the last cell creates a new row
|
|
5967
|
+
// Otherwise, jumping between cells is handled in the defaultKeyDownTable
|
|
5968
|
+
|
|
5969
|
+
|
|
5970
|
+
if (event.key === 'Tab' && !event.shiftKey) {
|
|
5931
5971
|
event.preventDefault();
|
|
5932
|
-
|
|
5933
|
-
|
|
5972
|
+
var res = getTableCellEntry(editor, {});
|
|
5973
|
+
|
|
5974
|
+
if (res) {
|
|
5975
|
+
var tableElement = res.tableElement,
|
|
5976
|
+
tableRow = res.tableRow,
|
|
5977
|
+
tableCell = res.tableCell;
|
|
5978
|
+
var isLastCell = isLastChild(tableRow, tableCell[1]);
|
|
5979
|
+
var isLastRow = isLastChild(tableElement, tableRow[1]);
|
|
5980
|
+
|
|
5981
|
+
if (isLastRow && isLastCell) {
|
|
5982
|
+
addRowBelow(editor); // skip default handler
|
|
5983
|
+
|
|
5984
|
+
return;
|
|
5985
|
+
}
|
|
5986
|
+
}
|
|
5934
5987
|
}
|
|
5935
5988
|
|
|
5936
5989
|
defaultHandler(event);
|
|
@@ -5943,32 +5996,13 @@ var createTablePlugin = function createTablePlugin() {
|
|
|
5943
5996
|
return createTablePlugin$1({
|
|
5944
5997
|
type: BLOCKS.TABLE,
|
|
5945
5998
|
handlers: {
|
|
5946
|
-
onKeyDown:
|
|
5999
|
+
onKeyDown: onKeyDownTable
|
|
5947
6000
|
},
|
|
5948
|
-
withOverrides: function withOverrides(editor) {
|
|
6001
|
+
withOverrides: function withOverrides(editor, plugin) {
|
|
6002
|
+
// injects important fixes from plate's original table plugin
|
|
6003
|
+
withTable(editor, plugin);
|
|
5949
6004
|
addTableTrackingEvents(editor);
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
editor.insertFragment = function (fragments) {
|
|
5953
|
-
var _editor$selection;
|
|
5954
|
-
|
|
5955
|
-
// We need to make sure we have a new, empty and clean paragraph in order to paste tables as-is due to how Slate behaves
|
|
5956
|
-
// More info: https://github.com/ianstormtaylor/slate/pull/4489 and https://github.com/ianstormtaylor/slate/issues/4542
|
|
5957
|
-
var isInsertingTable = fragments.some(function (fragment) {
|
|
5958
|
-
return isTable(fragment);
|
|
5959
|
-
});
|
|
5960
|
-
var isTableFirstFragment = fragments.findIndex(function (fragment) {
|
|
5961
|
-
return isTable(fragment);
|
|
5962
|
-
}) === 0;
|
|
5963
|
-
var currentLineHasText = getText(editor, (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path) !== '';
|
|
5964
|
-
|
|
5965
|
-
if (isInsertingTable && isTableFirstFragment && currentLineHasText) {
|
|
5966
|
-
insertEmptyParagraph(editor);
|
|
5967
|
-
}
|
|
5968
|
-
|
|
5969
|
-
insertFragment(fragments);
|
|
5970
|
-
};
|
|
5971
|
-
|
|
6005
|
+
editor.insertFragment = insertTableFragment(editor);
|
|
5972
6006
|
return editor;
|
|
5973
6007
|
},
|
|
5974
6008
|
overrideByKey: (_overrideByKey = {}, _overrideByKey[ELEMENT_TABLE] = {
|