From 1267690497cec2ab6caf49ff632e3fb203e7afba Mon Sep 17 00:00:00 2001 From: Aron Griffis Date: Fri, 8 Dec 2023 08:36:35 -0500 Subject: [PATCH 1/2] refactor(playground): kill disused TableNode.tsx This was missed in #5237 because of ts-ignore. --- .../src/nodes/TableNode.tsx | 424 ------------------ 1 file changed, 424 deletions(-) delete mode 100644 packages/lexical-playground/src/nodes/TableNode.tsx diff --git a/packages/lexical-playground/src/nodes/TableNode.tsx b/packages/lexical-playground/src/nodes/TableNode.tsx deleted file mode 100644 index 03941110b33..00000000000 --- a/packages/lexical-playground/src/nodes/TableNode.tsx +++ /dev/null @@ -1,424 +0,0 @@ -/** - * 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. - * - */ - -import type { - DOMConversionMap, - DOMConversionOutput, - DOMExportOutput, - EditorConfig, - LexicalEditor, - LexicalNode, - NodeKey, - SerializedLexicalNode, - Spread, -} from 'lexical'; - -import {DecoratorNode} from 'lexical'; -import * as React from 'react'; -import {Suspense} from 'react'; - -export type Cell = { - colSpan: number; - json: string; - type: 'normal' | 'header'; - id: string; - width: number | null; -}; - -export type Row = { - cells: Array; - height: null | number; - id: string; -}; - -export type Rows = Array; - -export const cellHTMLCache: Map = new Map(); -export const cellTextContentCache: Map = new Map(); - -const emptyEditorJSON = - '{"root":{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'; - -const plainTextEditorJSON = (text: string) => - text === '' - ? emptyEditorJSON - : `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":${text},"type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`; - -const TableComponent = React.lazy( - // @ts-ignore - () => import('./TableComponent'), -); - -export function createUID(): string { - return Math.random() - .toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 5); -} - -function createCell(type: 'normal' | 'header'): Cell { - return { - colSpan: 1, - id: createUID(), - json: emptyEditorJSON, - type, - width: null, - }; -} - -export function createRow(): Row { - return { - cells: [], - height: null, - id: createUID(), - }; -} - -export type SerializedTableNode = Spread< - { - rows: Rows; - }, - SerializedLexicalNode ->; - -export function extractRowsFromHTML(tableElem: HTMLTableElement): Rows { - const rowElems = tableElem.querySelectorAll('tr'); - const rows: Rows = []; - for (let y = 0; y < rowElems.length; y++) { - const rowElem = rowElems[y]; - const cellElems = rowElem.querySelectorAll('td,th'); - if (!cellElems || cellElems.length === 0) { - continue; - } - const cells: Array = []; - for (let x = 0; x < cellElems.length; x++) { - const cellElem = cellElems[x] as HTMLElement; - const isHeader = cellElem.nodeName === 'TH'; - const cell = createCell(isHeader ? 'header' : 'normal'); - cell.json = plainTextEditorJSON( - JSON.stringify(cellElem.innerText.replace(/\n/g, ' ')), - ); - cells.push(cell); - } - const row = createRow(); - row.cells = cells; - rows.push(row); - } - return rows; -} - -function convertTableElement(domNode: HTMLElement): null | DOMConversionOutput { - const rowElems = domNode.querySelectorAll('tr'); - if (!rowElems || rowElems.length === 0) { - return null; - } - const rows: Rows = []; - for (let y = 0; y < rowElems.length; y++) { - const rowElem = rowElems[y]; - const cellElems = rowElem.querySelectorAll('td,th'); - if (!cellElems || cellElems.length === 0) { - continue; - } - const cells: Array = []; - for (let x = 0; x < cellElems.length; x++) { - const cellElem = cellElems[x] as HTMLElement; - const isHeader = cellElem.nodeName === 'TH'; - const cell = createCell(isHeader ? 'header' : 'normal'); - cell.json = plainTextEditorJSON( - JSON.stringify(cellElem.innerText.replace(/\n/g, ' ')), - ); - cells.push(cell); - } - const row = createRow(); - row.cells = cells; - rows.push(row); - } - return {node: $createTableNode(rows)}; -} - -export function exportTableCellsToHTML( - rows: Rows, - rect?: {startX: number; endX: number; startY: number; endY: number}, -): HTMLElement { - const table = document.createElement('table'); - const colGroup = document.createElement('colgroup'); - const tBody = document.createElement('tbody'); - const firstRow = rows[0]; - - for ( - let x = rect != null ? rect.startX : 0; - x < (rect != null ? rect.endX + 1 : firstRow.cells.length); - x++ - ) { - const col = document.createElement('col'); - colGroup.append(col); - } - - for ( - let y = rect != null ? rect.startY : 0; - y < (rect != null ? rect.endY + 1 : rows.length); - y++ - ) { - const row = rows[y]; - const cells = row.cells; - const rowElem = document.createElement('tr'); - - for ( - let x = rect != null ? rect.startX : 0; - x < (rect != null ? rect.endX + 1 : cells.length); - x++ - ) { - const cell = cells[x]; - const cellElem = document.createElement( - cell.type === 'header' ? 'th' : 'td', - ); - cellElem.innerHTML = cellHTMLCache.get(cell.json) || ''; - rowElem.appendChild(cellElem); - } - tBody.appendChild(rowElem); - } - - table.appendChild(colGroup); - table.appendChild(tBody); - return table; -} - -export class TableNode extends DecoratorNode { - __rows: Rows; - - static getType(): string { - return 'tablesheet'; - } - - static clone(node: TableNode): TableNode { - return new TableNode(Array.from(node.__rows), node.__key); - } - - static importJSON(serializedNode: SerializedTableNode): TableNode { - return $createTableNode(serializedNode.rows); - } - - exportJSON(): SerializedTableNode { - return { - rows: this.__rows, - type: 'tablesheet', - version: 1, - }; - } - - static importDOM(): DOMConversionMap | null { - return { - table: (_node: Node) => ({ - conversion: convertTableElement, - priority: 0, - }), - }; - } - - exportDOM(): DOMExportOutput { - return {element: exportTableCellsToHTML(this.__rows)}; - } - - constructor(rows?: Rows, key?: NodeKey) { - super(key); - this.__rows = rows || []; - } - - createDOM(): HTMLElement { - return document.createElement('div'); - } - - updateDOM(): false { - return false; - } - - mergeRows(startX: number, startY: number, mergeRows: Rows): void { - const self = this.getWritable(); - const rows = self.__rows; - const endY = Math.min(rows.length, startY + mergeRows.length); - for (let y = startY; y < endY; y++) { - const row = rows[y]; - const mergeRow = mergeRows[y - startY]; - const cells = row.cells; - const cellsClone = Array.from(cells); - const rowClone = {...row, cells: cellsClone}; - const mergeCells = mergeRow.cells; - const endX = Math.min(cells.length, startX + mergeCells.length); - for (let x = startX; x < endX; x++) { - const cell = cells[x]; - const mergeCell = mergeCells[x - startX]; - const cellClone = {...cell, json: mergeCell.json, type: mergeCell.type}; - cellsClone[x] = cellClone; - } - rows[y] = rowClone; - } - } - - updateCellJSON(x: number, y: number, json: string): void { - const self = this.getWritable(); - const rows = self.__rows; - const row = rows[y]; - const cells = row.cells; - const cell = cells[x]; - const cellsClone = Array.from(cells); - const cellClone = {...cell, json}; - const rowClone = {...row, cells: cellsClone}; - cellsClone[x] = cellClone; - rows[y] = rowClone; - } - - updateCellType(x: number, y: number, type: 'header' | 'normal'): void { - const self = this.getWritable(); - const rows = self.__rows; - const row = rows[y]; - const cells = row.cells; - const cell = cells[x]; - const cellsClone = Array.from(cells); - const cellClone = {...cell, type}; - const rowClone = {...row, cells: cellsClone}; - cellsClone[x] = cellClone; - rows[y] = rowClone; - } - - insertColumnAt(x: number): void { - const self = this.getWritable(); - const rows = self.__rows; - for (let y = 0; y < rows.length; y++) { - const row = rows[y]; - const cells = row.cells; - const cellsClone = Array.from(cells); - const rowClone = {...row, cells: cellsClone}; - const type = (cells[x] || cells[x - 1]).type; - cellsClone.splice(x, 0, createCell(type)); - rows[y] = rowClone; - } - } - - deleteColumnAt(x: number): void { - const self = this.getWritable(); - const rows = self.__rows; - for (let y = 0; y < rows.length; y++) { - const row = rows[y]; - const cells = row.cells; - const cellsClone = Array.from(cells); - const rowClone = {...row, cells: cellsClone}; - cellsClone.splice(x, 1); - rows[y] = rowClone; - } - } - - addColumns(count: number): void { - const self = this.getWritable(); - const rows = self.__rows; - for (let y = 0; y < rows.length; y++) { - const row = rows[y]; - const cells = row.cells; - const cellsClone = Array.from(cells); - const rowClone = {...row, cells: cellsClone}; - const type = cells[cells.length - 1].type; - for (let x = 0; x < count; x++) { - cellsClone.push(createCell(type)); - } - rows[y] = rowClone; - } - } - - insertRowAt(y: number): void { - const self = this.getWritable(); - const rows = self.__rows; - const prevRow = rows[y] || rows[y - 1]; - const cellCount = prevRow.cells.length; - const row = createRow(); - for (let x = 0; x < cellCount; x++) { - const cell = createCell(prevRow.cells[x].type); - row.cells.push(cell); - } - rows.splice(y, 0, row); - } - - deleteRowAt(y: number): void { - const self = this.getWritable(); - const rows = self.__rows; - rows.splice(y, 1); - } - - addRows(count: number): void { - const self = this.getWritable(); - const rows = self.__rows; - const prevRow = rows[rows.length - 1]; - const cellCount = prevRow.cells.length; - - for (let y = 0; y < count; y++) { - const row = createRow(); - for (let x = 0; x < cellCount; x++) { - const cell = createCell(prevRow.cells[x].type); - row.cells.push(cell); - } - rows.push(row); - } - } - - updateColumnWidth(x: number, width: number): void { - const self = this.getWritable(); - const rows = self.__rows; - for (let y = 0; y < rows.length; y++) { - const row = rows[y]; - const cells = row.cells; - const cellsClone = Array.from(cells); - const rowClone = {...row, cells: cellsClone}; - cellsClone[x].width = width; - rows[y] = rowClone; - } - } - - decorate(_: LexicalEditor, config: EditorConfig): JSX.Element { - return ( - - - - ); - } - - isInline(): false { - return false; - } -} - -export function $isTableNode( - node: LexicalNode | null | undefined, -): node is TableNode { - return node instanceof TableNode; -} - -export function $createTableNode(rows: Rows): TableNode { - return new TableNode(rows); -} - -export function $createTableNodeWithDimensions( - rowCount: number, - columnCount: number, - includeHeaders = true, -): TableNode { - const rows: Rows = []; - for (let y = 0; y < columnCount; y++) { - const row: Row = createRow(); - rows.push(row); - for (let x = 0; x < rowCount; x++) { - row.cells.push( - createCell( - includeHeaders === true && (y === 0 || x === 0) ? 'header' : 'normal', - ), - ); - } - } - return new TableNode(rows); -} From 150354fe9b1ad4cebf1f919efbe6486902383b65 Mon Sep 17 00:00:00 2001 From: Aron Griffis Date: Wed, 6 Dec 2023 08:17:10 -0500 Subject: [PATCH 2/2] refactor(playground): kill ts-ignore Replace with ts-expect-error where still needed. --- packages/lexical-playground/src/Editor.tsx | 2 +- packages/lexical-playground/src/collaboration.ts | 2 +- packages/lexical-playground/src/commenting/index.ts | 4 ++-- packages/lexical-playground/src/nodes/EquationNode.tsx | 5 +---- .../lexical-playground/src/nodes/ExcalidrawNode/index.tsx | 5 +---- packages/lexical-playground/src/nodes/ImageNode.tsx | 5 +---- packages/lexical-playground/src/nodes/PollNode.tsx | 5 +---- packages/lexical-playground/src/nodes/StickyNode.tsx | 5 +---- .../src/plugins/CollapsiblePlugin/index.ts | 5 +++-- .../src/plugins/ContextMenuPlugin/index.tsx | 4 ++-- .../src/plugins/EmojiPickerPlugin/index.tsx | 3 +-- .../src/plugins/SpeechToTextPlugin/index.ts | 2 +- packages/lexical-playground/src/server/validation.ts | 3 +-- 13 files changed, 17 insertions(+), 33 deletions(-) diff --git a/packages/lexical-playground/src/Editor.tsx b/packages/lexical-playground/src/Editor.tsx index f54a7ee3cc6..af278d36820 100644 --- a/packages/lexical-playground/src/Editor.tsx +++ b/packages/lexical-playground/src/Editor.tsx @@ -72,7 +72,7 @@ import ContentEditable from './ui/ContentEditable'; import Placeholder from './ui/Placeholder'; const skipCollaborationInit = - // @ts-ignore + // @ts-expect-error window.parent != null && window.parent.frames.right === window; export default function Editor(): JSX.Element { diff --git a/packages/lexical-playground/src/collaboration.ts b/packages/lexical-playground/src/collaboration.ts index 618ebd5c8c9..ca22311cdef 100644 --- a/packages/lexical-playground/src/collaboration.ts +++ b/packages/lexical-playground/src/collaboration.ts @@ -31,7 +31,7 @@ export function createWebsocketProvider( doc.load(); } - // @ts-ignore + // @ts-expect-error return new WebsocketProvider( WEBSOCKET_ENDPOINT, WEBSOCKET_SLUG + '/' + WEBSOCKET_ID + '/' + id, diff --git a/packages/lexical-playground/src/commenting/index.ts b/packages/lexical-playground/src/commenting/index.ts index 4b8ab2de5ff..9182a2599ca 100644 --- a/packages/lexical-playground/src/commenting/index.ts +++ b/packages/lexical-playground/src/commenting/index.ts @@ -230,7 +230,7 @@ export class CommentStore { _withRemoteTransaction(fn: () => void): void { const provider = this._collabProvider; if (provider !== null) { - // @ts-ignore doc does exist + // @ts-expect-error doc does exist const doc = provider.doc; doc.transact(fn, this); } @@ -250,7 +250,7 @@ export class CommentStore { _getCollabComments(): null | YArray { const provider = this._collabProvider; if (provider !== null) { - // @ts-ignore doc does exist + // @ts-expect-error doc does exist const doc = provider.doc; // eslint-disable-next-line @typescript-eslint/no-explicit-any return doc.get('comments', YArray) as YArray; diff --git a/packages/lexical-playground/src/nodes/EquationNode.tsx b/packages/lexical-playground/src/nodes/EquationNode.tsx index 1ad46a62b1a..e00545ebfc2 100644 --- a/packages/lexical-playground/src/nodes/EquationNode.tsx +++ b/packages/lexical-playground/src/nodes/EquationNode.tsx @@ -21,10 +21,7 @@ import {$applyNodeReplacement, DecoratorNode, DOMExportOutput} from 'lexical'; import * as React from 'react'; import {Suspense} from 'react'; -const EquationComponent = React.lazy( - // @ts-ignore - () => import('./EquationComponent'), -); +const EquationComponent = React.lazy(() => import('./EquationComponent')); export type SerializedEquationNode = Spread< { diff --git a/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx b/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx index 6f6c20f2cbe..b190fc056c2 100644 --- a/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx +++ b/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx @@ -22,10 +22,7 @@ import {DecoratorNode} from 'lexical'; import * as React from 'react'; import {Suspense} from 'react'; -const ExcalidrawComponent = React.lazy( - // @ts-ignore - () => import('./ExcalidrawComponent'), -); +const ExcalidrawComponent = React.lazy(() => import('./ExcalidrawComponent')); export type SerializedExcalidrawNode = Spread< { diff --git a/packages/lexical-playground/src/nodes/ImageNode.tsx b/packages/lexical-playground/src/nodes/ImageNode.tsx index 6d978b6385b..129fff65811 100644 --- a/packages/lexical-playground/src/nodes/ImageNode.tsx +++ b/packages/lexical-playground/src/nodes/ImageNode.tsx @@ -23,10 +23,7 @@ import {$applyNodeReplacement, createEditor, DecoratorNode} from 'lexical'; import * as React from 'react'; import {Suspense} from 'react'; -const ImageComponent = React.lazy( - // @ts-ignore - () => import('./ImageComponent'), -); +const ImageComponent = React.lazy(() => import('./ImageComponent')); export interface ImagePayload { altText: string; diff --git a/packages/lexical-playground/src/nodes/PollNode.tsx b/packages/lexical-playground/src/nodes/PollNode.tsx index 98e0566c3f8..1bce4ac5671 100644 --- a/packages/lexical-playground/src/nodes/PollNode.tsx +++ b/packages/lexical-playground/src/nodes/PollNode.tsx @@ -27,10 +27,7 @@ export type Option = Readonly<{ votes: Array; }>; -const PollComponent = React.lazy( - // @ts-ignore - () => import('./PollComponent'), -); +const PollComponent = React.lazy(() => import('./PollComponent')); function createUID(): string { return Math.random() diff --git a/packages/lexical-playground/src/nodes/StickyNode.tsx b/packages/lexical-playground/src/nodes/StickyNode.tsx index 5d13fae80de..883974ee48e 100644 --- a/packages/lexical-playground/src/nodes/StickyNode.tsx +++ b/packages/lexical-playground/src/nodes/StickyNode.tsx @@ -21,10 +21,7 @@ import * as React from 'react'; import {Suspense} from 'react'; import {createPortal} from 'react-dom'; -const StickyComponent = React.lazy( - // @ts-ignore - () => import('./StickyComponent'), -); +const StickyComponent = React.lazy(() => import('./StickyComponent')); type StickyNoteColor = 'pink' | 'yellow'; diff --git a/packages/lexical-playground/src/plugins/CollapsiblePlugin/index.ts b/packages/lexical-playground/src/plugins/CollapsiblePlugin/index.ts index eb3c3f6d1fc..c5d9db4e015 100644 --- a/packages/lexical-playground/src/plugins/CollapsiblePlugin/index.ts +++ b/packages/lexical-playground/src/plugins/CollapsiblePlugin/index.ts @@ -235,8 +235,9 @@ export default function CollapsiblePlugin(): null { editor.registerCommand( INSERT_PARAGRAPH_COMMAND, () => { - // @ts-ignore - const windowEvent: KeyboardEvent | undefined = editor._window?.event; + const windowEvent = editor._window?.event as + | KeyboardEvent + | undefined; if ( windowEvent && diff --git a/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx index e4acd6684f0..f4b052d112f 100644 --- a/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx @@ -124,7 +124,7 @@ export default function ContextMenuPlugin(): JSX.Element { const item = items[0]; const permission = await navigator.permissions.query({ - // @ts-ignore These types are incorrect. + // @ts-expect-error These types are incorrect. name: 'clipboard-read', }); if (permission.state === 'denied') { @@ -149,7 +149,7 @@ export default function ContextMenuPlugin(): JSX.Element { onSelect: (_node) => { navigator.clipboard.read().then(async (...args) => { const permission = await navigator.permissions.query({ - // @ts-ignore These types are incorrect. + // @ts-expect-error These types are incorrect. name: 'clipboard-read', }); diff --git a/packages/lexical-playground/src/plugins/EmojiPickerPlugin/index.tsx b/packages/lexical-playground/src/plugins/EmojiPickerPlugin/index.tsx index 05e7c5660ce..8e930e3a021 100644 --- a/packages/lexical-playground/src/plugins/EmojiPickerPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/EmojiPickerPlugin/index.tsx @@ -94,8 +94,7 @@ export default function EmojiPickerPlugin() { const [emojis, setEmojis] = useState>([]); useEffect(() => { - // @ts-ignore - import('../../utils/emoji-list.ts').then((file) => setEmojis(file.default)); + import('../../utils/emoji-list').then((file) => setEmojis(file.default)); }, []); const emojiOptions = useMemo( diff --git a/packages/lexical-playground/src/plugins/SpeechToTextPlugin/index.ts b/packages/lexical-playground/src/plugins/SpeechToTextPlugin/index.ts index fc19d3cbb07..be076a4d9af 100644 --- a/packages/lexical-playground/src/plugins/SpeechToTextPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/SpeechToTextPlugin/index.ts @@ -49,7 +49,7 @@ function SpeechToTextPlugin(): null { const [editor] = useLexicalComposerContext(); const [isEnabled, setIsEnabled] = useState(false); const SpeechRecognition = - // @ts-ignore + // @ts-expect-error missing type window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = useRef(null); const report = useReport(); diff --git a/packages/lexical-playground/src/server/validation.ts b/packages/lexical-playground/src/server/validation.ts index 026d7973a78..180e49a677c 100644 --- a/packages/lexical-playground/src/server/validation.ts +++ b/packages/lexical-playground/src/server/validation.ts @@ -90,8 +90,7 @@ const validateEditorState = async ( }; const server = http.createServer(async (req, res) => { - // @ts-ignore - const pathname = url.parse(req.url).pathname; + const pathname = url.parse(req.url!).pathname; const {method} = req; res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*');