2 * Copyright (c) Meta Platforms, Inc. and affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
10 $insertDataTransferForPlainText,
11 $insertDataTransferForRichText,
12 } from '@lexical/clipboard';
13 import {$createListItemNode, $createListNode} from '@lexical/list';
14 import {registerRichText} from '@lexical/rich-text';
17 $createRangeSelection,
34 } from '../../../__tests__/utils';
35 import {$createHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
37 describe('LexicalTabNode tests', () => {
38 initializeUnitTest((testEnv) => {
39 beforeEach(async () => {
40 const {editor} = testEnv;
41 await editor.update(() => {
42 const root = $getRoot();
43 const paragraph = $createParagraphNode();
44 root.append(paragraph);
49 test('can paste plain text with tabs and newlines in plain text', async () => {
50 const {editor} = testEnv;
51 const dataTransfer = new DataTransferMock();
52 dataTransfer.setData('text/plain', 'hello\tworld\nhello\tworld');
53 await editor.update(() => {
54 const selection = $getSelection();
55 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
56 $insertDataTransferForPlainText(dataTransfer, selection);
58 expect(testEnv.innerHTML).toBe(
59 '<p><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span><br><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span></p>',
63 test('can paste plain text with tabs and newlines in rich text', async () => {
64 const {editor} = testEnv;
65 const dataTransfer = new DataTransferMock();
66 dataTransfer.setData('text/plain', 'hello\tworld\nhello\tworld');
67 await editor.update(() => {
68 const selection = $getSelection();
69 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
70 $insertDataTransferForRichText(dataTransfer, selection, editor);
72 expect(testEnv.innerHTML).toBe(
73 '<p><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span></p><p><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span></p>',
78 // test('can paste HTML with tabs and new lines #4429', async () => {
79 // const {editor} = testEnv;
80 // const dataTransfer = new DataTransferMock();
81 // // https://codepen.io/zurfyx/pen/bGmrzMR
82 // dataTransfer.setData(
84 // `<meta charset='utf-8'><span style="color: rgb(0, 0, 0); font-family: Times; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">hello world
85 // hello world</span>`,
87 // await editor.update(() => {
88 // const selection = $getSelection();
89 // invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
90 // $insertDataTransferForRichText(dataTransfer, selection, editor);
92 // expect(testEnv.innerHTML).toBe(
93 // '<p><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span><br><span data-lexical-text="true">hello</span><span data-lexical-text="true">\t</span><span data-lexical-text="true">world</span></p>',
97 test('can paste HTML with tabs and new lines (2)', async () => {
98 const {editor} = testEnv;
99 const dataTransfer = new DataTransferMock();
100 // GDoc 2-liner hello\tworld (like previous test)
101 dataTransfer.setData(
103 `<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-123"><p style="line-height:1.38;margin-left: 36pt;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Hello</span><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"><span class="Apple-tab-span" style="white-space:pre;"> </span></span><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">world</span></p><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Hello</span><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"><span class="Apple-tab-span" style="white-space:pre;"> </span></span><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">world</span></b>`,
105 await editor.update(() => {
106 const selection = $getSelection();
107 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
108 $insertDataTransferForRichText(dataTransfer, selection, editor);
110 expect(testEnv.innerHTML).toBe(
111 '<p><span style="color: rgb(0, 0, 0);" data-lexical-text="true">Hello</span><span data-lexical-text="true">\t</span><span style="color: rgb(0, 0, 0);" data-lexical-text="true">world</span></p><p><span style="color: rgb(0, 0, 0);" data-lexical-text="true">Hello</span><span data-lexical-text="true">\t</span><span style="color: rgb(0, 0, 0);" data-lexical-text="true">world</span></p>',
115 test('can type between two (leaf nodes) canInsertBeforeAfter false', async () => {
116 const {editor} = testEnv;
117 await editor.update(() => {
118 const tab1 = $createTabNode();
119 const tab2 = $createTabNode();
120 $insertNodes([tab1, tab2]);
122 $getSelection()!.insertText('f');
124 expect(testEnv.innerHTML).toBe(
125 '<p><span data-lexical-text="true">\t</span><span data-lexical-text="true">f</span><span data-lexical-text="true">\t</span></p>',