]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/lexical/core/nodes/__tests__/unit/LexicalTabNode.test.ts
d8525fb369f901c8af1451314dd3492380a67965
[bookstack] / resources / js / wysiwyg / lexical / core / nodes / __tests__ / unit / LexicalTabNode.test.ts
1 /**
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8
9 import {
10   $insertDataTransferForPlainText,
11   $insertDataTransferForRichText,
12 } from '@lexical/clipboard';
13 import {$createListItemNode, $createListNode} from '@lexical/list';
14 import {$createHeadingNode, registerRichText} from '@lexical/rich-text';
15 import {
16   $createParagraphNode,
17   $createRangeSelection,
18   $createTabNode,
19   $createTextNode,
20   $getRoot,
21   $getSelection,
22   $insertNodes,
23   $isElementNode,
24   $isRangeSelection,
25   $isTextNode,
26   $setSelection,
27   KEY_TAB_COMMAND,
28 } from 'lexical';
29
30 import {
31   DataTransferMock,
32   initializeUnitTest,
33   invariant,
34 } from '../../../__tests__/utils';
35
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);
44         paragraph.select();
45       });
46     });
47
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);
56       });
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>',
59       );
60     });
61
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);
70       });
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>',
73       );
74     });
75
76     // TODO fixme
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(
82     //         'text/html',
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>`,
85     //       );
86     //       await editor.update(() => {
87     //         const selection = $getSelection();
88     //         invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
89     //         $insertDataTransferForRichText(dataTransfer, selection, editor);
90     //       });
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>',
93     //       );
94     // });
95
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(
101         'text/html',
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>`,
103       );
104       await editor.update(() => {
105         const selection = $getSelection();
106         invariant($isRangeSelection(selection), 'isRangeSelection(selection)');
107         $insertDataTransferForRichText(dataTransfer, selection, editor);
108       });
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>',
111       );
112     });
113
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]);
120         tab1.select(1, 1);
121         $getSelection()!.insertText('f');
122       });
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>',
125       );
126     });
127   });
128 });