mirror of
https://github.com/facebook/lexical.git
synced 2025-05-21 00:57:23 +08:00
Add clipboard package, remove lexical event helpers (#1361)
* add clipboard package, remove lexica event helpers * bump version after rebase * rename - wip * rename things
This commit is contained in:
@ -36,7 +36,6 @@ module.name_mapper='^@lexical/helpers/selection' -> '<PROJECT_ROOT>/packages/lex
|
||||
module.name_mapper='^@lexical/helpers/text' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalTextHelpers.js'
|
||||
module.name_mapper='^@lexical/helpers/nodes' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalNodeHelpers.js'
|
||||
module.name_mapper='^@lexical/helpers/elements' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalElementHelpers.js'
|
||||
module.name_mapper='^@lexical/helpers/events' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalEventHelpers.js'
|
||||
module.name_mapper='^@lexical/helpers/offsets' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalOffsetHelpers.js'
|
||||
module.name_mapper='^@lexical/helpers/root' -> '<PROJECT_ROOT>/packages/lexical-helpers/src/LexicalRootHelpers.js'
|
||||
|
||||
|
@ -21,11 +21,11 @@ module.exports = {
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^./dist/(.+)': './src/$1',
|
||||
'^@lexical/clipboard$':
|
||||
'<rootDir>/packages/lexical-clipboard/src/index.js',
|
||||
'^@lexical/file$': '<rootDir>/packages/lexical-file/src/index.js',
|
||||
'^@lexical/helpers/elements$':
|
||||
'<rootDir>/packages/lexical-helpers/src/LexicalElementHelpers.js',
|
||||
'^@lexical/helpers/events$':
|
||||
'<rootDir>/packages/lexical-helpers/src/LexicalEventHelpers.js',
|
||||
'^@lexical/helpers/nodes$':
|
||||
'<rootDir>/packages/lexical-helpers/src/LexicalNodeHelpers.js',
|
||||
'^@lexical/helpers/offsets$':
|
||||
|
11487
package-lock.json
generated
11487
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
3
packages/lexical-clipboard/LexicalClipboard.js
Normal file
3
packages/lexical-clipboard/LexicalClipboard.js
Normal file
@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./dist/LexicalClipboard.js');
|
37
packages/lexical-clipboard/LexicalClipboard.js.flow
Normal file
37
packages/lexical-clipboard/LexicalClipboard.js.flow
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 {
|
||||
LexicalEditor,
|
||||
RangeSelection,
|
||||
} from "lexical";
|
||||
|
||||
/*
|
||||
* Rich Text
|
||||
*/
|
||||
|
||||
|
||||
declare export function $insertDataTransferForRichText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
editor: LexicalEditor,
|
||||
): void;
|
||||
|
||||
declare export function getHtmlContent(editor: LexicalEditor): string;
|
||||
declare export function getLexicalContent(editor: LexicalEditor): string;
|
||||
|
||||
/*
|
||||
* Plain Text
|
||||
*/
|
||||
|
||||
|
||||
declare export function $insertDataTransferForPlainText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
): void;
|
3
packages/lexical-clipboard/README.md
Normal file
3
packages/lexical-clipboard/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@lexical/clipboard`
|
||||
|
||||
This package contains the functionality for the clipboard feature of Lexical.
|
27
packages/lexical-clipboard/package.json
Normal file
27
packages/lexical-clipboard/package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@lexical/clipboard",
|
||||
"author": {
|
||||
"name": "Dominic Gannaway",
|
||||
"email": "dg@domgan.com"
|
||||
},
|
||||
"description": "This package provides the copy/paste functionality for Lexical.",
|
||||
"keywords": [
|
||||
"lexical",
|
||||
"editor",
|
||||
"rich-text",
|
||||
"copy",
|
||||
"paste"
|
||||
],
|
||||
"license": "MIT",
|
||||
"version": "0.1.11",
|
||||
"main": "LexicalClipboard.js",
|
||||
"peerDependencies": {
|
||||
"lexical": "0.1.11",
|
||||
"@lexical/helpers": "0.1.11"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facebook/lexical",
|
||||
"directory": "packages/lexical-clipboard"
|
||||
}
|
||||
}
|
@ -22,19 +22,99 @@ import {$cloneContents} from '@lexical/helpers/selection';
|
||||
import {
|
||||
$createNodeFromParse,
|
||||
$createParagraphNode,
|
||||
$getDecoratorNode,
|
||||
$getSelection,
|
||||
$isDecoratorNode,
|
||||
$isElementNode,
|
||||
$isRangeSelection,
|
||||
} from 'lexical';
|
||||
|
||||
// TODO the Flow types here needs fixing
|
||||
export type EventHandler = (
|
||||
// $FlowFixMe: not sure how to handle this generic properly
|
||||
event: Object,
|
||||
export function getHtmlContent(editor: LexicalEditor): string | null {
|
||||
const domSelection = window.getSelection();
|
||||
// If we haven't selected a range, then don't copy anything
|
||||
if (domSelection.isCollapsed) {
|
||||
return null;
|
||||
}
|
||||
const range = domSelection.getRangeAt(0);
|
||||
if (range) {
|
||||
const container = document.createElement('div');
|
||||
const frag = range.cloneContents();
|
||||
container.appendChild(frag);
|
||||
return container.innerHTML;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function $getLexicalContent(editor: LexicalEditor): string | null {
|
||||
const selection = $getSelection();
|
||||
if (selection !== null) {
|
||||
const namespace = editor._config.namespace;
|
||||
return JSON.stringify({namespace, state: $cloneContents(selection)});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function $insertDataTransferForPlainText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
): void {
|
||||
const text = dataTransfer.getData('text/plain');
|
||||
if (text != null) {
|
||||
selection.insertRawText(text);
|
||||
}
|
||||
}
|
||||
|
||||
export function $insertDataTransferForRichText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
editor: LexicalEditor,
|
||||
) => void;
|
||||
): void {
|
||||
const lexicalNodesString = dataTransfer.getData(
|
||||
'application/x-lexical-editor',
|
||||
);
|
||||
|
||||
if (lexicalNodesString) {
|
||||
const namespace = editor._config.namespace;
|
||||
try {
|
||||
const lexicalClipboardData = JSON.parse(lexicalNodesString);
|
||||
if (lexicalClipboardData.namespace === namespace) {
|
||||
const nodeRange = lexicalClipboardData.state;
|
||||
const nodes = $generateNodes(nodeRange);
|
||||
selection.insertNodes(nodes);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// Malformed, missing nodes..
|
||||
}
|
||||
}
|
||||
|
||||
const textHtmlMimeType = 'text/html';
|
||||
const htmlString = dataTransfer.getData(textHtmlMimeType);
|
||||
|
||||
if (htmlString) {
|
||||
const parser = new DOMParser();
|
||||
const dom = parser.parseFromString(htmlString, textHtmlMimeType);
|
||||
const nodes = $generateNodesFromDOM(dom, editor);
|
||||
// Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
|
||||
const topLevelBlocks = [];
|
||||
let currentBlock = null;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (!$isElementNode(node) || node.isInline()) {
|
||||
if (currentBlock === null) {
|
||||
currentBlock = $createParagraphNode();
|
||||
topLevelBlocks.push(currentBlock);
|
||||
}
|
||||
if (currentBlock !== null) {
|
||||
currentBlock.append(node);
|
||||
}
|
||||
} else {
|
||||
topLevelBlocks.push(node);
|
||||
currentBlock = null;
|
||||
}
|
||||
}
|
||||
selection.insertNodes(topLevelBlocks);
|
||||
return;
|
||||
}
|
||||
$insertDataTransferForPlainText(dataTransfer, selection);
|
||||
}
|
||||
|
||||
function $generateNodes(nodeRange: {
|
||||
nodeMap: ParsedNodeMap,
|
||||
@ -77,7 +157,7 @@ function getConversionFunction(
|
||||
return currentConversion !== null ? currentConversion.conversion : null;
|
||||
}
|
||||
|
||||
export function $createNodesFromDOM(
|
||||
function $createNodesFromDOM(
|
||||
node: Node,
|
||||
editor: LexicalEditor,
|
||||
forChildMap: Map<string, DOMChildConversion> = new Map(),
|
||||
@ -145,191 +225,3 @@ function $generateNodesFromDOM(
|
||||
}
|
||||
return lexicalNodes;
|
||||
}
|
||||
|
||||
export function $insertDataTransferForRichText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
const lexicalNodesString = dataTransfer.getData(
|
||||
'application/x-lexical-editor',
|
||||
);
|
||||
|
||||
if (lexicalNodesString) {
|
||||
const namespace = editor._config.namespace;
|
||||
try {
|
||||
const lexicalClipboardData = JSON.parse(lexicalNodesString);
|
||||
if (lexicalClipboardData.namespace === namespace) {
|
||||
const nodeRange = lexicalClipboardData.state;
|
||||
const nodes = $generateNodes(nodeRange);
|
||||
selection.insertNodes(nodes);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// Malformed, missing nodes..
|
||||
}
|
||||
}
|
||||
|
||||
const textHtmlMimeType = 'text/html';
|
||||
const htmlString = dataTransfer.getData(textHtmlMimeType);
|
||||
|
||||
if (htmlString) {
|
||||
const parser = new DOMParser();
|
||||
const dom = parser.parseFromString(htmlString, textHtmlMimeType);
|
||||
const nodes = $generateNodesFromDOM(dom, editor);
|
||||
// Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
|
||||
const topLevelBlocks = [];
|
||||
let currentBlock = null;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (!$isElementNode(node) || node.isInline()) {
|
||||
if (currentBlock === null) {
|
||||
currentBlock = $createParagraphNode();
|
||||
topLevelBlocks.push(currentBlock);
|
||||
}
|
||||
if (currentBlock !== null) {
|
||||
currentBlock.append(node);
|
||||
}
|
||||
} else {
|
||||
topLevelBlocks.push(node);
|
||||
currentBlock = null;
|
||||
}
|
||||
}
|
||||
selection.insertNodes(topLevelBlocks);
|
||||
return;
|
||||
}
|
||||
$insertDataTransferForPlainText(dataTransfer, selection);
|
||||
}
|
||||
|
||||
export function $insertDataTransferForPlainText(
|
||||
dataTransfer: DataTransfer,
|
||||
selection: RangeSelection,
|
||||
): void {
|
||||
const text = dataTransfer.getData('text/plain');
|
||||
if (text != null) {
|
||||
selection.insertRawText(text);
|
||||
}
|
||||
}
|
||||
|
||||
export function $shouldOverrideDefaultCharacterSelection(
|
||||
selection: RangeSelection,
|
||||
isBackward: boolean,
|
||||
): boolean {
|
||||
const possibleNode = $getDecoratorNode(selection.focus, isBackward);
|
||||
return $isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
||||
}
|
||||
|
||||
export function onPasteForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const clipboardData = event.clipboardData;
|
||||
if (clipboardData != null && $isRangeSelection(selection)) {
|
||||
$insertDataTransferForPlainText(clipboardData, selection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onPasteForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const clipboardData = event.clipboardData;
|
||||
if (clipboardData != null && $isRangeSelection(selection)) {
|
||||
$insertDataTransferForRichText(clipboardData, selection, editor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCutForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
onCopyForPlainText(event, editor);
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection)) {
|
||||
selection.removeText();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCutForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
onCopyForRichText(event, editor);
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection)) {
|
||||
selection.removeText();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCopyForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const clipboardData = event.clipboardData;
|
||||
const selection = $getSelection();
|
||||
if (selection !== null) {
|
||||
if (clipboardData != null) {
|
||||
const domSelection = window.getSelection();
|
||||
// If we haven't selected a range, then don't copy anything
|
||||
if (domSelection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
const range = domSelection.getRangeAt(0);
|
||||
if (range) {
|
||||
const container = document.createElement('div');
|
||||
const frag = range.cloneContents();
|
||||
container.appendChild(frag);
|
||||
clipboardData.setData('text/html', container.innerHTML);
|
||||
}
|
||||
clipboardData.setData('text/plain', selection.getTextContent());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCopyForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const clipboardData = event.clipboardData;
|
||||
const selection = $getSelection();
|
||||
if (selection !== null) {
|
||||
if (clipboardData != null) {
|
||||
const domSelection = window.getSelection();
|
||||
// If we haven't selected a range, then don't copy anything
|
||||
if (domSelection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
const range = domSelection.getRangeAt(0);
|
||||
if (range) {
|
||||
const container = document.createElement('div');
|
||||
const frag = range.cloneContents();
|
||||
container.appendChild(frag);
|
||||
clipboardData.setData('text/html', container.innerHTML);
|
||||
}
|
||||
clipboardData.setData('text/plain', selection.getTextContent());
|
||||
const namespace = editor._config.namespace;
|
||||
clipboardData.setData(
|
||||
'application/x-lexical-editor',
|
||||
JSON.stringify({namespace, state: $cloneContents(selection)}),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
22
packages/lexical-clipboard/src/index.js
Normal file
22
packages/lexical-clipboard/src/index.js
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 {
|
||||
$getLexicalContent,
|
||||
$insertDataTransferForPlainText,
|
||||
$insertDataTransferForRichText,
|
||||
getHtmlContent,
|
||||
} from './clipboard';
|
||||
|
||||
export {
|
||||
$getLexicalContent,
|
||||
$insertDataTransferForPlainText,
|
||||
$insertDataTransferForRichText,
|
||||
getHtmlContent,
|
||||
};
|
@ -19,6 +19,7 @@ import type {
|
||||
} from 'lexical';
|
||||
|
||||
import {
|
||||
$getDecoratorNode,
|
||||
$isDecoratorNode,
|
||||
$isElementNode,
|
||||
$isLeafNode,
|
||||
@ -608,3 +609,11 @@ export function $isAtNodeEnd(point: Point): boolean {
|
||||
}
|
||||
return point.offset === point.getNode().getChildrenSize();
|
||||
}
|
||||
|
||||
export function $shouldOverrideDefaultCharacterSelection(
|
||||
selection: RangeSelection,
|
||||
isBackward: boolean,
|
||||
): boolean {
|
||||
const possibleNode = $getDecoratorNode(selection.focus, isBackward);
|
||||
return $isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ module.exports = {
|
||||
'@lexical/helpers/nodes': '@lexical/helpers/dist/LexicalNodeHelpers',
|
||||
'@lexical/helpers/elements':
|
||||
'@lexical/helpers/dist/LexicalElementHelpers',
|
||||
'@lexical/helpers/events': '@lexical/helpers/dist/LexicalEventHelpers',
|
||||
'@lexical/helpers/file': '@lexical/helpers/dist/LexicalFileHelpers',
|
||||
'@lexical/helpers/offsets': '@lexical/helpers/dist/LexicalOffsetHelpers',
|
||||
'@lexical/helpers/root': '@lexical/helpers/dist/LexicalRootHelpers',
|
||||
@ -37,6 +36,7 @@ module.exports = {
|
||||
'@lexical/list': '@lexical/list/dist/LexicalList.js',
|
||||
'@lexical/table': '@lexical/table/dist/LexicalTable.js',
|
||||
'@lexical/file': '@lexical/file/dist/LexicalFile.js',
|
||||
'@lexical/clipboard': '@lexical/clipboard/dist/LexicalClipboard.js',
|
||||
|
||||
// Lexical React
|
||||
'@lexical/react/LexicalTreeView': '@lexical/react/dist/LexicalTreeView',
|
||||
|
@ -12,6 +12,7 @@
|
||||
"@lexical/list": "0.1.11",
|
||||
"@lexical/table": "0.1.11",
|
||||
"@lexical/file": "0.1.11",
|
||||
"@lexical/clipboard": "0.1.11",
|
||||
"link-preview-generator": "1.0.7",
|
||||
"@craco/craco": "6.1.2",
|
||||
"@excalidraw/excalidraw": "0.11.0",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"@lexical/helpers": "0.1.11",
|
||||
"@lexical/table": "0.1.11",
|
||||
"@lexical/yjs": "0.1.11",
|
||||
"@lexical/clipboard": "0.1.11",
|
||||
"react": ">=17.x",
|
||||
"react-dom": ">=17.x"
|
||||
},
|
||||
|
107
packages/lexical-react/src/shared/clipboardEvents.js
Normal file
107
packages/lexical-react/src/shared/clipboardEvents.js
Normal file
@ -0,0 +1,107 @@
|
||||
import type {LexicalEditor} from 'lexical';
|
||||
|
||||
import {
|
||||
$getLexicalContent,
|
||||
$insertDataTransferForPlainText,
|
||||
$insertDataTransferForRichText,
|
||||
getHtmlContent,
|
||||
} from '@lexical/clipboard';
|
||||
import {$getSelection, $isRangeSelection} from 'lexical';
|
||||
|
||||
export function onPasteForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const clipboardData = event.clipboardData;
|
||||
if (clipboardData != null && $isRangeSelection(selection)) {
|
||||
$insertDataTransferForPlainText(clipboardData, selection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCutForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
onCopyForPlainText(event, editor);
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection)) {
|
||||
selection.removeText();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCopyForPlainText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const clipboardData = event.clipboardData;
|
||||
const selection = $getSelection();
|
||||
if (selection !== null) {
|
||||
if (clipboardData != null) {
|
||||
const htmlString = getHtmlContent(editor);
|
||||
if (htmlString !== null) {
|
||||
clipboardData.setData('text/html', htmlString);
|
||||
}
|
||||
clipboardData.setData('text/plain', selection.getTextContent());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCutForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
onCopyForRichText(event, editor);
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection)) {
|
||||
selection.removeText();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onCopyForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const clipboardData = event.clipboardData;
|
||||
const selection = $getSelection();
|
||||
if (selection !== null) {
|
||||
if (clipboardData != null) {
|
||||
const htmlString = getHtmlContent(editor);
|
||||
const lexicalString = $getLexicalContent(editor);
|
||||
if (htmlString !== null) {
|
||||
clipboardData.setData('text/html', htmlString);
|
||||
}
|
||||
if (lexicalString !== null) {
|
||||
clipboardData.setData('application/x-lexical-editor', lexicalString);
|
||||
}
|
||||
clipboardData.setData('text/plain', selection.getTextContent());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onPasteForRichText(
|
||||
event: ClipboardEvent,
|
||||
editor: LexicalEditor,
|
||||
): void {
|
||||
event.preventDefault();
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const clipboardData = event.clipboardData;
|
||||
if (clipboardData != null && $isRangeSelection(selection)) {
|
||||
$insertDataTransferForRichText(clipboardData, selection, editor);
|
||||
}
|
||||
});
|
||||
}
|
@ -7,8 +7,7 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {EventHandler} from '@lexical/helpers/events';
|
||||
import type {LexicalEditor} from 'lexical';
|
||||
import type {EventHandler, LexicalEditor} from 'lexical';
|
||||
|
||||
import useLayoutEffect from 'shared/useLayoutEffect';
|
||||
|
||||
|
@ -10,17 +10,19 @@
|
||||
import type {InitialEditorStateType} from './PlainRichTextUtils';
|
||||
import type {CommandListenerEditorPriority, LexicalEditor} from 'lexical';
|
||||
|
||||
import {$insertDataTransferForPlainText} from '@lexical/clipboard';
|
||||
import {
|
||||
$insertDataTransferForPlainText,
|
||||
$moveCharacter,
|
||||
$shouldOverrideDefaultCharacterSelection,
|
||||
onCopyForPlainText,
|
||||
onCutForPlainText,
|
||||
onPasteForPlainText,
|
||||
} from '@lexical/helpers/events';
|
||||
import {$moveCharacter} from '@lexical/helpers/selection';
|
||||
} from '@lexical/helpers/selection';
|
||||
import {$getSelection, $isRangeSelection} from 'lexical';
|
||||
import {useEffect} from 'react';
|
||||
|
||||
import {
|
||||
onCopyForPlainText,
|
||||
onCutForPlainText,
|
||||
onPasteForPlainText,
|
||||
} from './clipboardEvents';
|
||||
import {initializeEditor} from './PlainRichTextUtils';
|
||||
import useLexicalDragonSupport from './useLexicalDragonSupport';
|
||||
|
||||
|
@ -15,14 +15,11 @@ import type {
|
||||
TextFormatType,
|
||||
} from 'lexical';
|
||||
|
||||
import {$insertDataTransferForRichText} from '@lexical/clipboard';
|
||||
import {
|
||||
$insertDataTransferForRichText,
|
||||
$moveCharacter,
|
||||
$shouldOverrideDefaultCharacterSelection,
|
||||
onCopyForRichText,
|
||||
onCutForRichText,
|
||||
onPasteForRichText,
|
||||
} from '@lexical/helpers/events';
|
||||
import {$moveCharacter} from '@lexical/helpers/selection';
|
||||
} from '@lexical/helpers/selection';
|
||||
import {
|
||||
$getSelection,
|
||||
$isElementNode,
|
||||
@ -31,6 +28,11 @@ import {
|
||||
} from 'lexical';
|
||||
import {useLayoutEffect} from 'react';
|
||||
|
||||
import {
|
||||
onCopyForRichText,
|
||||
onCutForRichText,
|
||||
onPasteForRichText,
|
||||
} from './clipboardEvents';
|
||||
import {initializeEditor} from './PlainRichTextUtils';
|
||||
import useLexicalDragonSupport from './useLexicalDragonSupport';
|
||||
|
||||
|
@ -930,6 +930,14 @@ declare export function $getDecoratorNode(
|
||||
isBackward: boolean,
|
||||
): null | LexicalNode;
|
||||
|
||||
// TODO the Flow types here needs fixing
|
||||
export type EventHandler = (
|
||||
// $FlowFixMe: not sure how to handle this generic properly
|
||||
event: Object,
|
||||
editor: LexicalEditor,
|
||||
) => void;
|
||||
|
||||
|
||||
/**
|
||||
* LexicalVersion
|
||||
*/
|
||||
|
@ -52,10 +52,12 @@ if (isClean) {
|
||||
fs.removeSync(path.resolve('./packages/lexical-list/dist'));
|
||||
fs.removeSync(path.resolve('./packages/lexical-table/dist'));
|
||||
fs.removeSync(path.resolve('./packages/lexical-file/dist'));
|
||||
fs.removeSync(path.resolve('./packages/lexical-clipboard/dist'));
|
||||
fs.removeSync(path.resolve('./packages/lexical-yjs/dist'));
|
||||
}
|
||||
|
||||
const wwwMappings = {
|
||||
'@lexical/clipboard': 'LexicalClipboard',
|
||||
'@lexical/file': 'LexicalFile',
|
||||
'@lexical/list': 'LexicalList',
|
||||
'@lexical/table': 'LexicalTable',
|
||||
@ -107,6 +109,7 @@ const externals = [
|
||||
'@lexical/list',
|
||||
'@lexical/table',
|
||||
'@lexical/file',
|
||||
'@lexical/clipboard',
|
||||
'@lexical/yjs',
|
||||
'react-dom',
|
||||
'react',
|
||||
@ -188,12 +191,6 @@ async function build(name, inputFile, outputFile, isProd) {
|
||||
'packages/lexical-helpers/src/LexicalTextHelpers',
|
||||
),
|
||||
},
|
||||
{
|
||||
find: '@lexical/helpers/events',
|
||||
replacement: path.resolve(
|
||||
'packages/lexical-helpers/src/LexicalEventHelpers',
|
||||
),
|
||||
},
|
||||
{
|
||||
find: '@lexical/helpers/offsets',
|
||||
replacement: path.resolve(
|
||||
@ -365,6 +362,17 @@ const packages = [
|
||||
outputPath: './packages/lexical-file/dist/',
|
||||
sourcePath: './packages/lexical-file/src/',
|
||||
},
|
||||
{
|
||||
modules: [
|
||||
{
|
||||
outputFileName: 'LexicalClipboard',
|
||||
sourceFileName: 'index.js',
|
||||
},
|
||||
],
|
||||
name: 'Lexical File',
|
||||
outputPath: './packages/lexical-clipboard/dist/',
|
||||
sourcePath: './packages/lexical-clipboard/src/',
|
||||
},
|
||||
{
|
||||
modules: lexicalNodes.map((module) => ({
|
||||
name: module,
|
||||
|
@ -10,6 +10,7 @@ const DEFAULT_PKGS = [
|
||||
'lexical-list',
|
||||
'lexical-table',
|
||||
'lexical-file',
|
||||
'lexical-clipboard',
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
|
@ -93,9 +93,6 @@ async function prepareLexicalHelpersPackage() {
|
||||
await exec(
|
||||
`mv ./packages/${LEXICAL_HELPERS_PKG}/npm/LexicalTextHelpers.js ./packages/${LEXICAL_HELPERS_PKG}/npm/text.js`,
|
||||
);
|
||||
await exec(
|
||||
`mv ./packages/${LEXICAL_HELPERS_PKG}/npm/LexicalEventHelpers.js ./packages/${LEXICAL_HELPERS_PKG}/npm/events.js`,
|
||||
);
|
||||
await exec(
|
||||
`mv ./packages/${LEXICAL_HELPERS_PKG}/npm/LexicalOffsetHelpers.js ./packages/${LEXICAL_HELPERS_PKG}/npm/offsets.js`,
|
||||
);
|
||||
|
@ -10,6 +10,7 @@
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const packages = {
|
||||
'@lexical/clipboard': 'lexical-clipboard',
|
||||
'@lexical/file': 'lexical-file',
|
||||
'@lexical/helpers': 'lexical-helpers',
|
||||
'@lexical/list': 'lexical-list',
|
||||
|
Reference in New Issue
Block a user