Deprecate editor.isEmpty (#793)

This commit is contained in:
Gerard Rovira
2021-11-03 18:33:27 +00:00
committed by acywatson
parent 85d2651102
commit cfeecc9fc3
12 changed files with 160 additions and 18 deletions

View File

@ -33,6 +33,7 @@ module.name_mapper='^outline/keys' -> '<PROJECT_ROOT>/packages/outline/src/helpe
module.name_mapper='^outline/nodes' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineNodeHelpers.js' module.name_mapper='^outline/nodes' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineNodeHelpers.js'
module.name_mapper='^outline/events' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineEventHelpers.js' module.name_mapper='^outline/events' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineEventHelpers.js'
module.name_mapper='^outline/offsets' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineOffsetHelpers.js' module.name_mapper='^outline/offsets' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineOffsetHelpers.js'
module.name_mapper='^outline/validation' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineValidationHelpers.js'
module.name_mapper='^outline-react/OutlineTreeView' -> '<PROJECT_ROOT>/packages/outline-react/src/OutlineTreeView.js' module.name_mapper='^outline-react/OutlineTreeView' -> '<PROJECT_ROOT>/packages/outline-react/src/OutlineTreeView.js'
module.name_mapper='^outline-react/useOutlineEditor' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlineEditor.js' module.name_mapper='^outline-react/useOutlineEditor' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlineEditor.js'

View File

@ -49,6 +49,8 @@ module.exports = {
'<rootDir>/packages/outline/src/helpers/OutlineNodeHelpers.js', '<rootDir>/packages/outline/src/helpers/OutlineNodeHelpers.js',
'^outline/events$': '^outline/events$':
'<rootDir>/packages/outline/src/helpers/OutlineEventHelpers.js', '<rootDir>/packages/outline/src/helpers/OutlineEventHelpers.js',
'^outline/validation$':
'<rootDir>/packages/outline/src/helpers/OutlineValidationHelpers.js',
'^shared/getDOMTextNodeFromElement$': '^shared/getDOMTextNodeFromElement$':
'<rootDir>/packages/shared/src/getDOMTextNodeFromElement.js', '<rootDir>/packages/shared/src/getDOMTextNodeFromElement.js',
'^shared/isImmutableOrInert$': '^shared/isImmutableOrInert$':

View File

@ -18,6 +18,7 @@ module.exports = {
'outline/nodes': 'outline/dist/OutlineNodeHelpers', 'outline/nodes': 'outline/dist/OutlineNodeHelpers',
'outline/events': 'outline/dist/OutlineEventHelpers', 'outline/events': 'outline/dist/OutlineEventHelpers',
'outline/offsets': 'outline/dist/OutlineOffsetHelpers', 'outline/offsets': 'outline/dist/OutlineOffsetHelpers',
'outline/validation': 'outline/dist/OutlineValidationHelpers',
// Outline React // Outline React
'outline-react/OutlineTreeView': 'outline-react/dist/OutlineTreeView', 'outline-react/OutlineTreeView': 'outline-react/dist/OutlineTreeView',
'outline-react/useOutlineEditor': 'outline-react/dist/useOutlineEditor', 'outline-react/useOutlineEditor': 'outline-react/dist/useOutlineEditor',

View File

@ -10,6 +10,7 @@
import type {OutlineEditor, EditorThemeClasses, EditorState} from 'outline'; import type {OutlineEditor, EditorThemeClasses, EditorState} from 'outline';
import {createEditor} from 'outline'; import {createEditor} from 'outline';
import {canShowPlaceholder} from 'outline/validation';
import {useCallback, useMemo, useRef, useState} from 'react'; import {useCallback, useMemo, useRef, useState} from 'react';
import useLayoutEffect from './shared/useLayoutEffect'; import useLayoutEffect from './shared/useLayoutEffect';
@ -40,11 +41,14 @@ export default function useOutlineEditor<EditorContext>(editorConfig?: {
return editor.addListener('error', onError); return editor.addListener('error', onError);
}, [editor, onError]); }, [editor, onError]);
useLayoutEffect(() => { useLayoutEffect(() => {
return editor.addListener('update', () => { return editor.addListener('update', ({editorState}) => {
const canShowPlaceholder = editor.canShowPlaceholder(); const currentCanShowPlaceholder = canShowPlaceholder(
if (showPlaceholderRef.current !== canShowPlaceholder) { editorState,
showPlaceholderRef.current = canShowPlaceholder; editor.isComposing(),
setShowPlaceholder(canShowPlaceholder); );
if (showPlaceholderRef.current !== currentCanShowPlaceholder) {
showPlaceholderRef.current = currentCanShowPlaceholder;
setShowPlaceholder(currentCanShowPlaceholder);
} }
}); });
}, [editor]); }, [editor]);

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {OutlineEditor} from 'outline';
import useLayoutEffect from './shared/useLayoutEffect';
import {useState} from 'react';
import {isBlank} from 'outline/validation';
/**
* DEPRECATED. Use useOutlineIsBlank
*/
export default function useCometOutlineIsBlank(editor: OutlineEditor): boolean {
const [isCurrentlyBlank, setIsBlank] = useState(true);
useLayoutEffect(() => {
return editor.addListener('update', ({editorState}) => {
const isComposing = editor.isComposing();
setIsBlank(isBlank(editorState, isComposing));
});
}, [editor]);
return isCurrentlyBlank;
}

View File

@ -11,13 +11,18 @@ import type {OutlineEditor} from 'outline';
import useLayoutEffect from './shared/useLayoutEffect'; import useLayoutEffect from './shared/useLayoutEffect';
import {useState} from 'react'; import {useState} from 'react';
import {isBlank} from 'outline/validation';
/**
* DEPRECATED. Use useOutlineIsBlank
*/
export default function useCometOutlineIsEmpty(editor: OutlineEditor): boolean { export default function useCometOutlineIsEmpty(editor: OutlineEditor): boolean {
const [isCurrentlyEmpty, setIsEmpty] = useState(true); const [isCurrentlyEmpty, setIsEmpty] = useState(true);
useLayoutEffect(() => { useLayoutEffect(() => {
return editor.addListener('update', () => { return editor.addListener('update', ({editorState}) => {
setIsEmpty(editor.isEmpty()); const isComposing = editor.isComposing();
setIsEmpty(isBlank(editorState, isComposing));
}); });
}, [editor]); }, [editor]);
return isCurrentlyEmpty; return isCurrentlyEmpty;

View File

@ -30,6 +30,7 @@
"./history": "./OutlineHistoryHelpers.js", "./history": "./OutlineHistoryHelpers.js",
"./offsets": "./OutlineOffsetHelpers.js", "./offsets": "./OutlineOffsetHelpers.js",
"./nodes": "./OutlineNodeHelpers.js", "./nodes": "./OutlineNodeHelpers.js",
"./validation": "./OutlineValidationHelpers.js",
"./CodeNode": "./OutlineCodeNode.js", "./CodeNode": "./OutlineCodeNode.js",
"./ParagraphNode": "./OutlineParagraphNode.js", "./ParagraphNode": "./OutlineParagraphNode.js",
"./QuoteNode": "./OutlineQuoteNode.js", "./QuoteNode": "./OutlineQuoteNode.js",

View File

@ -950,14 +950,5 @@ describe('OutlineEditor tests', () => {
'<div contenteditable="true" data-outline-editor="true"><p><div><span data-outline-text="true">A</span><div><span data-outline-text="true">C</span></div></div><div><span data-outline-text="true">B</span></div></p></div>', '<div contenteditable="true" data-outline-editor="true"><p><div><span data-outline-text="true">A</span><div><span data-outline-text="true">C</span></div></div><div><span data-outline-text="true">B</span></div></p></div>',
); );
}); });
it('isEmpty', async () => {
expect(editor.isEmpty()).toBe(true);
await update((state: State) => {
const paragraph = state.getRoot().getFirstChild();
paragraph.append(createTextNode('foo'));
});
expect(editor.isEmpty()).toBe(false);
});
}); });
}); });

