@udecode/plate-list
Advanced tools
Comparing version 2.0.0 to 3.0.4
# @udecode/plate-list | ||
## 3.0.4 | ||
### Patch Changes | ||
- [#971](https://github.com/udecode/plate/pull/971) [`46398095`](https://github.com/udecode/plate/commit/4639809567e4c96d58912c2a16e74948474d4547) Thanks [@vimtor](https://github.com/vimtor)! - List plugin was preventing all tab key strokes without checking if a list item was being selected. Fix: Don't prevent tab if list is not selected. | ||
## 2.0.0 | ||
@@ -4,0 +10,0 @@ |
import { getPlatePluginOptions, getPlatePluginType, getPlatePluginTypes, mapPlatePluginKeysToOptions, isElement, getRenderElement, getSlateClass } from '@udecode/plate-core'; | ||
import { getElementDeserializer, findNode, getParent, match, wrapNodes, findDescendant, getLastChildPath, moveChildren, setNodes, ELEMENT_DEFAULT, unwrapNodes, getAbove, isLastChild, insertNodes, getNode, getNodes, someNode, getChildren, insertEmptyElement, isCollapsed, isFirstChild, isExpanded, getPreviousPath, deleteFragment, isSelectionAtBlockStart, isRangeAcrossBlocks, isBlockTextEmptyAfterSelection, isBlockAboveEmpty, getNodeDeserializer, getToggleElementOnKeyDown } from '@udecode/plate-common'; | ||
import { getElementDeserializer, findNode, getParent, match, wrapNodes, findDescendant, getLastChildPath, moveChildren, setNodes, ELEMENT_DEFAULT, unwrapNodes, getAbove, isLastChild, insertNodes, getNode, getNodes, isBlockTextEmptyAfterSelection, isFirstChild, isExpanded, getPreviousPath, deleteFragment, someNode, getChildren, insertEmptyElement, isCollapsed, isSelectionAtBlockStart, isRangeAcrossBlocks, isBlockAboveEmpty, getNodeDeserializer, getToggleElementOnKeyDown } from '@udecode/plate-common'; | ||
import { Path, Editor, Transforms, Range, Node } from 'slate'; | ||
@@ -693,2 +693,286 @@ import { getResetNodeOnKeyDown, SIMULATE_BACKSPACE } from '@udecode/plate-reset-node'; | ||
const indentListItems = editor => { | ||
moveListItems(editor, true); | ||
}; | ||
/** | ||
* Insert list item if selection in li>p. | ||
* TODO: test | ||
*/ | ||
const insertListItem = editor => { | ||
const liType = getPlatePluginType(editor, ELEMENT_LI); | ||
const licType = getPlatePluginType(editor, ELEMENT_LIC); | ||
if (editor.selection) { | ||
const licEntry = getAbove(editor, { | ||
match: { | ||
type: licType | ||
} | ||
}); | ||
if (!licEntry) return; | ||
const [, paragraphPath] = licEntry; | ||
const listItemEntry = getParent(editor, paragraphPath); | ||
if (!listItemEntry) return; | ||
const [listItemNode, listItemPath] = listItemEntry; | ||
if (listItemNode.type !== liType) return; | ||
if (!Range.isCollapsed(editor.selection)) { | ||
Transforms.delete(editor); | ||
} | ||
const isStart = Editor.isStart(editor, editor.selection.focus, paragraphPath); | ||
const isEnd = isBlockTextEmptyAfterSelection(editor); | ||
const nextParagraphPath = Path.next(paragraphPath); | ||
const nextListItemPath = Path.next(listItemPath); | ||
/** | ||
* If start, insert a list item before | ||
*/ | ||
if (isStart) { | ||
insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: listItemPath | ||
}); | ||
return true; | ||
} | ||
/** | ||
* If not end, split nodes, wrap a list item on the new paragraph and move it to the next list item | ||
*/ | ||
if (!isEnd) { | ||
Editor.withoutNormalizing(editor, () => { | ||
Transforms.splitNodes(editor); | ||
wrapNodes(editor, { | ||
type: liType, | ||
children: [] | ||
}, { | ||
at: nextParagraphPath | ||
}); | ||
Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath | ||
}); | ||
Transforms.select(editor, nextListItemPath); | ||
Transforms.collapse(editor, { | ||
edge: 'start' | ||
}); | ||
}); | ||
} else { | ||
/** | ||
* If end, insert a list item after and select it | ||
*/ | ||
const marks = Editor.marks(editor) || {}; | ||
insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '', | ||
...marks | ||
}] | ||
}] | ||
}, { | ||
at: nextListItemPath | ||
}); | ||
Transforms.select(editor, nextListItemPath); | ||
} | ||
/** | ||
* If there is a list in the list item, move it to the next list item | ||
*/ | ||
if (listItemNode.children.length > 1) { | ||
Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath.concat(1) | ||
}); | ||
} | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Move fromListItem sublist list items to the end of `toListItem` sublist. | ||
* If there is no `toListItem` sublist, insert one. | ||
*/ | ||
const moveListItemSublistItemsToListItemSublist = (editor, { | ||
fromListItem, | ||
toListItem, | ||
start | ||
}) => { | ||
const [, fromListItemPath] = fromListItem; | ||
const [, toListItemPath] = toListItem; | ||
const fromListItemSublist = findDescendant(editor, { | ||
at: fromListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
if (!fromListItemSublist) return 0; | ||
const [, fromListItemSublistPath] = fromListItemSublist; | ||
const toListItemSublist = findDescendant(editor, { | ||
at: toListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
let to; | ||
if (!toListItemSublist) { | ||
const fromList = getParent(editor, fromListItemPath); | ||
if (!fromList) return 0; | ||
const [fromListNode] = fromList; | ||
const fromListType = fromListNode.type; | ||
const toListItemSublistPath = toListItemPath.concat([1]); | ||
insertNodes(editor, { | ||
type: fromListType, | ||
children: [] | ||
}, { | ||
at: toListItemSublistPath | ||
}); | ||
to = toListItemSublistPath.concat([0]); | ||
} else if (start) { | ||
const [, toListItemSublistPath] = toListItemSublist; | ||
to = toListItemSublistPath.concat([0]); | ||
} else { | ||
to = Path.next(getLastChildPath(toListItemSublist)); | ||
} | ||
const moved = moveChildren(editor, { | ||
at: fromListItemSublistPath, | ||
to | ||
}); // Remove the empty list | ||
Transforms.delete(editor, { | ||
at: fromListItemSublistPath | ||
}); | ||
return moved; | ||
}; | ||
const moveListSiblingsAfterCursor = (editor, { | ||
at, | ||
to | ||
}) => { | ||
const offset = at[at.length - 1]; | ||
at = Path.parent(at); | ||
const listNode = Node.get(editor, at); | ||
const listEntry = [listNode, at]; | ||
if (!match(listNode, { | ||
type: getListTypes(editor) | ||
}) || Path.isParent(at, to) // avoid moving nodes within its own list | ||
) { | ||
return 0; | ||
} | ||
return moveChildren(editor, { | ||
at: listEntry, | ||
to, | ||
fromStartIndex: offset + 1 | ||
}); | ||
}; | ||
/** | ||
* If list is not nested and if li is not the first child, move li up. | ||
*/ | ||
const removeFirstListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [, listPath] = list; | ||
const [, listItemPath] = listItem; | ||
if (!isListNested(editor, listPath) && !isFirstChild(listItemPath)) { | ||
moveListItemUp(editor, { | ||
list, | ||
listItem | ||
}); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Remove list item and move its sublist to list if any. | ||
*/ | ||
const removeListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [liNode, liPath] = listItem; // Stop if the list item has no sublist | ||
if (isExpanded(editor.selection) || !hasListChild(editor, liNode)) { | ||
return false; | ||
} | ||
const previousLiPath = getPreviousPath(liPath); | ||
/** | ||
* If there is a previous li, we need to move sub-lis to the previous li. | ||
* As we need to delete first, we will: | ||
* 1. insert a temporary li: tempLi | ||
* 2. move sub-lis to tempLi | ||
* 3. delete | ||
* 4. move sub-lis from tempLi to the previous li. | ||
* 5. remove tempLi | ||
*/ | ||
if (previousLiPath) { | ||
const previousLi = Editor.node(editor, previousLiPath); // 1 | ||
let tempLiPath = Path.next(liPath); | ||
insertNodes(editor, { | ||
type: getPlatePluginType(editor, ELEMENT_LI), | ||
children: [{ | ||
type: getPlatePluginType(editor, ELEMENT_LIC), | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: tempLiPath | ||
}); | ||
const tempLi = Editor.node(editor, tempLiPath); | ||
const tempLiPathRef = Editor.pathRef(editor, tempLi[1]); // 2 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: listItem, | ||
toListItem: tempLi | ||
}); // 3 | ||
deleteFragment(editor, { | ||
reverse: true | ||
}); | ||
tempLiPath = tempLiPathRef.unref(); // 4 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: [tempLi[0], tempLiPath], | ||
toListItem: previousLi | ||
}); // 5 | ||
Transforms.removeNodes(editor, { | ||
at: tempLiPath | ||
}); | ||
return true; | ||
} // If it's the first li, move the sublist to the parent list | ||
moveListItemsToList(editor, { | ||
fromListItem: listItem, | ||
toList: list, | ||
toListIndex: 1 | ||
}); | ||
}; | ||
const toggleList = (editor, { | ||
@@ -737,9 +1021,22 @@ type | ||
const unindentListItems = editor => { | ||
moveListItems(editor, false); | ||
}; | ||
const getListOnKeyDown = pluginKeys => editor => e => { | ||
const listTypes = getPlatePluginTypes([ELEMENT_UL, ELEMENT_OL])(editor); | ||
if (e.key === 'Tab') { | ||
e.preventDefault(); | ||
moveListItems(editor, !e.shiftKey); | ||
return; | ||
if (e.key === 'Tab' && editor.selection) { | ||
const listSelected = getAbove(editor, { | ||
at: editor.selection, | ||
match: { | ||
type: listTypes | ||
} | ||
}); | ||
if (listSelected) { | ||
e.preventDefault(); | ||
moveListItems(editor, !e.shiftKey); | ||
return; | ||
} | ||
} | ||
@@ -971,153 +1268,2 @@ | ||
/** | ||
* If list is not nested and if li is not the first child, move li up. | ||
*/ | ||
const removeFirstListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [, listPath] = list; | ||
const [, listItemPath] = listItem; | ||
if (!isListNested(editor, listPath) && !isFirstChild(listItemPath)) { | ||
moveListItemUp(editor, { | ||
list, | ||
listItem | ||
}); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Move fromListItem sublist list items to the end of `toListItem` sublist. | ||
* If there is no `toListItem` sublist, insert one. | ||
*/ | ||
const moveListItemSublistItemsToListItemSublist = (editor, { | ||
fromListItem, | ||
toListItem, | ||
start | ||
}) => { | ||
const [, fromListItemPath] = fromListItem; | ||
const [, toListItemPath] = toListItem; | ||
const fromListItemSublist = findDescendant(editor, { | ||
at: fromListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
if (!fromListItemSublist) return 0; | ||
const [, fromListItemSublistPath] = fromListItemSublist; | ||
const toListItemSublist = findDescendant(editor, { | ||
at: toListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
let to; | ||
if (!toListItemSublist) { | ||
const fromList = getParent(editor, fromListItemPath); | ||
if (!fromList) return 0; | ||
const [fromListNode] = fromList; | ||
const fromListType = fromListNode.type; | ||
const toListItemSublistPath = toListItemPath.concat([1]); | ||
insertNodes(editor, { | ||
type: fromListType, | ||
children: [] | ||
}, { | ||
at: toListItemSublistPath | ||
}); | ||
to = toListItemSublistPath.concat([0]); | ||
} else if (start) { | ||
const [, toListItemSublistPath] = toListItemSublist; | ||
to = toListItemSublistPath.concat([0]); | ||
} else { | ||
to = Path.next(getLastChildPath(toListItemSublist)); | ||
} | ||
const moved = moveChildren(editor, { | ||
at: fromListItemSublistPath, | ||
to | ||
}); // Remove the empty list | ||
Transforms.delete(editor, { | ||
at: fromListItemSublistPath | ||
}); | ||
return moved; | ||
}; | ||
/** | ||
* Remove list item and move its sublist to list if any. | ||
*/ | ||
const removeListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [liNode, liPath] = listItem; // Stop if the list item has no sublist | ||
if (isExpanded(editor.selection) || !hasListChild(editor, liNode)) { | ||
return false; | ||
} | ||
const previousLiPath = getPreviousPath(liPath); | ||
/** | ||
* If there is a previous li, we need to move sub-lis to the previous li. | ||
* As we need to delete first, we will: | ||
* 1. insert a temporary li: tempLi | ||
* 2. move sub-lis to tempLi | ||
* 3. delete | ||
* 4. move sub-lis from tempLi to the previous li. | ||
* 5. remove tempLi | ||
*/ | ||
if (previousLiPath) { | ||
const previousLi = Editor.node(editor, previousLiPath); // 1 | ||
let tempLiPath = Path.next(liPath); | ||
insertNodes(editor, { | ||
type: getPlatePluginType(editor, ELEMENT_LI), | ||
children: [{ | ||
type: getPlatePluginType(editor, ELEMENT_LIC), | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: tempLiPath | ||
}); | ||
const tempLi = Editor.node(editor, tempLiPath); | ||
const tempLiPathRef = Editor.pathRef(editor, tempLi[1]); // 2 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: listItem, | ||
toListItem: tempLi | ||
}); // 3 | ||
deleteFragment(editor, { | ||
reverse: true | ||
}); | ||
tempLiPath = tempLiPathRef.unref(); // 4 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: [tempLi[0], tempLiPath], | ||
toListItem: previousLi | ||
}); // 5 | ||
Transforms.removeNodes(editor, { | ||
at: tempLiPath | ||
}); | ||
return true; | ||
} // If it's the first li, move the sublist to the parent list | ||
moveListItemsToList(editor, { | ||
fromListItem: listItem, | ||
toList: list, | ||
toListIndex: 1 | ||
}); | ||
}; | ||
const getListDeleteBackward = (editor, unit) => { | ||
@@ -1289,108 +1435,2 @@ const res = getListItemEntry(editor, {}); | ||
/** | ||
* Insert list item if selection in li>p. | ||
* TODO: test | ||
*/ | ||
const insertListItem = editor => { | ||
const liType = getPlatePluginType(editor, ELEMENT_LI); | ||
const licType = getPlatePluginType(editor, ELEMENT_LIC); | ||
if (editor.selection) { | ||
const licEntry = getAbove(editor, { | ||
match: { | ||
type: licType | ||
} | ||
}); | ||
if (!licEntry) return; | ||
const [, paragraphPath] = licEntry; | ||
const listItemEntry = getParent(editor, paragraphPath); | ||
if (!listItemEntry) return; | ||
const [listItemNode, listItemPath] = listItemEntry; | ||
if (listItemNode.type !== liType) return; | ||
if (!Range.isCollapsed(editor.selection)) { | ||
Transforms.delete(editor); | ||
} | ||
const isStart = Editor.isStart(editor, editor.selection.focus, paragraphPath); | ||
const isEnd = isBlockTextEmptyAfterSelection(editor); | ||
const nextParagraphPath = Path.next(paragraphPath); | ||
const nextListItemPath = Path.next(listItemPath); | ||
/** | ||
* If start, insert a list item before | ||
*/ | ||
if (isStart) { | ||
insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: listItemPath | ||
}); | ||
return true; | ||
} | ||
/** | ||
* If not end, split nodes, wrap a list item on the new paragraph and move it to the next list item | ||
*/ | ||
if (!isEnd) { | ||
Editor.withoutNormalizing(editor, () => { | ||
Transforms.splitNodes(editor); | ||
wrapNodes(editor, { | ||
type: liType, | ||
children: [] | ||
}, { | ||
at: nextParagraphPath | ||
}); | ||
Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath | ||
}); | ||
Transforms.select(editor, nextListItemPath); | ||
Transforms.collapse(editor, { | ||
edge: 'start' | ||
}); | ||
}); | ||
} else { | ||
/** | ||
* If end, insert a list item after and select it | ||
*/ | ||
const marks = Editor.marks(editor) || {}; | ||
insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '', | ||
...marks | ||
}] | ||
}] | ||
}, { | ||
at: nextListItemPath | ||
}); | ||
Transforms.select(editor, nextListItemPath); | ||
} | ||
/** | ||
* If there is a list in the list item, move it to the next list item | ||
*/ | ||
if (listItemNode.children.length > 1) { | ||
Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath.concat(1) | ||
}); | ||
} | ||
return true; | ||
} | ||
}; | ||
const getListInsertBreak = editor => { | ||
@@ -1575,34 +1615,3 @@ if (!editor.selection) return; | ||
const indentListItems = editor => { | ||
moveListItems(editor, true); | ||
}; | ||
const moveListSiblingsAfterCursor = (editor, { | ||
at, | ||
to | ||
}) => { | ||
const offset = at[at.length - 1]; | ||
at = Path.parent(at); | ||
const listNode = Node.get(editor, at); | ||
const listEntry = [listNode, at]; | ||
if (!match(listNode, { | ||
type: getListTypes(editor) | ||
}) || Path.isParent(at, to) // avoid moving nodes within its own list | ||
) { | ||
return 0; | ||
} | ||
return moveChildren(editor, { | ||
at: listEntry, | ||
to, | ||
fromStartIndex: offset + 1 | ||
}); | ||
}; | ||
const unindentListItems = editor => { | ||
moveListItems(editor, false); | ||
}; | ||
export { CLASS_TODO_LIST_CHECKED, DEFAULTS_TODO_LIST, ELEMENT_LI, ELEMENT_LIC, ELEMENT_OL, ELEMENT_TODO_LI, ELEMENT_UL, KEYS_LIST, createListPlugin, createTodoListPlugin, getDeepInlineChildren, getHighestEmptyList, getListDeleteBackward, getListDeleteFragment, getListDeserialize, getListInsertBreak, getListItemEntry, getListNormalizer, getListOnKeyDown, getListRoot, getListTypes, getTodoListDeserialize, hasListChild, indentListItems, insertListItem, isAcrossListItems, isListNested, moveListItemDown, moveListItemSublistItemsToListItemSublist, moveListItemUp, moveListItems, moveListItemsToList, moveListSiblingsAfterCursor, normalizeListItem, removeFirstListItem, removeListItem, toggleList, unindentListItems, unwrapList, withList }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -697,2 +697,286 @@ 'use strict'; | ||
const indentListItems = editor => { | ||
moveListItems(editor, true); | ||
}; | ||
/** | ||
* Insert list item if selection in li>p. | ||
* TODO: test | ||
*/ | ||
const insertListItem = editor => { | ||
const liType = plateCore.getPlatePluginType(editor, ELEMENT_LI); | ||
const licType = plateCore.getPlatePluginType(editor, ELEMENT_LIC); | ||
if (editor.selection) { | ||
const licEntry = plateCommon.getAbove(editor, { | ||
match: { | ||
type: licType | ||
} | ||
}); | ||
if (!licEntry) return; | ||
const [, paragraphPath] = licEntry; | ||
const listItemEntry = plateCommon.getParent(editor, paragraphPath); | ||
if (!listItemEntry) return; | ||
const [listItemNode, listItemPath] = listItemEntry; | ||
if (listItemNode.type !== liType) return; | ||
if (!slate.Range.isCollapsed(editor.selection)) { | ||
slate.Transforms.delete(editor); | ||
} | ||
const isStart = slate.Editor.isStart(editor, editor.selection.focus, paragraphPath); | ||
const isEnd = plateCommon.isBlockTextEmptyAfterSelection(editor); | ||
const nextParagraphPath = slate.Path.next(paragraphPath); | ||
const nextListItemPath = slate.Path.next(listItemPath); | ||
/** | ||
* If start, insert a list item before | ||
*/ | ||
if (isStart) { | ||
plateCommon.insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: listItemPath | ||
}); | ||
return true; | ||
} | ||
/** | ||
* If not end, split nodes, wrap a list item on the new paragraph and move it to the next list item | ||
*/ | ||
if (!isEnd) { | ||
slate.Editor.withoutNormalizing(editor, () => { | ||
slate.Transforms.splitNodes(editor); | ||
plateCommon.wrapNodes(editor, { | ||
type: liType, | ||
children: [] | ||
}, { | ||
at: nextParagraphPath | ||
}); | ||
slate.Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath | ||
}); | ||
slate.Transforms.select(editor, nextListItemPath); | ||
slate.Transforms.collapse(editor, { | ||
edge: 'start' | ||
}); | ||
}); | ||
} else { | ||
/** | ||
* If end, insert a list item after and select it | ||
*/ | ||
const marks = slate.Editor.marks(editor) || {}; | ||
plateCommon.insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '', | ||
...marks | ||
}] | ||
}] | ||
}, { | ||
at: nextListItemPath | ||
}); | ||
slate.Transforms.select(editor, nextListItemPath); | ||
} | ||
/** | ||
* If there is a list in the list item, move it to the next list item | ||
*/ | ||
if (listItemNode.children.length > 1) { | ||
slate.Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath.concat(1) | ||
}); | ||
} | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Move fromListItem sublist list items to the end of `toListItem` sublist. | ||
* If there is no `toListItem` sublist, insert one. | ||
*/ | ||
const moveListItemSublistItemsToListItemSublist = (editor, { | ||
fromListItem, | ||
toListItem, | ||
start | ||
}) => { | ||
const [, fromListItemPath] = fromListItem; | ||
const [, toListItemPath] = toListItem; | ||
const fromListItemSublist = plateCommon.findDescendant(editor, { | ||
at: fromListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
if (!fromListItemSublist) return 0; | ||
const [, fromListItemSublistPath] = fromListItemSublist; | ||
const toListItemSublist = plateCommon.findDescendant(editor, { | ||
at: toListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
let to; | ||
if (!toListItemSublist) { | ||
const fromList = plateCommon.getParent(editor, fromListItemPath); | ||
if (!fromList) return 0; | ||
const [fromListNode] = fromList; | ||
const fromListType = fromListNode.type; | ||
const toListItemSublistPath = toListItemPath.concat([1]); | ||
plateCommon.insertNodes(editor, { | ||
type: fromListType, | ||
children: [] | ||
}, { | ||
at: toListItemSublistPath | ||
}); | ||
to = toListItemSublistPath.concat([0]); | ||
} else if (start) { | ||
const [, toListItemSublistPath] = toListItemSublist; | ||
to = toListItemSublistPath.concat([0]); | ||
} else { | ||
to = slate.Path.next(plateCommon.getLastChildPath(toListItemSublist)); | ||
} | ||
const moved = plateCommon.moveChildren(editor, { | ||
at: fromListItemSublistPath, | ||
to | ||
}); // Remove the empty list | ||
slate.Transforms.delete(editor, { | ||
at: fromListItemSublistPath | ||
}); | ||
return moved; | ||
}; | ||
const moveListSiblingsAfterCursor = (editor, { | ||
at, | ||
to | ||
}) => { | ||
const offset = at[at.length - 1]; | ||
at = slate.Path.parent(at); | ||
const listNode = slate.Node.get(editor, at); | ||
const listEntry = [listNode, at]; | ||
if (!plateCommon.match(listNode, { | ||
type: getListTypes(editor) | ||
}) || slate.Path.isParent(at, to) // avoid moving nodes within its own list | ||
) { | ||
return 0; | ||
} | ||
return plateCommon.moveChildren(editor, { | ||
at: listEntry, | ||
to, | ||
fromStartIndex: offset + 1 | ||
}); | ||
}; | ||
/** | ||
* If list is not nested and if li is not the first child, move li up. | ||
*/ | ||
const removeFirstListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [, listPath] = list; | ||
const [, listItemPath] = listItem; | ||
if (!isListNested(editor, listPath) && !plateCommon.isFirstChild(listItemPath)) { | ||
moveListItemUp(editor, { | ||
list, | ||
listItem | ||
}); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Remove list item and move its sublist to list if any. | ||
*/ | ||
const removeListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [liNode, liPath] = listItem; // Stop if the list item has no sublist | ||
if (plateCommon.isExpanded(editor.selection) || !hasListChild(editor, liNode)) { | ||
return false; | ||
} | ||
const previousLiPath = plateCommon.getPreviousPath(liPath); | ||
/** | ||
* If there is a previous li, we need to move sub-lis to the previous li. | ||
* As we need to delete first, we will: | ||
* 1. insert a temporary li: tempLi | ||
* 2. move sub-lis to tempLi | ||
* 3. delete | ||
* 4. move sub-lis from tempLi to the previous li. | ||
* 5. remove tempLi | ||
*/ | ||
if (previousLiPath) { | ||
const previousLi = slate.Editor.node(editor, previousLiPath); // 1 | ||
let tempLiPath = slate.Path.next(liPath); | ||
plateCommon.insertNodes(editor, { | ||
type: plateCore.getPlatePluginType(editor, ELEMENT_LI), | ||
children: [{ | ||
type: plateCore.getPlatePluginType(editor, ELEMENT_LIC), | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: tempLiPath | ||
}); | ||
const tempLi = slate.Editor.node(editor, tempLiPath); | ||
const tempLiPathRef = slate.Editor.pathRef(editor, tempLi[1]); // 2 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: listItem, | ||
toListItem: tempLi | ||
}); // 3 | ||
plateCommon.deleteFragment(editor, { | ||
reverse: true | ||
}); | ||
tempLiPath = tempLiPathRef.unref(); // 4 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: [tempLi[0], tempLiPath], | ||
toListItem: previousLi | ||
}); // 5 | ||
slate.Transforms.removeNodes(editor, { | ||
at: tempLiPath | ||
}); | ||
return true; | ||
} // If it's the first li, move the sublist to the parent list | ||
moveListItemsToList(editor, { | ||
fromListItem: listItem, | ||
toList: list, | ||
toListIndex: 1 | ||
}); | ||
}; | ||
const toggleList = (editor, { | ||
@@ -741,9 +1025,22 @@ type | ||
const unindentListItems = editor => { | ||
moveListItems(editor, false); | ||
}; | ||
const getListOnKeyDown = pluginKeys => editor => e => { | ||
const listTypes = plateCore.getPlatePluginTypes([ELEMENT_UL, ELEMENT_OL])(editor); | ||
if (e.key === 'Tab') { | ||
e.preventDefault(); | ||
moveListItems(editor, !e.shiftKey); | ||
return; | ||
if (e.key === 'Tab' && editor.selection) { | ||
const listSelected = plateCommon.getAbove(editor, { | ||
at: editor.selection, | ||
match: { | ||
type: listTypes | ||
} | ||
}); | ||
if (listSelected) { | ||
e.preventDefault(); | ||
moveListItems(editor, !e.shiftKey); | ||
return; | ||
} | ||
} | ||
@@ -975,153 +1272,2 @@ | ||
/** | ||
* If list is not nested and if li is not the first child, move li up. | ||
*/ | ||
const removeFirstListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [, listPath] = list; | ||
const [, listItemPath] = listItem; | ||
if (!isListNested(editor, listPath) && !plateCommon.isFirstChild(listItemPath)) { | ||
moveListItemUp(editor, { | ||
list, | ||
listItem | ||
}); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Move fromListItem sublist list items to the end of `toListItem` sublist. | ||
* If there is no `toListItem` sublist, insert one. | ||
*/ | ||
const moveListItemSublistItemsToListItemSublist = (editor, { | ||
fromListItem, | ||
toListItem, | ||
start | ||
}) => { | ||
const [, fromListItemPath] = fromListItem; | ||
const [, toListItemPath] = toListItem; | ||
const fromListItemSublist = plateCommon.findDescendant(editor, { | ||
at: fromListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
if (!fromListItemSublist) return 0; | ||
const [, fromListItemSublistPath] = fromListItemSublist; | ||
const toListItemSublist = plateCommon.findDescendant(editor, { | ||
at: toListItemPath, | ||
match: { | ||
type: getListTypes(editor) | ||
} | ||
}); | ||
let to; | ||
if (!toListItemSublist) { | ||
const fromList = plateCommon.getParent(editor, fromListItemPath); | ||
if (!fromList) return 0; | ||
const [fromListNode] = fromList; | ||
const fromListType = fromListNode.type; | ||
const toListItemSublistPath = toListItemPath.concat([1]); | ||
plateCommon.insertNodes(editor, { | ||
type: fromListType, | ||
children: [] | ||
}, { | ||
at: toListItemSublistPath | ||
}); | ||
to = toListItemSublistPath.concat([0]); | ||
} else if (start) { | ||
const [, toListItemSublistPath] = toListItemSublist; | ||
to = toListItemSublistPath.concat([0]); | ||
} else { | ||
to = slate.Path.next(plateCommon.getLastChildPath(toListItemSublist)); | ||
} | ||
const moved = plateCommon.moveChildren(editor, { | ||
at: fromListItemSublistPath, | ||
to | ||
}); // Remove the empty list | ||
slate.Transforms.delete(editor, { | ||
at: fromListItemSublistPath | ||
}); | ||
return moved; | ||
}; | ||
/** | ||
* Remove list item and move its sublist to list if any. | ||
*/ | ||
const removeListItem = (editor, { | ||
list, | ||
listItem | ||
}) => { | ||
const [liNode, liPath] = listItem; // Stop if the list item has no sublist | ||
if (plateCommon.isExpanded(editor.selection) || !hasListChild(editor, liNode)) { | ||
return false; | ||
} | ||
const previousLiPath = plateCommon.getPreviousPath(liPath); | ||
/** | ||
* If there is a previous li, we need to move sub-lis to the previous li. | ||
* As we need to delete first, we will: | ||
* 1. insert a temporary li: tempLi | ||
* 2. move sub-lis to tempLi | ||
* 3. delete | ||
* 4. move sub-lis from tempLi to the previous li. | ||
* 5. remove tempLi | ||
*/ | ||
if (previousLiPath) { | ||
const previousLi = slate.Editor.node(editor, previousLiPath); // 1 | ||
let tempLiPath = slate.Path.next(liPath); | ||
plateCommon.insertNodes(editor, { | ||
type: plateCore.getPlatePluginType(editor, ELEMENT_LI), | ||
children: [{ | ||
type: plateCore.getPlatePluginType(editor, ELEMENT_LIC), | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: tempLiPath | ||
}); | ||
const tempLi = slate.Editor.node(editor, tempLiPath); | ||
const tempLiPathRef = slate.Editor.pathRef(editor, tempLi[1]); // 2 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: listItem, | ||
toListItem: tempLi | ||
}); // 3 | ||
plateCommon.deleteFragment(editor, { | ||
reverse: true | ||
}); | ||
tempLiPath = tempLiPathRef.unref(); // 4 | ||
moveListItemSublistItemsToListItemSublist(editor, { | ||
fromListItem: [tempLi[0], tempLiPath], | ||
toListItem: previousLi | ||
}); // 5 | ||
slate.Transforms.removeNodes(editor, { | ||
at: tempLiPath | ||
}); | ||
return true; | ||
} // If it's the first li, move the sublist to the parent list | ||
moveListItemsToList(editor, { | ||
fromListItem: listItem, | ||
toList: list, | ||
toListIndex: 1 | ||
}); | ||
}; | ||
const getListDeleteBackward = (editor, unit) => { | ||
@@ -1293,108 +1439,2 @@ const res = getListItemEntry(editor, {}); | ||
/** | ||
* Insert list item if selection in li>p. | ||
* TODO: test | ||
*/ | ||
const insertListItem = editor => { | ||
const liType = plateCore.getPlatePluginType(editor, ELEMENT_LI); | ||
const licType = plateCore.getPlatePluginType(editor, ELEMENT_LIC); | ||
if (editor.selection) { | ||
const licEntry = plateCommon.getAbove(editor, { | ||
match: { | ||
type: licType | ||
} | ||
}); | ||
if (!licEntry) return; | ||
const [, paragraphPath] = licEntry; | ||
const listItemEntry = plateCommon.getParent(editor, paragraphPath); | ||
if (!listItemEntry) return; | ||
const [listItemNode, listItemPath] = listItemEntry; | ||
if (listItemNode.type !== liType) return; | ||
if (!slate.Range.isCollapsed(editor.selection)) { | ||
slate.Transforms.delete(editor); | ||
} | ||
const isStart = slate.Editor.isStart(editor, editor.selection.focus, paragraphPath); | ||
const isEnd = plateCommon.isBlockTextEmptyAfterSelection(editor); | ||
const nextParagraphPath = slate.Path.next(paragraphPath); | ||
const nextListItemPath = slate.Path.next(listItemPath); | ||
/** | ||
* If start, insert a list item before | ||
*/ | ||
if (isStart) { | ||
plateCommon.insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '' | ||
}] | ||
}] | ||
}, { | ||
at: listItemPath | ||
}); | ||
return true; | ||
} | ||
/** | ||
* If not end, split nodes, wrap a list item on the new paragraph and move it to the next list item | ||
*/ | ||
if (!isEnd) { | ||
slate.Editor.withoutNormalizing(editor, () => { | ||
slate.Transforms.splitNodes(editor); | ||
plateCommon.wrapNodes(editor, { | ||
type: liType, | ||
children: [] | ||
}, { | ||
at: nextParagraphPath | ||
}); | ||
slate.Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath | ||
}); | ||
slate.Transforms.select(editor, nextListItemPath); | ||
slate.Transforms.collapse(editor, { | ||
edge: 'start' | ||
}); | ||
}); | ||
} else { | ||
/** | ||
* If end, insert a list item after and select it | ||
*/ | ||
const marks = slate.Editor.marks(editor) || {}; | ||
plateCommon.insertNodes(editor, { | ||
type: liType, | ||
children: [{ | ||
type: licType, | ||
children: [{ | ||
text: '', | ||
...marks | ||
}] | ||
}] | ||
}, { | ||
at: nextListItemPath | ||
}); | ||
slate.Transforms.select(editor, nextListItemPath); | ||
} | ||
/** | ||
* If there is a list in the list item, move it to the next list item | ||
*/ | ||
if (listItemNode.children.length > 1) { | ||
slate.Transforms.moveNodes(editor, { | ||
at: nextParagraphPath, | ||
to: nextListItemPath.concat(1) | ||
}); | ||
} | ||
return true; | ||
} | ||
}; | ||
const getListInsertBreak = editor => { | ||
@@ -1579,33 +1619,2 @@ if (!editor.selection) return; | ||
const indentListItems = editor => { | ||
moveListItems(editor, true); | ||
}; | ||
const moveListSiblingsAfterCursor = (editor, { | ||
at, | ||
to | ||
}) => { | ||
const offset = at[at.length - 1]; | ||
at = slate.Path.parent(at); | ||
const listNode = slate.Node.get(editor, at); | ||
const listEntry = [listNode, at]; | ||
if (!plateCommon.match(listNode, { | ||
type: getListTypes(editor) | ||
}) || slate.Path.isParent(at, to) // avoid moving nodes within its own list | ||
) { | ||
return 0; | ||
} | ||
return plateCommon.moveChildren(editor, { | ||
at: listEntry, | ||
to, | ||
fromStartIndex: offset + 1 | ||
}); | ||
}; | ||
const unindentListItems = editor => { | ||
moveListItems(editor, false); | ||
}; | ||
exports.CLASS_TODO_LIST_CHECKED = CLASS_TODO_LIST_CHECKED; | ||
@@ -1612,0 +1621,0 @@ exports.DEFAULTS_TODO_LIST = DEFAULTS_TODO_LIST; |
{ | ||
"name": "@udecode/plate-list", | ||
"version": "2.0.0", | ||
"version": "3.0.4", | ||
"description": "List plugin for Plate", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
312954
3122