Move KeyHelpers to Outline package (#389)

* Move KeyHelpers to Outline package

* More tweaks

* More tweaks

* More fixes

* Fix test

* Fix test

* Fix test
This commit is contained in:
Dominic Gannaway
2021-06-16 16:08:01 +01:00
committed by acywatson
parent e87decc372
commit 2f6274737c
19 changed files with 42 additions and 144 deletions

View File

@ -28,6 +28,7 @@ module.name_mapper='^outline/CodeNode' -> '<PROJECT_ROOT>/packages/outline/src/e
module.name_mapper='^outline/HistoryHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineHistoryHelpers.js' module.name_mapper='^outline/HistoryHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineHistoryHelpers.js'
module.name_mapper='^outline/SelectionHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineSelectionHelpers.js' module.name_mapper='^outline/SelectionHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineSelectionHelpers.js'
module.name_mapper='^outline/TextHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineTextHelpers.js' module.name_mapper='^outline/TextHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineTextHelpers.js'
module.name_mapper='^outline/KeyHelpers' -> '<PROJECT_ROOT>/packages/outline/src/helpers/OutlineKeyHelpers.js'
module.name_mapper='^outline-react/useOutlineRichText' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlineRichText.js' module.name_mapper='^outline-react/useOutlineRichText' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlineRichText.js'
module.name_mapper='^outline-react/useOutlinePlainText' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlinePlainText.js' module.name_mapper='^outline-react/useOutlinePlainText' -> '<PROJECT_ROOT>/packages/outline-react/src/useOutlinePlainText.js'
@ -37,6 +38,7 @@ module.name_mapper='^outline-react/useOutlineAutoFormatter' -> '<PROJECT_ROOT>/p
module.name_mapper='^shared/isImmutableOrInertOrSegmented' -> '<PROJECT_ROOT>/packages/shared/src/isImmutableOrInertOrSegmented.js' module.name_mapper='^shared/isImmutableOrInertOrSegmented' -> '<PROJECT_ROOT>/packages/shared/src/isImmutableOrInertOrSegmented.js'
module.name_mapper='^shared/invariant' -> '<PROJECT_ROOT>/packages/shared/src/invariant.js' module.name_mapper='^shared/invariant' -> '<PROJECT_ROOT>/packages/shared/src/invariant.js'
module.name_mapper='^shared/getDOMTextNodeFromElement' -> '<PROJECT_ROOT>/packages/shared/src/getDOMTextNodeFromElement.js' module.name_mapper='^shared/getDOMTextNodeFromElement' -> '<PROJECT_ROOT>/packages/shared/src/getDOMTextNodeFromElement.js'
module.name_mapper='^shared/environment' -> '<PROJECT_ROOT>/packages/shared/src/environment.js'
munge_underscores=false munge_underscores=false

View File

@ -40,11 +40,14 @@ module.exports = {
'<rootDir>/packages/outline/src/helpers/OutlineSelectionHelpers.js', '<rootDir>/packages/outline/src/helpers/OutlineSelectionHelpers.js',
'^outline/TextHelpers$': '^outline/TextHelpers$':
'<rootDir>/packages/outline/src/helpers/OutlineTextHelpers.js', '<rootDir>/packages/outline/src/helpers/OutlineTextHelpers.js',
'^outline/KeyHelpers$':
'<rootDir>/packages/outline/src/helpers/OutlineKeyHelpers.js',
'^shared/getDOMTextNodeFromElement$': '^shared/getDOMTextNodeFromElement$':
'<rootDir>/packages/shared/src/getDOMTextNodeFromElement.js', '<rootDir>/packages/shared/src/getDOMTextNodeFromElement.js',
'^shared/isImmutableOrInertOrSegmented$': '^shared/isImmutableOrInertOrSegmented$':
'<rootDir>/packages/shared/src/isImmutableOrInertOrSegmented.js', '<rootDir>/packages/shared/src/isImmutableOrInertOrSegmented.js',
'^shared/invariant$': '<rootDir>/packages/shared/src/invariant.js', '^shared/invariant$': '<rootDir>/packages/shared/src/invariant.js',
'^shared/environment$': '<rootDir>/packages/shared/src/environment.js',
'^./dist/(.+)': './src/$1', '^./dist/(.+)': './src/$1',
}, },
globals: { globals: {

View File

@ -13,6 +13,7 @@ module.exports = {
'outline/SelectionHelpers': 'outline/dist/OutlineSelectionHelpers', 'outline/SelectionHelpers': 'outline/dist/OutlineSelectionHelpers',
'outline/TextHelpers': 'outline/dist/OutlineTextHelpers', 'outline/TextHelpers': 'outline/dist/OutlineTextHelpers',
'outline/HistoryHelpers': 'outline/dist/OutlineHistoryHelpers', 'outline/HistoryHelpers': 'outline/dist/OutlineHistoryHelpers',
'outline/KeyHelpers': 'outline/dist/OutlineKeyHelpers',
// Outline React // Outline React
'outline-react/useOutlineRichText': 'outline-react/useOutlineRichText':
'outline-react/dist/useOutlineRichText', 'outline-react/dist/useOutlineRichText',

View File

@ -10,107 +10,20 @@ import {createTextNode} from 'outline';
import {createParagraphNode} from 'outline/ParagraphNode'; import {createParagraphNode} from 'outline/ParagraphNode';
import useEvent from './useEvent'; import useEvent from './useEvent';
import React, {useState, useCallback, useRef, useEffect} from 'react'; import React, {useState, useCallback, useRef, useEffect} from 'react';
import {
// stolen from Keyboard.js isDeleteBackward,
isDeleteForward,
const CAN_USE_DOM: boolean = isDeleteLineBackward,
typeof window !== 'undefined' && isDeleteLineForward,
typeof window.document !== 'undefined' && isDeleteWordBackward,
typeof window.document.createElement !== 'undefined'; isDeleteWordForward,
isLineBreak,
const IS_APPLE: boolean = isParagraph,
CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform); isBold,
isItalic,
function isBackspace(event: KeyboardEvent): boolean { isUndo,
return event.keyCode === 8; isRedo,
} } from 'outline/KeyHelpers';
function isDelete(event: KeyboardEvent): boolean {
return event.keyCode === 46;
}
function isDeleteBackward(event: KeyboardEvent): boolean {
const {keyCode, altKey, metaKey, ctrlKey} = event;
if (IS_APPLE) {
if (altKey || metaKey) {
return false;
}
return isBackspace(event) || (keyCode === 72 && ctrlKey);
}
if (ctrlKey || altKey || metaKey) {
return false;
}
return isBackspace(event);
}
function isDeleteForward(event: KeyboardEvent): boolean {
const {keyCode, shiftKey, altKey, metaKey, ctrlKey} = event;
if (IS_APPLE) {
if (shiftKey || altKey || metaKey) {
return false;
}
return isDelete(event) || (keyCode === 68 && ctrlKey);
}
if (ctrlKey || altKey || metaKey) {
return false;
}
return isDelete(event);
}
function isDeleteWordBackward(event: KeyboardEvent): boolean {
return isBackspace(event) && (IS_APPLE ? event.altKey : event.ctrlKey);
}
function isDeleteWordForward(event: KeyboardEvent): boolean {
return isDelete(event) && (IS_APPLE ? event.altKey : event.ctrlKey);
}
function isDeleteLineForward(event: KeyboardEvent): boolean {
return IS_APPLE && event.metaKey && isDelete(event);
}
function isDeleteLineBackward(event: KeyboardEvent): boolean {
return IS_APPLE && event.metaKey && isBackspace(event);
}
function isEnter(event: KeyboardEvent): boolean {
return event.key === 'Enter' || event.keyCode === 13;
}
function isParagraph(event: KeyboardEvent): boolean {
return isEnter(event) && !event.shiftKey;
}
function isLineBreak(event: KeyboardEvent): boolean {
return isEnter(event) && event.shiftKey;
}
function controlOrMeta(event: KeyboardEvent): boolean {
if (IS_APPLE) {
return event.metaKey;
}
return event.ctrlKey;
}
function isUndo(event: KeyboardEvent): boolean {
return event.keyCode === 90 && !event.shiftKey && controlOrMeta(event);
}
function isRedo(event: KeyboardEvent): boolean {
const {keyCode, shiftKey, ctrlKey} = event;
if (IS_APPLE) {
return keyCode === 90 && event.metaKey && shiftKey;
}
return (keyCode === 89 && ctrlKey) || (keyCode === 90 && ctrlKey && shiftKey);
}
function isBold(event: KeyboardEvent): boolean {
return event.keyCode === 66 && controlOrMeta(event);
}
function isItalic(event: KeyboardEvent): boolean {
return event.keyCode === 73 && controlOrMeta(event);
}
// stolen from OutlineSelection-test // stolen from OutlineSelection-test
function sanitizeSelection(selection) { function sanitizeSelection(selection) {

View File

@ -17,7 +17,7 @@ import type {
View, View,
} from 'outline'; } from 'outline';
import {CAN_USE_BEFORE_INPUT, IS_FIREFOX, IS_SAFARI} from './Environment'; import {CAN_USE_BEFORE_INPUT, IS_FIREFOX, IS_SAFARI} from 'shared/environment';
import { import {
isDeleteBackward, isDeleteBackward,
isDeleteForward, isDeleteForward,
@ -36,7 +36,7 @@ import {
isMoveBackward, isMoveBackward,
isMoveForward, isMoveForward,
isMoveWordForward, isMoveWordForward,
} from './Keyboard'; } from 'outline/KeyHelpers';
import getDOMTextNodeFromElement from 'shared/getDOMTextNodeFromElement'; import getDOMTextNodeFromElement from 'shared/getDOMTextNodeFromElement';
import isImmutableOrInertOrSegmented from 'shared/isImmutableOrInertOrSegmented'; import isImmutableOrInertOrSegmented from 'shared/isImmutableOrInertOrSegmented';
import { import {

View File

@ -10,7 +10,7 @@
import type {OutlineEditor, ViewModel} from 'outline'; import type {OutlineEditor, ViewModel} from 'outline';
import {isTextNode} from 'outline'; import {isTextNode} from 'outline';
import {isRedo, isUndo} from './Keyboard'; import {isRedo, isUndo} from 'outline/KeyHelpers';
import {useEffect, useMemo} from 'react'; import {useEffect, useMemo} from 'react';
import {viewModelsWithoutHistory} from 'outline/HistoryHelpers'; import {viewModelsWithoutHistory} from 'outline/HistoryHelpers';

View File

@ -15,7 +15,7 @@ import {useEffect, useMemo} from 'react';
import {createTextNode} from 'outline'; import {createTextNode} from 'outline';
import useOutlineEditorEvents from './useOutlineEditorEvents'; import useOutlineEditorEvents from './useOutlineEditorEvents';
import {createParagraphNode, ParagraphNode} from 'outline/ParagraphNode'; import {createParagraphNode, ParagraphNode} from 'outline/ParagraphNode';
import {CAN_USE_BEFORE_INPUT} from './shared/Environment'; import {CAN_USE_BEFORE_INPUT} from 'shared/environment';
import { import {
onSelectionChange, onSelectionChange,
onKeyDownForPlainText, onKeyDownForPlainText,

View File

@ -21,7 +21,7 @@ import {CodeNode} from 'outline/CodeNode';
import {ParagraphNode} from 'outline/ParagraphNode'; import {ParagraphNode} from 'outline/ParagraphNode';
import {ListItemNode} from 'outline/ListItemNode'; import {ListItemNode} from 'outline/ListItemNode';
import {createParagraphNode} from 'outline/ParagraphNode'; import {createParagraphNode} from 'outline/ParagraphNode';
import {CAN_USE_BEFORE_INPUT} from './shared/Environment'; import {CAN_USE_BEFORE_INPUT} from 'shared/environment';
import { import {
onSelectionChange, onSelectionChange,
onKeyDownForRichText, onKeyDownForRichText,

View File

@ -20,7 +20,8 @@ import {
BlockNode, BlockNode,
} from '.'; } from '.';
import {getActiveViewModel, errorOnReadOnly} from './OutlineView'; import {getActiveViewModel, errorOnReadOnly} from './OutlineView';
import {generateRandomKey, getTextDirection, invariant} from './OutlineUtils'; import {generateRandomKey, getTextDirection} from './OutlineUtils';
import invariant from 'shared/invariant';
import { import {
IS_DIRECTIONLESS, IS_DIRECTIONLESS,
IS_IMMUTABLE, IS_IMMUTABLE,

View File

@ -15,12 +15,12 @@ import type {Node as ReactNode} from 'react';
import {isTextNode, isBlockNode} from '.'; import {isTextNode, isBlockNode} from '.';
import { import {
invariant,
isSelectionWithinEditor, isSelectionWithinEditor,
getDOMTextNodeFromElement, getDOMTextNodeFromElement,
isImmutableOrInertOrSegmented, isImmutableOrInertOrSegmented,
} from './OutlineUtils'; } from './OutlineUtils';
import {IS_INERT, IS_RTL, IS_LTR, IS_DIRTY_DECORATOR} from './OutlineConstants'; import {IS_INERT, IS_RTL, IS_LTR, IS_DIRTY_DECORATOR} from './OutlineConstants';
import invariant from 'shared/invariant';
let subTreeTextContent = ''; let subTreeTextContent = '';
let editorTextContent = ''; let editorTextContent = '';

View File

@ -15,11 +15,11 @@ import {getNodeKeyFromDOM} from './OutlineReconciler';
import {getNodeByKey} from './OutlineNode'; import {getNodeByKey} from './OutlineNode';
import {isTextNode, isBlockNode, isLineBreakNode, TextNode} from '.'; import {isTextNode, isBlockNode, isLineBreakNode, TextNode} from '.';
import { import {
invariant,
isImmutableOrInertOrSegmented, isImmutableOrInertOrSegmented,
isSelectionWithinEditor, isSelectionWithinEditor,
} from './OutlineUtils'; } from './OutlineUtils';
import {OutlineEditor} from './OutlineEditor'; import {OutlineEditor} from './OutlineEditor';
import invariant from 'shared/invariant';
export class Selection { export class Selection {
anchorKey: string; anchorKey: string;

View File

@ -16,10 +16,10 @@ import {getWritableNode} from './OutlineNode';
import {getSelection, makeSelection} from './OutlineSelection'; import {getSelection, makeSelection} from './OutlineSelection';
import { import {
getTextDirection, getTextDirection,
invariant,
isArray, isArray,
isImmutableOrInertOrSegmented, isImmutableOrInertOrSegmented,
} from './OutlineUtils'; } from './OutlineUtils';
import invariant from 'shared/invariant';
import {errorOnReadOnly} from './OutlineView'; import {errorOnReadOnly} from './OutlineView';
import { import {
IS_CODE, IS_CODE,

View File

@ -11,25 +11,12 @@ import type {OutlineEditor} from './OutlineEditor';
import type {OutlineNode} from './OutlineNode'; import type {OutlineNode} from './OutlineNode';
import {RTL_REGEX, LTR_REGEX} from './OutlineConstants'; import {RTL_REGEX, LTR_REGEX} from './OutlineConstants';
import invariant from 'shared/invariant';
export const emptyFunction = () => {}; export const emptyFunction = () => {};
let keyCounter = 0; let keyCounter = 0;
// invariant(condition, message) will refine types based on "condition", and
// if "condition" is false will throw an error. This function is special-cased
// in flow itself, so we can't name it anything else.
export function invariant(
condition: boolean,
format: string,
...args: Array<string>
) {
throw new Error(
'Internal Outline error: invariant() is meant to be replaced at compile ' +
'time. There is no runtime version.',
);
}
export function resetRandomKey(): void { export function resetRandomKey(): void {
keyCounter = 0; keyCounter = 0;
} }

View File

@ -28,7 +28,7 @@ import {
markNodeAsDirty, markNodeAsDirty,
} from './OutlineNode'; } from './OutlineNode';
import {isBlockNode, isTextNode, isLineBreakNode} from '.'; import {isBlockNode, isTextNode, isLineBreakNode} from '.';
import {invariant} from './OutlineUtils'; import invariant from 'shared/invariant';
export type View = { export type View = {
clearSelection(): void, clearSelection(): void,

View File

@ -9,7 +9,6 @@ import {createTextNode} from 'outline';
import { import {
emptyFunction, emptyFunction,
invariant,
resetRandomKey, resetRandomKey,
generateRandomKey, generateRandomKey,
getAdjustedSelectionOffset, getAdjustedSelectionOffset,
@ -55,11 +54,6 @@ describe('OutlineUtils tests', () => {
expect(emptyFunction()).toBe(undefined); expect(emptyFunction()).toBe(undefined);
}); });
test('invariant()', () => {
expect(invariant).toBeInstanceOf(Function);
expect(() => invariant()).toThrow();
});
test('resetRandomKey()', () => { test('resetRandomKey()', () => {
resetRandomKey(); resetRandomKey();
const key1 = generateRandomKey(); const key1 = generateRandomKey();

View File

@ -7,7 +7,7 @@
* @flow strict * @flow strict
*/ */
import {IS_APPLE} from './Environment'; import {IS_APPLE} from 'shared/environment';
function controlOrMeta(event: KeyboardEvent): boolean { function controlOrMeta(event: KeyboardEvent): boolean {
if (IS_APPLE) { if (IS_APPLE) {

View File

@ -20,10 +20,5 @@
"type": "git", "type": "git",
"url": "https://github.com/facebookexternal/Outline", "url": "https://github.com/facebookexternal/Outline",
"directory": "packages/shared" "directory": "packages/shared"
},
"exports": {
"./getDOMTextNodeFromElement": "./dist/getDOMTextNodeFromElement.js",
"./isImmutableOrInertOrSegmented": "./dist/isImmutableOrInertOrSegmented.js",
"./invariant": "./dist/invariant.js"
} }
} }

View File

@ -124,24 +124,26 @@ async function build(name, inputFile, outputFile) {
plugins: [ plugins: [
alias({ alias({
entries: [ entries: [
{find: 'shared', replacement: path.resolve('packages/shared/dist')}, {find: 'shared', replacement: path.resolve('packages/shared/src')},
// We inline both these helpers to improve the bundle size of the outline-react modules // We inline both these helpers to improve the bundle size of the outline-react modules
{ {
find: isWWW find: isWWW
? 'Outline/SelectionHelpers' ? 'Outline/SelectionHelpers'
: 'outline/SelectionHelpers', : 'outline/SelectionHelpers',
replacement: path.resolve( replacement: path.resolve(
isWWW 'packages/outline/src/helpers/OutlineSelectionHelpers',
? 'packages/outline/dist/OutlineSelectionHelpers.dev' ),
: 'packages/outline/dist/OutlineSelectionHelpers', },
{
find: isWWW ? 'Outline/KeyHelpers' : 'outline/KeyHelpers',
replacement: path.resolve(
'packages/outline/src/helpers/OutlineKeyHelpers',
), ),
}, },
{ {
find: isWWW ? 'Outline/TextHelpers' : 'outline/TextHelpers', find: isWWW ? 'Outline/TextHelpers' : 'outline/TextHelpers',
replacement: path.resolve( replacement: path.resolve(
isWWW 'packages/outline/src/helpers/OutlineTextHelpers',
? 'packages/outline/dist/OutlineTextHelpers.dev'
: 'packages/outline/dist/OutlineTextHelpers',
), ),
}, },
], ],