View File

@ -247,6 +247,9 @@ class BaseOutlineEditor {
isComposing(): boolean { isComposing(): boolean {
return this._compositionKey != null; return this._compositionKey != null;
} }
/**
* Deprecated. To be removed within a week.
*/
isEmpty(trim: boolean = true): boolean { isEmpty(trim: boolean = true): boolean {
if (this.isComposing()) { if (this.isComposing()) {
return false; return false;
@ -422,6 +425,9 @@ class BaseOutlineEditor {
); );
} }
} }
/**
* Deprecated. To be removed within a week.
*/
canShowPlaceholder(): boolean { canShowPlaceholder(): boolean {
if (!this.isEmpty(false)) { if (!this.isEmpty(false)) {
return false; return false;
@ -479,7 +485,7 @@ declare export class OutlineEditor {
getObserver(): null | MutationObserver; getObserver(): null | MutationObserver;
isComposing(): boolean; isComposing(): boolean;
isEmpty(trim?: boolean): boolean; // isEmpty(trim?: boolean): boolean;
registerNodeType(nodeType: string, klass: Class<OutlineNode>): void; registerNodeType(nodeType: string, klass: Class<OutlineNode>): void;
addListener(type: 'error', listener: ErrorListener): () => void; addListener(type: 'error', listener: ErrorListener): () => void;
addListener(type: 'update', listener: UpdateListener): () => void; addListener(type: 'update', listener: UpdateListener): () => void;
@ -498,7 +504,7 @@ declare export class OutlineEditor {
parseEditorState(stringifiedEditorState: string): EditorState; parseEditorState(stringifiedEditorState: string): EditorState;
update(updateFn: (state: State) => void, callbackFn?: () => void): boolean; update(updateFn: (state: State) => void, callbackFn?: () => void): boolean;
focus(callbackFn?: () => void): void; focus(callbackFn?: () => void): void;
canShowPlaceholder(): boolean; // canShowPlaceholder(): boolean;
} }
export function getEditorFromElement(element: Element): null | OutlineEditor { export function getEditorFromElement(element: Element): null | OutlineEditor {

View File

@ -0,0 +1,62 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/
import type {EditorState} from 'outline';
import {getEditorStateTextContent} from '../core/OutlineUtils';
import {isBlockNode, isTextNode} from 'outline';
export function isBlank(
editorState: EditorState,
isEditorComposing: boolean,
trim?: boolean = true,
): boolean {
if (isEditorComposing) {
return false;
}
let text = getEditorStateTextContent(editorState);
if (trim) {
text = text.trim();
}
return text === '';
}
export function canShowPlaceholder(
editorState: EditorState,
isComposing: boolean,
): boolean {
if (!isBlank(editorState, isComposing, false)) {
return false;
}
const nodeMap = editorState._nodeMap;
// $FlowFixMe: root is always in the Map
const root = ((nodeMap.get('root'): any): RootNode);
const topBlockIDs = root.__children;
const topBlockIDsLength = topBlockIDs.length;
if (topBlockIDsLength > 1) {
return false;
}
for (let i = 0; i < topBlockIDsLength; i++) {
const topBlock = nodeMap.get(topBlockIDs[i]);
if (isBlockNode(topBlock)) {
if (topBlock.__type !== 'paragraph') {
return false;
}
const children = topBlock.__children;
for (let s = 0; s < children.length; s++) {
const child = nodeMap.get(children[s]);
if (!isTextNode(child)) {
return false;
}
}
}
}
return true;
}

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/
import type {State} from 'outline';
import {createTextNode} from 'outline';
import {createParagraphNode} from 'outline/ParagraphNode';
import {isBlank} from 'outline/validation';
import {initializeUnitTest} from '../../../__tests__/utils';
describe('OutlineNodeHelpers tests', () => {
initializeUnitTest((testEnv) => {
it('isBlank', async () => {
const editor = testEnv.editor;
expect(isBlank(editor.getEditorState(), editor.isComposing())).toBe(true);
await editor.update((state: State) => {
const root = state.getRoot();
const paragraph = createParagraphNode();
const text = createTextNode('foo');
root.append(paragraph);
paragraph.append(text);
});
expect(isBlank(editor.getEditorState(), editor.isComposing())).toBe(
false,
);
});
});
});

View File

@ -172,6 +172,12 @@ async function build(name, inputFile, outputFile) {
'packages/outline/src/helpers/OutlineOffsetHelpers', 'packages/outline/src/helpers/OutlineOffsetHelpers',
), ),
}, },
{
find: isWWW ? 'Outline/validation' : 'outline/validation',
replacement: path.resolve(
'packages/outline/src/helpers/OutlineValidationHelpers',
),
},
], ],
}), }),
// Extract error codes from invariant() messages into a file. // Extract error codes from invariant() messages into a file.