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 {$createHeadingNode, registerRichText} from '@lexical/rich-text';
17 $createRangeSelection,
34 } from '../../../__tests__/utils';
36 describe('LexicalTabNode tests', () => {
37 initializeUnitTest((testEnv) => {
38 beforeEach(async () => {
39 const {editor} = testEnv;
40 await editor.update(() => {
41 const root = $getRoot();
42 const paragraph = $createParagraphNode();
43 root.append(paragraph);
48 test('can paste plain text with tabs and newlines in plain text', async () => {
49 const {editor} = testEnv;
50 const dataTransfer = new DataTransferMock();
51 dataTransfer.setData('text/plain', 'hello\tworld\nhello\tworld');
52 await editor.update(() => {
53 const selection = $getSelection();
54 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
55 $insertDataTransferForPlainText(dataTransfer, selection);
57 expect(testEnv.innerHTML).toBe(
58 '<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>',
62 test('can paste plain text with tabs and newlines in rich text', async () => {
63 const {editor} = testEnv;
64 const dataTransfer = new DataTransferMock();
65 dataTransfer.setData('text/plain', 'hello\tworld\nhello\tworld');
66 await editor.update(() => {
67 const selection = $getSelection();
68 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
69 $insertDataTransferForRichText(dataTransfer, selection, editor);
71 expect(testEnv.innerHTML).toBe(
72 '<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>',
77 // test('can paste HTML with tabs and new lines #4429', async () => {
78 // const {editor} = testEnv;
79 // const dataTransfer = new DataTransferMock();
80 // // https://codepen.io/zurfyx/pen/bGmrzMR
81 // dataTransfer.setData(
83 // `<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
84 // hello world</span>`,
86 // await editor.update(() => {
87 // const selection = $getSelection();
88 // invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
89 // $insertDataTransferForRichText(dataTransfer, selection, editor);
91 // expect(testEnv.innerHTML).toBe(
92 // '<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>',
96 test('can paste HTML with tabs and new lines (2)', async () => {
97 const {editor} = testEnv;
98 const dataTransfer = new DataTransferMock();
99 // GDoc 2-liner hello\tworld (like previous test)
100 dataTransfer.setData(
102 `<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>`,
104 await editor.update(() => {
105 const selection = $getSelection();
106 invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
107 $insertDataTransferForRichText(dataTransfer, selection, editor);
109 expect(testEnv.innerHTML).toBe(
110 '<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>',
114 test('can type between two (leaf nodes) canInsertBeforeAfter false', async () => {
115 const {editor} = testEnv;
116 await editor.update(() => {
117 const tab1 = $createTabNode();
118 const tab2 = $createTabNode();
119 $insertNodes([tab1, tab2]);
121 $getSelection()!.insertText('f');
123 expect(testEnv.innerHTML).toBe(
124 '<p><span data-lexical-text="true">\t</span><span data-lexical-text="true">f</span><span data-lexical-text="true">\t</span></p>',