From 801068c8fe4eb5b60233ce369c771d490feb65c7 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 Dec 2022 18:26:09 -0500 Subject: [PATCH] chore: revises left indent --- .../forms/field-types/RichText/RichText.tsx | 3 + .../RichText/elements/ListButton.tsx | 2 +- .../RichText/elements/getCommonBlock.tsx | 6 +- .../RichText/elements/indent/index.tsx | 81 ++++++++++++++----- .../RichText/elements/isListActive.ts | 2 +- .../RichText/elements/toggleList.tsx | 62 ++++++++++++-- test/fields/collections/RichText/index.ts | 6 +- 7 files changed, 128 insertions(+), 34 deletions(-) diff --git a/src/admin/components/forms/field-types/RichText/RichText.tsx b/src/admin/components/forms/field-types/RichText/RichText.tsx index b873dc92c0..ce01cbe9a0 100644 --- a/src/admin/components/forms/field-types/RichText/RichText.tsx +++ b/src/admin/components/forms/field-types/RichText/RichText.tsx @@ -4,6 +4,7 @@ import { createEditor, Transforms, Node, Element as SlateElement, Text, BaseEdit import { ReactEditor, Editable, withReact, Slate } from 'slate-react'; import { HistoryEditor, withHistory } from 'slate-history'; import { useTranslation } from 'react-i18next'; +import e from 'express'; import { richText } from '../../../../../fields/validations'; import useField from '../../useField'; import withCondition from '../../withCondition'; @@ -347,9 +348,11 @@ const RichText: React.FC = (props) => { if (SlateElement.isElement(selectedElement) && selectedElement.type === 'li') { const selectedLeaf = Node.descendant(editor, editor.selection.anchor.path); if (Text.isText(selectedLeaf) && String(selectedLeaf.text).length === 0) { + event.preventDefault(); Transforms.unwrapNodes(editor, { match: (n) => SlateElement.isElement(n) && listTypes.includes(n.type), split: true, + mode: 'lowest', }); Transforms.setNodes(editor, { type: undefined }); diff --git a/src/admin/components/forms/field-types/RichText/elements/ListButton.tsx b/src/admin/components/forms/field-types/RichText/elements/ListButton.tsx index 1ab56b8fc1..6f15f4e3a8 100644 --- a/src/admin/components/forms/field-types/RichText/elements/ListButton.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/ListButton.tsx @@ -2,9 +2,9 @@ import React, { useCallback } from 'react'; import { useSlate } from 'slate-react'; import toggleList from './toggleList'; import { ButtonProps } from './types'; +import isListActive from './isListActive'; import '../buttons.scss'; -import isListActive from './isListActive'; export const baseClass = 'rich-text__button'; diff --git a/src/admin/components/forms/field-types/RichText/elements/getCommonBlock.tsx b/src/admin/components/forms/field-types/RichText/elements/getCommonBlock.tsx index f88ca817b2..1daae1352c 100644 --- a/src/admin/components/forms/field-types/RichText/elements/getCommonBlock.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/getCommonBlock.tsx @@ -1,6 +1,6 @@ -import { Editor, Node, NodeEntry } from 'slate'; +import { Editor, Node, NodeEntry, NodeMatch } from 'slate'; -export const getCommonBlock = (editor: Editor): NodeEntry => { +export const getCommonBlock = (editor: Editor, match?: NodeMatch): NodeEntry => { const range = Editor.unhangRange(editor, editor.selection, { voids: true }); const [common, path] = Node.common( @@ -14,6 +14,6 @@ export const getCommonBlock = (editor: Editor): NodeEntry => { } return Editor.above(editor, { at: path, - match: (n) => Editor.isBlock(editor, n) || Editor.isEditor(n), + match: match || ((n) => Editor.isBlock(editor, n) || Editor.isEditor(n)), }); }; diff --git a/src/admin/components/forms/field-types/RichText/elements/indent/index.tsx b/src/admin/components/forms/field-types/RichText/elements/indent/index.tsx index 17ba34aefd..262c2bbc76 100644 --- a/src/admin/components/forms/field-types/RichText/elements/indent/index.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/indent/index.tsx @@ -5,6 +5,9 @@ import IndentLeft from '../../../../../icons/IndentLeft'; import IndentRight from '../../../../../icons/IndentRight'; import { baseClass } from '../Button'; import isElementActive from '../isActive'; +import listTypes from '../listTypes'; +import { getCommonBlock } from '../getCommonBlock'; +import Edit from '../../../../../icons/Edit'; const indentType = 'indent'; @@ -24,30 +27,67 @@ const indent = { e.preventDefault(); if (dir === 'left') { - // Transforms.unwrapNodes(editor, { - // match: (n) => Element.isElement(n) && [indentType, ...listTypes].includes(n.type), - // split: true, - // mode: 'lowest', - // }); + if (isElementActive(editor, 'li')) { + const [, listPath] = getCommonBlock(editor, (n) => Element.isElement(n) && listTypes.includes(n.type)); - // if (isElementActive(editor, 'li')) { - // const [, parentLocation] = Editor.parent(editor, editor.selection); - // const [, parentDepth] = parentLocation; + const matchedParentList = Editor.above(editor, { + at: listPath, + match: (n) => !Editor.isEditor(n) && Editor.isBlock(editor, n), + }); - // if (parentDepth > 0 || parentDepth === 0) { - // Transforms.unwrapNodes(editor, { - // match: (n) => Element.isElement(n) && n.type === 'li', - // split: true, - // mode: 'lowest', - // }); - // } else { - // Transforms.unsetNodes(editor, ['type']); - // } - // } + if (matchedParentList) { + const [parentListItem, parentListItemPath] = matchedParentList; - const [previousNode, previousNodePath] = Editor.parent(editor, editor.selection, { depth: 4 }); + if (parentListItem.children.length > 1) { + console.log('we have more than one child'); + } else { + Transforms.unwrapNodes(editor, { + at: parentListItemPath, + match: (node, path) => { + return Element.isElement(node) + && node.type === 'li' + && path.length === parentListItemPath.length; + }, + }); - console.log({ previousNode, previousNodePath }); + Transforms.unwrapNodes(editor, { + match: (n) => Element.isElement(n) && listTypes.includes(n.type), + }); + } + } else { + // Remove type for any nodes that have more than one child + Transforms.setNodes(editor, { type: undefined }, { + at: listPath, + match: (node, path) => { + const matches = !Editor.isEditor(node) + && Element.isElement(node) + && node.children.length === 1 + && node.type === 'li' + && path.length === listPath.length + 1; + + return matches; + }, + }); + + // For nodes that have more than one child, unwrap it instead + Transforms.unwrapNodes(editor, { + at: listPath, + match: (node, path) => { + const matches = !Editor.isEditor(node) + && Element.isElement(node) + && node.children.length > 1 + && node.type === 'li' + && path.length === listPath.length + 1; + + return matches; + }, + }); + + Transforms.unwrapNodes(editor, { + match: (n) => Element.isElement(n) && listTypes.includes(n.type), + }); + } + } } if (dir === 'right') { @@ -100,6 +140,7 @@ const indent = { }, ); } else { + // Otherwise, just wrap the node in a list / li Transforms.wrapNodes( editor, { diff --git a/src/admin/components/forms/field-types/RichText/elements/isListActive.ts b/src/admin/components/forms/field-types/RichText/elements/isListActive.ts index d1052cac1b..b9682246d0 100644 --- a/src/admin/components/forms/field-types/RichText/elements/isListActive.ts +++ b/src/admin/components/forms/field-types/RichText/elements/isListActive.ts @@ -12,7 +12,7 @@ const isListActive = (editor: Editor, format: string): boolean => { return !Editor.isEditor(node) && Element.isElement(node) && node.type === format - && path.length >= topmostSelectedNodePath.length - 1; + && path.length >= topmostSelectedNodePath.length - 2; }, })); diff --git a/src/admin/components/forms/field-types/RichText/elements/toggleList.tsx b/src/admin/components/forms/field-types/RichText/elements/toggleList.tsx index 6c447a8a93..69a0fc3b1f 100644 --- a/src/admin/components/forms/field-types/RichText/elements/toggleList.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/toggleList.tsx @@ -1,5 +1,6 @@ -import { Editor, Element, Transforms } from 'slate'; +import { Editor, Element, Node, Text, Transforms } from 'slate'; import { ReactEditor } from 'slate-react'; +import { getCommonBlock } from './getCommonBlock'; import isListActive from './isListActive'; import listTypes from './listTypes'; @@ -10,18 +11,63 @@ const toggleList = (editor: Editor, format: string): void => { if (isListActive(editor, 'ul')) currentListFormat = 'ul'; // If the format is currently active, - // unwrap the list and set li type to undefined + // remove the list if (currentListFormat === format) { - Transforms.unwrapNodes(editor, { - match: (n) => Element.isElement(n) && listTypes.includes(n.type), - mode: 'lowest', - }); + const selectedLeaf = Node.descendant(editor, editor.selection.anchor.path); - Transforms.setNodes(editor, { type: undefined }); + // If on an empty bullet, leave the above list alone + // and unwrap only the active bullet + if (Text.isText(selectedLeaf) && String(selectedLeaf.text).length === 0) { + Transforms.unwrapNodes(editor, { + match: (n) => Element.isElement(n) && listTypes.includes(n.type), + split: true, + mode: 'lowest', + }); + + Transforms.setNodes(editor, { type: undefined }); + } else { + // Otherwise, we need to unset li on all lis in the parent list + // and unwrap the parent list itself + const [, listPath] = getCommonBlock(editor, (n) => Element.isElement(n) && n.type === format); + + // Remove type for any nodes that have more than one child + Transforms.setNodes(editor, { type: undefined }, { + at: listPath, + match: (node, path) => { + const matches = !Editor.isEditor(node) + && Element.isElement(node) + && node.children.length === 1 + && node.type === 'li' + && path.length === listPath.length + 1; + + return matches; + }, + }); + + // For nodes that have more than one child, unwrap it instead + Transforms.unwrapNodes(editor, { + at: listPath, + match: (node, path) => { + const matches = !Editor.isEditor(node) + && Element.isElement(node) + && node.children.length > 1 + && node.type === 'li' + && path.length === listPath.length + 1; + + return matches; + }, + }); + + // Finally, unwrap the UL itself + Transforms.unwrapNodes(editor, { + match: (n) => Element.isElement(n) && n.type === format, + mode: 'lowest', + }); + } // Otherwise, if a list is active and we are changing it, // change it - } else if (currentListFormat !== format) { + } else if (currentListFormat && currentListFormat !== format) { Transforms.setNodes( editor, { diff --git a/test/fields/collections/RichText/index.ts b/test/fields/collections/RichText/index.ts index d102202627..32662c9c65 100644 --- a/test/fields/collections/RichText/index.ts +++ b/test/fields/collections/RichText/index.ts @@ -334,7 +334,11 @@ export const richTextBulletsDoc = { type: 'li', children: [ { - text: 'This text precedes a nested list', + children: [ + { + text: 'This text precedes a nested list', + }, + ], }, { type: 'ul',